我是如何在 Vue 项目中作代码分割的

一般为了开发效率,咱们会使用 vue-cli 建立项目,这样建立的项目默认状况下编译是会对代码进行分割的。可是若是是自行配置的 webpack 环境的话,仍是颇有必要熟悉代码分割的相关知识的。css

为何要作代码分割

在配置 webpack 的过程当中,不少时候咱们的 webpack 入口只写了一个 entry: '${sourceDir}/index.js’,默认状况下只会生成一个 bundle 文件,包含了第三方库、公共代码及不一样页面所用到的业务逻辑,这必然会形成该 bundle 文件体积过大,影响页面首次的加载速度,所以咱们须要对代码进行分割,加快首次进入页面的速度。html

代码分割思路

首先把第三方库、公共代码抽离出来,由于这些代码变更的频率小,能够打包成一个文件,这样每次上线文件都不发生变化,能够充分利用网络缓存加快文件下载速度,分割的细的话就是,第三方库为一个 js 文件, 公共代码为一个 js 文件。vue

而后,按照路由(页面)进行代码分割,每一个页面生成一个 js 文件,这样每次首次进入就只加载公共代码和本页面用的的 js 文件, 而不用加载其它页面无关的代码。node

最后,再进行精细分割的话,就是根据组件使用状况进行分割,来实现组件的懒加载,好比:页面中的不一样 tab,能够根据 tab 的展现状况进行分割,把须要点击或者用户主动操做才能呈现的组件进行懒加载,这样就在页面级又进行了更细粒度的代码分割。webpack

代码分割实战

第三方库及公共代码分割

第一步咱们进行第三方库的分割,好比 vue、vue-router、vuex、axios 等三方库,把它们放到 vender.js 中,而后 utils、common 文件等放在 common.js 中。这些经过 webpack 的 entry 及 splitChunk 配置便可实现。ios

修改 entry 配置:web

{
  // ...
  entry: {
    // 把公共代码放到 common 里
    common: [`${sourceDir}/utils/index.js`],
    main: `${sourceDir}/index.js`,
  },
  // ...
}

splitChunk 配置:vue-router

{
  optimization: {
    // splitChunks 配置
    splitChunks: {
      cacheGroups: {
        default: {
          name: 'vendor',
          // 把第三方库放到 vendor 里,包括 vue, vue-router, vuex 等
          // 由于他们都是从 node_modules 里加载的,这里直接正则匹配
          test: /[\\/]node_modules[\\/]/,
          chunks: 'initial',
          // 调整优先级,优先处理
          priority: 10,
        },
        common: {
          chunks: 'all',
          name: 'common',
          // 匹配 entry 里的 common 配置
          test: 'common',
        },
      },
    },
      // runtime 代码放在 runtime 文件中
    runtimeChunk: {
      name: 'runtime',
    },
  }
}

另外就是 output 配置了,[name] 表示让 chunk 名称做为文件名, [chunkhash:8] 表示加上 hash,上线后不走缓存加载最新的代码。vuex

{
  output: {
    path: path.join(__dirname, './dist'),
    filename: 'static/[name].[chunkhash:8].bundle.js',
    chunkFilename: 'static/[name].[chunkhash:8].bundle.js',
  },
}

作完第三方库及公共代码分割,打包后生成的文件以下:vue-cli

