前言
现在距离 2018 年 2 月 15 号 webpack4.0.0 出来已经有一段时间了, 现在已经出了 @vue/cli 3.0, 但是楼主还没试过, 听说很强大, 想要试水的可以看文档 [@vue/cli][1], 官方脚手架都用上 webpack4 了, 你项目还停留在 webpack3, 甚至 webpack2, 是不是觉得落伍了. 受号称 0 配置的 parcel 启发, webpack4 增加了一些默认配置, 摒弃掉了一些难懂的配置, 对用户更加友好, 下面我来讲一讲比较大的一些变化
环境
不再支持 Node.js 4.
默认出入口
在 Webpack 4 中, 不再强制要求指定 entry 和 output 路径. webpack 4 会默认 entry 为 ./src,output 为 ./dist, 当然了, 这只是开胃菜.
mode 构建模式
webpack 提供了两种构建模式可供选择 development 和 production
选项 | 描述 |
---|---|
development | 会将 process.env.NODE_ENV 的值设为 development。启用 NamedChunksPlugin(固化 runtime 内以及在使用动态加载时分离出的 chunk 的 chunk id) 和 NamedModulesPlugin(开启 HMR[热重载] 的时候使用该插件会显示模块的相对路径)。 |
production | 会将 process.env.NODE_ENV 的值设为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin. |
也就是说如果 mode 为 development 时候官方脚手架可以砍掉的代码
- // webpack.development.config.js
- module.exports = {
- + mode: 'development'
- - plugins: [
- - new webpack.NamedModulesPlugin(),
- - new webpack.DefinePlugin({
- - 'process.env': require('../config/dev.env')
- - }),
- - ]
- }
复制代码
如果 mode 为 production 时候官方脚手架可以砍掉的代码
- // webpack.production.config.js
- module.exports = {
- + mode: 'production',
- - plugins: [
- - new UglifyJsPlugin(/* ... */),
- - new webpack.DefinePlugin({
- - 'process.env': require('../config/dev.env')
- - }),
- - new webpack.optimize.ModuleConcatenationPlugin()
- - ]
- }
复制代码
import(): 动态导入
在 webpack 4 中, import() 会返回一个带命名空间 (namespace) 的对象, 这对 ES Module 不会有影响, 但对于遵循 commonjs 规范的模块则会加一层包裹:
- // webpack 2/3
- import("./commonjs").then(exports => {
- // ...
- })
- // webpack 4
- import("./commonjs").then({default: exports}=> {
- // ...
- })
复制代码
optimization 配置项
配置项新增了 optimization 选项, 智能的根据所选模式 mode 为做运行优化.
使用这个配置的时候之前的一些插件可以使用 optimization 里的配置代替
NoEmitOnErrorsPlugin 替换为 optimization.noEmitOnErrors (默认只在 production 模式)
ModuleConcatenationPlugin 替换为 optimization.concatenateModules(默认只在 production 模式)
NamedModulesPlugin 替换为 optimization.namedModules(默认只在 develoment 模式) CommonsChunkPlugin 插件被弃用, 使用 optimization.splitChunks, optimization.runtimeChunk 代替
- // webpack.prod.conf.js
- const config = {
- // ...
- plugins: [
- - new webpack.NoEmitOnErrorsPlugin(),
- - new webpack.optimize.ModuleConcatenationPlugin(), // 预编译
- - new webpack.optimize.CommonsChunkPlugin({
- - name: 'vendor',
- - minChunks (module) {
- - // any required modules inside node_modules are extracted to vendor
- - return (
- - module.resource &&
- - /\.js$/.test(module.resource) &&
- - module.resource.indexOf(
- - path.join(__dirname, '../node_modules')
- - ) === 0
- - )
- - }
- - }),
- - new webpack.optimize.CommonsChunkPlugin({
- - name: 'manifest',
- - minChunks: Infinity
- - }),
- ],
- + optimization: {
- + noEmitOnErrors: true,
- + concatenateModules: true,
- + splitChunks: {
- + chunks: 'all',
- + name: 'common',
- + },
- + runtimeChunk: {
- + name: 'runtime'
- + }
- + }
- };
复制代码
- // webpack.dev.conf.js
- const config = {
- // ...
- plugins: [
- - new webpack.NamedModulesPlugin()
- ]
- + optimization: {
- + namedModules: true
- + }
- };
复制代码
optimization.splitChunks 默认是不用设置的. 如果 mode 是 production, 那 Webpack 4 就会开启 Code Splitting. 默认 Webpack 4 只会对按需加载的代码做分割. 如果我们需要配置初始加载的代码也加入到代码分割中, 可以设置 splitChunks.chunks 为'all'
压缩
webpack4 的 mode 设置成 production 时, 默认开启代码压缩, 但是我要敲黑板, 划重点了, uglifyjs-webpack-plugin 终于到 v1.0.0 版本了, 支持多进程压缩, 缓存以及 es6 语法, 无需单独安装转换器. 感动不感动. 想看的话可以看这里[顺风车][2]. 想要覆盖配置可以这样
- const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
- module.exports = {
- // ...
- optimization: {
- minimizer: [
- new UglifyJsPlugin() // 具体配置可看 github
- ]
- }
- }
复制代码
## 移除的功能 ## 移除了 module.loaders 移除了 loaderContext.options 移除了 Compilation.notCacheable 移除了 NoErrorsPlugin 移除了 Dependency.isEqualResource 移除了 NewWatchingPlugin 移除了 CommonsChunkPlugin
周边
既然讲了 webpack 做了比较大的更新, 周边的配套设施也不要不舍得, 改换久换, 由于我平时项目中使用 vue, 如果你也使用 vue 的话, 那么针对 vue 的有几个变化你要知道:
vue-loader
什么? 学不动了, 只要用官网的脚手架不就好了? 前端的知识不断更新, 固步自封, 只会不进则退. 但是你要相信, webpack 也好, vue-loader 也好, api 会越来越好懂, 性能也会更加高效, 所以, 扶我起来, 我还能学...
Vue Loader v15 使用了一个不一样的策略来推导语言块使用的 loader.[vue-loader v15][3] 在 v14 或更低版本中, 如果你想为一个推导出来的 loader 定制选项, 你不得不在 Vue Loader 自己的 loaders 选项中将它重复一遍. 在 v15 中你再也没有必要这么做了. 拿官方脚手架来说, 可以看到两个函数, 用来生成 vue-loader 的 options 还有 module.rule, 我把他们摘出来, 就可以看出来了.
- // util.js
- exports.CSSLoaders = function (options) {
- // ...
- }
- // Generate loaders for standalone style files (outside of .vue)
- exports.styleLoaders = function (options) {
- // ...
- }
- ```
- ````javascript
- // vue-loader-conf.js
- module.exports = {
- loaders: utils.cssLoaders({
- sourceMap: sourceMapEnabled,
- extract: isProduction
- }),
- ...
- }
- ```
- ```javascript
- // webpack.dev.config
- const devWebpackConfig = merge(baseWebpackConfig, {
- module: {
- rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
- },
- ...
- }
- ```
我刚入脚手架的坑的时候都蒙了, 为什么要这样写, 为了德玛西亚么? 当然不是, 是因为填 vue-loader v14 的坑
vue-loader v15 版本只要写一遍就好了, 但是要注意 ** 请确保在你的 webpack 配置中添加 Vue Loader 的插件 **
- ```javascript
- // webpack.config.js
- const VueLoaderPlugin = require('vue-loader/lib/plugin')
- module.exports = {
- module: {
- rules: [
- {
- test: /\.vue$/,
- loader: 'vue-loader'
- },
- // ...
- ]
- },
- plugins: [
- // 请确保引入这个插件!
- new VueLoaderPlugin()
- ]
- }
- ```
然后由于生产和测试环境对 css 文件处理不同. 在 webpack.dev.config.js 和 webpack.prod.config.js 里分别配置 less/scss css 的 loader 就好了:
- ```javascript
- {
- module: {
- rules: [
- // ...
- {
- test: /\.less$/,
- use: [
- 'vue-style-loader',
- 'css-loader',
- 'less-loader'
- ]
- }
- ]
- }
- }
- ```
- ### mini-css-extract-plugin css 抽取 ###
webpack v4 官方不在推荐使用 extract-text-webpack-plugin 了, 改换 mini-css-extract-plugin
- ```
- // webpack4
- npm install -D mini-css-extract-plugin
- // webpack.config.js
- var MiniCssExtractPlugin = require('mini-css-extract-plugin')
- module.exports = {
- // 其它选项...
- module: {
- rules: [
- // ... 忽略其它规则
- {
- test: /\.css$/,
- use: [
- process.env.NODE_ENV !== 'production'
- ? 'vue-style-loader'
- : MiniCssExtractPlugin.loader,
- 'css-loader'
- ]
- }
- ]
- },
- plugins: [
- // ... 忽略 vue-loader 插件
- new MiniCssExtractPlugin({
- filename: style.css
- })
- ]
- }
- ```
- ```
- // webpack3
- npm install -D extract-text-webpack-plugin
- // webpack.config.js
- var ExtractTextPlugin = require("extract-text-webpack-plugin")
- module.exports = {
- // 其它选项...
- module: {
- rules: [
- // ... 其它规则忽略
- {
- test: /\.css$/,
- loader: ExtractTextPlugin.extract({
- use: 'css-loader',
- fallback: 'vue-style-loader'
- })
- }
- ]
- },
- plugins: [
- // ...vue-loader 插件忽略
- new ExtractTextPlugin("style.css")
- ]
- }
- ```
- ## 福利 ##
对 webpack3 官方脚手架还不是很了解的同学可以看我根据自己理解写的注释, 详情点[这里][4]
觉得麻烦, 不想自己搞? 那也没关系, 我自己按照脚手架改了一套, 感兴趣的可以试试点[这里][5]
觉得不错请 star 哦, 另外, 我准备在下一篇文章中将如何如优化 webpack, 喜欢的话可关注
## 参考 ##
1. [webpack 文档][6]
2. [webpack github release][7]
3. [Webpack 4 配置最佳实践][8]
- [1]: https://cli.vuejs.org/guide/
- [2]: https://github.com/webpack-contrib/uglifyjs-webpack-plugin
- [3]: https://vue-loader.vuejs.org/zh/guide/#vue-cli
- [4]: https://github.com/leizore/webpack3-common
- [5]: https://github.com/leizore/vue-webpack4-template
- [6]: https://webpack.js.org/concepts/
- [7]: https://github.com/webpack/webpack/releases/tag/v4.0.0
[8]: https://juejin.im/post/5b304f1f51882574c72f19b0 复制代码
来源: https://juejin.im/post/5b4350ae6fb9a04fb309e47d