webpack学习
基础概念
本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包工具。当 webpack 处理应用程序时,它会在内部构建一个 依赖图(dependency graph),此依赖图会映射项目所需的每个模块,并生成一个或多个 bundle。
webpack 主要有五个核心概念:
- 入口
- 出口
- loader
- 插件
- 模式
入口
入口,通常是一个文件,用来指定 webpack 应该使用哪个模块用来构建内部依赖。
1 | module.exports = { |
出口
出口,指 webpack 打包过后生成浏览器可识别的 js 文件等。
1 | module.exports = { |
loader
webpack 只能理解 JavaScript 和 JSON 文件。loader 配置可以让 webpack 识别并处理其他类型的文件,然后转换成有效的模块,以供程序使用。
loader 中有两个常用的配置属性,test 和 use。其中 test 的值为正则表达式,匹配需要处理哪些文件;use 则是使用什么 loade 来进行处理。
1 | module.exports = { |
插件
插件可以用来优化打包的过程,配置打包环境等。
1 | module.exports = { |
模式
通过选择 development, production 或 none 之中的一个,来设置 mode 参数,你可以启用 webpack 内置在相应环境下的优化。其默认值为 production。
1 | module.exports = { |
常用配置
使用 loader
打包静态资源
图片
查阅了 webpack 官方文档,发现对于文件打包,webpack4 使用的是 file-loader,但是在 webpck5 的版本中,这个 loader 已经被废弃。于是我在 webpack5 中试了一下,但是依然还是可以用的,只不过还是按照官方文档说的来吧。
现在使用的是 asset module,允许使用资源文件(字体,图标等)而无需配置额外 loader。
asset/resource
就是用来取代 webpack4 中的file-loader
的。
1 | module.export = { |
配置好之后打包,发现图片正常出来了,但是图片名称是 hash 值,并且没有在 img 文件夹中,可以使用assetModuleFilename
来指定输出:
1 | module.export = { |
配置好之后,再次打包,可以发现所有图片都能够被打包到 images 文件夹中了,并且名称已经不是 hash 值了。
在 webpack4 中,图片转 base64 使用的是url-loader
,但是在 webpack5 中也已经被废弃了,取而代之的为asset/inline
。
1 | module.export = { |
打包后发现没有了 images 文件夹以及图片,这是因为图片被转成了 base64 编码。一般来说,图片过大就不适合转换成 base64 编码了,那么什么时候转换为 base64,什么时候不转换为 base64 呢?可以直接设置type
为asset
。webpack5 已经帮我们实现了这方面的规则,小于 8kb 的文件,将会视为 inline 模块类型,否则会被视为 resource 模块类型。
如果决定这个规则不好, 这时候可以使用Rule.parser.dataUrlCondition.maxSize
来对文件大小做限制。
1 | module.export = { |
样式
常用的样式 loader
有 css-loader
与 style-loader
,在写 rules
规则时,需要注意样式 loader
的顺序是反着来的,css-loader
放在后面,style-loader
放在前面。
1 | module.exports = { |
如果使用的是sass
或者less
等 css
预处理器,得先将其编译为css
,然后使用css-loader
和style-loader
进行编译打包。
比方说用sass
:
1 | npm install sass-loader sass --save-dev |
1 | module.exports = { |
在使用到一些高级 CSS
语法特性时,需要加上厂商前缀,可以使用postcss-loader
来进行帮助,首先安装postcss
和postcss-loader
:
1 | npm install --save-dev postcss-loader postcss |
1 | module.exports = { |
还有一个autoprefixer
插件,也是帮助 CSS
添加厂商前缀的,但是默认的postcss-preset-env
插件默认带上了autoprefixer
,也可以不用配置。除此之外,需要添加一个.browserslistrc
文件,添加以下内容之后postcss
才会生效:
1 | defaults, |
然后 CSS 高级语法特性就会自动添加厂商前缀了。
使用 plugins
配置让打包更编辑
html-webpack-plugin
html-webpack-plugin
可以配置一个html
文件模版,打包之后生成一个html
文件并且引入对应的js
文件。
1 | const HtmlWebpackPlugin = require('html-webpack-plugin'); |
clean-webpack-plugin
clean-webpack-plugin
用于清除上次打包之后的文件。
1 | const HtmlWebpackPlugin = require('html-webpack-plugin') |
entry
与output
基础配置
entry
为打包入口,可以是一个字符串也可以是一个对象;为对象时,代表打包多个页面。对应的,如果entry
打包多个页面,output
中的filename
就不能写死,否则会打包出错。可以使用占位符[name]
动态替换打包后的文件名称,name
对应entry
中的 key 值。
1 | module.exports = { |
sourceMap
代码调试映射
1 | dev: cheap-module-eval-source-map |
devServer
使用devServer
可以开启一个服务,自动打开打包后的 index.html 文件,解决了每次打包完毕后手动启动的麻烦。
首先安装依赖:
1 | npm install webpack-dev-server --save-dev |
在webpack.config.js
中添加以下代码:
1 | const path = require('path') |
添加服务之后,就可以不用每次改完代码都去重新打包了,但是必须要刷新浏览器才能让更改后的代码生效,这时可以使用热更新模块帮助页面刷新。
1 | const webpack = require('webpack') |
使用babel
处理 ES6 语法
一些低版本的浏览器是无法识别 ES6 语法的,可以使用babel
处理 ES6 语法的转换。
首先安装所需依赖:
1 | npm install --save-dev babel-loader @babel/core |
在webpack.config.js
中添加 loader:
1 | module.exports = { |
配置好 loader
之后,再次打包出来的 js 文件就是 ES5 的语法了,但是这样做 babel
会将所有的语法都转换为 ES6,出口文件的体积会变得很大。可以使用@babel/polyfill
来配置规则。
1 | npm install --save @babel/polyfill |
然后修改 webpack.config.js
中的 babel-loader
文件:
1 | module.exports = { |
再次打包,就可以发现代码体积变得很小了。
然后发现有一个警告,说是指定了 useBuiltIns
,还需要配置 corejs
:
1 | npm install --save core-js@2 |
1 | module.exports = { |
配置好后,便可以消除警告了。
组件库中的 babel
配置
如果需要编写组件库这类代码,上面的方法就不太合适。babel 转换后的代码是全局的,可能会影响其他的代码,若是业务代码,就没啥问题,但如果编写的是公共内库,就会有问题。
可以使用 @babel/plugin-transform-runtime
来解决这个问题,@babel/plugin-transform-runtime
使用闭包可以避免命名重复的问题。
1 | npm install --save-dev @babel/plugin-transform-runtime |
1 | npm install --save @babel/runtime @babel/runtime-corejs2 |
然后在 webpack.config.js 中修改 babel-loader:
1 | module.exports = { |
TreeShaking
TreeShaking 只支持 ESModule 模块导入