webpack
以一个默认的入口文件作为打包的起点,将所有的资源依赖关系记录,形成一个依赖关系树状图,根据这个树状图引入这些相关的资源。引入的资源形成一个chunk
(代码块),分别将这些chunk
进行处理(例如将es6
转化,将sass
预处理为css
等,这些操作统一称为打包),将打包好的文件输出为静态资源bundle
五个核心概念
-
Entry
指示
webpack
以哪个文件为打包的起点,并分析构建好内部资源依赖图。 -
Output
指示
webpack
将打包后的资源bundle
输出到哪里,以及如何命名。 -
Loader
让
webpack
能够去处理那些非js
代码(webpack
本身只理解js
代码),如同翻译官的角色。loader
模块下载后,课配置直接使用。 -
Plugins
可以用于执行范围更广泛的任务,包括从打包优化和压缩,到重新定义环境中的变量等。
plugins
插件下载后,还需引入才可配置使用。 -
Mode
development
:能让代码本地调试运行的环境production
:能让代码优化上线的运行环境
webpack
能处理js/json
资源,不能处理css/img
等其他资源;打包的生产环境或开发环境代码,ES6
模块化已经编译为浏览器能识别的模块化;打包的生产环境比开发环境多一个js
压缩的过程。
webpack.config.js
指示webpack
需要进行的工作,运行webpack
指令时,会加载文件内的配置。所有构建工具都是基于nodejs
平台运行的,默认采用commonjs
标准模块化。
css
文件编译处理
style-loader
:创建style
标签,将已转化为js的样式资源插入,然后添加到head
中生效;css-loader
:将css
文件转化为commonjs
模块加载到js中,模块内容为样式字符串;less-loader
:将less
文件编译成css文件,需要依赖less
插件。
{
test: /\.css$/, //匹配文件
use: [ //use中loader执行顺序从后往前
'style-loader', //创建style标签,将js中的样式资源插入,然后添加到head中生效
'css-loader', //将css文件变成commonjs模块加载到js中,模块内容为样式字符串
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader', //将less文件编译成css文件,需要依赖less插件
]
},
html
文件编译处理
html-webpack-plugin
:不添加任何配置,默认会创建一个空的html,自动引入打包输出的所有资源(js/css);如果需要有结构的html文件,可以进行自定义配置。
new HtmlWebpackPlugin({
template: './src/index', //复制./src/index.html文件,并自动引入打包输出的所有资源
})
图片资源编译处理
使用url-loader
(依赖file-loader
,默认处理不了html
中的img
图片,webpack5
不再使用)处理图片资源,limit
配置表示图片大小小于8kb的情况下,会通过base64
处理转换成字符串方式。base64
可以减少请求数量,减轻服务器压力,但同时图片体积会更大,文件请求速度会更慢。
使用html-loader
处理html
文件的img
图片,该插件负责引入img
图片,从而能被url-loader
进行处理。由于url-loader
是使用es6
模块处理文件,而html-loader
使用commonJs
引入图片,解析会出问题:[object Module]
,此时url-loader
应使用esModule
配置。
{
test: /\.(png|jpg|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[name]_[hash:10].[ext]', //name为图片文件名;hash:10取图片hash的前10位;ext取文件原来的扩展名
esModule: false, //关闭url-loader的es6模块化,使用commonJs解析
}
},
{
test: /\.html$/,
loader: 'html-loader'
}
在webpack5
中我们使用assets-module
,url-loader
在这个版本中已经被废弃。
{
test: /\.(png|jpe?g|gif)/,
type: 'assets',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024,
}
},
generator: {
filename: 'img/[name]_[hash:10].[ext]'
}
}
其他资源编译处理
{
exclude: /\.(css|jpg|png|gif|html|less|js)$/,
loader: 'file-loader',
options: {
name: '[name]_[hash:10].[ext]'
}
}
devServer
开发服务器,用来做自动化,能够自动编译,自动打开浏览器,自动刷新浏览器等。只会在内存中编译打包,不会有任何输出,output的配置将不再有用,终止服务器后,内存中存在的编译包将会自动删除。启动devServer
指令为:webpack-dev-server
(需下载该插件)
devServer: {
contentBase: resolve(__dirname, 'build'), //需要运行的项目的文件目录(构建后的目录),webpack5不用配置该选项(该选项已被删除)
compress: true, //启动gzip压缩,让项目体积更小,启动更快
port: 9006, //开发服务器的端口号
open: true, //自动打开浏览器
}
打包文件优化
mini-css-extract-plugin
插件可以将样式文件从js代码中抽离出来,单独成一个文件目录,通过link
标签引入。将css单独提取出来,可以减小js文件大小
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
{
test: /\.css$/, //匹配文件
use: [ //use中loader执行顺序从后往前
// 'style-loader',
MiniCssExtractPlugin.loader, //取代style-loader,提取出css代码
'css-loader',
]
},
plugins: [
new MiniCssExtractPlugin({
filename: './css/built.css', //对输出的css文件进行重命名,注意该路径为相对路径
})
]
css
兼容性处理
使用postcss
,依赖于插件postcss-loader
与postcss-preset-env
(帮助postcss
找到package.json
中browserslist
里面的配置,通过配置加载指定的css
兼容性样式,可以使兼容性精确到某一个浏览器版本。默认是找生产环境browserslist
,若要找development
环境,需要设置node
环境变量:process.env.NODE_ENV = development
)
"browserslist": { //package.json
"development": [
"last 1 chrome version", //兼容至少最近的一个chrome浏览器版本
"last 1 safari version"
],
"production": [
">0.2%", //大于99.8%的浏览器
"not dead", //不要已经废弃的浏览器版本
"not op_mini all", //不要op_mini浏览器,webpack5已经删除
]
}
{ //webpack.config.js
test: /\.css$/, //匹配文件
use: [ //use中loader执行顺序从后往前
// 'style-loader',
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss', //固定写法
plugins: () => [
require('postcss-preset-env')()
]
}
},
{ //webpack5用法
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: ['postcss-preset-env']
}
},
}
]
},
css
压缩
使用插件optimize-css-assets-webpack-plugin
,webpack.config.js
中直接调用插件,默认的配置已经足够。
js
语法检查
语法检查只针对js文件,使用eslint-loader
插件(依赖于eslint库),应该只检查自己的源代码,排除其他插件代码。需要在package.json
中eslintConfig
设置具体的检查规则。推荐使用airbnb
风格指南,指示如何规范的编写js代码。运用airbnb
可以通过使用插件eslint-config-airbnb
(包含react
风格建议)或eslint-config-airbnb-base
(不包含react风格建议)。
eslint-config-airbnb
依赖于插件eslint
,eslint-plugin-import
, eslint-plugin-react
, eslint-plugin-react-hooks
, eslint-plugin-jsx-a11y
eslint-config-airbnb-base
依赖于插件eslint
,eslint-plugin-import
{
test: /\.js$/,
exclude: /node_modules/,
enforce: 'pre', //优先执行
loader: 'eslint-loader',
options: {
fix: true, //自动修复代码格式问题
}
}
//eslint-disable-next-line 不检查下一行代码
{ //packag.json
"eslintConfig": {
"extends": "airbnb-base" //使用该包进行语法检查
}
}
js
兼容性处理
使用bable-loader
插件,依赖于插件@babel/core
与@babel/preset-env
,只能转换基本语法,如promise不能转换。
{
test: /\.js/,
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'], //指示babel做怎样的兼容性处理
}
}
全部js兼容性处理还需插件@babel/polyfill
,直接在js文件中引入import '@babel/polyfill'
。该插件会将所有兼容性代码全部引入,导致文件体积太大。
按需引入需要做兼容性处理的代码,需要借助corejs
,需要下载插件@babel/core
。使用这种方法就不能同时使用第二种方法。
{ //有报错
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage', //按需下载
corejs: {
version: 3, //指定corejs版本
},
targets: { //指定兼容性做到哪个版本浏览器
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17',
}
}
]
]
}
},
webpack
性能优化
开发环境性能优化
-
优化打包构建速度
HMR
:hot module replacement
(热模块替换/模块热替换),一个模块发生变化,只会重新打包这一个模块(而不是打包整个模块),不会重新刷新浏览器,极大提升构建速度。devServer
配置中添加hot: true
就可以使用该功能。样式文件由于style-loader
内部实现了HMR
功能,可以实现热更新。因此在开发环境中应该使用style-loader
,使样式文件打包更快;html
文件默认不支持该功能,由于项目中只存在一个,html
文件发生变化的时候也只需要更新这一个文件,因此不需要HMR
功能;js
文件默认也不支持该功能,若要实现该功能(只能处理非入口js文件),则需要添加代码:if(module.hot) { //为true则表示HMR功能为开启状态 module.hot.accept('./print.js', () => { //module.hot.accept监听print.js文件,一旦该文件发生变化,其他模块不会重新打包构建,只会再次执行当前这个回调函数 print(); }) }
-
优化代码调试
source-map
:一种提供源代码到构建后代码映射的技术,如果构建后代码出错了,通过映射,可以追踪到源代码错误位置。使用方式:在webpack.config.js
中添加配置devtool: 'source-map'
cheap-module-source-map
中module
表示会将loader
的source-map
也加入。开发环境推荐eval-source-map
更快,生产环境推荐source-map
生产环境性能
-
优化打包构建速度
one-of
可以在webpack
构建的时候,相应文件只用匹配一个规则,此是有一个问题,相同类型文件不能有两个规则来处理。解决方法是,将处理相同文件的多个规则移出one-of
。rules: [{}, {oneOf: []}]
babel
缓存:配置
babel-loader
规则选项cacheDirectory
为true
,表示在第二次构建时, 会读取之前的缓存。使第二次构建速度更快。 -
优化代码运行的性能
文件资源缓存:让代码上线运行缓存更好使用
hash
:每次webpack构建时,都会生成一个唯一的hash
值,将js
和css
文件名加上hash
值,可以使每次构建后都能拿到最新的代码。但由于webpack
每次构建都会生成一个新的hash
值,导致所有的缓存都会失效。chunkhash
:根据chunk
生成的hash
值,如果打包来源于同一个chunk
,hash
值就一样。chunk
:由入口文件加上入口文件中引入的js
或css
文件形成一个chunk
。由于css
是在js
中被引入的,因此同属于一个chunk
,所以在其中部分模块发生变化时,也会使这一个chunk
相关的所有缓存失效。cotenthash
:根据文件的内容生成相应的hash
值,不同文件的hash
值一定不一样,从而实现,当前文件内容更新,只更新当前文件的hash
值,获取最新文件代码,其他文件还是来自于缓存。tree shaking
去除无用代码,减少代码体积。在使用ES6模块 化,
webpack
中mode
为production
时,会自动开启该动能。如果配置sideEffects: false
表示所有代码都没有副作用,都可以进行tree shaking
,这样可能会导致直接引入的代码,例如css
引入被去除。配置sideEffects: [*.css]
,改类型文件将不会执行tree shaking
。代码分割
可以自动将
node_modules
中代码单独打包成一个chunk
最终输出;自动分析多入口chunk
中,有没有公共的文件,如果有,会打包成单独的一个chunk
;import
动态导入语法,能将某个文件单独打包,实现懒加载。{ optimization: { splitChunks: { chunks: 'all', } } }
多进程打包
使用thread-loader
模块,开启多进程打包。在thread-loader
配置后的loader
将会开启过进程打包。但进程启动大约需要600ms,进程通信也有一定的开销,因此只有工作消耗时间比较长(js代码比较多),才需要多进程打包。
{
loader: 'thread-loader',
options: {
worker: 2
}
}
网友评论