提取css代码

  1. 要求:让 webpack 把 css 代码内容字符串单独提取到 dist 下的 css 文件中
  2. 需要:mini-css-extract-plugin 插件来实现
  3. 步骤:
  • 下载 mini-css-extract-plugin 插件软件包到本地项目中
1
npm i --save-dev mini-css-extract-plugin
  • 配置 webpack.config.js 让 Webpack 拥有该插件功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const MiniCssExtractPlugin = require("mini-css-extract-plugin")

module.exports = {
// ...
module: {
rules: [
{
test: /\.css$/i,
// use: ['style-loader', 'css-loader']
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
plugins: [
// ...
new MiniCssExtractPlugin()
]
};
  1. 注意:不能和 style-loader 一起使用
  2. 好处:css 文件可以被浏览器缓存,减少 JS 文件体积,让浏览器并行下载 css 和 js 文件

压缩

  1. 需求:把提出的 css 文件内样式代码压缩
  2. 需要:css-minimizer-webpack-plugin 插件来实现
  3. 步骤:
  • 下载 mini-css-extract-plugin 插件软件包到本地项目中
1
npm i css-minimizer-webpack-plugin --save-dev 
  • 配置 webpack.config.js 让 Webpack 拥有该插件功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

module.exports = {
// ...
// 优化
optimization: {
// 最小化
minimizer: [
// 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即
// `terser-webpack-plugin`),将下一行取消注释(保证 JS 代码还能被压缩处理)
`...`,
new CssMinimizerPlugin(),
],
}
};

CDN使用

  1. 需求:开发模式使用本地第三方库,生产模式下使用 CDN 加载引入
  2. CDN定义:内容分发网络,指的是一组分布在各个地区的服务器
  3. 作用:把静态资源文件/第三方库放在 CDN 网络中各个服务器中,供用户就近请求获取
  4. 好处:减轻自己服务器请求压力,就近请求物理延迟低,配套缓存策略

实现需求的思路图:

使用:

  • 在 html 中引入第三方库的 CDN 地址 并用模板语法判断
1
2
3
<% if(htmlWebpackPlugin.options.useCdn){ %>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.2.3/css/bootstrap.min.css" rel="stylesheet">
<% } %>
  • 配置 webpack.config.js 中 externals 外部扩展选项(防止某些 import 的包被打包)
1
2
3
4
5
6
7
8
9
10
// 生产环境下使用相关配置
if (process.env.NODE_ENV === 'production') {
// 外部扩展(让 webpack 防止 import 的包被打包进来)
config.externals = {
// key:import from 语句后面的字符串
// value:留在原地的全局变量(最好和 cdn 在全局暴露的变量一致)
'bootstrap/dist/css/bootstrap.min.css': 'bootstrap',
'axios': 'axios'
}
}
1
2
3
4
5
6
7
8
9
const config = {
plugins: [
new HtmlWebpackPlugin({
// ...
// 自定义属性,在 html 模板中 <%=htmlWebpackPlugin.options.useCdn%> 访问使用
useCdn: process.env.NODE_ENV === 'production'
})
]
}

分割公共代码

需求:把 2 个以上页面引用的公共代码提取

步骤:

配置 webpack.config.js 的 splitChunks 分割功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const config = {
// ...
optimization: {
// ...
splitChunks: {
chunks: 'all', // 所有模块动态非动态移入的都分割分析
cacheGroups: { // 分隔组
commons: { // 抽取公共模块
minSize: 0, // 抽取的chunk最小大小字节
minChunks: 2, // 最小引用数
reuseExistingChunk: true, // 当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用
name(module, chunks, cacheGroupKey) { // 分离出模块文件名
const allChunksNames = chunks.map((item) => item.name).join('~') // 模块名1~模块名2
return `./js/${allChunksNames}` // 输出到 dist 目录下位置
}
}
}
}

按需加载

很多时候我们不需要一次性加载所有的JS文件,而应该在不同阶段去加载所需要的代码。webpack内置了强大的分割代码的功能可以实现按需加载。

比如,我们在点击了某个按钮之后,才需要使用使用对应的JS文件中的代码,需要使用 import() 语法:

1
2
3
document.getElementById('btn').onclick = function() {
import('./handle').then(fn => fn.default());
}

import() 语法,需要 @babel/plugin-syntax-dynamic-import 的插件支持,但是因为当前 @babel/preset-env 预设中已经包含了 @babel/plugin-syntax-dynamic-import,因此我们不需要再单独安装和配置。

直接 npm run build 进行构建,构建结果如下:

img

webpack 遇到 import(****) 这样的语法的时候,会这样处理:

  • 以 为入口新生成一个 Chunk
  • 当代码执行到 import 所在的语句时,才会加载该 Chunk 所对应的文件(如这里的1.bundle.8bf4dc.js)

大家可以在浏览器中的控制台中,在 NetworkTab页 查看文件加载的情况,只有点击之后,才会加载对应的 JS