webpack4配置入门和进阶
webpack作为一个模块打包器,主要用于前端工程中的依赖梳理和模块打包,将我们开发的具有高可读性和可维护性的代码文件打包成浏览器可以识别并正常运行的压缩代码,主要包括样式文件处理成
css
,各种新式的JavaScript
转换成浏览器认识的写法等,也是前端工程师进阶的不二法门,本文借鉴了部分vue-cli
对webpack
的配置思路,还有一些网上比较好的解决方案,在此对这些作者一并表示感谢。
webpack.config.js配置项简介
- Entry:入口文件配置,Webpack 执行构建的第一步将从 Entry 开始,完成整个工程的打包。
- Module:模块,在
Webpack
里一切皆模块,Webpack
会从配置的Entry
开始递归找出所有依赖的模块,最常用的是rules
配置项,功能是匹配对应的后缀,从而针对代码文件完成格式转换和压缩合并等指定的操作。 - Loader:模块转换器,用于把模块原内容按照需求转换成新内容,这个是配合
Module
模块中的rules
中的配置项来使用。 - Plugins:扩展插件,在
Webpack
构建流程中的特定时机注入扩展逻辑来改变构建结果或做你想要的事情。(插件API
) - Output:输出结果,在
Webpack
经过一系列处理并得出最终想要的代码后输出结果,配置项用于指定输出文件夹,默认是./dist
。 - DevServer:用于配置开发过程中使用的本机服务器配置,属于
webpack-dev-server
这个插件的配置项。
webpack打包流程简介
- 根据传入的参数模式(
development
|production
)来加载对应的默认配置 - 在
entry
里配置的module
开始递归解析entry
所依赖的所有module
- 每一个
module
都会根据rules
的配置项去寻找用到的loader
,接受所配置的loader
的处理 - 以
entry
中的配置对象为分组,每一个配置入口和其对应的依赖文件最后组成一个代码块文件(chunk)并输出 - 整个流程中
webpack
会在恰当的时机执行plugin
的逻辑,来完成自定义的插件逻辑
基本的webpack配置搭建
首先通过以下的脚本命令来建立初始化文件:
|
|
修改生成的package.json
文件,来引入webpack
打包命令:
|
|
对webpack.config.js
文件加入一些基本配置loader
,从而基本的webpack4.x
的配置成型(以两个页面入口为例):
|
|
在命令行下用以下命令安装loader
和依赖的插件,生成完全的package.json
项目依赖树。
|
|
默认打开的页面是index.html
页面,可以加上/page.html来打开page页面看效果。
PS: 关于loader
的详细说明可以参考webpack3.x
的学习介绍,上面配置中需要注意的是多页面的公共库的引入采用的是vendor
+暴露全局变量的方式,其实这种方式有诸多弊端,而webpack4
针对这种情况设置了新的API,有兴趣的话,就继续看下面的高级配置吧。
进阶的webpack4配置搭建
包含以下几个方面:
- 针对
CSS
和JS
的TreeShaking
来减少无用代码,针对JS
需要对已有的uglifyjs
进行一些自定义的配置(生产环境配置) - 新的公共代码抽取工具(
optimization.SplitChunksPlugin
)提取重用代码,减小打包文件。(代替commonchunkplugin
,生产和开发环境都需要) - 使用
HappyPack
进行javascript
的多进程打包操作,提升打包速度,并增加打包时间显示。(生产和开发环境都需要) - 创建一个
webpack.dll.config.js
文件打包常用类库到dll中,使得开发过程中基础模块不会重复打包,而是去动态连接库里获取,代替上一节使用的vendor
。(注意这个是在开发环境使用,生产环境打包对时间要求并不高,后者往往是项目持续集成的一部分) - 模块热替换,还需要在项目中增加一些配置,不过大型框架把这块都封装好了。(开发环境配置)
webpack3
新增的作用域提升会默认在production
模式下启用,不用特别配置,但只有在使用ES6模块才能生效。
关于第四点,需要在package.json中的script中增加脚本:
"build:dll": "webpack --config webpack.dll.config.js --mode development",
补充安装插件的命令行:
|
|
TreeShaking
需要增加的配置代码,这一块参考webpack
文档,需要三方面因素,分别是:
- 使用
ES6
模块(import/export
) - 在
package.json
文件中声明sideEffects
指定可以treeShaking
的模块 - 启用
UglifyJSPlugin
,多入口下用WebpackParallelUglifyPlugin
(这是下面的配置代码做的事情)
|
|
关于ES6
模块这个事情,上文的第六点也提到了只有ES6
模块写法才能用上最新的作用域提升的特性,首先webpack4.x
并不需要额外修改babelrc
的配置来实现去除无用代码,这是从webpack2.x
升级后支持的,改用sideEffect
声明来实现。但作用域提升仍然需要把babel
配置中的module
转换去掉,修改后的.babelrc
代码如下:
|
|
但这个时候会发现import
引入样式文件就被去掉了……只能使用require
来改写了。
打包DLL
第三方类库的配置项,用于开发环境:
webpack.dll.config.js
配置文件具体内容:
|
|
- 在
webpack.config.js
中增加的配置项:
|
|
多文件入口的公用代码提取插件配置:
|
|
PS: 这一块要多注意,对应入口的HTML
文件也要处理,关键是自定义的vendor
项,在开发环境中引入到html
中
HappyPack
的多进程打包处理:
|
|
PS:要记住这种使用方法下一定要在根目录下加.babelrc
文件来设置babel
的打包配置。
开发环境的代码热更新:
其实针对热刷新,还有两个方面要提及,一个是html文件里面写代码的热跟新(这个对于框架不需要,如果要实现,建议使用glup
,后面有代码),一个是写的样式代码的热更新,这两部分也要加进去。让我们一起看看热更新需要增加的配置代码:
|
|
在业务代码中要做一些改动,一个比较low
的例子为:
|
|
但还是不能实现在html
修改后自动刷新页面,这里有个概念是热更新不是针对页面级别的修改,这个问题有一些解决方法,但目前都不是很完美,可以参考这里,现在针对CSS的热重载有一套解决方案如下,需要放弃使用上文提到的ExtractTextWebapckPlugin
,引入mini-css-extract-plugin
和hot-css-loader
来实现,前者在webpack4.x上与hot-css-loader
有报错,让我们改造一番:
|
|
用于生产环境压缩css
的插件,看官方文档说明,样式文件压缩没有内置的,所以暂时引用第三方插件来做,以下是配置示例。
|
|
最终成果
在进阶部分我们对webpack
配置文件根据开发环境和生产环境的不同做了分别的配置,因此有必要分成两个文件,然后发现重复的配置代码很多,作为有代码洁癖的人不能忍,果断引入webpack-merge
,来把相同的配置抽出来,放到build/webpack.base.js
中,而后在build/webpack.dev.config.js
(开发环境)和build/webpack.prod.config.js
(生产环境)中分别引用,在这个过程中也要更改之前文件的路径设置,以免打包或者找文件的路径出错,同时将package.json
中的脚本命令修改为:
|
|
接下来就是代码的重构过程,这个过程其实我建议大家自己动手做一做,就能对webpack
配置文件结构更加清晰,下面的代码过于冗长,有兴趣请到我的github
地址来看。
build
文件夹下的webpack.base.js
文件
|
|
build
文件夹下的webpack.dev.config.js
文件
|
|
build
文件夹下的webpack.prod.config.js
文件
|
|
多说一句,就是实现JS打包的treeShaking
还有一种方法是编译期分析依赖,利用uglifyjs来完成,这种情况需要保留ES6模块才能实现,因此在使用这一特性的仓库中,.babelrc
文件的配置为:"presets": [["env", { "modules": false }], "stage-0"]
,就是打包的时候不要转换模块引入方式的含义。
接下来就可以运行npm start
,看一下进阶配置后的成果啦,吼吼,之后只要不进行build
打包操作,通过npm run dev
启动,不用重复打包vendor
啦。生产环境打包使用的是npm run build
。
以上就是对webpack4.x
配置的踩坑过程,期间参考了大量谷歌英文资料,希望能帮助大家更好地掌握wepback
最新版本的配置,以上内容亲测跑通,有问题的话,欢迎加我微信(kashao3824)讨论,来github
地址提issue
也可,欢迎fork/star
。
我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3o4rq79qmyasg