Vite 打包项目(一) : 全量打包一个类库

3,429 阅读1分钟

前言

最近接了一个类库的锅,需要打包发布,打包打算试试 Vite

选择原因: 团队里有自己手写一些 cli 打包,但是比较老旧了。新项目不选择 Webpack 的原因是据说 Vite 比 Webpack 轻量,作为一个纯 JS/TS 类库,可能打包不需要配置过于繁琐

使用 vite 初始化项目

https://vitejs.cn/

yarn create vite my-app / npm install vite@latest

选择模板 react-ts

vite 默认是构建 Web 项目,会默认使用根目录下 index.html 作为入口文件

// index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="favicon.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite App</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/main.js"></script>
  </body>
</html>

Vite 解析 <script type="module" src="..."> ,这个标签指向你的 JavaScript 源码

如何打包一个类库

如果目标是类库,需要开启构建库模式,原因有两个。首先,库的入口不可能以 html 作为 entry。同时,Vite 库模式,能够便捷的确保将那些你不想打包进库的依赖进行外部化处理,例如 vue 或 react

总的来说就是 3 个步骤:

  1. 开启构件库模式
  2. 确定打包入口文件
  3. 优化库打包的依赖 新建 vite.config.ts,并加入 build.lib 配置项

库模式入口项 entrystring 类型。从文档看,vite 默认打包是全量打包,只有一个入口文件,里面引用了你类库的所有源码。vite 会解析入口文件并压缩

// vite.config.ts
const { defineConfig } = require('vite')
const path = require('path')
const outDir = path.resolve(__dirname, 'lib')

module.exports = defineConfig({
  plugins: [react()],
  build: {
    outDir,
    lib: {
      entry: path.resolve(__dirname, 'lib/main.js'),
      name: 'MyLib',
      fileName: (format) => `my-lib.${format}.js`
    },
  }
})

rollupOptions 配置项中,配置不想打包的依赖项,并暴露全局变量。这样就可以避免类库将依赖项打包,使体积增大。配置后,类库被引用时,声明一个全局引用,在宿主包中寻找对应的依赖

// vite.config.ts
module.exports = defineConfig({
  build: {
    ...
    rollupOptions: {
      // 确保外部化处理那些你不想打包进库的依赖
      external: ['react'],
      output: {
        // 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
        globals: {
          react: 'React'
        }
      }
    }
  }
})

针对打包做一些其他的基础配置项,完整的配置如下

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

const path = require('path')

const entryDir = path.resolve(__dirname, 'lib/main.js')
const outDir = path.resolve(__dirname, 'lib')

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: [{ find: '@', replacement: path.resolve(__dirname, './src') }],
  },

  json: {
    // 是否支持从 .json 文件中进行按名导入
    namedExports: true,
    // 若设置为 true, 导入的 JSON 会被转换为 export default JSON.parse("...") 会比转译成对象字面量性能更好
    // 尤其是当 JSON 文件较大时
    // 开启此项, 则会禁用按名导入
    stringify: false,
  },

  build: {
    outDir,
    lib: {
      entry: entryDir,
      fileName: (format) => `${format}/[name].js`,
      formats: ['cjs', 'es'],
    },
    manifest: false,
    emptyOutDir: true,
    // chunk 大小警告的限制
    chunkSizeWarningLimit: 500,
    rollupOptions: {
      // 确保外部化处理那些你不想打包进库的依赖
      output: {
        // 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
        globals: {
          react: 'React',
        },
      },
      external: ['react'],
    }
  },
})

参考文档

Vite.js中文官方文档\