学一点Webpack配置:Webpack的优化
特别声明:小站对部分原创文章已开启付费阅读,并开通年费VIP通道,年费价格为 ¥365.00元。如果您喜欢小站的内容,可以点击开通会员进行全站阅读。如果您对付费阅读有任何建议或想法,欢迎发送邮件至: airenliao@gmail.com!(^_^)
在上一篇中花了14小节主要和大家一起探讨了Webpack 4.x的一些基本配置,比如初始化项目,添加各种Loader、React、Typescript、Sass、PostCSS、CSS Modules等配置、图片加载、字体加载以及各种代码检测的能力,比如ESLint的配置、Prettier的配置和StyleLint的配置。在接下来这个部分,主要和大家一起来探讨Webpack 4.x中的一些优化方面的配置。比如开发环境的优化、Webpack自身的优化、文件压缩和依赖监控以及应用分析相关的配置。如果感兴趣的话,欢迎继续往下阅读。
在阅读接下来的内容之前,如果你没有阅读上一篇,建议你先花点时间阅读上一篇,这样会更有系统性的学习。
Step15:开发环境优化
请把分支切换到
step15
查看代码。
开启局部模块热重载
在这一节中我们来对基本环境做一些优化。在开发环境中引入webpack.HotModuleReplacementPlugin
用于启用局部模块热重载,方便我们开发。
我们在Step03中将Webpack的环境分离出来了,有关于Webpack开发环境的配置都将在webpack.dev.js
做调整。如果我们要在开发环境加上webpack.HotModuleReplacementPlugin
就需要在webpack.dev.js
的plugins
来做调整:
// ...
module.exports = merge(commonConfig, {
// ...
// 开发环境下需要的相关插件配置
plugins: [new webpack.HotModuleReplacementPlugin()],
// ...
});
另外在devServer
也做一些调整:
// 开发服务器
devServer: {
hot: true, // 热更新,无需手动刷新
contentBase: DIST_PATH, //
host: '0.0.0.0', // host地址
port: 8080, // 服务器端口
historyApiFallback: true, // 该选项的作用所用404都连接到index.html
overlay: {
// 当出现编译错误或警告时,就在页面上显示一层黑色的背景层和错误信息
errors: true,
},
inline: true,
},
使用静态资源路径
网页中总是会使用到一些静态资源,将这些静态资源部署到CDN服务上,使用得用户可以就近访问资源,加快访问速度。在Webpack中,我们可以通过publicPatch
来配置CDN服务器对应的URL
。
就我们这个工程而言,可以在webpack.common.js
中output
中指定publicPath
:
// webpack.common.js
// 编译输出的JS入路径
// 告诉Webpack在哪里输出它所创建的bundle,以及如何命名这些文件
output: {
path: DIST_PATH, // 创建的bundle生成到哪里
filename: '[name].bundle.js', // 创建的bundle的名称
sourceMapFilename: '[name].js.map', // 创建的SourceMap的文件名
publicPath: '/', // 指定存放静态资源的CDN地址
},
为导出的JS文件添加hash
当我们修改代码,bundle
被重新打包,很可能在客户端上看到的效果并不是最新的效果,这有可能是缓存所造成的,有的时候需要多次刷新浏览器,甚至是要手动去清除缓存。不管是在开发环境还是生产环境,这直接影响我们的开发效率。在Webpack中我们可以很轻易的解决这个问题。只需要在输出的JS文件上加上hash
值,这样一来,每次输出的JS文件名都会不同,那么文件也就不会被缓存。
只需要在output
的filename
值上添加hash
值:
// webpack.common.js
output: {
path: DIST_PATH, // 创建的bundle生成到哪里
filename: '[name].bundle.[hash].js', // 创建的bundle的名称
sourceMapFilename: '[name].js.map', // 创建的SourceMap的文件名
publicPath: '/', // 指定存放静态资源的CDN地址
},
输出的bundle.js
会每次都带上相应的hash
值:
注意,如果你在Webpack配置中使用了webpack.HotModuleReplacementPlugin()
的话,那么在output.filename
中的值不能使用[chunkhash]
,只能使用[hash]
。
这样一来每次修改代码都会生成一个带hash
的JS文件。要是你执行npm run build
同样会这样,并且会让你项目中/dist
目录下有关于bundle.js
的文件会越来越多,比如:
编译前清理dist目录
上一节我们看到了,每次都会为bundle.js
新增文件,如果多次修改,再次编译或打包就会在/dist
目录下生成一堆的JS文件,但上一次打包的文件对于我们来说没有实际用处。因此,我们需要在每次打包时清除/dist
目录下的旧文件。
实现该功能,可以借助Webpack的CleanWebpackPlugin
来实现,在配置之前先安装该插件:
⇒ npm i clean-webpack-plugin -D
然后webpack.common.js
中添加相应的配置:
// webpack.common.js
// 注意最新版本引用CleanWebpackPlugin 不能使用 const CleanWebpackPlugin = require('clean-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
// ...
// 模块解析
module: {
rules: [
// ...
]
// 插件
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
inject: true,
template: HtmlWebpackTemplate,
appMountId: 'root',
filename: 'index.html',
}),
],
};
另外一个细节,如果配置中同时出现CleanWebpackPlugin
和HtmlWebpackPlugin
时,CleanWebpackPlugin
需要放置在HtmlWebpackPlugin
的前面。
配置完成之后,你在命令终端执行npm run build
的时候,/dist
目录下中以前的bundle.js
会自动清除。
这里额外提一下,在HtmlWebpackPlugin
的配置中我们可以添加minify
相关的配置,这样会将打包生的.js
和.css
文件引入到.html
文件中:
// webpack.common.js
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
inject: true,
template: HtmlWebpackTemplate,
appMountId: 'root',
filename: 'index.html',
minify: {
removeComments: true, // 去掉注释
collapseWhitespace: true, // 去掉多余空白
removeAttributeQuotes: true, // 去掉一些属性的引号,例如id="moo" => id=moo
},
}),
],
有了上面的配置之后,在代码中的注释、空白等就会自动清除,比如App.tsx
中的注释:
<!-- App.tsx -->
<div style={{ textAlign: 'center' }}>
<img src={String(Security)} />
{/* 下面这样引用,图片会报404错误 */}
{/* <img src="../../../../assets/images/security.svg" alt=""/> */}
</div>
编译出来.html
中就看不到了。如下图所示:
Step16:Webpack的优化
请把分支切换到
step16
查看代码。
在这一步我们主要来一起探讨Webpack中的一些优化。
文件路径优化
在Webpack中我们配置了resolve.extension
之后可以不用在require
或import
的时候加文件扩展名,Webpack会依次尝试添加扩展名进行匹配。在resolve
中还可以通过alias
来配置别名,可以加快Webpack查找模块的速度。
// webpack.common.js
alias: {
'@': path.resolve(__dirname, '../src'),
'@components': path.resolve(__dirname, '../src/components'),
'@pages': path.resolve(__dirname, '../src/pages'),
'@images': path.resolve(__dirname, '../src/assets/images'),
'@fonts': path.resolve(__dirname, '../src/assets/fonts'),
'@icons': path.resolve(__dirname, '../src/assets/icons'),
},
在实际使用的时候,我们就可以使用定义好的别名了:
<!-- App.tsx -->
const Security = require('@images/security.svg');
// app.css
body {
background: url("~@images/body-background.jpg") no-repeat center,
linear-gradient(to bottom, #f560a9, #09aefa, #2390af) no-repeat center;
}
有一点需要特别注意,在TypeScript环境下,如果仅在Webpack中配置别名是不够的,比如:
<!-- App.tsx -->
import Button from '@components/Button/Button';
编译的时候会报错:
Failed to compile.
[at-loader] ./src/pages/index/components/App/App.tsx:5:20
TS2307: Cannot find module '@components/Button/Button'.
我们需要在tsconfig.json
中添加paths
的配置:
{
"compilerOptions": {
"sourceMap": true,
"noImplicitAny": false,
"noUnusedLocals": true,
"noUnusedParameters": true,
"module": "es2015",
"target": "es6",
"lib": [
"es2015",
"es2017",
"dom"
],
"removeComments": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"moduleResolution": "node",
"pretty": true,
"jsx": "preserve",
"allowJs": true,
"baseUrl": ".",
"rootDir": "./src",
"outDir": "./dist/",
"paths": {
"@/*": ["./src/*"],
"@components/*": ["./src/components/*"],
"@pages/*": ["./src/pages/*"],
"@images/*": ["./src/assets/images/*"],
"@fonts/*": ["./src/assets/fonts/*"],
"@icons/*": ["./src/assets/icons/*"],
}
},
"include": ["./src/**/*"],
"exclude": ["node_modules"]
}
上面的问题就解决了。
优化CSS文件
如果不做相关的配置,打包的时候CSS代码会直接打到JavaScript文件中。在Webpack中使用MiniCssExtractPlugin
插件可以单独生成.css
文件。这样CSS和JavaScript文件可以并行下载,提高页面加载性能。
先安装mini-css-extract-plugin
:
⇒ npm i mini-css-extract-plugin -D
由于MiniCssExtractPlugin
插件还不支持HMR
,为了不影响开发效率,因为需要对开发环境做一下判断。目前有两种方式:
- 把
webpack.common.js
中有关于样式的配置分开到webpack.dev.js
和webpack.prod.js
中分别处理,在webpack.prod.js
中配置MiniCssExtractPlugin
插件 - 在
webpack.common.js
中通过process.env.NODE_ENV
的值来做判断,如果值为production
时才配置MiniCssExtractPlugin
插件
在这里我们采用第二种方式:
// webpack.common.js
// ...
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
// ...
// 模块解析
module: {
rules: [
// ...
// CSS Loader
{
test: /\.(sc|sa|c)ss$/,
exclude: /node_modules/,
include: path.resolve(__dirname, '../src'),
use: [
{
loader: process.env.NODE_ENV !== 'dev' ? MiniCssExtractPlugin.loader : 'style-loader',
options: {
sourceMap: true,
},
},
{
loader: 'css-modules-typescript-loader',
options: {
named
如需转载,烦请注明出处:https://www.w3cplus.com/javascript/webpack-config-part2.html
如果文章中有不对之处,烦请各位大神拍正。如果你觉得这篇文章对你有所帮助,打个赏,让我有更大的动力去创作。(^_^)。看完了?还不过瘾?点击向作者提问!