Code split 代码分割
默认情况下,一些第三方库以及一些首页用不到的业务代码很可能都打到相同的bundle中在第一时间加载,那将使首页加载的速度变慢
代码分割的主要目的是将代码分割到不同的bundle中,这样就可以对bundle进行选择性的并行加载或者按需加载
默认情况下,打包代码时会将所有js文件打包到一个文件中,体检太大了。如果我们只渲染首页,就应该只加载首页的js文件,其他文件不应该加载
所以我们要将打包生成的文件进行代码分割,生成多个js文件。渲染哪个页面只加载某个js文件。这样加载的资源就少,速度就更快。
代码分割(Code Split) 主要做了两件事:
1、分割文件: 将打包生成的文件进行分割,生成多个js文件
2、按需加载:需要哪个文件就加载哪个文件
多入口对应多出口 配置了几个入口,至少输出几个 js 文件。
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
//单入口
//entry: './src/index.js',
多入口
entry:{
app:'./src/app.js',
index:'./src/index.js'
}
output: {
path: path.resolve(__dirname, 'build'),
////当entry有多个入口文件时,用[]可以输出多个文件 filename: '[name].js',
// 入口文件打包输出的文件名
filename: 'static/js/[name].js',
// 给打包输出的其他文件命名
chunkFilename:"static/js/[name].chunk.js",
//自动清空上次打包的内容
// 原理:在打包前,将path整个目录清空,再进行打包
clean: true
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'})
]
}
》》》 提取重复代码
如果多入口文件中都引用了同一份代码,我们不希望这份代码被打包到两个文件中,导致代码重复,体积更大。
我们需要提取多入口的重复代码,只打包生成一个 js 文件,其他文件引用它就好。
/*
1. 可以将node_modules中代码单独打包一个chunk最终输出
2. 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk
*/
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// 单入口
// entry: './src/js/index.js',
entry: {
index: './src/js/index.js',
test: './src/js/test.js'
},
output: {
// 入口文件打包输出的文件名
filename: 'static/js/[name].[contenthash:10].js',
// 给打包输出的其他文件命名
chunkFilename:"static/js/[name].[contenthash:10].chunk.js",
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
/*
1. 可以将node_modules中代码单独打包一个chunk最终输出
2. 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk
*/
optimization: {
splitChunks: {
chunks: 'all'
//其他配置 采用默认配置
}
},
mode: 'production'
};
》》optimization 的默认配置
optimization: {
// 代码分割配置
splitChunks: {
chunks: "all", // 对所有模块都进行分割
// 以下是默认值
// minSize: 20000, // 分割代码最小的大小
// minRemainingSize: 0, // 类似于minSize,最后确保提取的文件大小不能为0
// minChunks: 1, // 至少被引用的次数,满足条件才会代码分割
// maxAsyncRequests: 30, // 按需加载时并行加载的文件的最大数量
// maxInitialRequests: 30, // 入口js文件最大并行请求数量
// enforceSizeThreshold: 50000, // 超过50kb一定会单独打包(此时会忽略minRemainingSize、maxAsyncRequests、maxInitialRequests)
// cacheGroups: { // 组,哪些模块要打包到一个组
// defaultVendors: { // 组名
// test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
// priority: -10, // 权重(越大越高)
// reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
// },
// default: { // 其他没有写的配置会使用上面的默认值
// minChunks: 2, // 这里的minChunks权重更大
// priority: -20,
// reuseExistingChunk: true,
// },
// },
// 修改配置
cacheGroups: {
// 组,哪些模块要打包到一个组
// defaultVendors: { // 组名
// test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
// priority: -10, // 权重(越大越高)
// reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
// },
default: {
// 其他没有写的配置会使用上面的默认值
minSize: 0, // 我们定义的文件体积太小了,所以要改打包的最小文件体积
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
}
动态导入 - 按需加载
// 案例:点击按钮时加载一个重型模块
document.getElementById('btn').addEventListener('click', async () => {
// 使用魔法注释指定 chunk 名称
// import 动态导入:会将动态导入的文件代码 分割(拆分成单独模块),在需要使用的时候自动加载
const { zen} = await import(
/* webpackChunkName: "chart" */
'./xxx.js'
);
zen();
//或者, eslint 不能识别动态导入需要,需要额外追加配置 import
import(/*webpackChunkName:"zen"*/,'./xxjs').then({zen})=>{}).catch((err)=>{})
});
// React 组件懒加载
const HeavyComponent = React.lazy(() =>
import(/* webpackChunkName: "heavy-comp" */ './HeavyComponent')
);
抽离代码 splitChunks
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// 单入口
entry: './src/js/index.js',
output: {
// 入口文件打包输出的文件名
filename: 'static/js/[name].[contenthash:10].js',
// 给打包输出的其他文件命名
chunkFilename:"static/js/[name].[contenthash:10].chunk.js",
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
/*
1. 可以将node_modules中代码单独打包一个chunk最终输出
2. 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk
*/
optimization: {
splitChunks: {
chunks: 'all',
//其他配置 采用默认配置
}
},
mode: 'production'
};
webpack 5 资源的统一命令
output: {
// 入口文件打包输出的文件名
filename: 'static/js/[name].[contenthash:10].js',
// 给打包输出的其他文件命名
chunkFilename:"static/js/[name].[contenthash:10].chunk.js",
path: resolve(__dirname, 'build'),
// 图片、字体等通过 type:asset 处理的资源的命名方式
assertModuleFileName:"static/media/[hash:10][ext][query]"
},
{
test: /\.(png|jpg|jpeg|gif|svg|webp|ico)$/, // 匹配所有的图片文件
type: "asset", // 图片资源类型
// 因为 output 配置了 assertModuleFileName 下面可以不要了
// 图片资源生成配置
//generator: {
// 输出文件名
//filename: "images/[name].[ext]",
//}
}
preload prefetch 预加载
# Preload: 告诉浏览器立即加载资源
# Prefetch: 告诉浏览器在空闲时才开始加载资源
eslint 配置
npm i eslint-plugin-import -D
// .eslintrc.js
module.exports = {
// 继承 Eslint 规则
extends: ["eslint:recommended"],
env: {
node: true, // 启用node中全局变量
browser: true, // 启用浏览器中全局变量
},
plugins: ["import"], // 解决动态导入import语法报错问题 --> 实际使用eslint-plugin-import的规则解决的
parserOptions: {
ecmaVersion: 6,
sourceType: "module",
},
rules: {
"no-var": 2, // 不能使用 var 定义变量
},
plugins:["import"]
};