一、描述

vue & webpack 的开发模式如果网站内容特别多,会导致 SPA 打出来的包的大小非常的大,经常超过 1M,因此一般会使用 webpack 的 code spliting 把代码分割成不同的 chunk。

按需加载 vue 支持异步组件的方式,因此 vue-router 提供了路由懒加载,可以在路由切换之后再去请求相关路由组件的资源,从而在某种程度上减少 bundle 的大小。

开发的脚手架是之前自己用 webpack4.x 配置的,可以在 https://github.com/postbird/webpack4.x-vue-develop 直接 clone 项目,然后:

yarn install 
yarn start

即可,不对 webpack 配置 vue 基本的开发环境做过多的阐述,不过目前的脚手架没有配置 router,需要自己配置。文章结束之后我会发一个本篇文章的 demo 到 github,可以直接运行

二、传统的 router 配置

直接上配置文件,通过 import 的方式引入组件,然后在 routes 中配置相关的路由信息,很基本的配置了:

import VueRouter from 'vue-router';

import Index from '../components/Index.vue';
import Hello from '../components/Hello.vue';
import List from '../components/List.vue';


const routes = [
  { path: '/', alias:'/index', component: Index },
  { path: '/hello', component: Hello },
  { path: '/list', component: List }
];

const router = new VueRouter({ routes });

export default router;

在模板中使用的时候也是如此,正常使用:

    <ul>
      <li><router-link to="/index">Index</router-link></li>
      <li><router-link to="/hello">Hello</router-link></li>
      <li><router-link to="/list">List</router-link></li>
    </ul>
    <router-view></router-view>

最终的结果:

进入首页,将 main.bundle.js 完整的请求下来

1.jpg

切换其他路由后不会进行新的资源请求

GIF.gif

二、路由懒加载 router 配置及作用

路由懒加载其实依赖于 webpack 的 code-spliting 以及 vue 的异步组件,关于 vue 的异步组件可以看:

而异步组依赖动态 import,react 也有这个思想:https://reactjs.org/docs/code-splitting.html#import

vue-router 结合动态 import 及 异步组件的支持,通过将之前配置的 import Index from '../components/Index.vue'; 这种直接 import 的方式改变成 const Index = () => import('../components/Index.vue'); 这种能够被 webpack 识别并自动分割代码的组件。

因此 router 的配置变化如下:



import VueRouter from 'vue-router';

const Index  = () => import('../components/Index.vue');
const Hello = () => import( '../components/Hello.vue');
const List = () => import( '../components/List.vue');


const routes = [
  { path: '/', alias:'/index', component: Index },
  { path: '/hello', component: Hello },
  { path: '/list', component: List }
];

const router = new VueRouter({ routes });

export default router;

除了 router 的配置会发生变化之外,如果使用了 babel,则 webpack 进行代码分割的时候需要依赖 babel 的一个插件 @babel/babel-plugin-syntax-dynamic-import,文档地址:https://babeljs.io/docs/en/babel-plugin-syntax-dynamic-import/

因此需要更改 webpack 中 babel 的配置,因为我是直接写在了 webpack.dev.config.js,所以还是直接更新 webpack.dev.config.js:(prod.config.js 没更改,因为只是 demo)

      {
        test: /\.(js)$/,
        exclude: /(node_modules)/,
        use:{
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
            plugins: ['@babel/transform-runtime', "@babel/plugin-syntax-dynamic-import"]
          }
        }
      },

首次进入,可以发现除了加载了一个 bundle.js 之外,还加载了一个 2.bundle.js

2.jpg

当切换路由的时候,会发现每次切换的路由都多请求了一个 x.bundle.js,而里面的内容则是路由组件的内容

2222.gif

3.jpg

四、问题

两次对比其实有一个很明显的问题可以发现,路由懒加载之前,main.bundle.js 的大小是 183kb,而路由懒加载之后,main.bundle.js 还是 183kb,根本没有减少。

第二个问题是,在 main.bundle.js 都相同的情况下,使用路由懒加载后,每次都会多请求 1.4kbx.bundle.js,这个特别尴尬。路由懒加载之后 bundle 不但没减少,反而多请求了好几 kb 的资源 好几个网络请求。

因为我的每个组件内容都很少,基本都是下面特别简单的内容:

<template>
  <div>
    <h1>Hello</h1>
  </div>
</template>

所以分离出去懒加载后,对整体的 main.bundle.js 没有什么大的影响,大小未发生变化,每个 bundle 单独打包,webpack 又会注入自己的规范代码,导致多注入了很多代码(见上面截图)。

所以 路由懒加载 一定要看实际的情况,并不是使用了就一定有好处,有些极端情况下,反而会带来更多的压力。

五、demo 代码

请注意,文章的 demo 在 dev/router-lzay-loading 分支: