聊聊webpack

随着前端的迅速发展,web项目复杂度也是越来越高。为了便捷开发和利于优化,将一个复杂项目拆分成一个个小的模块,于是模块化开发出现了。但是由于缺乏规范化管理,出现了很多种模块化规范,从针对nodejs的commonjs规范,到针对浏览器端的CMD、AMD,终于在ES6里规范了前端模块化。

前端构建工具

虽然前端开发在模块化进程上搞得风生水起,但是有个问题就是:源代码无法直接运行,必须通过构建工具转换后才可以正常运行。基于nodejs常见的构建工具有gulp、fis3、webpack。

gulp

Gulp是一个基于流的自动化构建工具。 Gulp 被设计得非常简单,只通过下面5种方法就可以支持几乎所有构建场景:

1.通过 gulp.task注册一个任务;
2.通过 gulp.run 执行任务;
3.通过 gulp.watch 监听文件的变化;
4.通过 gulp.src 读取文件:
5.通过 gulp.dest 写文件。

Gulp的优点是好用又不失灵活,既可以单独完成构建,也可以和其他工具搭配使用 。其缺点是集成度不高,要写很多配置后才可以用,无法做到开箱即用 。

fis3

Fis3 是一个来自百度的国产构建工具。相对于Gulp只提供了基本功能的工具,Fis3集成了Web开发中的常用构建功能,如下所述。

1.读写文件: 通过 fis.match 读文件,release 配置文件的输出路径。
2.资源定位: 解析文件之间的依赖关系和文件位置。
3.文件指纹: 在通过 useHash 配置输出文件时为文件 URL 加上 md5 戳,来优化浏览器的缓存。
4.文件编译: 通过 parser 配置文件解析器做文件转换,例如将 ES6 编译成 ES5。
5.压缩资源: 通过 optimizer 配置代码压缩方法。
6.图片合并: 通过 spriter 配置合并 css 里导入的图片到一个文件中,来减少 Hπp 请求数。

Fis3的优点是集成了各种 Web 开发所需的构建功能,配置简单、开箱即用 。
Fis3 是一种专注于 Web 开发的完整解决方案,如果将 Gulp 比作汽车的发动机, 则可以将 Fis3 比作 一辆完整的汽车。

webpack

Webpack 是一个打包模块化 JavaScript 的工具,在 Webpack 里一 切文件皆模块,通过 Loader转换文件,通过 Plugin注入钩子,最后输出由多个模块组合成的文件。 Webpack专注于构建模块化项目。

《聊聊webpack》

Webpack的优点是 :

1.专注于处理模块化的项目,能做到开箱即用、 一步到位:
2.可通过 Plugin 扩展,完整好用又不失灵活 ;
3.使用场景不局限于 Web 开发:
4.社区庞大活跃 ,经常引入紧跟时代发展的新特性,能为大多数场景找到已有的开源扩展:
5.良好的开发体验 。

Webpack的缺点是只能用于采用模块化开发的项目 。

webpack 常见api简介

webpack的工作就是把我们的静态资源模块通过递归形成依赖关系图,然后将这些模块打包成一个或多个 bundle文件。
它的核心api是entry、module(loader)、plugin、output、mode。接下来我们看一下这些api的功能及用法。

entry 入口

入口起点:构建依赖的开始,通过该起点文件寻找处理依赖

module.exports = {
  entry: './path/to/my/entry/file.js'//字符串形式
  entry: ['./path/to/my/entry/file.js','./path/to/my/entry/file1.js']//数组形式
  entry: {
             name:'./path/to/my/entry/file.js',
             name1:'./path/to/my/entry/file1.js'
         }//对象形式
};

output 出口

output 属性告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件

const path = require('path');

module.exports = {
  entry: './path/to/my/entry/file.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js',
    filename: '[name].js',//多出口
    publicPath: "http://cdn.example.com/assets/[hash]/",//cdn + hash
  }
};

loader 文件处理

loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理。

module.exports = {
    module: {
        rules: [
          { test: /\.txt$/, use: 'raw-loader' }
        ]
      }
}      

plugins 插件

插件的使用范围从打包优化和压缩,一直到重新定义环境中的变量。插件接口功能极其强大,可以用来处理各种各样的任务。通过使用 new 操作符来创建它的一个实例。

