什么是代码分离?好处?怎么分?
代码分离是 webpack 中最引人注目的特性之一,能够把代码分离到不同的 bundle 中,然后可以按需加载或并行加载。代码分离可以获取更小的budle,以控制资源加载优先级,使用合理会极大影响加载时间。
常用的方法有三种:
- 入口起点:使用 entry 配置手动的分离代码
- 防止重复:使用 Enty dependencies 或者 SplitChunksPlugin 去重和分离 chunk
- 动态导入:通过模块的内联函数调用来分离代码
入口起点
迄今为止最为简单直观的方法准备
在src中新建 another.js ```javascript import _ from ‘lodash’ // 引入 lodash
console.log(_.join([‘another’, ‘hello’, ‘lodash’], ‘ ‘)) // 拼接字符串
<a name="PXqN1"></a>
#### 配置
```javascript
entry: {
index: './src/index.js', // 配置 index.js 打包入口
another: './src/another.js' // 配置 another.js 打包入口
},
output: { // 出口文件
filename: '[name].bundle.js', // [name] 继承入口文件名 + .bundle.js 后缀
path: path.resolve(__dirname, './dist'), // 出口文件路径
clean: true // 生成新文件的同时是否删除旧文件
},
npx webpack 打包,发现 another.bundle.js 比 index.bundle.js 大很多,原因是我们在 another.js 中引入了 lodash ,webpack会把文件所需要的包也打包进去。
注意
如果多个文件需要引入了同样的包,webpack依然会全部编译,这就导致每个包都很大,严重影响打包效率,这也是 入口起点 代码分离方式的痛点。
防止重复
这个方法依然需要在 entry 中做一些配置,但是相比上面那种方法,他能有效地避免打包重复的代码
准备
我们在 index.js 中也引入 lodash
import _ from 'lodash' // 引入 lodash
console.log(_.join(['index', 'hello', 'lodash'], ' ')) // 拼接字符串
配置
entry: {
index: {
import: './src/index.js',
dependOn: 'shared'
},
another: {
import: './src/another.js',
dependOn: 'shared'
},
shared: 'lodash'
}, // 入口文件路径
output: { // 出口文件
filename: '[name].bundle.js', // 出口文件名
path: path.resolve(__dirname, './dist'), // 出口文件路径
clean: true // 生成新文件的同时是否删除旧文件
},
npx webpack 打包,多出来了一个 shared.bundle.js 文件,他就把我们的lodash单独打包出来了
SplitChunksPlugin
配置
entry: {
index: './src/index.js', // 配置 index.js 打包入口
another: './src/another.js' // 配置 another.js 打包入口
},
optimization: {
splitChunks: {
chunks: 'all' // 配置 SplitChunksPlugin 自动抽离代码
}
}
动态导入
webpack提供了两个动态代码拆分,第一种也是推荐的方式是,使用符合 ECMAScript 提案的 import() 语法来实现动态导入。第二种是webpack特定的 require.ensure。
准备
在开始之前,我们先将上述示例配置的多余 entry 和 optimization 全部注释掉。
我们新建一个 async_module.js 并写入以下内容
function getComponent() {
const element = document.createElement('div');
return import('lodash')
.then(({ default: _ }) => {
const element = document.createElement('div');
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
return element;
})
.catch((error) => 'An error occurred while loading the component');
}
getComponent().then((component) => {
document.body.appendChild(component);
});
在index.js中引入 async_module.js 并打包,发现 lodash 已经被单独打包出来了
优化
我们能否同时打包动态和静态资源呢?
我们将之前的注释打开,然后通过 npx webpack 打包,我们发现动态和静态引入可以被打包出一个公共资源包
疑问
看起来我们通过 SplitChunksPlugin 和 动态导入 没有明显区别,甚至动态导入还会让代码变得复杂,那我们为什么不采用静态导入,而要使用动态导入呢?