简介
首页展示的时候只需要对应的js,并不需要全部的js模块,所以这里就可以用按需加载。
目标:配合es6的按需加载import()方法,可以做到减少首页包体积,加快首页的请求速度,只有当需要的时候才会加载对应js。
按需加载某种程度上是代码的打包分割,默认只输出一个chunk.js, 配置动态按需加载之后,会出现多个chunk.js
实践
借助es6的
import(*)的语法
备注: 按需加载,我们需要明白触发时机,比如目前常见的两种形式:
- 事件触发(触发点击事件进而触发动态加载)
- 路由触发(地址栏变化触发动态路由懒加载)
demo1事件触发
// main.js
window.document.getElementById('btn').addEventListener('click', function () {
// 当按钮被点击后才去加载 show.js 文件,文件加载成功后执行文件导出的函数
import(/* webpackChunkName: "show" */ './show').then((show) => {
show('Webpack');
})
});
// show.js
module.exports = function (content) {
window.alert('Hello ' + content);
};
解析:
import(/* webpackChunkName: "show" */ './show') Webpack 内置了对 import(*) 语句的支持。Webpack会以 ./show.js 为入口新生成一个 Chunk(就像main.js入口生成默认chunk一样),当click事件被点击,此时就会加载import中指定的show.js,加载完show.js之后,import()会返回一个promise,并且将show.js中的默认导出内容作为下一个then的参数。
为了正确的输出在/* webpackChunkName: "show" */中配置的 ChunkName,还需要配置下 Webpack,配置如下:
module.exports = {
// JS 执行入口文件
entry: {
main: './main.js',
},
output: {
// 为从 entry 中配置生成的 Chunk 配置输出文件的名称
filename: '[name].js',
// 为动态加载的 Chunk 配置输出文件的名称
chunkFilename: '[name].js',
}
};
demo2路由触发
// 示例:router/index.js 路由配置文件
import Foo form './component/Foo.vue'
import Bar form './component/Bar.vue'
import Baz form './component/Baz.vue'
// 将上面的3行import导入修改为下面的import()d动态导入
// Foo.vue 和Bar.vue会被打包到同一个chunk为`group-foo`中
// Baz.vue 被单独打包到`group-baz`这个chunk中
const Foo = () => import(/*webpackChunkName: "group-foo"*/ './component/Foo.vue')
const Bar = () => import(/*webpackChunkName: "group-foo"*/ './component/Bar.vue')
const Baz = () => import(/*webpackChunkName: "group-baz"*/ './component/Baz.vue')
Vue.use(VueRouter);
const routes = [
{ path: "/foo", component: Foo },
{ path: "/bar", component: Bar },
{ path: "/baz", component: Baz },
];
备注
问题1:需要babel转换代码时,Babel 报出错误说不认识 import(*) 语法?
导致上面问题的原因是 import(*) 语法还没有被加入到在 ES6语言中提到的 ECMAScript 标准中去, 为此我们需要安装一个 Babel 插件 @babel/plugin-syntax-dynamic-import,用来支持 import(*) ,并且需要在 .babelrc /babel.config.js中进行配置
// .babelrc
{
"presets": [
"env",
"react"
],
"plugins": [
"@babel/plugin-syntax-dynamic-import"
]
}
问题2:浏览器不支持promise怎么办?
在使用 import() 分割代码后,你的浏览器并且要支持 Promise API 才能让代码正常运行, 因为 import() 返回一个 Promise,它依赖 Promise。对于不原生支持Promise的浏览器,你可以注入 Promise polyfill
问题2:import(/* webpackChunkName: "show" */)中的/**/包含的是什么?
/* webpackChunkName: "show" */ 的含义是为动态生成的 Chunk 赋予一个名称,如果不指定动态生成的Chunk的名称,默认名称将会是 [id].js。 /* webpackChunkName: "show" */ 是在 Webpack3 中引入的新特性,在 Webpack3 之前是无法为动态生成的 Chunk 赋予名称的。