Skip to content

6.4 Vite 配置解析

Vite 执行构建时可以设置丰富的配置选项。默认情况下,执行 vite 命令时会读取项目根目录下的 vite.config.js 文件,该文件会导出自定义的 Vite 配置。

但 Vite 是开箱即用的,即便没有导出任何配置,也可以直接运行,这是因为 Vite 内置了一套经过优化的默认配置选项。当不指定配置项时,就会读取默认配置项;当指定配置项时,则会覆盖默认配置项。

js
// vite.config.js
import { defineConfig } from "vite";
export default defineConfig({
  // ... 自定义配置项
});

上面的配置文件中,使用 defineConfig 函数可以带来配置项的类型提示。请注意观察,这里使用了 ESM 语法,而不是像 Webpack 的配置文件一样必须使用 CommonJS 语法。这是因为 Vite 在加载配置文件前会先进行预处理,这样我们可以在项目中的任何地方统一使用 ESM。

多环境配置

大多数情况下,开发环境和生产环境的构建配置是不一样的,Webpack 也是如此。Vite 同样支持通过环境,甚至通过命令参数来设定不同的配置,这需要导出一个函数,方法如下。

js
// vite.config.js
import { defineConfig } from "vite";
export default defineConfig(({ command, mode }) => {
  return {};
});

函数接收 command、mode 两个参数,并返回真正的配置对象。command 表示 vite 命令后的第一个参数,mode 表示当前环境。当执行不同的命令时,command 和 mode 对应的值如下。

sh
$ vite
# command:serve,mode:development
$ vite build
# command:build,mode:production

根据不同场景下不同的 command、mode 值,我们可以判断导出不同的配置项,通过这种方式来实现多环境配置。当然你也可以将配置文件拆分成多个,执行不同命令时加载不同的配置文件。我们还是以同一个配置文件中导出不同的配置为例,书写方式如下。

js
// vite.config.js
import { defineConfig } from "vite";
export default defineConfig(({ command, mode }) => {
  let envDir = command == "serve" ? ".env.dev" : ".env.pro";
  if (mode == "development") {
    return { envDir, clearScreen: true };
  } else {
    return { envDir, clearScreen: false };
  }
});

通用配置

通用配置是指在开发服务器、项目打包、预览构建都适用的配置。Vite 的通用配置比较多,我们只介绍常用的选项,更多选项清参考官方文档。

  1. base

开发或生产环境的公共基础路径。默认是“/”。这个选项非常重要,它决定了最终项目部署时正确的 URL 是什么。默认情况下,假设使用 http://localhost:8080 可以打开项目,如果将 base 的值修改为 /test,那么正确的 URL 应该是 http://localhost:8080/test

当项目部署到服务器上,并分配一个二级域名时,此时必须修改 base 选项和二级域名一致,这样才可以保证项目的正常访问。

  1. mode

项目的两种模式。'development' 表示开发模式,'production'表示生产模式。这两种模式分别启用了不同的配置项优化,比如开发模式增强了对开发预览的优化,而生产模式则增强了对打包构建的优化。不同的模式还支持加载不同的环境变量。

  1. plugins

需要用到的插件数组。这部分非常关键,所有导入的插件必须定义到这里才能生效。

  1. publicDir

静态资源文件目录,默认是 public。该目录下存放的静态文件不会经过任何的编译和转换处理,在打包后会直接被复制到输出目录下,因此这里特别适合存放在 index.html 中直接引用的文件。切记最好不要在源码中引用该目录下的文件,Vite 不推荐这么做,你可以将需要在源码中引用的资源放在 src/assets 目录下。

  1. cacheDir

存储缓存文件的目录。在 6.3 节我们介绍过,Vite 会将依赖缓存起来以提高构建性能,其中文件系统缓存就存储在 “node_modules/.vite” 目录下,该目录便是 cacheDir 配置项的默认值。

你可以修改缓存目录,如设置 cacheDir: ".vite",那么重新编译时文件系统的缓存就会存储到 “.vite” 目录下。

  1. resolve

该选项是定义如何解析的选项,值是一个对象,可以定义许多解析规则。我们最常用的子选项有两个,分别是 alias 和 extensions。

(1)resolve.alias:用于定义路径别名,这个非常常用,大部分的项目中会定义别名 “@” 表示 src 目录的地址,在导入模块时就可以使用别名,看起来更方便。下面是定义方法:

js
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
export default defineConfig({
  resolve: {
    alias: {
      "@": fileURLToPath(new URL("./src", import.meta.url)),
    },
  },
});

