花式引入组件和资源-打包时拆包减少js体积

title: 花式引入组件和资源-打包时拆包减少js体积 id: d46985b3bf0b96ef45ea7c784fa3e22d tags: [] date: 2000/01/01 00:00:00 updated: 2023/03/04 19:29:12 isPublic: true --#|[分隔]|#--

花式引入组件和资源-打包时拆包减少js体积

注:以下方式部分也适用于 React

开发时,经常会有以下问题和需求:

  • 页面文件打包后是 app.js 文件,如果页面过多,会导致这个文件过大,首次加载消耗时间。

  • npm 安装的依赖,比如 UI 框架、js 插件等等,打包后是 chunk-vendors.js 文件,如果这些依赖过多,或某个依赖体积较大,也会导致这个文件过大。

  • 权限系统,并不是所有用户都有权查看所有页面,不用每位用户都得到完整路由和路由对应页面的文件资源

  • ...

以上痛点,我也经常遇到,虽然使用按需引入,可仍然没什么效果,下面根据我最近的经验,整理一下解决办法。

分页面打包成js,打开页面时异步引入

这个算是最常见的处理方式了,需要修改 router 路由配置文件。

正常写 router 路由配置文件时,写法如下:

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router);

// 直接引入所有页面文件
import Index from '@/views/Index'
import Home from '@/views/Home'
import User from '@/views/User'

const router = new Router({
  mode: 'history',
  routes: [
    {
      path: '/',
      name: 'index',
      component: Index,
    },
    {
      path: '/home',
      name: 'home',
      component: Home,
    },
    {
      path: '/user',
      name: 'user',
      component: User,
    },
  ]
});

export default router;

修改为一下方式,这样一来,除了 Index 首页的其他页面,都会单独打包为独立的 js 资源文件,只有在用户即将进入页面时,才会当场加载那个页面的 js 资源文件,加载完成后才会跳页进入。

解决的问题

  • 页面过多导致的 app.js 文件过大,使初次进入页面也不用加载所有页面资源,减少加载时间,缩短首屏渲染完成时间。

缺点

  • 用户每次进入的页面,如果之前从未打开过,那么没有缓存文件,会自动的当场从服务器加载文件,导致页面没有立即跳转,稍微影响用户体验(如果网速快,则影响很小)。

npm 安装的依赖按需引入

最常见的就是 element-ui,提供按需引入的功能,也就是在需要使用该插件的某个 vue 组件中,解构引入用注册:

解决的问题

  • 依赖的插件,每个插件都不用全量加载,只打包插件中我们使用的那几个方法和资源,减小 chunk-vendors.js 的体积。

缺点

  • 使用麻烦,每个需要使用 element-ui 的组件,都需单独引入,即使把用到的进行全局注册,也是稍微有点麻烦。

  • 效果不明显。

npm 安装的依赖,直接用静态资源的方式引入依赖

这种方式比较直接,就是直接在 index.html 中,引入我们需要的依赖的资源文件。

当然是需要判断操作的,当我们是本地启动服务开发时,不用关系文件体积大小,可以仍然照常开发。

当是 build 打包时,才需要进行以下配置,下面的配置,也包含判断操作的逻辑。

所以,我们需要做的有三件事:

  • 判断当前操作,是打包还是启动开发服务。

  • 打包时,index.html 使用资源路径,来引入我们项目需要的依赖,资源对象自动绑定到 window 对象上。

  • 打包时,需要配置 webpack 的文件复制功能,把 index.html 通过路径引入的资源文件,复制到对应目录。

  • 打包时,配置 webpack 的 externals,让项目中使用这些 index.html 通过路径引入的资源时,从 window 中查找并返回给项目,而不是再从 node_modules 中取。

判断当前操作,package.json 文件中:

配置使用资源路径来引入依赖,index.html 文件中:

配置webpack,vue.config.js 文件中:

注意上面的例子中,打包时的 vue 也是使用资源路径的引入方式,这是因为,由于我们是使用资源路径的方式引用 element-ui,而 element-ui 要求必须在它之前先引入 vue,否则会报错,所以,我们不得不把 vue 也使用这种方式引入了。

解决的问题

  • 打包后 app.jschunk-vendors.js 体积问题,能大幅减小他们。

  • 反正资源已经全量引入了,项目中可以全局全量注册,不用每个页面再单独解构引入想用的组件了。

缺点

  • 配置稍微麻烦点,但配置我都已经写在上面了

  • 如果更换了这些资源的版本,但文件名没变,这样用户打开是,可能会访问到缓存文件,不过这种可能性比较小,一个项目的依赖,一般是不会换版本的,而且我们也可以再编辑一下配置,给引入的资源文件加上版本号,这里没有做这个。

异步添加路由

顾名思义,这种方式需要使用 vue-router 的 addRoute 的方式。

使用场景,一般是用于权限系统,即当用户输入 url 即将进入项目时,此时进行拦截,开始获取接口得到当前用户能访问的页面列表,添加这些路由后再放行。

如果用户有权访问,那么当前打开的项目,就有这个页面,可以进入;如果没有权限,那当前根本也就没有这个路由,自动走路由错误的处理。

router 的配置文件:

注意里面的 loadPage 方法中的 import() 方法,需要讲一下。

import() 方法

前面虽然也使用这个方法,但都是直接引入指定的确定文件,而这里我们需要按规则引入某些目录下的文件。

上面方法中,使它的方式如下:

当 webpack 编译到此处,发现 import 中是 路径 + 变量 的模式,会自动把他们转为正则,然后按照正则匹配目录下文件,把所有符合这个路径的文件全部编译打包为单文件 js,当我们使用时,真的去引用规则中某个文件时,就可以引入了。

注意这里不能直接以 import(file) 的形式使用,因为这么写的话,路径完全是个 file 变量,按照规则,webpack 需要把整个硬盘中的文件都打包,它认为这是个错误的行为,会直接报错。

以不同方式使用 import() 的几种效果

下面上来自上面 router 的配置文件 的内容的摘抄,下面我使用不同的语法来使用 import(),它也会有几种不同的执行效果。

1. 默认的推荐写法,添加路由后,用户打开哪个页面,才会加载某个页面的 js 资源文件。

2. 同步引入,在添加路由时,直接把新页面的 js 资源们全部顺序引入。

3. 还有一种极不推荐的写法,直接在编译时,就把所有匹配到的文件 js 资源,打包进 app.js 中

新增:使用 webpack 配置

其实早该用这个方法了,只是这个配置实在不太容易理解,我也不敢确保我写的是正确的。

下面是一种比较暴力的配置方法,使用 webpack 自带插件 optimization

官方教程:https://webpack.docschina.org/plugins/split-chunks-plugin/#optimizationsplitchunks

下面是用法,主要是 minSizemaxSize 两个字段。

Last updated

Was this helpful?