9
头图

Usually for development efficiency, we will use vue-cli create a project, so that the created project will be compiled by default to split the code. But if it is a self-configured webpack environment, it is still necessary to be familiar with the knowledge of code segmentation.

Why do code splitting

In the process of configuring webpack, many times our webpack entry only writes a entry: '${sourceDir}/index.js’ . By default, only one bundle file is generated, which contains third-party libraries, common code, and business logic used in different pages, which will inevitably cause The bundle file is too large and affects the first loading speed of the page. Therefore, we need to split the code to speed up the first time entering the page.

Code splitting ideas

First, separate the third-party libraries and public codes. Because these codes change frequently, they can be packaged into a file so that the file does not change every time the file is online. You can make full use of the network cache to speed up the file download speed. If the division is detailed That is, the third-party library is a js file, and the common code is a js file.

Then, divide the code according to the route (page), and each page generates a js file, so that every time you enter for the first time, only the common code and the js file used by this page are loaded, instead of loading other pages irrelevant code.

Finally, for fine segmentation, segmentation is based on component usage to achieve lazy loading of components. For example, different tabs in the page can be segmented according to the display situation of the tabs, and the ones that need to be clicked or user active operations can be displayed. The components are lazily loaded, so that more fine-grained code segmentation is performed at the page level.

Code splitting in action

Third-party libraries and common code segmentation

In the first step, we split the third-party libraries, such as vue, vue-router, vuex, axios and other three-party libraries, put them in vender.js, and then put utils and common files in common.js. These can be achieved through webpack's entry and splitChunk configuration.

Modify the entry configuration:

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

splitChunk configuration:

{
  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',
    },
  }
}

The other is the output configuration. [name] means let the chunk name be the file name, [chunkhash:8] means add hash, and load the latest code without going to the cache after going online.

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

After finishing the third-party library and common code segmentation, the files generated after packaging are as follows:

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)

We can see that the code is divided into different files. Vender.js contains all third-party libraries, main.js contains the business logic of our pages, the common code is in common, and the runtime contains the runtime code. This code They are scattered into different files, each performing its own duties, and it is conducive to simultaneous loading.

But main.js still contains the code of multiple pages. If you just enter the homepage, the code of other pages is redundant, and then optimize it.

Split by route

This one is easier to handle, just change the routing configuration and load the page component in the way of () => 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',
  },
];

At this time, the packaging will see a lot of files. This is to split the code of different pages into different JS files. Only when the corresponding page is accessed will the relevant code be loaded.

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]

Of course, this place may be controversial. The controversial place is: "When the page enters, it downloads the code of all pages, and then enters other pages faster?". It depends on the project situation, it depends on whether to focus on the page opening in seconds, or focus on the page switching experience. If you focus on the second opening, it will be better to cooperate with SSR processing.

Fine-grained segmentation

If you have higher requirements for page opening speed or performance, you can also do more fine-grained code segmentation, such as lazy loading of functional modules in the page.

Here is an example of loading the corresponding component when the button is clicked to demonstrate the code:

There is a Load Lazy Demo LazyComponent component is loaded when it is clicked. The LazyComponent component is nothing special, and the writing method is the same as that of a normal component.

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

Here, a showLazyComponent control the display of the component. When the button is clicked, showLazyComponent set to true, and then the code corresponding to LazyComponent is loaded. In fact, the key is to introduce components () => import(path)

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

OK, the above is the relevant content of the code segmentation I did in the Vue project.


EthanProcess
213 声望4 粉丝