(2)resolve.extensions:定义导入模块时可以省略的扩展名,值是一个数组,默认是['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json']。以这些扩展名为后缀的文件在导入时可以省略后缀,Vite 会自动查找匹配的文件。假设现在有文件 src/demo.ts,结合别名,以下三种导入方式效果是一样的:

js
import demo from "./src/demo.ts";
import demo from "./src/demo";
import demo from "@/demo";
  1. css

该选项定义如何解析 CSS,最常用的选项只有一个:css.devSourcemap。表示是否开启 devSourcemap。

devSourcemap 即源代码映射。我们知道 Vite 会将 CSS 编译到 html 文件的 <style> 标签内,我们在浏览器中调试代码时,点击样式也会定位到 <style> 标签下。实际上,我们更想知道样式存在于源代码中的哪个位置,此时开启 devSourcemap 再点击调试,就能看到样式已经定位到源码中的位置了。

devSourcemap 在生产模式下不生效,只是方便于开发模式下调试,所以直接开启即可,不会影响到生产环境的性能。

  1. esbuild

该选项用于定义 esbuild 的 Transform API,主要的应用场景是自定义 JSX。选项主要包含以下两个属性:jsxFactory、jsxFragment。jsxFactory 表示转换 JSX 的构造函数,jsxFragment 表示批量创建元素时无外部包裹的函数。

一般在 Preact 中需要自定义 JSX,其配置如下:

js
export default defineConfig({
  esbuild: {
    jsxFactory: "h",
    jsxFragment: "Fragment",
  },
});

这表示在 Preact 中使用 JSX 时,其转换规则如下:

js
const dom = (
  <>
    <p>1</p>
    <span>2</span>
  </>
);
// 转换后
const { h, Fragment } = "preact";
const dom = h(Fragment, null, [h("p", null, "1"), h("span", null, "2")]);
  1. envDir

该选项表示用于加载 .env 文件的目录,默认是项目根目录。.env 用于定义环境变量,当需要按照不同模式加载不同的环境变量时,也会定义像 .env.staging 这样的文件,这些文件的位置都通过 envDir 来设置。当需要在多个项目共享环境变量时,该选项非常有用。

  1. envPrefix

该选项表示有效的环境变量前缀,默认是 “VITE_”。为了安全,Vite 只认为符合该选项配置前缀的环境变量才是有效的。比如 VITE_BASEURL 是个有效的环境变量,可以通过 import.meta.env.VITE_BASEURL 访问。而 BASEURL 是个无效的环境变量,不能通过 import.meta.env.BASEURL 访问。

开发服务器配置

开发服务器配置项大多数都是制定开发服务器如何运行。在 vite.config.js 中,开发服务器配置被定义在 server 选项下,下面介绍的所有配置都是 server 对象下的属性,我们来看一下具体有哪些配置。

  1. host

指定开发服务器 IP 地址,默认为 localhost。一般情况下本地项目运行的地址都是 localhost,不过有时候为了在一个局域网内的多台设备互相访问,我们可能需要局域网的 IP 地址,这些 Vite 都已经帮你做好了。运行 “yarn run dev --host”,可以看到以下结果。

这里提供了两个 IP,第二个就是局域网的 IP 地址,同一个局域网内的其他电脑也可以打开,这对协作调试和测试非常有帮助。

  1. port

指定开发服务器监听端口,默认为 5173。如果 5173 端口已被占用,Vite 会尝试使用下一个端口(默认端口号+1)。当然通过该配置修改默认端口号后,如果端口占用,Vite 还是会继续尝试下一个端口,保证开发服务器可以运行起来。

  1. strictPort

使用 port 选项设置端口后,如果端口占用,则会尝试下一个端口。但也许你并不想切换端口,此时可以将 strictPort 选项设置为 true,当端口已被占用则会直接退出。

  1. https

是否启动 https,默认不启动。如果启动 https,还需要一个合法可用的证书,此时可以使用插件 @vitejs/plugin-basic-ssl 来帮我们自动生成一个自签名的证书。不过这种证书只适合在开发环境下使用,当线上部署时,请使用第三方机构颁发的证书。

  1. open

启动开发服务器时,是否在浏览器中自动打开该网址,默认值为 true。

  1. proxy

这个选项是开发服务器中比较重要的,用于设置 HTTP 请求代理。在前端开发的过程中,直接调用后端提供的接口,往往会遇到跨域问题,这非常令人头疼。通常跨域在前端的解决方案就是使用代理,将符合规则的本地 IP 转换为真实 IP。

