FrankKai.github.io
FrankKai.github.io copied to clipboard
ES6之使用import()做动态引入
项目中有用到vue-router和webpack实现异步加载组件,使用的就是import的函数语法import()
语法
在学习webpack的代码拆分章节时,也有专门的一个章节用来讲这个,因此需要系统性学习一下import的函数语法import()
。
- 最简单的结构
- 初识import()
- 为什么要动态引入
- 动态引入使用示例
- 如何在webpack中使用import()实现动态引入
- vue-router中如何结合webpack如何动态引入
最简单的结构
var promise = import("module-name");
初识import()
标准版的import语法是static的,因此会在加载时就引入所有的代码。 但是很多情况下我们需要动态引入模块,也就是说满足特定条件才加载模块,我们可以使用动态引入去做这件事。
为什么要动态引入
一共有5个原因。
- 全部是静态引入的话,会减慢我们代码的加载,而且需要用到导入的代码的可能性很低,或者你想一会儿再使用这一段代码
- 全部是静态引入的话,会增大程序的内存使用而且这些消耗大量内存的代码可能现在并不需要
- 加载时如果引入的模块不存在
- 当import()被动态添加时(静态import只能静态添加)
- 当导入的模块有副作用时,除非有些条件是真的,否则你不想有这些副作用。(建议不要在模块中产生任何副作用,但有时无法在模块依赖项中控制这一点。)
动态引入使用示例
在必要时使用动态引入。 静态引入用于加载初始化的依赖,可以从静态分析工具和tree shaking中做优化。
为了做到动态引入一个module,import需要被当做一个函数去调用。 import当函数调用时,返回结果是一个promise。
import('/modules/my-modules.js')
.then((module)=>{
// 用module做点什么
})
还可以用await语法:
let module = await import('/modules/my-module.js');
如何在webpack中使用import()实现动态引入
// project
webpack-demo
|- package.json
|- webpack.config.js
|- /dist
|- /src
|- index.js
|- /node_modules
// src/index.js
+ function getComponent() {
+ return import(/* webpackChunkName: "lodash" */ '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);
+ })
或者
// src/index.js
+ async function getComponent() {
+ const element = document.createElement('div');
+ const { default: _ } = await import(/* webpackChunkName: "lodash" */ 'lodash');
+
+ element.innerHTML = _.join(['Hello', 'webpack'], ' ');
+
+ return element;
}
getComponent().then(component => {
document.body.appendChild(component);
});
打包后的结果为:体积很小的主程序;体积很大的vendor程序。主程序动态引入verdor。
...
Asset Size Chunks Chunk Names
index.bundle.js 7.88 KiB index [emitted] index
vendors~lodash.bundle.js 547 KiB vendors~lodash [emitted] vendors~lodash
Entrypoint index = index.bundle.js
...
vue-router中如何结合webpack如何动态引入
// router.js
const Foo = () => import('./Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-bar" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-baz" */ './Baz.vue')
打包出来的结果为:
0.23f238869b2a7076bb5c.js
group-bar.34f238869b2a776bbd2.js
group-baz.43f23882b2a707623b2c.js
const chat = () => import(/* webpackChunkName: "chat" */ './chat.vue');
打包出来的结果为:chat.35f23886902a7076bb5c.js
当我们访问Foo 页面时,会只加载0.23f238869b2a7076bb5c.js。 此时访问Bar,动态引入group-bar.34f238869b2a776bbd2.js。 访问Baz,动态引入group-baz.43f23882b2a707623b2c.js。
资源加载过程为:
// srouces 访问Foo
0.23f238869b2a7076bb5c.js
// srouces 访问Foo后访问Bar
0.23f238869b2a7076bb5c.js
group-bar.34f238869b2a776bbd2.js
// srouces 访问Foo后访问Bar,再访问Baz
0.23f238869b2a7076bb5c.js
group-bar.34f238869b2a776bbd2.js
group-baz.43f23882b2a707623b2c.js
webpack是通过webpackJsonp实现动态引入的。
webpackJsonp动态引入本质上是JSONP,动态增删script,从script引入需要的文件。
参考资料: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import https://webpack.js.org/guides/code-splitting/
这只是异步加载 不是按需导入
这只是异步加载 不是按需导入
纠正过来了。按需加载应该是https://www.npmjs.com/package/babel-plugin-import 这样的