知海

生产环境构建

vite-main使用指南

生产环境构建

当需要将应用部署到生产环境时,只需运行 vite build 命令。默认情况下,它使用 <root>/index.html 作为构建入口点,并生成适合在静态托管服务上提供的应用捆绑包。查看部署静态站点可获取流行服务的指南。

Scrimba 上观看互动课程

浏览器兼容性

默认情况下,生产构建包以与 Baseline Widely Available 兼容的最低浏览器版本为目标,这一基线日期在每个主版本发布时固定。该主版本的默认浏览器支持范围如下:

  • Chrome >=111
  • Edge >=111
  • Firefox >=114
  • Safari >=16.4

您可以通过 build.target 配置选项指定自定义目标,最低目标为 es2015。如果设置了更低的目标,Vite 仍将要求这些最低浏览器支持范围,因为它依赖于原生 ESM 动态导入import.meta

  • Chrome >=64
  • Firefox >=67
  • Safari >=11.1
  • Edge >=79

请注意,默认情况下,Vite 仅处理语法转换,不包含 polyfill。您可以查看 https://cdnjs.cloudflare.com/polyfill/ ,它会根据用户的浏览器 UserAgent 字符串自动生成 polyfill 包。

旧版浏览器可以通过 @vitejs/plugin-legacy 获得支持,该插件会自动生成旧版代码块和相应的 ES 语言特性 polyfill。旧版代码块仅在缺少原生 ESM 支持的浏览器中有条件地加载。

公共基础路径

如果要在嵌套公共路径下部署项目,只需指定 base 配置选项,所有资源路径都会相应地被重写。此选项也可以通过命令行标志指定,例如 vite build --base=/my/public/path/

JS 导入的资源 URL、CSS url() 引用以及 .html 文件中的资源引用在构建时都会自动调整并遵循此选项。

例外情况是当您需要动态拼接 URL 时。在这种情况下,您可以使用全局注入的 import.meta.env.BASE_URL 变量,它就是公共基础路径。请注意,该变量在构建时会进行静态替换,因此它必须原样出现(例如 import.meta.env['BASE_URL'] 将不起作用)。

如需更高级的基础路径控制,请参阅高级基础路径选项

相对基础路径

如果您事先不知道基础路径,可以设置相对基础路径,如 "base": "./""base": ""。这将使所有生成的 URL 相对于每个文件。

::: warning 使用相对基础路径时对旧版浏览器的支持
使用相对基础路径需要支持 import.meta。如果您需要支持不支持 import.meta 的浏览器,可以使用 legacy 插件

自定义构建

可以通过多种构建配置选项自定义构建。具体来说,您可以通过 build.rolldownOptions 直接调整底层 Rolldown 选项

js [vite.config.js] 复制代码
export default defineConfig({
  build: {
    rolldownOptions: {
      // https://rolldown.rs/reference/
    },
  },
})

例如,您可以指定多个 Rolldown 输出,并使用仅在构建期间应用的插件。

拆包策略

您可以使用 build.rolldownOptions.output.codeSplitting 配置如何拆分代码块(参见 Rolldown 文档)。如果您使用框架,请参阅其文档以了解如何配置拆分代码块。

加载错误处理

当 Vite 加载动态导入失败时,会触发 vite:preloadError 事件。event.payload 包含原始的导入错误。如果调用 event.preventDefault(),则不会抛出错误。

js twoslash 复制代码
window.addEventListener('vite:preloadError', (event) => {
  window.location.reload() // 例如,刷新页面
})

当发生新部署时,托管服务可能会删除之前部署的资源。因此,之前访问过您网站的用户可能会遇到导入错误。此事件可用于处理这种情况。在这种情况下,请务必在 HTML 文件上设置 Cache-Control: no-cache,否则旧资源仍会被引用。

文件变化时重新构建

您可以使用 vite build --watch 启用 Rolldown 监视器。或者,您也可以通过 build.watch 直接调整底层 WatcherOptions

js [vite.config.js] 复制代码
export default defineConfig({
  build: {
    watch: {
      // https://rolldown.rs/reference/InputOptions.watch
    },
  },
})