assets by path static/*.js 138 KiB
  asset static/vendor.4391b08b.bundle.js 133 KiB [emitted] [immutable] [minimized] (name: vendor) (id hint: default)
  asset static/main.0d6dab3a.bundle.js 3.9 KiB [emitted] [immutable] [minimized] (name: main)
  asset static/runtime.bdaa3432.bundle.js 1.1 KiB [emitted] [immutable] [minimized] (name: runtime)
  asset static/common.3f62940b.bundle.js 204 bytes [emitted] [immutable] [minimized] (name: common)
asset index.html 537 bytes [emitted]
asset static/main.acdc2841.bundle.css 127 bytes [emitted] [immutable] [minimized] (name: main)

咱们能够看到代码分割到了不一样的文件中,vender.js 包含了全部的第三方库,main.js 包含了咱们各个页面的业务逻辑,公共代码在 common 中,runtime 包含了运行时代码,这样代码就分散到了不一样的文件中,各司其职,且有利于同时进行加载。

可是 main.js 仍是包含了多个页面的代码,若是只是进入首页的话,其它页面的代码就是多余的,接下来再进行优化。

按路由分割

这一个比较容易处理,只需改变下路由配置便可,以 () => import(path) 的方式加载页面组件:

const routes = [
  {
    path: '/',
    // component: Home,
    component: () => import('./pages/Home'),
  },
  {
    path: '/todos',
    // component: Todos,
    component: () => import('./pages/Todos'),
  },
  {
    path: '/about',
    // component: About,
    component: () => import('./pages/About'),
  },
  {
    path: '/404',
    // component: NotFound,
    component: () => import('./pages/NotFound'),
  },
  {
    path: '*',
    redirect: '/404',
  },
];

此时打包会看到多了不少文件,这是把不一样页面的代码分割到了不一样的 JS 文件中,只有访问对应的页面才会加载相关的代码。

assets by path static/*.js 142 KiB
  asset static/vendor.4391b08b.bundle.js 133 KiB [emitted] [immutable] [minimized] (name: vendor) (id hint: default)
  asset static/runtime.07c35c52.bundle.js 3.99 KiB [emitted] [immutable] [minimized] (name: runtime)
  asset static/821.7ba5112d.bundle.js 1.89 KiB [emitted] [immutable] [minimized]
  asset static/main.1697fd27.bundle.js 1.68 KiB [emitted] [immutable] [minimized] (name: main)
  asset static/820.de28fd7b.bundle.js 562 bytes [emitted] [immutable] [minimized]
  asset static/646.a902d0eb.bundle.js 406 bytes [emitted] [immutable] [minimized]
  asset static/114.26876aa2.bundle.js 402 bytes [emitted] [immutable] [minimized]
  asset static/common.3f62940b.bundle.js 204 bytes [emitted] [immutable] [minimized] (name: common)
assets by path static/*.css 127 bytes
  asset static/main.beb1183a.bundle.css 75 bytes [emitted] [immutable] [minimized] (name: main)
  asset static/821.cd9a22a5.bundle.css 52 bytes [emitted] [immutable] [minimized]
asset index.html 537 bytes [emitted]

固然,这个地方可能会有争议,争议的地方就是:「页面进入时就把全部页面的代码都下载下来,再进入其它页面不是更快吗?」。这就取决于项目状况了,看是着重于页面秒开,仍是着重于页面切换体验。若是着重于秒开的话,配合 SSR 处理效果会更好。

更细粒度的分割

若是对于页面打开速度或性能有更高的要求,还能够作更细粒度的代码分割,好比页面中功能模块的懒加载。

这里以一个点击按钮时加载相应的组件为例,进行代码演示:

这里有一个 Load Lazy Demo 按钮,点击时才加载 LazyComponent 组件,LazyComponent 组件并无什么特别之处,写法跟普通组件同样。

<template>
  <button @click="loadLazyDemo">Load Lazy Demo</button>
  <template v-if="showLazyComponent">
    <lazy-component />
  </template>
</template>

这里经过一个 showLazyComponent 控制组件的显示,当点击按钮时,把 showLazyComponent 置为 true,而后就加载 LazyComponent 对应的代码了。其实关键仍是经过 () => import(path) 的方式引入组件。

<script>
export default {
  data() {
    return {
      showLazyComponent: false,
    };
  },
  methods: {
    loadLazyDemo() {
      this.showLazyComponent = true;
    },
  },
  components: {
    'lazy-component': () => import('../components/LazyComponent'),
  },
};
</script>

OK,以上就是我在 Vue 项目中作的代码分割的相关内容。

相关文章
相关标签/搜索