大家好!我是萝卜,这一章跟大家介绍 webpack 4 常见的配置。
webpack.config.js 配置文件
webpack 是可配置的模块打包工具,可以通过修改 webpack.config.js 的配置文件对 webpack 进行配置,webpack 的配置文件遵循 Nodejs 的 CommonJS 模块规范,可通过 require() 语法导入其他文件或者使用 Nodejs 内置的模块,其实 webpack.config.js 是一个 Nodejs 的模块。
一个简单的 webpack.config.js 例子
const path = require('path');
module.exports = {
mode: 'development',
entry: './entry.js',
output: {path: path.resolve(__dirname, 'dist'),
filename: 'entry.bundle.js'
}
};
上面例子中使用 CommonJS 的 require 引入 Nodejs 内置的 path 模块,然后通过 module.exports 将 webpack 的配置导出。
Tips: webpack 的配置是一个 Nodejs 模块,并不是 JSON 对象。
webpack 配置支持多种语言
webpack 不仅仅支持 js 配置,还支持 TypeScript、CoffeeScript 甚至 JSX 语法的配置,但是不论使用什么语言,核心配置项是相同的,只不过是语法不同。除了配置文件的语法多样之外,对于配置的类型也是多样的,最常见的是作为一个对象来使用,除了对象,webpack 还支持函数、Promise 和多配置数组。
如何使用 webpack.config.js 配置文件
默认情况下,webpack 会查找执行目录下的 webpack.config.js 作为配置,如果需要指定某个配置文件,可以使用命令:
npx webpack --config webpack.config.js
或者在项目目录下运行
node ./node_modules/webpack/bin/webpack --config webpack.config.js
webpack 的核心概念
虽然 webpack 的功能强大且配置项多,但是只要理解了以下的几个核心概念,就能随心应手的使用它,webpack 有以下几个核心概念:
- entry: 项目入口,webpack 执行构建的第一步将从 entry 开始,可抽象成输入。
- module: 模块,在 webpack 中一切皆模块,一个模块对应一个文件,模块不局限于 js,也可以是 css、图片等。webpack 会从配置文件的 entry 开始递归找出所有依赖的模块。
- chunk: 代码块,一个 chunk 可以由多个模块组合而成,用于代码合并与分割。
- loader: 模块转换器,用于将模块的原内容按照需求转换成新内容。
- plugin: 扩展插件,在 webpack 构建流程中的特定时机注入扩展逻辑,可以完成 loader 完不成的任务。
- output: 输出结果,在 webpack 经过一系列处理并得出最终想要的代码后输出结果。
webpack 的入口 (entry) 和输出(output)
webpack 是一个模块打包工具,能够从一个需要处理的 javascript 文件开始,构建一个依赖关系图 (dependency graph),该图映射到了项目中每个模块,然后将这个依赖关系图输出到一个或者多个 bundle 中。
webpack 是从指定的入口文件(entry) 开始,经过加工处理,最终按照 output 输出固定内容的 bundle。而这个加工处理的过程,就用到了 loader 和 plugin 两个工具,loader 是源代码的处理器,plugin 解决的是 loader 处理不了的事情。
entry 入口
webpack 的 entry 支持多种类型,包括字符串、对象、数组。从作用上说,包括单文件入口和多文件入口两种方式。
单文件入口
module.exports = {entry: 'path/index.js'}
// 使用对象的方式
module.exports = {
entry: {main: 'path/index.js'}
}
单文件入口可以快速创建一个只有单一文件入口的情况,但是相对简单,在扩展配置时灵活性较低。
module.exports = {
mode: 'development',
entry: ['./src/index1.js', './src/index2.js']
}
无论是字符串还是字符串数组的 entry,实际上都是只有一个入口,但是在打包产出上会有差异:
如果直接是 string 的形式,那么 webpack 就是直接把该 string 指定的模块作为入口模块。
如果是数组的形式,那么 webpack 会自动生成另一个入口模块,并将数组中的每个元素指定的模块加载进来,并将最后一个模块的 module.exports 作为入口模块的 module.exports 导出。
多文件入口
多文件入口是使用对象语法来通过支持多个 entry,多文件入口的对象语法相对于单文件入口,具有更高的灵活性,例如多页应用、页面模块化分离优化。
module.exports = {
entry: {
home: 'path/home.js',
search: 'path/search.js',
list: 'path/list.js'
}
}
上面的语法将 entry 分成了 3 个独立的入口文件,这样会打包出来三个对应的 bundle。
Tips: 对于一个 html 页面,我推荐只用一个 entry,通过统一入口,解析出来的依赖关系更方便管理和维护。
output 输出
webpack 的 output 是指定了 entry 对应文件编译打包后的输出 bundle。output 的常用属性是:
- path: 规定了打包后输出的 bundle 的存放路径。
- filename: 这个是 bundle 的名称。
- publicPath: 指定了一个在浏览器中被引用的 URL 地址。
Tips: 当不指定 output 的时候,默认输出到 dist/main.js,即 output.path 是
dist,output.filename 是 main。
一个 webpack 的配置,可以包含多个 entry,但是只能有一个 output。对于不同的 entry 可以通过 output.filename 占位符来区分。
module.exports = {
entry: {
home: 'path/home.js',
search: 'path/search.js',
list: 'path/list.js'
},
output: {filename: '[name].js',
path: __dirname + '/dist'
}
}
其中 [name] 就是占位符,它对应的是 entry 的 key (home、search、list)。
目前 webpack 支持的占位符有:
- [hash] 模块标识符的 hash
- [chunkhash] chunk 内容的 hash
- [name] 模块名称
- [id] 模块标识符
- [query] 模块的 query,例如,文件名?后面的字符串
- [function] 一个 return 出一个 string 作为 filename 的函数
[hash] 和 [chunkhash] 的长度可以使用[hash:16] (默认为 20) 来指定,或者通过指定 output.hashDigestLength 在全局配置长度,那么他们之间的区别是什么?
- [hash]:是整个项目的 hash 值,其根据每次编译内容计算得到,每次编译之后都会生成新的 hash,即修改任何文件都会导致所有文件的 hash 发生改变;在一个项目中虽然入口不同,但是 hash 是相同的;hash 无法实现前端静态资源在浏览器上长缓存,这时候应该使用 chunkhash;
- [chunkhash]:根据不同的入口文件(entry)进行依赖文件解析,构建对应的 chunk,生成相应的 hash;只要组成
entry 的模块文件没有变化,则对应的 hash
也是不变的,所以一般项目优化时,会将公共库代码拆分到一起,因为公共库代码变动较少的,使用 chunkhash 可以发挥最长缓存的作用; - [contenthash]:使用 chunkhash 存在一个问题,当在一个 JS 文件中引入了 CSS 文件,编译后它们的 hash
是相同的。而且,只要 JS 文件内容发生改变,与其关联的 CSS 文件 hash 也会改变,针对这种情况,可以把 CSS 从 JS 中使用
mini-css-extract-plugin 或 extract-text-webpack-plugin 抽离出来并使用
contenthash。
[hash]、[chunkhash] 和 [contenthash] 都支持 [xxx:length] 语法。
Tips: 占位符是可以组合使用的,例如 [name]-[hash:8]
output.publicPath
我们构建出的静态资源文件都是通过 <script> 或者 <link> 标签进行加载的,而且这些静态资源文件都是需要部署在静态资源服务器或者 CDN 上,那么如何将这些静态资源文件放在不同的域名或者 CDN 上面呢?这时就要用到 output.publicPath 来进行配置:
module.exports = {
output: {filename: '[name]_[chunkhash:8].js',
publicPath: 'https://cdn.ezample.com/assets/'
}
}
则输出:
<script src="https://cdn.ezample.com/assets/a_456456456.js"></script>
output.library 与 output.libraryTarget
我们在实际开发中总是需要去打包一些供团队其他小伙伴使用的库,这时就需要用到 output.library 与 output.libraryTarget,output.library 用来指定库的名称,output.libraryTarget 用来指定打包出来的规范,比如:commonjs2、amd、umd2 等。
小结
这一章我们从 webpack 的配置文件 webpack.config.js 基本语法入手,讲解了配置的基本用法以及 mode、context、entry、output 基础概念,希望能给大家带来一些帮助,如果想了解更多,请持续关注我的文章。