代码分离是 Webpack 最引人注目的特性之一。
(1)这个特性可以将代码分离到不同的bundle中,然后按需加载或并行加载这些文件
。
(2)所谓bundle,就是我们打包出来的文件。代码分离可以用于获取更小的bundle
,以及控制资源加载优先级
,如果使用合理,可以极大影响加载时间
。从而提高首屏加载速度。
(3)常用的代码分离方法:
文章图片
一、入口起点 —— entry 1、在src下面建一个another-module.js,这个模块里面引入loadash
npm install loadash --save-dev
import _ from 'lodash'
console.log(_.join(['Another', 'module', 'loaded!'], ' '))
webpack.config.js:
module.exports = {
entry: { // *定义两个入口文件,分别key值为index和another
index: './src/index.js',
another: './src/another-module.js'
},
output: {
filename: '[name].bundle.js' // *这里的[name]就会去取entry的key值。例如, another.bundle.js
}
}
执行 npx webpack 可以看到 another.bundle.js 的大小有1.38MB,引入的 loadash.js 也打包在了 another.bundle.js 中。打开 app.html ,可以发现 script 里面引入了这两个 bundle.js.
2、这时候,修改 index.js,即另一个入口文件,也加上 another.bundle.js 的以下代码:
import _ from 'lodash'
console.log(_.join(['Another', 'module', 'loaded!'], ' '))
打包后发现 index.js 也变大了,同时也打包了 loadash.js。
3、因此,entry 入口起点这种方式存在一些问题:
(1)如果入口 chunk 之间包含重复的模块,这些重复模块会被引入各自的 bundle中;
(2)这个方法不够灵活,不能动态地将核心应用程序逻辑中的代码拆分出来。
二、防止重复 1、入口依赖entry的方式
webpack.config.js
module.exports = {
entry: {
index: { // *不采用字符串,采用对象的方式
import: './src/index.js',
dependOn: 'shared'
},
another: {
import: './src/another-module.js',
dependOn: 'shared'
},
shared: 'loadash' // *表示当上面两个模块中有loadash这个模块的时候,就会把他抽离出来,并且把它取名为shared这样一个chunk
},
output: {
filename: '[name].bundle.js'
}
}
打包后可以看到 sahred.bundle.js 被打包出来了,说明把 loadash.js 打包到这个chunk 里面了;其他两个 js 的大小也减小了。并且在 app.html 里面也引入了这三个 js.
文章图片
2、split-chunk-plugin
除了上面 entry 的方式,还可以使用 split-chunks-plugin 这个插件,这个插件也可以把模块中依赖的公共文件给抽离成单独的 chunk。
webpack.config.js:
module.exports = {
entry: {
index: './src/index.js', // *采用字符串
another: './src/another-module.js'
},
output: {
filename: '[name].bundle.js'
},
optimization: {
splitChunks: { // *使用split-chunks-plugin插件
chunks: 'all'
}
}
}
箭头指向的两个文件就是公共部分的chunk
文章图片
三、动态导入 当涉及到
动态代码拆分
时,webpack 提供了两个类似的技术。第一种,也是推荐选择的方式是,使用符合 ECMAScript 提案的
import()
语法来实现动态导入。第二种,则是 webpack 的遗留功能,使用 webpack 特定的
require.ensure
。【webpack|webpack基础(8).代码分离】1、通过import() 语法动态引入
(1)创建 async-module.js 文件
文章图片
function getComponent() {
// *采用import的方式引入
return import('lodash')
.then(({default: _}) => {
const element = document.createElement('div')element.innerHTML = _.join(['Hello', 'webpack'], ' ')return element
})
}getComponent().then((element) => {
document.body.appendChild(element)
})
(2)导入模块
在入口文件 index.js 中 引入刚刚建的async-module.js
index.js:
import ./async-module.js
可以看到公共模块单独打包在了一个文件。
四、动态导入的应用 1. 懒加载 懒加载或者按需加载,是一种很好的优化网页或应用的方式。
这种方式实际上是,先把你的代码在一些逻辑断点处分离开,然后在一些代码块中完成某些操作后,立引用或即将引用另外一些新的代码块。
这样加快了应用的初始加载速度,减轻了它的总体体积,因为有些代码可能永远不会加载。
创建一个math.js,主页面里面点击按钮调用其中的函数。
math.js
export const add = (x, y) => {
return x + y
}export const minus = (x, y) => {
return x - y
}
index.js
const button = document.createElement('button')
button.textContent = '点击执行加法运算'
button.addEventListener('click', () => {
// *使用import动态加载的方式实现懒加载。在这里就是点击了按钮才加载 math.js 文件
// *import里面有一个魔法注释/**/,表示 webpack 打包后的文件名为 math.js
import(/* webpackChunkName: 'math' */'./math.js').then(({ add }) => {
console.log(add(4, 5))
})
})
document.body.appendChild(button)
上例中,采用 import 动态导入的方式,引入了 math.js。打包后发现生成了一个 src_math_js.bundle.js,且其他打包文件大小没有变大。刷新 html 页面,没有加载src_math_js.bundle.js,点击按钮后才加载了这个文件。说明我们懒加载成功了。
import里面有一个注释/**/,我们称它为
魔法注释
,表示 webpack 打包后的文件名为 math.js。再次执行打包之后发现 src_math_js.bundle.js 变成了 math.js。2. 预获取、预加载 Webpack v4.6.0+ 增加了对预获取和预加载的支持。
在声明 import 时,使用下面这些内置指令,可以让 webpack 输出"resource hint(资源提示)",来告知浏览器:
prefetch
: 预获取。在将来某些导航下可能需要的资源;preload
: 预加载。在当前导航下可能需要的资源。(1)prefetch
编辑 index.js 文件,在上一个例子的魔法注释中加第二句
webpackPrefetch: true
const button = document.createElement('button')
button.textContent = '点击执行加法运算'
button.addEventListener('click', () => {
// *添加预获取的魔法注释
import(/* webpackChunkName: 'math', webpackPrefetch: true */'./math.js').then(({ add }) => {
console.log(add(4, 5))
})
})
document.body.appendChild(button)
打包之后发现,浏览器中 html 页面头部追加了一个
,这表示浏览器会在闲置时间预获取 main.js 文件
。且在浏览器中可以观察到,还没有点击按钮就加载好了 math.js。这种方式比刚刚的懒加载还要优秀一点。
(2) preload
也是改一哈魔法注释。效果和懒加载类似,点击按钮之后才加载文件。是并行加载。
/* webpackChunkName: 'math', webpackPreload: true */
prefetch 和 preload 的区别:
- preload chunk 会在父 chunk 加载时,以并行的方式加载。prefetch chunk 会在父 chunk 加载结束后开始加载。
- preload chunk 具有中等优先级,会立即下载。prefetch chunk 在浏览器闲置时下载。
- preload chunk 会在父 chunk 中立即请求,用于当下时刻。prefetch chunk 会用于未来某个时刻。
- 浏览器支持成都不同。
- 代码分离:可以把多个模块共享的代码抽离出去,减少入口文件的大小,从而提高首屏的加载速度。
- 分离代码有三种方法:
(1)入口起点(entry):在 entry 中配置多个入口实现代码的分离。但是可能会有重复的代码。
(2)防止重复:也是在 entry 里面配置,但是可以把共享的代码单独抽离成一个文件,从而防止重复的代码打包。
(3)动态导入:通过 ES6的 import 方法实现代码分离。 - 动态导入有两个应用:
(1)懒加载:在编译的时候把模块打包好,什么时候需要才加载。实现了按需加载。
(2)预获取和预加载: - prefetch: 在网络空闲的时候加载。既不影响首屏加载速度,又省去了将来模块的加载延迟。
- preload: 需要的时候加载。实现了页面模块的并行加载。
推荐阅读
- Webpack5完整教程|webpack(八)代码分离
- vue|vue环境搭建
- webpack|webpack知识点
- webpack|webpack 代码分离
- webpack|webpack 代码分离-08
- 学习|Git、node、npm、webpack、yarn、脚手架是什么
- Java|ElasticSearch 7.8.1教程(from b站狂神)+JD商城仿站
- Nebula|开源图编辑库 NebulaGraph VEditor 的设计思路分享
- #项目: electron仿客户端QQ简易版