启用 --watch 标志后,对需要打包的文件进行的更改将触发重新构建。请注意,对配置及其依赖项的更改需要重新启动构建命令。

多页面应用

假设您有以下源代码结构:

复制代码
├── package.json
├── vite.config.js
├── index.html
├── main.js
└── nested
    ├── index.html
    └── nested.js

在开发期间,只需导航或链接到 /nested/ 即可正常使用,就像普通的静态文件服务器一样。

在构建时,您需要做的只是将多个 .html 文件指定为入口点:

js twoslash [vite.config.js] 复制代码
import { resolve } from 'node:path'
import { defineConfig } from 'vite'

export default defineConfig({
  input: {
    main: resolve(import.meta.dirname, 'index.html'),
    nested: resolve(import.meta.dirname, 'nested/index.html'),
  },
})

如果您指定了不同的 root,请记住,在解析输入路径时,import.meta.dirname 仍然是您的 vite.config.js 文件所在的文件夹。因此,您需要将 root 入口添加到 resolve 的参数中。

请注意,对于 HTML 文件,Vite 会忽略 rolldownOptions.input 对象中为入口给出的名称,而是在生成 dist 文件夹中的 HTML 资源时遵循文件的解析 id。这确保了与开发服务器工作方式一致的结构。

库模式

当您开发面向浏览器的库时,大部分时间可能花在导入实际库的测试/演示页面上。使用 Vite,您可以利用 index.html 来实现这一点,获得流畅的开发体验。

当需要打包库以供分发时,请使用 build.lib 配置选项。同时,请确保将不想打包进库的任何依赖项外部化,例如 vuereact: code-group

js twoslash [vite.config.js(单入口)] 复制代码
import { resolve } from 'node:path'
import { defineConfig } from 'vite'

export default defineConfig({
  build: {
    lib: {
      entry: resolve(import.meta.dirname, 'lib/main.js'),
      name: 'MyLib',
      // 将添加适当的扩展名
      fileName: 'my-lib',
    },
    rolldownOptions: {
      // 请务必外部化不应打包到库中的依赖项
      external: ['vue'],
      output: {
        // 为外部化的依赖项提供用于 UMD 构建的全局变量
        globals: {
          vue: 'Vue',
        },
      },
    },
  },
})
js twoslash [vite.config.js(多入口)] 复制代码
import { resolve } from 'node:path'
import { defineConfig } from 'vite'

export default defineConfig({
  build: {
    lib: {
      entry: {
        'my-lib': resolve(import.meta.dirname, 'lib/main.js'),
        secondary: resolve(import.meta.dirname, 'lib/secondary.js'),
      },
      name: 'MyLib',
    },
    rolldownOptions: {
      // 请务必外部化不应打包到库中的依赖项
      external: ['vue'],
      output: {
        // 为外部化的依赖项提供用于 UMD 构建的全局变量
        globals: {
          vue: 'Vue',
        },
      },
    },
  },
})

入口文件应包含可由您软件包的用户导入的导出:

js [lib/main.js] 复制代码
import Foo from './Foo.vue'
import Bar from './Bar.vue'
export { Foo, Bar }

使用此配置运行 vite build 会使用一个面向库发布的 Rollup 预设,并生成两种捆绑格式:

  • esumd(对于单入口)
  • escjs(对于多入口)

这些格式可以通过 build.lib.formats 选项进行配置。

复制代码
$ vite build
building for production...
dist/my-lib.js      0.08 kB / gzip: 0.07 kB
dist/my-lib.umd.cjs 0.30 kB / gzip: 0.16 kB

为您的库推荐的 package.json: code-group

json [package.json(单入口)] 复制代码
{
  "name": "my-lib",
  "type": "module",
  "files": ["dist"],
  "main": "./dist/my-lib.umd.cjs",
  "module": "./dist/my-lib.js",
  "exports": {
    ".": {
      "import": "./dist/my-lib.js",
      "require": "./dist/my-lib.umd.cjs"
    }
  }
}
json [package.json(多入口)] 复制代码
{
  "name": "my-lib",
  "type": "module",
  "files": ["dist"],
  "main": "./dist/my-lib.cjs",
  "module": "./dist/my-lib.js",
  "exports": {
    ".": {
      "import": "./dist/my-lib.js",
      "require": "./dist/my-lib.cjs"
    },
    "./secondary": {
      "import": "./dist/secondary.js",
      "require": "./dist/secondary.cjs"
    }
  }
}