假设真实的服务端接口地址是 http://api.test.com,我希望在前端请求 /api 时可以自动代理请求到服务端地址,那么配置如下:

js
defineConfig({
  server: {
    proxy: {
      "/api/*": {
        target: "http://api.test.com",
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, ""),
      },
    },
  },
});

假设本地开发服务器的地址是 http://loclahost:3479,此时在项目中发起请求,其代理规则如下:

js
http.get("/api/get-name/1");
// 代理后等于
http.get("http://api.test.com/get-name/1");
  1. watch

模块热替换使用 chokidar 监听文件变化,监听到变化后才能执行重新构建。当项目工程变大时,监听庞大的文件非常耗费性能,因此可以通过该配置项修改文件监听的范围。

默认情况下,Vite 会忽略对 .git 和 node_modules 目录的监听,我们可以通过该选项的 ignored 属性修改监听目录(包括添加和排除目录)。比如要排除对 index.html 文件修改的监听,添加对 node_modules/dayjs 模块的监听,配置方式如下:

js
defineConfig({
  server: {
    watch: {
      ignored: ["**/index.html", "!**/node_modules/dayjs/**"],
    },
  },
});

上面配置中,“**”表示对多层目录和文件的匹配,“*”表示对单层目录和文件的匹配,这样我们就匹配到了项目中对应的文件路径。“!”表示取反,意思是为已经忽略的目录添加监听。

打包构建配置

项目打包时会把打包后的代码输出到一个文件夹,打包构建配置就是用于配置项目打包细节以及文件输出到哪里等。打包配置多数是 rollup 配置,因为打包时不会使用 esbuild,这是与开发服务器配置最大的区别。

  1. target

该选项表示构建目标,也就是打包后的代码在哪里可以运行,默认值是 “modules”,表示支持 ESM、import() 动态导入和 import.meta 的现代浏览器。另一个值是 “esnext”,表示不支持 import() 的浏览器,选择该选项打包会做降级处理,由 esbuild 执行降级转换。

  1. outDir

打包后的代码输出路径,默认是 dist 目录(相对于项目根目录)。

  1. assetsDir

打包后的静态资源的存放路径,默认是 assets 目录(相对于 outDir)。

  1. assetsInlineLimit

该选项指定一个阈值用于决定是否将导入的资源转换为 base64 编码,从而避免额外的 http 请求,默认值为 4kb。当导入资源小于该值时,会转换成 base64 内置于代码中,反之则生成文件输出到 assets 目录中。设置为 0 可以禁用 base64 转换。

  1. cssCodeSplit

是否启用 CSS 代码分割,默认为 true。启用时会按照异步导入规则将 CSS 拆分到多个 chunk 中,否则所有样式都会被提取到一个 CSS 文件中。

  1. cssTarget

CSS 转换目标,默认与 target 选项一致。该选项主要用于处理 CSS 兼容性,对于不支持某些属性的构建目标,比如安卓微信中的 Webview 不支持 #RGBA 颜色,此时可以通过该选项做 CSS 降级,设置为 chrome61 即可。

  1. sourcemap

该选项很重要,是否启用 sourcemap,默认为 false。生产环境下为了减少构建提体积一般不会启用 sourcemap,缺点是当报错时无法定位源码中的错误位置。如果启用 sourcemap 则会生成单独的 sourcemap 文件,该文件的作用只是为了帮助调试。

一般情况下,我们可以在预发环境启用 sourcemap,生产环境禁用 sourcemap。

  1. rollupOptions

该选项用于自定义 rollup 打包配置,配置细节请查看 rollup 文档。指定后的配置将与 Vite 默认的 rollup 配置合并,可以大大提高 Vite 的扩展性。

  1. lib

当要开发一个第三方 npm 库的时候,该选项非常重要,可以指定库的入口文件、模块化系统、全局变量等等。开发普通项目时则不需要使用该选项。

  1. manifest

是否生成 manifest.json 文件,默认为 false。manifest.json 一般用于为 SPA 提供应用的描述信息,比如应用名称、作者、图标、主题等,这里也可以为服务端框架提供正确的资源引入链接。另一个选项 ssrManifest 与该选项类似,是为服务端渲染生产清单文件。

  1. ssr

该选项表示是否启用服务端渲染,默认 false。也可以直接设置服务端渲染的入口文件,此时会自动启用服务端渲染。

  1. minify

打包时压缩代码的工具,默认值为 esbuild。另一个选项是使用 terser,但它的速度要比 esbuild 慢 20-40 倍。

  1. emptyOutDir

