升级到 webpack4.x
转眼间,时间来到了2018年的四月,webpack也在前不久发布了它的 4.0 版本,而在写这篇文章时,它的版本已然更新到 4.5 了。似乎永远也赶不上它们的脚步,果然,这世界上不变的,永远是变化。
来看看 webpack4.x 有哪些变化。
基本
webpack && webpack-cli
貌似从 4.0 开始,webpack 拆分成 webpack 和 webpack-cli,如果只安装 webpack,会有报错提示:
cnpm i -g webpack@4.5.0 webpack-cli |
全局安装后,还要本地安装。否者,当你结合插件运行时,提示如下错误:
> webpack-dev-server -o --mode development |
这说明需要本地安装 webpack。
cnpm i -D webpack@4.5.0 webpack-cli |
当使用 npm i ...
安装出现失败时,尝试着使用 cnpm i ...
升级 node 和 npm 版本
当尝试安装最新版本的webpack时,提示node版本过低,于是先升级,在写本篇文章时,node的LTS版本为 8.11.1
:
$ cnpm i webpack webpack-cli -D |
无需配置入口和出口文件
由于在webpack4之前,需要手动指定入口文件和输出文件,这用起来还是比较麻烦。终于,在webpack4 中,当你未配置上述文件时,它会自动查找 ./src/index.js
这个目录的文件,并且把它作为入口文件。同时,将 ./dist/main.js
作为默认的输出文件。
执行 npm run server
命令后,将会在 dist
目录下生成 main.js
文件,该文件是未压缩的,并且它的代码是通过 eval
函数将源文件中 index.js
内容进行动态运行。
而运行 npm run build
,则在 dist
目录生成的 main.js
是压缩的,并且它的代码是一个自执行的匿名函数。
配置 mode 选项
当运行 npm run dev
时,会出现如下错误:
The 'mode' option has not been set, webpack will fallback to 'production' for th is value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. |
从4.0开始,webpack 新增了 mode
配置,它包含 development | production
这两个值,对于不同的模式,webpack会采用对应的优化打包策略。
如果不指定对应的 mode
,则会出现上面的警告信息,并且将 mode
的值默认指定为 production
,这也意味着,process.env.NODE_ENV
的值不用再单独定义了。为了根据环境灵活打包,我们得根据文档来进行一下配置,更新 package.json 如下:
// package.json |
或者在 webpack.config.js
文件中,单独设置:
// webpack.config.js |
optimization
如果你没在 webpack.config.js
中配置 optimization
属性,则默认情况下,webpack会根据 mode
配置,打包时采用对应的 optimization
策略。
其中,--mode development
模式下有以下特点:
- 浏览器调试,提供有效错误信息
- 加速增量编译
而 --mode production
:
- 压缩输出JS文件的体积(默认使用 uglifyjs-webpack-plugin)
- 优化执行效率
如果你在 webpack.config.js
配置了 optimization
属性,则打包时,可能会导致这些默认策略失效,因为一些 optimization
的一些默认属性被覆盖了。
另外,倘若你需要配置多个压缩插件,可在里面使用 minimizer
,但要注意到是,minimizer
会覆盖 minimize
的属性值。
// webpack.config.js |
支持 JSON 文件的编译
在之前,webpack只能解析 js 文件,其他文件都需要特定的 loader 才能进行解析。但从 webpack 4.x
开始,它执行 json文件 的解析。因此,你可以在代码中,直接引用 json 文件了。
// index.js |
loader 被移除
在 webpack4.x
之前,我们可以在 loaders
中配置不同的文件解析包。 但在这之后,官网废弃了 loaders
,取而代之的是使用 rules
:
// webpack.config.js |
CommonsChunkPlugin 被移除
在 webpack4.x
之前,如果需要在页面引入第三方库,并且防止模块重复引用第三方库,可以像下面这样使用 CommonsChunkPlugin
进行引入:
// webpack.config.js |
如果你基于 webpack4.x
再这样进行打包,则会报错:

因为从这个版本开始,移除了 CommonsChunkPlugin
,现在官网推荐使用 optimization.splitChunks
和 optimization.runtimeChunk
:
optimization: { |
将文本(样式)分割成独立一个文件
之前将样式独立成文件时,都是使用 ExtractTextPlugin
npm i -D extract-text-webpack-plugin |
// webpack.config.js |
但到了 webpack 4.x
时,却报错了:
throw new Error( |
官方的说法是暂时没有针对 webpack >= v4.0.0
的版本做更新处理,建议使用其他方案或者等待更新。后面有人提出以下解决方案:
npm i -D extract-text-webpack-plugin@next |
不过注意,到目前为止,它还是一个 beta 版本,可能存在不稳定。
过了一段时间后,又有人指出,对于 extract-text-webpack-plugin
支持 webpack >= v4.0.0
的工作已经迁移到 mini-css-extract-plugin 这个项目了。并且,对于生成环境,如果你希望将样式进行压缩,你需要再单独使用 optimize-css-assets-webpack-plugin:
npm i -D mini-css-extract-plugin optimize-css-assets-webpack-plugin |
// webpack.config.js |
其他错误
getaddrinfo ENOTFOUND localhost
events.js:183 |
在 MAC 上会出现此类错误,是因为没有指定 localhost。可通过切换host的工具进行以下指定:
127.0.0.1 localhost |
启动服务端口号被占用
当使用 webpack-dev-server --open --port 8100 --mode development
启动服务时,出现如下错误,即我们指定的端口号被占用。后来发现,之前通过 webpack-dev-server
启动的服务,端口一直是自增的,而且在命令行中使用 ctrl + c
无法关闭之前的服务。所以,才会导致端口号被占用的情况。
events.js:183 |
有两种解决方案。
方案一: 使用 tskill node
干掉所有的node进程,这种方法比较简单粗暴。
方案二: 根据服务端口号,找到对应的进程端口(PID),然后,将这个进程干掉。
// 通过服务端口号,找到 进程端口(假设服务端口为 8100) |
// 杀掉进程(假设对应的进程端口为 32120) |
经过查找各方资料,种种尝试。当我使用系统自带的命令窗口去启动和关闭服务时,发现不会复现上述问题。这就表明在系统自带命令窗口中使用 ctrl + c
可以干掉进程。
当我使用 vscode
集成的终端来启动和关闭服务,也不会复现上述问题。
由于我之前都是基于 git-bash
进行命令编译的,这说明问题就出在 git-bash
,查看当前使用的 git 版本为 2.13.2
。
晚上回去试了家里的 git-bash
,也不会复现上述的问题,查看 git 版本为 2.8.2
。再次证明,这是 git 版本的问题。
相关资料:http server doesn’t shut down with Ctrl-C in Windows Git Bash , Capturing Ctrl-C in MINGW-Bash shell
npm 找不到 node-gyp 模块
npm ERR! code MODULE_NOT_FOUND |
node-gyp
模块可能被损坏,重新安装 nodejs 即可。
ES6定义类的错误
定义一个这样的类:
// widgetImg.js |
在另外一个文件引入用它:
import WidgetImg from '../widgetImg'; |
结果发现报错了,提示:

经过各方搜寻资料,发现需要单独配置 babel 文件。首先,删除 webpack.config.js
里的一些内容:
module.exports = { |
在项目根目录新增一个 .babelrc
文件:
{ |
重新运行启动服务即可。它的实际问题,就是没有配置 transform-class-properties 这款插件。类似的,如果你项目中需要使用 rest运算 和 spread扩展符,你也可以再配置 transform-object-rest-spread。