这是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战
代码拆分(Code Split)
想象一个情景:
- 用户访问
index.html
,它引用了main-aaaa.js
,main-aaaa.js
缓存期设为一个月,index.html
不缓存。 - 第二天,程序员改动了
main.js
中的一个字符,重新打包main.js
会得到main-bbbb.js
。 - 用户再次访问
index.html
,它引用了main-bbbb.js
,浏览器需要重新请求文件,之前的main-aaaa.js
缓存会在用户硬盘里躺一个月,然后被浏览器清理。 发现什么问题了吗?缓存失效得太快了!任何一个改动都会导致整个 JS 的缓存失效。
怎么解决这个问题?程序员需要根据改动频率将代码分成多个文件。可以将 index.html
的 JS 文分为四个文件:
runtime.js
,该文件是 webpack 自己生成的代码,跟我们的代码隔离开比较好。假设我们不改代码,只是将 webpack 升级,那么就只有runtime.js
会变。vendors.js
,该文件包含全局使用的第三方基础库,比如 React 全家桶和 Vue 全家桶,一般来说我们不会去改这部分代码,只会升级它们。common.js
,该文件包含公司内部的基础库,比如公司内部的 UI 组件库,程序员大概几个月会改一次或升级一次这部分代码。page-index.js
,该文件只包含当前页面的逻辑,每周都会变动。不同的页面拥有不同的page-x.js
文件。
这样一来,如果程序员只是改动了某个页面的 JS,比如 page-login.js
,那么只有 page-login.js
需要被用户重新下载,其他三个文件的缓存就不会失效。
如果程序员只是升级了 Vue,那么只有 vendors.js
需要被用户重新下载。 因此,我们就可以大大减少用户下载的内容的体积了。
除此之外,有些特殊的体积较大的第三方库可以使用动态导入技术。
动态导入(Dynamic Imports)
如果一个 JS 文件太大,不仅下载会慢,而且执行起来也会很耗时。
因此在工作中,不建议让首页的 JS 体积太大,首页 JS 只运行必要的功能,后续功能对应的 JS 使用动态引入来加载。写法如下:
const array = [1,2,3]
import('lodash').then( _ => {
const clone = _.cloneDeep(array)
})
尤其是单页面应用,如果把所有路由对应的 JS 都放到一个 JS 文件里,那么文件体积可能会超过 3Mb,解决办法是把非当前页面的路由对应的组件全都变成动态引入。
使用 Vue Router 的程序员经常会这么写,以达到动态引入组件的效果:
const router = new VueRouter({
routes: [
{ path: '/home', component: () => import('./Home.vue') },
{ path: '/about, component: () => ({
component: import('./About.vue'),
loading: LoadingComponent,
error: ErrorComponent,
})},
]
})
这样一来,就能让大大减少用户查看网页首屏时的下载量了,也就算是加快了页面加载速度。
为什么是「算是」呢?因为首屏虽然变快了,但是每次切换路由时的速度却变慢了。
为了解决动态导入使得用户的后续操作变慢的问题,我们可以使用「预加载」来缓解。 另外,由于 Webpack 可以把动态加载的文件单独打成一个包,与非动态加载的文件分隔开,所以这种方法也属于「代码拆分」.
最后说一句
如果这篇文章对您有所帮助,或者有所启发的话,帮忙关注一下,您的支持是我坚持写作最大的动力,多谢支持。