使用vite external减小产物大小

1,626 阅读3分钟

前言

前几个月工作过程中遇到了 Javascript heap out of memory 问题,当时想着减小前端的产物大小,通过 vite.external解决这问题,查了很多文章,不过都以失败告终,经过不懈努力和大佬的指点,终于成功了,故此分享。

前置工作

首先创建一个vue的项目(不清楚的掘友点击这里 cn.vuejs.org/guide/quick…

本地运行 pnpm dev 启动项目

image.png

image.png

项目可以正常运行,执行 pnpm build 开始构建

image.png

可以看到js文件的大小为 62.20KB

打包出来的目录为 docs,是因为我配置了 output.dir,想了解更多信息可以访问 rollupjs.org/configurati…

步骤

设置你想要排除的依赖

比如你想你的代码打包出来的code不包括 vue

/// vite.config.ts

export default defineConfig({
  build: {
    rollupOptions: {
      external: ['vue']
    }
  }
})

我们再执行下 build 命令,看看产物大小

image.png

可以看到js文件大小为 8.33KB,相较于 62.20KB 小了不少,我们把代码推送到github,部署到 github pages 看看效果

image.png

image.png

发现页面上什么内容都没有,控制台报错,说没有找到vue这个module,我们来看下产物

image.png

这里引入了vue,但是我们打包的时候,vue是排除了的,所以找不到vue,就报错了,我之前也在这里卡住过,去网上查解决方法,有人说,你要通过 cdn 引入 vue

image.png

那我们第二步通过cdn引入

cdn 引入相关依赖

image.png

这一步我其实刚刚在做第一步的时候就做了,还是有问题。我们来看下 vue 的 cdn 内容

image.png

通过var声明了一个叫 Vue 的变量,后面是一个自执行函数,但是我们的语法正常都是像上面产物那样

import { ref, reactive } from 'vue';

import vue from 'vue';

这样一想,报错也就不奇怪了,我们要是能把 vue引入的内容通过 Vue.xxx 替换掉,不就解决了这个问题,毕竟var声明的变量是全局的

设置 globals

这里我之前尝试的时候,看到网上很多教程让我设置 output.globals,后来发现根本不生效,就去翻了 rollupjs.org/configurati…

image.png

文档写的很清楚,你要是打包成 umd 或者 iife 格式,可以设置这个参数,但是我是要打包成 esm 格式(这就很尴尬了)

image.png

然后我就找到了一个rollup插件 rollup-plugin-external-globals,解决了我的问题

image.png

我们看到包的大小相较于 8.33KB 大了一点,为什么呢?我引入了一个插件就变大了,直接来看下产物

image.png

眼尖的掘友已经发现了,没有 import { xxx } from 'vue';,那vue呢

image.png

这个Vue在代码运行的时候会沿着作用域链一直找到 Window,刚好我们引入的 vue cdn通过var声明了一个Vue,这样就对上了。至于为什么打包产物大小变大了,是因为字符数变多了。

我们推下代码,验证下想法

image.png

image.png

大功告成!!!

疑问

为什么要设置 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"
      })
   ],
  }
})

结尾

如有错误,欢迎指正