打包时是否会清空输出文件,默认为 true。但如果输出目录不在项目根目录下,则该选项默认为 false,这是为了避免删除项目外的重要文件。可以将此选项设置为 true 强制清空。

  1. chunkSizeWarningLimit

当打包生成的 chunk 体积大于该选项时,控制台会提示警告,告诉我们项目该优化了。该选项默认值为 500kb,当触发警告时,可以通过拆分组件和异步加载来解决问题。

  1. watch

是否启用 rollup 监听器,默认为 null。当设置为一个配置对象时,则启用监听器。启用监听器后,当修改源码时会自动重新打包并输出文件,这对一些跨平台框架非常适用。

性能优化配置

Vite 在开发环境下的性能已经非常不错了,在某些情况下可以做依赖优化。生产环境下的优化主要是对 Rollup 打包的优化,比如合适的分包、压缩、Tree Shaking 等。

  1. 依赖优化

Vite 会根据模块导入自动搜寻依赖,一般情况下不需要修改。然而有时候我们确定某个模块不需要预构建,就可以通过配置手动将该依赖排除,从而提高构建效率。依赖配置通过 optimizeDeps 配置选项实现,该选项可以调整自动搜寻依赖的规则。

默认情况下,Vite 只会从 node_modules 目录下抓取依赖项。使用 optimizeDeps.exclude 可以将 node_modules 目录下的某些依赖排除在外。如果要将一个不在 node_modules 目录下的模块添加为依赖,则可以通过 optimizeDeps.include 设置。exclude 和 include 的值都是一个数组,可以添加多个需要匹配的模块或目录文件。

假设要将 node_modules/dayjs 模块排除在依赖项之外,并将 src/test.js 添加为依赖,则可以这样配置:

js
defineConfig({
  optimizeDeps: {
    exclude: ["dayjs"],
    include: ["src/test.js"],
  },
});

重新运行项目,此时 dayjs 模块会跳过构建被直接导入并使用,而 src/test.js 会被构建并输出到 node_modules/.vite 目录下。

  1. Tree Shaking

Tree Shaking 也被称为 “摇树优化”。简单来讲,就是在保证代码正常运行的前提下,去除无用的代码,这样可以大幅度的减少构建体积。在 Vue3 中默认开启 Tree Shaking 优化,但有一个前提,必须是 ESM 才可以支持。

比如常用的 dayjs,它是 CommonJS 风格的模块,无法进行 Tree Shaking 优化。在项目中导入该模块并使用其中的某一个函数,打包后 Vite 会将整个模块全都打进去,很显然这会大大增加构建体积。那怎么办呢?最简单的方法就是使用 dayjs-es 模块代替,Tree Shaking 会自然开启。

所以在使用一个第三方模块时,尽量使用 ESM 类型的模块。如果一个常用的模块是 CommonJS 风格,请搜索是否有 “xxx-es” 的包名,这很可能是该模块的 ESM 版的实现。

  1. 分包策略

默认情况下,当浏览器重复请求相同名称的资源时,会直接使用缓存。利用这个机制我们可以将常用的第三方模块单独打包成一个文件,这样就可以减少 HTTP 请求,提高加载速度。

该分包策略需要在 Rollup 中配置,方法如下:

js
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        manualChunks: (id) => {
          // 将 node_modules 中的代码单独打包成一个 JS 文件
          if (id.includes("node_modules")) {
            return "vendor";
          }
        },
      },
    },
  },
});

上述配置中会将所有用到的 node_modules 中的模块单独打包,生成 vendor.xxx.js 文件。如果你只想打包部分模块,直接修改 manualChunks 方法中的判断规则。

服务端渲染配置

Vite 的另一大特点是支持服务端渲染构建。与默认构建不同的是,服务端渲染需要打包产物与服务端框架集成,因此它会打包出多个 html 页面用于与服务端的路由集成,这与 SPA 页面完全不同。Vite 服务端渲染构建对 Node.js 支持最友好,也推荐使用 Node.js 作为渲染服务器。

服务端渲染配置定义在 ssr 选项下,包括的属性如下。

  1. external

不知道啥意思,待研究。

  1. noExternal

是否禁用外部依赖。

  1. target

SSR 服务器构建目标,默认是 Node.js,也推荐 Node.js。

  1. format

SSR 服务器构建后的语法格式,有 esm 和 cjs 两种。cjs 表示 CommonJS,是 Node.js 的语法风格,从 Vite v3 开始默认值为 esm,不推荐使用 cjs。