使用 vite external 减小产物体积的方法实现
作者:前端毕业班
写在前面
前几个月工作过程中遇到了 Javascript heap out of memory 问题,当时想着减小前端的产物大小,通过 vite.external解决这问题,查了很多文章,不过都以失败告终,经过不懈努力和大佬的指点,终于成功了,故此分享。
前置工作
首先创建一个vue的项目,本地运行 pnpm dev 启动项目
$ pnpm dev > test-external@0.0.0 dev /Users/.../test-external > vite VITE v5.4.2 ready in 138 ms ➜ Local: http://localhost:5173/ ➜ Network: use --host to expose
项目可以正常运行,执行 pnpm build 开始构建
$ pnpm build vite v5.4.2 building for production... ✓ 67 modules transformed. dist/index.html 0.51 kB │ gzip: 0.32 kB dist/assets/index-B5GNdBo.css 0.32 kB │ gzip: 0.24 kB dist/assets/index-Dwy3Kika.js 62.20 kB │ gzip: 25.16 kB
可以看到js文件的大小为 62.20KB
设置你想要排除的依赖
比如你想你的代码打包出来的code不包括 vue
// vite.config.ts
export default defineConfig({
build: {
rollupOptions: {
external: ['vue']
}
}
})我们再执行下 build 命令,看看产物大小
$ pnpm build vite v5.4.2 building for production... ✓ 62 modules transformed. dist/index.html 0.51 kB │ gzip: 0.32 kB dist/assets/index-DY_q8tlo.js 8.33 kB │ gzip: 3.28 kB
可以看到js文件大小为 8.33KB,相较于 62.20KB 小了不少,我们把代码推送到github,部署到 github pages 看看效果
核心报错: Failed to resolve module specifier "vue"
浏览器找不到名为 vue 的 ESM 模块,因为打包产物里保留了 from "vue",但线上环境没有提供这个模块。
发现页面上什么内容都没有,控制台报错,说没有找到vue这个module,我们来看下产物
import {
createElementBlock as e,
createElementVNode as n,
toDisplayString as f,
ref as s,
createApp as y
} from "vue";
这里引入了vue,但是我们打包的时候,vue是排除了的,所以找不到vue,就报错了,我之前也在这里卡住过,去网上查解决方法,有人说,你要通过 cdn 引入 vue,我们第二步通过cdn引入。
cdn 引入相关依赖
<!-- index.html --> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
这一步我其实刚刚在做第一步的时候就做了,还是有问题。我们来看下 vue 的 cdn 内容
// https://unpkg.com/vue@3/dist/vue.global.js
var Vue = (function (exports) {
'use strict';
// ...
return exports;
})({});通过var声明了一个叫 Vue 的变量,后面是一个自执行函数,但是我们的语法正常都是像上面产物那样
import { ref, reactive } from 'vue';
import vue from 'vue';
这样一想,报错也就不奇怪了,我们要是能把 vue引入的内容通过 Vue.xxx 替换掉,不就解决了这个问题,毕竟var声明的变量是全局的
设置 globals
这里我之前尝试的时候,看到网上很多教程让我设置 output.globals,后来发现根本不生效,就去翻了rollup的文档
output.globals
只对 umd / iife 产物生效,用于告诉 Rollup:某个 external 依赖在运行时对应哪个全局变量。
文档写的很清楚,你要是打包成 umd 或者 iife 格式,可以设置这个参数,但是我是要打包成 esm 格式(这就很尴尬了)
output.format 默认值是 es。
- es:保留为 ES module
- iife:自执行函数,适合直接通过 <script> 引入
- umd:兼容 AMD / CommonJS / IIFE 的通用格式
所以这里的关键问题是:我的目标产物是 ESM,不是 umd 或 iife,因此单独配置 output.globals 并不能解决问题。
然后我就找到了一个rollup插件 rollup-plugin-external-globals,解决了我的问题
// vite.config.ts
import { defineConfig } from 'vite';
import externalGlobals from 'rollup-plugin-external-globals';
export default defineConfig({
plugins: [
externalGlobals({
vue: 'Vue'
})
],
build: {
rollupOptions: {
external: ['vue']
}
}
});
$ pnpm build vite v5.4.2 building for production... ✓ 62 modules transformed. dist/assets/index-*.js 9.59 kB
我们看到包的大小相较于 8.33KB 大了一点,为什么呢?我引入了一个插件就变大了,直接来看下产物
const {
createElementVNode,
openBlock,
createElementBlock,
ref,
createApp
} = Vue;没有 import { xxx } from 'vue';,这个Vue在代码运行的时候会沿着作用域链一直找到 Window,刚好我们引入的 vue cdn通过var声明了一个Vue,这样就对上了。至于为什么打包产物大小变大了,是因为字符数变多了。我们推下代码,验证下想法
控制台不再出现 Failed to resolve module specifier "vue" 的报错。
大功告成!!!
QA
为什么要设置 external ?我直接设置cdn,代码里面不用import,也能行啊 🤔️ ?
这么做确实没啥问题,代码也能正常运行,部署到生产也不会有啥问题,不用import,就失去了类型提示,引入提示等依赖带来的好处,内容都是有上下文的,不会觉得奇怪
为什么这套配置开发环境下有问题
由于vite的开发环境用的是esbuild,打包用的是rollup,而rollup-plugin-external-globals插件是rollup插件,不建议在开发环境使用,以避免引起不必要的麻烦
/// vite.config.ts
import { defineConfig } from 'vite';
import externalGlobals from "rollup-plugin-external-globals";
const isProduction = process.env.NODE_ENV === 'production'
export default defineConfig(() => {
return {
plugins: [
...,
isProduction && externalGlobals({
vue: "Vue"
})
],
}
})
写在最后
到此这篇关于使用 vite external 减小产物体积的文章就介绍到这了,更多相关vite external 减小体积内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
