Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vue - 延迟加载和代码拆分 #37

Open
tomoya06 opened this issue Oct 8, 2020 · 0 comments
Open

Vue - 延迟加载和代码拆分 #37

tomoya06 opened this issue Oct 8, 2020 · 0 comments

Comments

@tomoya06
Copy link
Owner

tomoya06 commented Oct 8, 2020

延迟加载和代码拆分

前言

本文来自InfoQ博客:Vue性能优化:如何实现延迟加载和代码拆分?,原文总结的很有逻辑。

Webpack的打包原理参考Webpack篇issue,简单来说就是,Webpack会从入口出发,构建出一个依赖图,并把依赖图中的所有模块打包成一个bundle。

定义

延迟加载:就是延迟加载应用程序的部分内容。换句话说,只在真正需要它们时加载它们。
代码拆分:是指将应用程序拆分成可以延迟加载的块。

通过延迟加载适当的组件和库,打包出来的主bundle体积会大大减少。

实现

可以使用 Webpack动态导入来加载应用程序的某些部分。

标准的js模块导入语法如下:

 // main.js
import ModuleA from './module_a.js'
ModuleA.doStuff()

此时main.jsmodule_a.js都会被打包到同一个bundle。

若仅在某些情况下需要ModuleA,就可以使用动态导入的方法。如下述代码,对main/ModuleA/ModuleB/ModuleC分别用不同方法引入:

//main.js
import ModuleB from './mobile_b.js'
const getModuleA = () => import('./module_a.js')
getModuleA()
  .then({ doStuff } => doStuff()
)
//module_a.js
import ModuleC from './module_c.js'

实际构建出来的依赖图如下,相当于创建了一个新的入口:

image

Vueの实践

延迟加载组件

在Vue中可以延迟加载整个 SFC 以及它的 css 和 html,语法和之前一样:

<template>
  <div> 
    <lazy-component v-if="lazyLoad" />
  </div>
</template>
<script>
const lazyComponent = () => import('Component.vue')
export default {
  data() {
    return {};
  },
  components: { lazyComponent }
}
</script>

这样,只有当请求在模板中渲染组件时,才会调用 lazyComponent 函数。例如,如果lazyLoad = false,那么就不会导入组件。

路由懒加载

vue-router也支持路由懒加载。官方文档参考这里。语法类似:

const routes = [
  { path: /', component: () => import('./components/Home.vue') },
  { path: /about', component: () => import('./components/About.vue') },
]

依赖图变化如下,Webpack将创建三个包:

  • app.js:主捆绑包,包含应用程序入口点(main.js)和每个路由所需的库或组件;
  • home.js:包含主页的捆绑包,当用户输入 / 路径时才会加载;
  • about.js:包含关于页面的捆绑包,当用户输入 /about 路径时才会加载。

image

Vuex模块

指的是对Vue modules的延迟加载。参考Vuex文档的模块动态注册,即使用store.registerModule方法来动态注册。

// store.js
import { userAccountModule } from './modules/userAccount'
export const store = new Vuex.Store({
  modules: {
    user: userAccountModule, 
    // admin: adminModule,
  }
})
// Admin.vue
import adminModule from './admin.js'
export default { 
  // other component logic
  mounted () { 
    this.$store.registerModule('admin', adminModule)
  },
  beforeDestroy () {
   this.$store.unregisterModule('admin')
  }
}

这样只有在Admin组件被加载时,adminModule子模块才会被加载。依赖图的变化如下:

image

第三方依赖

这里主要以lodash为例。原文介绍的方法是使用 webpack 的 splitChunksPlugin 插件,这样可以保证只有用到了lodash的页面才引入lodash,不过引入的时候还是全量引入。

另外常见的方法如下,参考掘金博客

  1. 只对单个使用到的方法按需引用,并且从文件引用。但引用模块较多时写法麻烦
import isEqual from 'lodash.isequal';
// 或者
import difference from 'lodash/difference';
  1. 使用babel-plugin-lodashlodash-webpack-plugin插件
// webpack.config.js
var LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
var webpack = require('webpack');

module.exports = {
    module: {
        rules: [
            {
                use: 'babel-loader',
                test: /\.js$/,
                exclude: /node_modules/,
                options: {
                    plugins: ['lodash'],
                    presets: [['env', {modules: false, targets: {node: 4}}]]
                }
            }
        ]
    },
    plugins: [new LodashModuleReplacementPlugin(), new webpack.optimize.UglifyJsPlugin()]
};
  1. 改用lodash-es
import {isEmpty, isObject, cloneDeep} from 'lodash-es';
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant