欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

vue3 + vite 项目打包体积优化

程序员文章站 2022-05-31 09:15:56
...

如果不想听原理部分,可以直接跳到 开始使用


原理部分讲解

现在 vue3 已经逐渐成熟,所以想做几个 vue3 + vite 项目练练手
入口文件如下

import App from './App.vue'
import { router } from './route';
import {createApp} from 'vue';
import antd from 'ant-design-vue';
import "ant-design-vue/dist/antd.css"

const app = createApp(App)
app.use(router)
app.use(antd)
app.mount('#app')

就在我打算打包部署的时候,看到下面这张图的时候我直接傻了

vue3 + vite 项目打包体积优化
1MB 多的 vendor 文件


然后我的项目打包体积优化之旅就开始了 …
在百度了一个下午之后,我放弃了。。。 根本没有人发布 vite 或者 vue3 应该如何优化体积的相关文章。

只能自己解决了,这里我想了很久才想到一个解决办法,因为 vue3 采用的是组合式Api,不可能单独的在 main.ts 删除引用,其他文件也会有引用,然后被打包进去,所以唯一的解决方法只能是对每个文件进行 import 修改, 吧 import xxx from 'xxx' 改成 var xxx = xxx 这样才能引入外部 cdn 进行使用。


原理如下 :

  1. 写一个 vite 插件,对每个打包的文件进行处理
  2. 对每个文件的导入依赖进行判断,是否需要修改成 cdn 引入
  3. 进行依赖修改,吧所有 import 改成 变量声明,然后返回给 vite 进行打包处理, 由于没有 import 所以 vite 不会打包相关的依赖,这样就实现了体积压缩
  4. 浏览器访问打包后的文件,因为 cdn 已经将全局变量挂载到 window 上,所以每个文件可以直接运行。

例子如下:

import _vue , {defineComponent as _d , ref as _ref , reactive} from 'vue'
import router from 'vue-router'

我们需要转换成如下语句 :

var _vue = window.Vue
var {defineComponent,ref,reactive}  =  window.Vue
var _d = defineComponent ;
var _ref = ref;
var router  = window.VueRouter

这里必须着重讲一下为什么要加 window 在变量前,因为 ts 和 js 模块中的 this 指向并不是一样的,所以必须要在 window 变量中去访问 CDN 的全局变量,否则 Vue 或者 VueRouter 等变量将会是 undefined

开始使用

我写了一个 vite 插件 rollup-plugin-external-import 来解决 vue3 + ts 的体积优化问题

安装

# 安装
npm install rollup-plugin-external-import -D

vite.config.ts 中配置

import { ExternalImport, VueImport, VueRouterImport, AntDesignVueImport } from 'rollup-plugin-external-import';

export default defineConfig({
  plugins: [
    vue(),
    // 配置外部导入处理
    ExternalImport({
    	// vue 
        VueImport,
        // vue-router
        VueRouterImport,
        // ant-design-vue
        AntDesignVueImport,
        // 自定义处理
        {
          importName: "axios",
          variableName: "windos.axios"
        }
    })
  ],

})

引入CDN

unpkgjsdelivr 都是很好的 CDN 资源平台,按照自己的需求导入,唯一需要注意的就是 variableName 要和 CDN 的全局变量名一致,并且带有 window 前缀

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <link rel="icon" href="/favicon.ico" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <!-- vue -->
  <script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>

  <!-- vue router -->
  <script src="https://unpkg.com/[email protected]/dist/vue-router.global.js"></script>

  <!-- ant desgin vue css-->
  <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/antd.min.css" rel="stylesheet">
  
  <!-- ant desgin vue js-->
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/antd.min.js"></script>

  <!-- axios -->
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js"></script>
  
  <title>xxxx</title>
</head>

<body>
  <div id="app"></div>
  <script type="module" src="/src/main.ts"></script>
</body>

</html>

运行打包即可**

你不需要修改任何代码。

npm run build

打包后 1MB 压缩到了 26KB 将近优化了 50倍
vue3 + vite 项目打包体积优化

解析

VueImport VueRouterImport AntDesignVueImport …等等是默认提供的处理器,

ExternalImport({
    	// vue 
        VueImport,
        // vue-router
        VueRouterImport,
        // ant-design-vue
        AntDesignVueImport,
        // 自定义处理
        {
          importName: "axios",
          variableName: "windos.axios"
        }
    })

等同于

ExternalImport({
    	// vue 
        {
          importName: "vue",
          variableName: "windos.Vue"
        },
        // vue-router
        {
          importName: "vue-router",
          variableName: "windos.VueRouter"
        },
        // ant-design-vue
        {
          importName: "ant-design-vue",
          variableName: "windos.antd"
        },
        // 自定义处理
        {
          importName: "axios",
          variableName: "windos.axios"
        }
    })

更多的 Api 和详情请移步到 github: https://github.com/enncy/rollup-plugin-external-import