开发和生产环境构建配置差异
日常的前端开发工作中,一般都会有两套构建环境:一套开发时使用,构建结果用于本地开发调试,不进行代码压缩,打印 debug 信息,包含 sourcemap 文件;另外一套构建后的结果是直接应用于线上的,即代码都是压缩后,运行时不打印 debug 信息,静态文件不包括 sourcemap 的。有的时候可能还需要多一套测试环境,在运行时直接进行请求 mock 等工作。
Webpack4默认支持mode参数用于区分production环境和development环境。指定使用 production mode 时,默认会启用各种性能优化的功能,包括构建结果优化以及 webpack 运行性能优化,而如果是 development mode 的话,则会开启 debug 工具,运行时打印详细的错误信息,以及更加快速的增量编译构建。
webpack 的 mode 参数已经给我们带来了一些很方便的环境差异化配置,但是针对一些项目情况,例如使用 css-loader 或者 url-loader 等,不同环境传入 loader 的配置也不一样,而 mode 并没有帮助我们做这些事情,因此有些配置还是需要手动区分环境后来进行调整。
在配置文件中区分 mode
4.x 使用 mode 参数,3.x 使用 Node.js 的 process.env.NODE_ENV
webpack 的运行时环境是 Node.js,我们可以通过 Node.js 提供的机制给要运行的 webpack 程序传递环境变量,来控制不同环境下的构建行为。例如,我们在 npm 中的 scripts 字段添加一个用于生产环境的构建命令:
3.x版本:
1 | { |
4.x版本
1 | "scripts": { |
常见的环境差异配置
- 生产环境可能需要分离 CSS 成单独的文件,以便多个页面共享同一个 CSS 文件
- 生产环境需要压缩 HTML/CSS/JS 代码
- 生产环境需要压缩图片
- 开发环境需要生成 sourcemap 文件
- 开发环境需要打印 debug 信息
- 开发环境需要 live reload 或者 hot reload 的功能
webpack 4.x 的 mode 已经提供了上述差异配置的大部分功能,mode 为 production 时默认使用 JS 代码压缩,而 mode 为 development 时默认启用 hot reload,等等。这样让我们的配置更为简洁,我们只需要针对特别使用的 loader 和 plugin 做区分配置就可以了。
模式 | 默认配置 |
---|---|
production | 通过DefinePlugin设置 process.env.NODE_ENV=production。启用FlagDependencyUsagePlugin、FlagIncludedChunksPlugin、ModuleConcatenationPlugin、NoEmitOnErrorsPlugin、OccurrenceOrderPlugin、SideEffectsFlagPlugin 和 UglifyJsPlugin插件。 |
development | 通过DefinePlugin设置process.env.NODE_ENV=development。启用 NamedChunksPlugin和NamedModulesPlugin插件。 |
webpack 3.x 版本还是只能自己动手修改配置来满足大部分环境差异需求。
拆分配置
由于2个环境的配置有相同部分又有差异部分,因此通常的做法是提供3个webpack配置文件,一个是公有的配置文件,一个是针对production的配置文件,一个针对development,后两个配置文件通过webpack-merge引入公有的配置文件。
- webpack.base.js:基础部分,即多个文件中共享的配置
- webpack.development.js:开发环境使用的配置
- webpack.production.js:生产环境使用的配置
- webpack.test.js:测试环境使用的配置
我们通过配置mode参数声明当前配置所处的环境。另外,还需要修改一下package.json中的scripts:
1 | ... |
source map
source map有多种风格配置,不同风格各有利弊,对于不同的环境推荐配置如下:
- development:inline-source-map
- production:source-map
代码分割
production环境通常需要进行代码分割,而development环境则没有这样的需求。
- 分割javascript代码
对webpack的运行时代码进行抽离:
1 | ... |
另外,所有第三方库单独抽离:
1 | ... |
为了支持缓存,加入HashedModuleIdsPlugin插件:
1 | ... |
- 分割css代码
当前,css代码被style-loader直接添加到js文件里面了,在production环境中,我们通常希望将css文件单独抽离出来,此时可以采用mini-css-extract-plugin插件。
对于production环境,我们将使用MiniCssExtractPlugin.loader替换style-loader:
1 | ... |
还需要将css文件分割到单独的css chunk中:
1 | ... |
webpack.base.js
1 | const path = require('path'); |
webpack.development.js
1 | const merge = require('webpack-merge'); |
webpack.production.js
1 | const merge = require('webpack-merge'); |