CSS 支持

如果您的库导入了任何 CSS,除了构建的 JS 文件之外,它还会被打包成一个单独的 CSS 文件,例如 dist/my-lib.css。该名称默认为 build.lib.fileName,但也可以通过 build.lib.cssFileName 更改。

您可以在 package.json 中导出 CSS 文件,以供用户导入:

json {12} 复制代码
{
  "name": "my-lib",
  "type": "module",
  "files": ["dist"],
  "main": "./dist/my-lib.umd.cjs",
  "module": "./dist/my-lib.js",
  "exports": {
    ".": {
      "import": "./dist/my-lib.js",
      "require": "./dist/my-lib.umd.cjs"
    },
    "./style.css": "./dist/my-lib.css"
  }
}
``` tip 文件扩展名

如果 package.json 不包含 "type": "module",Vite 将生成不同的文件扩展名以确保 Node.js 兼容性。.js 将变为 .mjs.cjs 将变为 .js

::: tip 环境变量
在库模式下,所有 import.meta.env.* 的用法在生产构建时都会被静态替换。但是,process.env.* 的用法不会被替换,以便库的使用者可以动态更改它。如果这不是您想要的,您可以使用 define: { 'process.env.NODE_ENV': '"production"' } 来静态替换它们,或者使用 esm-env 以获得与打包器和运行时更好的兼容性。

::: warning 高级用法
库模式包含一个简单且带有明确默认约定的配置,适用于面向浏览器和 JS 框架的库。如果您构建的是非浏览器库,或者需要高级构建流程,可以直接使用 tsdownRolldown

高级基础路径选项 warning

此功能为实验性功能。提供反馈
:::

对于高级用例,已部署的资源和公共文件可能位于不同的路径,例如使用不同的缓存策略。用户可以选择在三个不同的路径中部署:

  • 生成的入口 HTML 文件(可能在 SSR 期间处理)
  • 生成的带哈希的资源(JS、CSS 和其他文件类型,如图像)
  • 复制的公共文件

在这些场景下,单一的静态 base 是不够的。Vite 在构建期间通过 experimental.renderBuiltUrl 提供对高级基础路径选项的实验性支持。

ts twoslash 复制代码
import type { UserConfig } from 'vite'
// prettier-ignore
const config: UserConfig = {
// ---cut-before---
experimental: {
  renderBuiltUrl(filename, { hostType }) {
    if (hostType === 'js') {
      return { runtime: `window.__toCdnUrl(${JSON.stringify(filename)})` }
    } else {
      return { relative: true }
    }
  },
},
// ---cut-after---
}

如果带哈希的资源与公共文件没有一起部署,则可以使用传给函数的第二个 context 参数中包含的资源 type 独立地为每组定义选项。

ts twoslash 复制代码
import type { UserConfig } from 'vite'
import path from 'node:path'
// prettier-ignore
const config: UserConfig = {
// ---cut-before---
experimental: {
  renderBuiltUrl(filename, { hostId, hostType, type }) {
    if (type === 'public') {
      return 'https://www.domain.com/' + filename
    } else if (path.extname(hostId) === '.js') {
      return {
        runtime: `window.__assetsPath(${JSON.stringify(filename)})`
      }
    } else {
      return 'https://cdn.domain.com/assets/' + filename
    }
  },
},
// ---cut-after---
}

请注意,传入的 filename 是解码后的 URL,如果函数返回 URL 字符串,它也应该是解码后的。Vite 在渲染 URL 时会自动处理编码。如果返回带有 runtime 的对象,则在需要的地方应自行处理编码,因为运行时代码将按原样渲染。

帮助我们改进文档

发现翻译问题或内容错误?请告诉我们。