const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
module.exports = {
  module: {
    rules: [
      { test: /\.txt$/, use: 'raw-loader' }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};

mode 模式

通过mode参数配置,开启开发或者生产环境下的webpack内置优化。

《聊聊webpack》

module.exports = {
  mode: 'production' //development
};

resolve 解析

设置模块如何被解析。
1.resolve.alias

import Utility from '../../utilities/utility';

alias: {
  Utilities: path.resolve(__dirname, 'src/utilities/'),
  Templates: path.resolve(__dirname, 'src/templates/')
}

使用alias配置别名,可以按下面方式引用
import Utility from 'Utilities/utility';

2.resolve.modules
webpack 解析模块时应该搜索的目录

modules: [path.resolve(__dirname, "src"), "node_modules"]

webpack使用指南

配置导出

webpack是需要传入一个配置对象(configuration object)。可以通过两种方式之一:终端或Node.js。
除了导出单个配置对象,还有可以有其他导出方式:
1.导出函数

module.exports = function(env, argv) {
  return {
    mode: env.production ? 'production' : 'development',
    devtool: env.production ? 'source-maps' : 'eval',
     plugins: [
       new webpack.optimize.UglifyJsPlugin({
        compress: argv['optimize-minimize'] // 只有传入 -p 或 --optimize-minimize
       })
     ]
  };
};

2.导出promise
webpack 将运行由配置文件导出的函数,并且等待 Promise 返回。便于需要异步地加载所需的配置变量。

module.exports = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({
        entry: './app.js',
        /* ... */
      })
    }, 5000)
  })
}

3.导出多个配置对象
运行 webpack 时,所有的配置对象都会构建。例如,导出多个配置对象,对于针对多个构建目标(例如 AMD 和 CommonJS)打包一个 library 非常有用。

module.exports = [{
  output: {
    filename: './dist-amd.js',
    libraryTarget: 'amd'
  },
  entry: './app.js',
  mode: 'production',
}, {
  output: {
    filename: './dist-commonjs.js',
    libraryTarget: 'commonjs'
  },
  entry: './app.js',
  mode: 'production',
}]

devServer 开发中

1.contentBase
告诉服务器从哪里提供内容。只有在你想要提供静态文件时才需要。devServer.publicPath 将用于确定应该从哪里提供 bundle,并且此选项优先。

默认情况下,将使用当前工作目录作为提供内容的目录,但是你可以修改为其他目录:

contentBase: path.join(__dirname, "public")//可以访问publick文件夹下文件
contentBase: [path.join(__dirname, "public"), path.join(__dirname, "assets")]
contentBase: false

2.publicPath

此路径下的打包文件可在浏览器中访问。publicPath 总是以斜杠(/)开头和结尾

publicPath: "/assets/"  //将打包后文件放入assets文件夹下,并可以通过浏览器访问

3.host

host: "0.0.0.0" //服务器外部可访问

4.hot

启用 webpack 的模块热替换特性

5.proxy

proxy: {
  "/api": {
    target: "https://other-server.example.com",
    pathRewrite: {"^/api" : ""},//重写url
    secure: false,//https
  }
}
//也可以通过context混合书写
proxy: [{
  context: ["/auth", "/api"],
  target: "http://localhost:3000",
}]

webpack优化

待更新

webpack工作流程

Webpack 的构建流程可以分为以下三大阶段:

《聊聊webpack》

1.初始化

启动构建,读取与合并配置参数,加载 Plugin,实例化 Compiler。

《聊聊webpack》

2.编译

**:从 Entry 发出,针对每个 Module 串行调用对应的 Loader 去翻译文件的内容, 再找到该Module 依赖的 Module,递归地进行编译处理 。

《聊聊webpack》

在编译阶段中,最重要的事件是 compilation,因为在 compilation 阶段调用了Loader, 完成了每个模块的转换操作。在 compilation 阶段又会发生很多小事件。

《聊聊webpack》

3.输出

将编译后的 Module 组合成 Chunk,将 Chunk 转换成文件,输出到文件系统中 。

《聊聊webpack》

    原文作者:搁浅
    原文地址: https://segmentfault.com/a/1190000019882037
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