导航栏: 首页 评论列表

iView及VUE中的异步组件及懒加载 [name].chunk.js

默认分类 2019/06/12 08:07

在研究iView的源码时,看到各个组件用到的JS都是按需加载的,也就是懒加载,如下:

https://file.iviewui.com/dist/vendors.a175e0b04162b38943ca.js
https://file.iviewui.com/dist/main.a175e0b04162b38943ca.js
https://file.iviewui.com/dist/69.a175e0b04162b38943ca.chunk.js
https://file.iviewui.com/dist/98.a175e0b04162b38943ca.chunk.js
https://file.iviewui.com/dist/10.a175e0b04162b38943ca.chunk.js
https://file.iviewui.com/dist/118.a175e0b04162b38943ca.chunk.js
https://file.iviewui.com/dist/119.a175e0b04162b38943ca.chunk.js
https://file.iviewui.com/dist/134.a175e0b04162b38943ca.chunk.js
https://file.iviewui.com/dist/121.a175e0b04162b38943ca.chunk.js

之前在另一个页面埋点的项目中使用 webpack 的 require.ensure() 可以实现把首次用不到的打包成 [name].chunk.js 的 方式用到再加载,即懒加载。可是搜了下,iView Doc的源码,根本没找到 require.ensure()。 继续研究,发现每次切换 router 才会加载所需JS,就推测到应该是由 router.js 控制的,然后找到如下代码:

{
  path: '/components/input',
  meta: {
    title: '输入框 Input'
  },
  component: (resolve) => require(['./views/components/input.vue'], resolve)
},
{
  path: '/components/input-en',
  meta: {
    title: 'Input'
  },
  component: (resolve) => require(['./views/components/input-en.vue'], resolve)
},
{
  path: '/components/radio',
  meta: {
    title: '单选框 Radio'
  },
  component: (resolve) => require(['./views/components/radio.vue'], resolve)
},

没看到 require.ensure() ,只有require([..], fn),这个和之前的常规用法不同,以前常会类似下面的用法:

import Input from './component/input.vue'
...
{
  path: '/components/input',
  meta: {
    title: '输入框 Input'
  },
  component: Input
},
...

找了下官网 https://cn.vuejs.org/v2/guide/components-dynamic-async.html 查阅到如下关于 “异步组件” 的描述:

异步组件

在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。为了简化,Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。例如:

Vue.component('async-example', function (resolve, reject) {
  setTimeout(function () {
    // 向 `resolve` 回调传递组件定义
    resolve({
      template: '<div>I am async!</div>'
    })
  }, 1000)
})

如你所见,这个工厂函数会收到一个 resolve 回调,这个回调函数会在你从服务器得到组件定义的时候被调用。你也可以调用 reject(reason) 来表示加载失败。这里的 setTimeout 是为了演示用的,如何获取组件取决于你自己。一个推荐的做法是将异步组件和 webpack 的 code-splitting 功能一起配合使用:

Vue.component('async-webpack-example', function (resolve) {
  // 这个特殊的 `require` 语法将会告诉 webpack
  // 自动将你的构建代码切割成多个包,这些包
  // 会通过 Ajax 请求加载
  require(['./my-async-component'], resolve)
})

你也可以在工厂函数中返回一个 Promise,所以把 webpack 2 和 ES2015 语法加在一起,我们可以写成这样:

Vue.component(
  'async-webpack-example',
  // 这个 `import` 函数会返回一个 `Promise` 对象。
  () => import('./my-async-component')
)

当使用局部注册的时候,你也可以直接提供一个返回 Promise 的函数:

new Vue({
  // ...
  components: {
    'my-component': () => import('./my-async-component')
  }
})

由于 import() 这种方式非原生用法,因此需要使用 babel-plugin-syntax-dynamic-import 插件, 安装如下:

我们还希望能够在项目对一些组件进行懒加载,所以还需要一个Babel插件:

npm i babel-plugin-syntax-dynamic-import -D

在 .babelrc 文件中加入plugins配置:

{
  "presets": [
    "@babel/preset-env"
  ],
  "plugins": [
    "syntax-dynamic-import"
  ]
}

或者

use: [{
  loader: 'babel-loader',
  options: {
    presets: [['es2015', {modules: false}]],
    plugins: ['syntax-dynamic-import']
  }
}]

........... 至此结束。

一些查到的其他资料:

配合webpack支持的异步加载方法

resolve => require([URL], resolve), 支持性好
() => system.import(URL) , webpack2官网上已经声明将逐渐废除, 不推荐使用
() => import(URL), webpack2官网推荐使用, 属于es7范畴, 需要配合babel的syntax-dynamic-import插件使用, 具体使用方法如下

npm安装包:

npm install --save-dev babel-core babel-loader babel-plugin-syntax-dynamic-import babel-preset-es2015

代码:

use: [{
  loader: 'babel-loader',
  options: {
    presets: [['es2015', {modules: false}]],
    plugins: ['syntax-dynamic-import']
  }
}]

四、具体实例中实现懒加载

1、路由中配置异步组件

export default new Router({
  routes: [
    {
      mode: 'history',
      path: '/my',
      name: 'my',
      component:  resolve => require(['../page/my/my.vue'], resolve),//懒加载
    },
  ]
})

参考链接:

https://cn.vuejs.org/v2/guide/components-dynamic-async.html https://www.cnblogs.com/zhensg123/p/7671129.html https://www.cnblogs.com/zhanyishu/p/6587571.html https://segmentfault.com/a/1190000017898866?utm_source=tag-newest


>> 留言评论