diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 00000000..7e3b604b
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,24 @@
+name: "\U0001F4DA 反馈中文文档项目问题"
+description: 反馈 Vite 官方中文文档项目的相关问题
+labels: [documentation]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ 感谢您对 Vite 的支持,这里是 Vite 官方中文文档的翻译项目相关 issue 区,请不要在此提交关于 Vite 使用的问题或报 Bug。
+ - type: checkboxes
+ id: documentation_is
+ attributes:
+ label: 文档的
+ options:
+ - label: 翻译缺失
+ - label: 翻译不准确
+ - label: 其他问题
+ - type: textarea
+ id: description
+ attributes:
+ label: 详细描述
+ description: 请简明扼要地阐述您的问题。如果您愿意提交 PR 修改,请参考 [贡献指南](https://github.com/vitejs/docs-cn/wiki/%E5%90%88%E4%BD%9C%E8%A7%84%E8%8C%83)。
+ placeholder: xxx章节下的翻译有歧义... xxx章节与英文原文对应不上...
+ validations:
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 00000000..d3e4ab32
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,8 @@
+blank_issues_enabled: false
+contact_links:
+ - name: Vite Issue 区
+ url: https://github.com/vitejs/vite/issues
+ about: 与 Vite 相关的 Bug 上报,请移步 Vite 主仓库 issue 区
+ - name: Vite Discussion 区
+ url: https://github.com/vitejs/vite/discussions
+ about: 与 Vite 相关的讨论和使用问题,请移步 Vite 主仓库 discussion 区
diff --git a/.gitignore b/.gitignore
index 34570f14..becbdc49 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,4 +7,5 @@ node_modules/
package-lock.json
yarn.lock
.vitepress/dist
-*.local
\ No newline at end of file
+*.local
+.vitepress/cache
\ No newline at end of file
diff --git a/.vitepress/buildEnd.config.ts b/.vitepress/buildEnd.config.ts
new file mode 100644
index 00000000..8e0d72b7
--- /dev/null
+++ b/.vitepress/buildEnd.config.ts
@@ -0,0 +1,50 @@
+import path from 'node:path'
+import { writeFileSync } from 'node:fs'
+import { Feed } from 'feed'
+import type { SiteConfig } from 'vitepress'
+import { createContentLoader } from 'vitepress'
+
+const siteUrl = 'https://vite.dev'
+const blogUrl = `${siteUrl}/blog`
+
+export const buildEnd = async (config: SiteConfig): Promise => {
+ const feed = new Feed({
+ title: 'Vite',
+ description: 'Next Generation Frontend Tooling',
+ id: blogUrl,
+ link: blogUrl,
+ language: 'en',
+ image: 'https://vite.dev/og-image.png',
+ favicon: 'https://vite.dev/logo.svg',
+ copyright: 'Copyright © 2019-present VoidZero Inc. & Vite Contributors',
+ })
+
+ const posts = await createContentLoader('blog/*.md', {
+ excerpt: true,
+ render: true,
+ }).load()
+
+ posts.sort(
+ (a, b) =>
+ +new Date(b.frontmatter.date as string) -
+ +new Date(a.frontmatter.date as string),
+ )
+
+ for (const { url, excerpt, frontmatter, html } of posts) {
+ feed.addItem({
+ title: frontmatter.title,
+ id: `${siteUrl}${url}`,
+ link: `${siteUrl}${url}`,
+ description: excerpt,
+ content: html,
+ author: [
+ {
+ name: frontmatter.author.name,
+ },
+ ],
+ date: frontmatter.date,
+ })
+ }
+
+ writeFileSync(path.join(config.outDir, 'blog.rss'), feed.rss2())
+}
diff --git a/.vitepress/config.ts b/.vitepress/config.ts
index e57cc909..e8a9f85d 100644
--- a/.vitepress/config.ts
+++ b/.vitepress/config.ts
@@ -1,11 +1,79 @@
+import type { DefaultTheme } from 'vitepress'
import { defineConfig } from 'vitepress'
-import renderPermaLink from './render-perma-link'
-import MarkDownItCustomAnchor from './markdown-it-custom-anchor'
+import { transformerTwoslash } from '@shikijs/vitepress-twoslash'
+import {
+ groupIconMdPlugin,
+ groupIconVitePlugin,
+} from 'vitepress-plugin-group-icons'
+import { buildEnd } from './buildEnd.config'
const ogDescription = 'Next Generation Frontend Tooling'
-const ogImage = 'https://vitejs.dev/og-image.png'
+const ogImage = 'https://vite.dev/og-image.jpg'
const ogTitle = 'Vite'
-const ogUrl = 'https://vitejs.dev'
+const ogUrl = 'https://vite.dev'
+
+// netlify envs
+const deployURL = process.env.DEPLOY_PRIME_URL || ''
+const commitRef = process.env.COMMIT_REF?.slice(0, 8) || 'dev'
+
+const deployType = (() => {
+ switch (deployURL) {
+ case 'https://main--vite-docs-main.netlify.app':
+ return 'main'
+ case '':
+ return 'local'
+ default:
+ return 'release'
+ }
+})()
+const additionalTitle = ((): string => {
+ switch (deployType) {
+ case 'main':
+ return ' (main branch)'
+ case 'local':
+ return ' (local)'
+ case 'release':
+ return ''
+ }
+})()
+const versionLinks = ((): DefaultTheme.NavItemWithLink[] => {
+ const oldVersions: DefaultTheme.NavItemWithLink[] = [
+ {
+ text: 'Vite 6 Docs',
+ link: 'https://v6.vite.dev',
+ },
+ {
+ text: 'Vite 5 Docs',
+ link: 'https://v5.vite.dev',
+ },
+ {
+ text: 'Vite 4 Docs',
+ link: 'https://v4.vite.dev',
+ },
+ {
+ text: 'Vite 3 Docs',
+ link: 'https://v3.vite.dev',
+ },
+ {
+ text: 'Vite 2 Docs',
+ link: 'https://v2.vite.dev',
+ },
+ ]
+
+ switch (deployType) {
+ case 'main':
+ case 'local':
+ return [
+ {
+ text: 'Vite 7 Docs (release)',
+ link: 'https://vite.dev',
+ },
+ ...oldVersions,
+ ]
+ case 'release':
+ return oldVersions
+ }
+})()
export default defineConfig({
title: 'Vite 官方中文文档',
@@ -14,103 +82,201 @@ export default defineConfig({
head: [
['link', { rel: 'icon', type: 'image/svg+xml', href: '/logo.svg' }],
+ [
+ 'link',
+ { rel: 'alternate', type: 'application/rss+xml', href: '/blog.rss' },
+ ],
+ ['link', { rel: 'preconnect', href: 'https://fonts.googleapis.com' }],
+ [
+ 'link',
+ {
+ rel: 'preconnect',
+ href: 'https://fonts.gstatic.com',
+ crossorigin: 'true',
+ },
+ ],
+ [
+ 'link',
+ {
+ rel: 'preload',
+ href: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Manrope:wght@600&family=IBM+Plex+Mono:wght@400&display=swap',
+ as: 'style',
+ },
+ ],
+ [
+ 'link',
+ {
+ rel: 'stylesheet',
+ href: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Manrope:wght@600&family=IBM+Plex+Mono:wght@400&display=swap',
+ },
+ ],
+ ['link', { rel: 'me', href: 'https://m.webtoo.ls/@vite' }],
['meta', { property: 'og:type', content: 'website' }],
['meta', { property: 'og:title', content: ogTitle }],
['meta', { property: 'og:image', content: ogImage }],
['meta', { property: 'og:url', content: ogUrl }],
['meta', { property: 'og:description', content: ogDescription }],
+ ['meta', { property: 'og:site_name', content: 'vitejs' }],
['meta', { name: 'twitter:card', content: 'summary_large_image' }],
['meta', { name: 'twitter:site', content: '@vite_js' }],
- ['meta', { name: 'theme-color', content: '#646cff' }]
+ ['meta', { name: 'theme-color', content: '#646cff' }],
+ [
+ 'script',
+ {
+ src: 'https://cdn.usefathom.com/script.js',
+ 'data-site': 'TPLGJZGR',
+ 'data-spa': 'auto',
+ defer: '',
+ },
+ ],
],
- vue: {
- reactivityTransform: true
+ locales: {
+ root: { label: '简体中文' },
+ en: { label: 'English', link: 'https://vite.dev' },
+ ja: { label: '日本語', link: 'https://ja.vite.dev' },
+ es: { label: 'Español', link: 'https://es.vite.dev' },
+ pt: { label: 'Português', link: 'https://pt.vite.dev' },
+ ko: { label: '한국어', link: 'https://ko.vite.dev' },
+ de: { label: 'Deutsch', link: 'https://de.vite.dev' },
+ fa: { label: 'فارسی', link: 'https://fa.vite.dev' },
},
themeConfig: {
logo: '/logo.svg',
editLink: {
+ pattern: 'https://github.com/vitejs/docs-cn/edit/main/:path',
text: '为此页提供修改建议',
- pattern: 'https://github.com/vitejs/docs-cn/edit/main/:path'
+ },
+
+ outline: {
+ label: '本页目录',
+ level: [2, 3],
},
socialLinks: [
- { icon: 'twitter', link: 'https://twitter.com/vite_js' },
- { icon: 'discord', link: 'https://chat.vitejs.dev' },
- { icon: 'github', link: 'https://github.com/vitejs/vite' }
+ { icon: 'bluesky', link: 'https://bsky.app/profile/vite.dev' },
+ { icon: 'mastodon', link: 'https://elk.zone/m.webtoo.ls/@vite' },
+ { icon: 'x', link: 'https://x.com/vite_js' },
+ { icon: 'discord', link: 'https://chat.vite.dev' },
+ { icon: 'github', link: 'https://github.com/vitejs/vite' },
],
- algolia: {
- appId: '7H67QR5P0A',
- apiKey: 'deaab78bcdfe96b599497d25acc6460e',
- indexName: 'vitejs',
- searchParameters: {
- facetFilters: ['tags:cn']
+ search: {
+ provider: 'local',
+ options: {
+ translations: {
+ button: {
+ buttonText: '搜索',
+ buttonAriaLabel: '搜索'
+ },
+ modal: {
+ footer: {
+ selectText: '选择',
+ navigateText: '切换',
+ closeText: '关闭',
+ },
+ }
+ },
}
},
- carbonAds: {
- code: 'CEBIEK3N',
- placement: 'vitejsdev'
+ docFooter: {
+ prev: '上一页',
+ next: '下一页'
},
- localeLinks: {
- text: '简体中文',
- items: [
- { text: 'English', link: 'https://vitejs.dev' },
- { text: '日本語', link: 'https://ja.vitejs.dev' },
- { text: 'Español', link: 'https://es.vitejs.dev' }
- ]
- },
+ // Using WwAds for China
+ // carbonAds: {
+ // code: 'CEBIEK3N',
+ // placement: 'vitejsdev',
+ // },
footer: {
+ message: `Released under the MIT License. (${commitRef})`,
copyright:
- '本中文文档内容版权为 Vite 官方中文翻译团队所有,保留所有权利。'
+ 'Copyright © 2019-present VoidZero Inc. & Vite Contributors'
},
nav: [
+ {
+ component: 'ReleaseTag'
+ },
{ text: '指引', link: '/guide/', activeMatch: '/guide/' },
{ text: '配置', link: '/config/', activeMatch: '/config/' },
{ text: '插件', link: '/plugins/', activeMatch: '/plugins/' },
{
text: '相关链接',
items: [
- { text: 'Team', link: '/team' },
+ { text: '团队成员', link: '/team' },
+ { text: '最新博客', link: '/blog' },
+ { text: '发布策略', link: '/releases' },
{
- text: 'Twitter',
- link: 'https://twitter.com/vite_js'
+ items: [
+ {
+ text: 'Bluesky',
+ link: 'https://bsky.app/profile/vite.dev',
+ },
+ {
+ text: 'Mastodon',
+ link: 'https://elk.zone/m.webtoo.ls/@vite',
+ },
+ {
+ text: 'X',
+ link: 'https://x.com/vite_js',
+ },
+ {
+ text: 'Discord 聊天室',
+ link: 'https://chat.vite.dev',
+ },
+ {
+ text: 'Awesome Vite',
+ link: 'https://github.com/vitejs/awesome-vite'
+ },
+ {
+ text: 'ViteConf',
+ link: 'https://viteconf.org',
+ },
+ {
+ text: 'Dev.to 社区',
+ link: 'https://dev.to/t/vite'
+ },
+ {
+ text: '更新日志',
+ link: 'https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md',
+ },
+ {
+ text: '贡献指南',
+ link: 'https://github.com/vitejs/vite/blob/main/CONTRIBUTING.md',
+ },
+ ],
},
+ ]
+ },
+ {
+ text: '历史版本',
+ items: [
{
- text: 'Discord Chat',
- link: 'https://chat.vitejs.dev'
+ text: 'Vite v6 文档(英文)',
+ link: 'https://v6.vite.dev'
},
{
- text: 'Awesome Vite',
- link: 'https://github.com/vitejs/awesome-vite'
+ text: 'Vite v5 文档(英文)',
+ link: 'https://v5.vite.dev'
},
{
- text: 'Dev.to 社区',
- link: 'https://dev.to/t/vite'
+ text: 'Vite v4 文档(英文)',
+ link: 'https://v4.vite.dev'
},
{
- text: 'Rollup 插件兼容',
- link: 'https://vite-rollup-plugins.patak.dev/'
+ text: 'Vite v3 文档(英文)',
+ link: 'https://v3.vite.dev'
},
{
- text: '更新日志',
- link: 'https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md'
- }
- ]
- },
- {
- text: 'Version',
- items: [
- {
- text: 'Vite v2 文档',
- link: 'https://v2.vitejs.dev'
- }
+ text: 'Vite v2 文档(英文)',
+ link: 'https://v2.vite.dev'
+ },
]
}
],
@@ -118,19 +284,32 @@ export default defineConfig({
sidebar: {
'/guide/': [
{
- text: '指引',
+ text: '介绍',
items: [
{
- text: '为什么选 Vite',
- link: '/guide/why'
+ text: '开始',
+ link: '/guide/',
},
{
- text: '开始',
- link: '/guide/'
+ text: '理念',
+ link: '/guide/philosophy',
},
+ {
+ text: '为什么选 Vite',
+ link: '/guide/why',
+ },
+ ],
+ },
+ {
+ text: '指引',
+ items: [
{
text: '功能',
- link: '/guide/features'
+ link: '/guide/features',
+ },
+ {
+ text: '命令行接口',
+ link: '/guide/cli'
},
{
text: '使用插件',
@@ -165,18 +344,26 @@ export default defineConfig({
link: '/guide/backend-integration'
},
{
- text: '比较',
- link: '/guide/comparisons'
+ text: '故障排除',
+ link: '/guide/troubleshooting',
},
{
- text: '故障排除',
- link: '/guide/troubleshooting'
+ text: '性能',
+ link: '/guide/performance',
+ },
+ {
+ text: 'Rolldown',
+ link: '/guide/rolldown',
+ },
+ {
+ text: '从 v6 迁移',
+ link: '/guide/migration',
},
{
- text: '从 v2 迁移',
- link: '/guide/migration'
- }
- ]
+ text: '破坏性变更',
+ link: '/changes/',
+ },
+ ],
},
{
text: 'API',
@@ -187,18 +374,43 @@ export default defineConfig({
},
{
text: 'HMR API',
- link: '/guide/api-hmr'
+ link: '/guide/api-hmr',
},
{
text: 'JavaScript API',
- link: '/guide/api-javascript'
+ link: '/guide/api-javascript',
},
{
text: '配置参考',
- link: '/config/'
- }
- ]
- }
+ link: '/config/',
+ },
+ ],
+ },
+ {
+ text: '环境 API',
+ items: [
+ {
+ text: '介绍',
+ link: '/guide/api-environment',
+ },
+ {
+ text: '环境实例',
+ link: '/guide/api-environment-instances',
+ },
+ {
+ text: '插件',
+ link: '/guide/api-environment-plugins',
+ },
+ {
+ text: '框架',
+ link: '/guide/api-environment-frameworks',
+ },
+ {
+ text: '运行时',
+ link: '/guide/api-environment-runtimes',
+ },
+ ],
+ },
],
'/config/': [
{
@@ -234,20 +446,89 @@ export default defineConfig({
},
{
text: 'Worker 选项',
- link: '/config/worker-options'
- }
- ]
- }
- ]
- }
+ link: '/config/worker-options',
+ },
+ ],
+ },
+ ],
+ '/changes/': [
+ {
+ text: '破坏性变更',
+ link: '/changes/',
+ },
+ {
+ text: '现在',
+ items: [],
+ },
+ {
+ text: '未来',
+ items: [
+ {
+ text: '钩子函数中的 this.environment',
+ link: '/changes/this-environment-in-hooks',
+ },
+ {
+ text: 'HMR hotUpdate 插件钩子',
+ link: '/changes/hotupdate-hook',
+ },
+ {
+ text: '迁移到基于环境的API',
+ link: '/changes/per-environment-apis',
+ },
+ {
+ text: '使用 ModuleRunner API 进行服务端渲染',
+ link: '/changes/ssr-using-modulerunner',
+ },
+ {
+ text: '构建过程中的共享插件',
+ link: '/changes/shared-plugins-during-build',
+ },
+ ],
+ },
+ {
+ text: '过去',
+ items: [],
+ },
+ ],
+ },
+ },
+ transformPageData(pageData) {
+ const canonicalUrl = `${ogUrl}/${pageData.relativePath}`
+ .replace(/\/index\.md$/, '/')
+ .replace(/\.md$/, '')
+ pageData.frontmatter.head ??= []
+ pageData.frontmatter.head.unshift(
+ ['link', { rel: 'canonical', href: canonicalUrl }],
+ ['meta', { property: 'og:title', content: pageData.title }],
+ )
+ return pageData
},
-
markdown: {
- anchor: {
- permalink: renderPermaLink
+ // languages used for twoslash and jsdocs in twoslash
+ languages: ['ts', 'js', 'json'],
+ codeTransformers: [transformerTwoslash()],
+ config(md) {
+ md.use(groupIconMdPlugin)
},
- config: (md) => {
- md.use(MarkDownItCustomAnchor)
- }
- }
+ },
+ vite: {
+ plugins: [
+ // @ts-ignore
+ groupIconVitePlugin({
+ customIcon: {
+ firebase: 'vscode-icons:file-type-firebase',
+ '.gitlab-ci.yml': 'vscode-icons:file-type-gitlab',
+ },
+ }),
+ ],
+ optimizeDeps: {
+ include: [
+ '@shikijs/vitepress-twoslash/client',
+ 'gsap',
+ 'gsap/dist/ScrollTrigger',
+ 'gsap/dist/MotionPathPlugin',
+ ],
+ },
+ },
+ buildEnd,
})
diff --git a/.vitepress/rewrite-title/index.js b/.vitepress/rewrite-title/index.js
index f310ef33..33308779 100644
--- a/.vitepress/rewrite-title/index.js
+++ b/.vitepress/rewrite-title/index.js
@@ -1,6 +1,8 @@
-const path = require('path')
-const fsp = require('fs').promises
-const matterService = require('../utils/frontmatter-service')
+import path from 'node:path'
+import fsp from 'node:fs/promises'
+import matterService from '../utils/frontmatter-service.js'
+import { fileURLToPath } from 'node:url'
+const __dirname = path.dirname(fileURLToPath(import.meta.url))
const workspacePath = path.resolve(__dirname, '..', '..')
const h1MdRegExp = /^#\s+(.+)\s+(\{#([\w-]+)\})$/
@@ -41,4 +43,4 @@ const ergodicDirectory = async (dirPath) => {
}
}
-module.exports = () => ergodicDirectory(workspacePath)
+export default () => ergodicDirectory(workspacePath)
diff --git a/.vitepress/theme/components/AsideSponsors.vue b/.vitepress/theme/components/AsideSponsors.vue
index 789f1e0e..55a52c48 100644
--- a/.vitepress/theme/components/AsideSponsors.vue
+++ b/.vitepress/theme/components/AsideSponsors.vue
@@ -1,29 +1,34 @@
-
-
+
+
-
- ViteConf - Oct 11
-
+
+ ViteConf 2025
+
@@ -34,47 +39,42 @@ const sponsors = computed(() => {
margin-top: 1rem;
margin-bottom: 1rem;
border-radius: 14px;
- padding-left: 2.5rem;
padding-top: 0.4rem;
padding-bottom: 0.4rem;
position: relative;
- font-size: 1rem;
+ font-size: 0.9rem;
font-weight: 700;
line-height: 1.1rem;
- filter: grayscale(100%);
display: flex;
align-items: center;
justify-content: center;
- gap: 0.75rem;
+ width: 100%;
+ gap: 1rem;
background-color: var(--vp-c-bg-alt);
border: 2px solid var(--vp-c-bg-alt);
transition: border-color 0.5s;
}
.viteconf:hover {
- filter: grayscale(0%);
border: 2px solid var(--vp-c-brand-light);
}
.viteconf img {
- position: absolute;
- left: 1.5rem;
transition: transform 0.5s;
+ transform: scale(1.25);
}
.viteconf:hover img {
transform: scale(1.75);
}
-
-.viteconf:hover .heading {
+.viteconf .heading {
background-image: linear-gradient(
120deg,
- #bd34fe 16%,
- var(--vp-c-brand-light),
- var(--vp-c-brand-light)
+ #b047ff 16%,
+ var(--vp-c-brand-lighter),
+ var(--vp-c-brand-lighter)
);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
-
.viteconf .extra-info {
color: var(--vp-c-text-1);
opacity: 0;
diff --git a/.vitepress/theme/components/BlogIndex.vue b/.vitepress/theme/components/BlogIndex.vue
new file mode 100644
index 00000000..5f77ee19
--- /dev/null
+++ b/.vitepress/theme/components/BlogIndex.vue
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+ {{
+ post.date.string
+ }}
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/HomeSponsors.vue b/.vitepress/theme/components/HomeSponsors.vue
deleted file mode 100644
index 16ea073b..00000000
--- a/.vitepress/theme/components/HomeSponsors.vue
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
diff --git a/.vitepress/theme/components/ReleaseTag.vue b/.vitepress/theme/components/ReleaseTag.vue
new file mode 100644
index 00000000..c16538ae
--- /dev/null
+++ b/.vitepress/theme/components/ReleaseTag.vue
@@ -0,0 +1,37 @@
+
+
+
+
+ {{ releaseTag }}
+
+
+
+
diff --git a/.vitepress/theme/components/WwAds.vue b/.vitepress/theme/components/WwAds.vue
new file mode 100644
index 00000000..7a526b5b
--- /dev/null
+++ b/.vitepress/theme/components/WwAds.vue
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/YouTubeVideo.vue b/.vitepress/theme/components/YouTubeVideo.vue
new file mode 100644
index 00000000..59f05d56
--- /dev/null
+++ b/.vitepress/theme/components/YouTubeVideo.vue
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/1. hero-section/HeroDiagram.vue b/.vitepress/theme/components/landing/1. hero-section/HeroDiagram.vue
new file mode 100644
index 00000000..171f58e0
--- /dev/null
+++ b/.vitepress/theme/components/landing/1. hero-section/HeroDiagram.vue
@@ -0,0 +1,841 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/1. hero-section/HeroSection.vue b/.vitepress/theme/components/landing/1. hero-section/HeroSection.vue
new file mode 100644
index 00000000..52bce68e
--- /dev/null
+++ b/.vitepress/theme/components/landing/1. hero-section/HeroSection.vue
@@ -0,0 +1,136 @@
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/1. hero-section/svg-elements/SvgBlueIndicator.vue b/.vitepress/theme/components/landing/1. hero-section/svg-elements/SvgBlueIndicator.vue
new file mode 100644
index 00000000..6f5854f7
--- /dev/null
+++ b/.vitepress/theme/components/landing/1. hero-section/svg-elements/SvgBlueIndicator.vue
@@ -0,0 +1,242 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/1. hero-section/svg-elements/SvgInputs.vue b/.vitepress/theme/components/landing/1. hero-section/svg-elements/SvgInputs.vue
new file mode 100644
index 00000000..c4fe4d32
--- /dev/null
+++ b/.vitepress/theme/components/landing/1. hero-section/svg-elements/SvgInputs.vue
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/1. hero-section/svg-elements/SvgOutputs.vue b/.vitepress/theme/components/landing/1. hero-section/svg-elements/SvgOutputs.vue
new file mode 100644
index 00000000..320e9997
--- /dev/null
+++ b/.vitepress/theme/components/landing/1. hero-section/svg-elements/SvgOutputs.vue
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/1. hero-section/svg-elements/SvgPinkIndicator.vue b/.vitepress/theme/components/landing/1. hero-section/svg-elements/SvgPinkIndicator.vue
new file mode 100644
index 00000000..063816b6
--- /dev/null
+++ b/.vitepress/theme/components/landing/1. hero-section/svg-elements/SvgPinkIndicator.vue
@@ -0,0 +1,253 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/2. feature-section/FeatureCI.vue b/.vitepress/theme/components/landing/2. feature-section/FeatureCI.vue
new file mode 100644
index 00000000..cf7b3386
--- /dev/null
+++ b/.vitepress/theme/components/landing/2. feature-section/FeatureCI.vue
@@ -0,0 +1,503 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
CI Tests
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/2. feature-section/FeatureFlexiblePlugins.vue b/.vitepress/theme/components/landing/2. feature-section/FeatureFlexiblePlugins.vue
new file mode 100644
index 00000000..1b8360ff
--- /dev/null
+++ b/.vitepress/theme/components/landing/2. feature-section/FeatureFlexiblePlugins.vue
@@ -0,0 +1,556 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/2. feature-section/FeatureHMR.vue b/.vitepress/theme/components/landing/2. feature-section/FeatureHMR.vue
new file mode 100644
index 00000000..56ce9ef2
--- /dev/null
+++ b/.vitepress/theme/components/landing/2. feature-section/FeatureHMR.vue
@@ -0,0 +1,515 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/2. feature-section/FeatureInstantServerStart.vue b/.vitepress/theme/components/landing/2. feature-section/FeatureInstantServerStart.vue
new file mode 100644
index 00000000..55b35cfd
--- /dev/null
+++ b/.vitepress/theme/components/landing/2. feature-section/FeatureInstantServerStart.vue
@@ -0,0 +1,427 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Ready in 96ms
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/2. feature-section/FeatureOptimizedBuild.vue b/.vitepress/theme/components/landing/2. feature-section/FeatureOptimizedBuild.vue
new file mode 100644
index 00000000..9b38d068
--- /dev/null
+++ b/.vitepress/theme/components/landing/2. feature-section/FeatureOptimizedBuild.vue
@@ -0,0 +1,623 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/2. feature-section/FeatureRichFeatures.vue b/.vitepress/theme/components/landing/2. feature-section/FeatureRichFeatures.vue
new file mode 100644
index 00000000..f80ef9dd
--- /dev/null
+++ b/.vitepress/theme/components/landing/2. feature-section/FeatureRichFeatures.vue
@@ -0,0 +1,280 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/2. feature-section/FeatureSSRSupport.vue b/.vitepress/theme/components/landing/2. feature-section/FeatureSSRSupport.vue
new file mode 100644
index 00000000..b7d36131
--- /dev/null
+++ b/.vitepress/theme/components/landing/2. feature-section/FeatureSSRSupport.vue
@@ -0,0 +1,539 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ .JS
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Client transform
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Server transform
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/2. feature-section/FeatureSection.vue b/.vitepress/theme/components/landing/2. feature-section/FeatureSection.vue
new file mode 100644
index 00000000..a0264d01
--- /dev/null
+++ b/.vitepress/theme/components/landing/2. feature-section/FeatureSection.vue
@@ -0,0 +1,319 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ title }}
+
+
{{ description }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/2. feature-section/FeatureTypedAPI.vue b/.vitepress/theme/components/landing/2. feature-section/FeatureTypedAPI.vue
new file mode 100644
index 00000000..7076a664
--- /dev/null
+++ b/.vitepress/theme/components/landing/2. feature-section/FeatureTypedAPI.vue
@@ -0,0 +1,240 @@
+
+
+
+
+
+
+
+ import { createServer }
+ from
+ 'vite'
+ const server =
+ await
+ createServer ({
+ // user config options
+ })
+
+
+ await server.listen ()
+
+
+
+
+
+ (method) ViteDevServer.listen (port?: number
+ | undefined, isRestart?:
+ boolean | undefined ):
+ Promise < ViteDevServer>
+ Start the server.
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/2. feature-section/images/css3.svg b/.vitepress/theme/components/landing/2. feature-section/images/css3.svg
new file mode 100644
index 00000000..afa66d98
--- /dev/null
+++ b/.vitepress/theme/components/landing/2. feature-section/images/css3.svg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/2. feature-section/images/js.svg b/.vitepress/theme/components/landing/2. feature-section/images/js.svg
new file mode 100644
index 00000000..59a03751
--- /dev/null
+++ b/.vitepress/theme/components/landing/2. feature-section/images/js.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/2. feature-section/images/json.svg b/.vitepress/theme/components/landing/2. feature-section/images/json.svg
new file mode 100644
index 00000000..20d86ed7
--- /dev/null
+++ b/.vitepress/theme/components/landing/2. feature-section/images/json.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/2. feature-section/images/postcss.svg b/.vitepress/theme/components/landing/2. feature-section/images/postcss.svg
new file mode 100644
index 00000000..5251081b
--- /dev/null
+++ b/.vitepress/theme/components/landing/2. feature-section/images/postcss.svg
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/2. feature-section/images/ts.svg b/.vitepress/theme/components/landing/2. feature-section/images/ts.svg
new file mode 100644
index 00000000..223587b2
--- /dev/null
+++ b/.vitepress/theme/components/landing/2. feature-section/images/ts.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/2. feature-section/images/wa.svg b/.vitepress/theme/components/landing/2. feature-section/images/wa.svg
new file mode 100644
index 00000000..8e6f976d
--- /dev/null
+++ b/.vitepress/theme/components/landing/2. feature-section/images/wa.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/3. frameworks-section/FrameworkCard.vue b/.vitepress/theme/components/landing/3. frameworks-section/FrameworkCard.vue
new file mode 100644
index 00000000..f154f7ab
--- /dev/null
+++ b/.vitepress/theme/components/landing/3. frameworks-section/FrameworkCard.vue
@@ -0,0 +1,127 @@
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/3. frameworks-section/FrameworksSection.vue b/.vitepress/theme/components/landing/3. frameworks-section/FrameworksSection.vue
new file mode 100644
index 00000000..6e97d81e
--- /dev/null
+++ b/.vitepress/theme/components/landing/3. frameworks-section/FrameworksSection.vue
@@ -0,0 +1,465 @@
+
+
+
+
+ 支持你喜爱的框架和工具
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/3. frameworks-section/images/adonis.svg b/.vitepress/theme/components/landing/3. frameworks-section/images/adonis.svg
new file mode 100644
index 00000000..0808286a
--- /dev/null
+++ b/.vitepress/theme/components/landing/3. frameworks-section/images/adonis.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/.vitepress/theme/components/landing/3. frameworks-section/images/analog.svg b/.vitepress/theme/components/landing/3. frameworks-section/images/analog.svg
new file mode 100644
index 00000000..2e7fe7d6
--- /dev/null
+++ b/.vitepress/theme/components/landing/3. frameworks-section/images/analog.svg
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/3. frameworks-section/images/angular.svg b/.vitepress/theme/components/landing/3. frameworks-section/images/angular.svg
new file mode 100644
index 00000000..b6eb20ab
--- /dev/null
+++ b/.vitepress/theme/components/landing/3. frameworks-section/images/angular.svg
@@ -0,0 +1 @@
+
diff --git a/.vitepress/theme/components/landing/3. frameworks-section/images/astro.svg b/.vitepress/theme/components/landing/3. frameworks-section/images/astro.svg
new file mode 100644
index 00000000..744c7e9f
--- /dev/null
+++ b/.vitepress/theme/components/landing/3. frameworks-section/images/astro.svg
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/3. frameworks-section/images/ember.svg b/.vitepress/theme/components/landing/3. frameworks-section/images/ember.svg
new file mode 100644
index 00000000..4f1e6889
--- /dev/null
+++ b/.vitepress/theme/components/landing/3. frameworks-section/images/ember.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/3. frameworks-section/images/hono.svg b/.vitepress/theme/components/landing/3. frameworks-section/images/hono.svg
new file mode 100644
index 00000000..9c7a84b5
--- /dev/null
+++ b/.vitepress/theme/components/landing/3. frameworks-section/images/hono.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/.vitepress/theme/components/landing/3. frameworks-section/images/laravel.svg b/.vitepress/theme/components/landing/3. frameworks-section/images/laravel.svg
new file mode 100644
index 00000000..a8d8fb19
--- /dev/null
+++ b/.vitepress/theme/components/landing/3. frameworks-section/images/laravel.svg
@@ -0,0 +1 @@
+
diff --git a/.vitepress/theme/components/landing/3. frameworks-section/images/marko.svg b/.vitepress/theme/components/landing/3. frameworks-section/images/marko.svg
new file mode 100644
index 00000000..44c26273
--- /dev/null
+++ b/.vitepress/theme/components/landing/3. frameworks-section/images/marko.svg
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/3. frameworks-section/images/nuxt.svg b/.vitepress/theme/components/landing/3. frameworks-section/images/nuxt.svg
new file mode 100644
index 00000000..fb2de2c6
--- /dev/null
+++ b/.vitepress/theme/components/landing/3. frameworks-section/images/nuxt.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/3. frameworks-section/images/playwright.svg b/.vitepress/theme/components/landing/3. frameworks-section/images/playwright.svg
new file mode 100644
index 00000000..63ef7c4c
--- /dev/null
+++ b/.vitepress/theme/components/landing/3. frameworks-section/images/playwright.svg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/3. frameworks-section/images/preact.svg b/.vitepress/theme/components/landing/3. frameworks-section/images/preact.svg
new file mode 100644
index 00000000..246a3b22
--- /dev/null
+++ b/.vitepress/theme/components/landing/3. frameworks-section/images/preact.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/3. frameworks-section/images/qwik.svg b/.vitepress/theme/components/landing/3. frameworks-section/images/qwik.svg
new file mode 100644
index 00000000..606a2b7c
--- /dev/null
+++ b/.vitepress/theme/components/landing/3. frameworks-section/images/qwik.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/3. frameworks-section/images/react.svg b/.vitepress/theme/components/landing/3. frameworks-section/images/react.svg
new file mode 100644
index 00000000..c4fcecce
--- /dev/null
+++ b/.vitepress/theme/components/landing/3. frameworks-section/images/react.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/3. frameworks-section/images/redwood.svg b/.vitepress/theme/components/landing/3. frameworks-section/images/redwood.svg
new file mode 100644
index 00000000..2d611735
--- /dev/null
+++ b/.vitepress/theme/components/landing/3. frameworks-section/images/redwood.svg
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/3. frameworks-section/images/remix.svg b/.vitepress/theme/components/landing/3. frameworks-section/images/remix.svg
new file mode 100644
index 00000000..a9457061
--- /dev/null
+++ b/.vitepress/theme/components/landing/3. frameworks-section/images/remix.svg
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/3. frameworks-section/images/solid.svg b/.vitepress/theme/components/landing/3. frameworks-section/images/solid.svg
new file mode 100644
index 00000000..1cf619e5
--- /dev/null
+++ b/.vitepress/theme/components/landing/3. frameworks-section/images/solid.svg
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/3. frameworks-section/images/storybook.svg b/.vitepress/theme/components/landing/3. frameworks-section/images/storybook.svg
new file mode 100644
index 00000000..43176b92
--- /dev/null
+++ b/.vitepress/theme/components/landing/3. frameworks-section/images/storybook.svg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/3. frameworks-section/images/svelte.svg b/.vitepress/theme/components/landing/3. frameworks-section/images/svelte.svg
new file mode 100644
index 00000000..62309a1d
--- /dev/null
+++ b/.vitepress/theme/components/landing/3. frameworks-section/images/svelte.svg
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/3. frameworks-section/images/vitest.svg b/.vitepress/theme/components/landing/3. frameworks-section/images/vitest.svg
new file mode 100644
index 00000000..c9d5fd3e
--- /dev/null
+++ b/.vitepress/theme/components/landing/3. frameworks-section/images/vitest.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/3. frameworks-section/images/vue.svg b/.vitepress/theme/components/landing/3. frameworks-section/images/vue.svg
new file mode 100644
index 00000000..b29e1a42
--- /dev/null
+++ b/.vitepress/theme/components/landing/3. frameworks-section/images/vue.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/4. community-section/CommunityCard.vue b/.vitepress/theme/components/landing/4. community-section/CommunityCard.vue
new file mode 100644
index 00000000..161c9738
--- /dev/null
+++ b/.vitepress/theme/components/landing/4. community-section/CommunityCard.vue
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/4. community-section/CommunitySection.vue b/.vitepress/theme/components/landing/4. community-section/CommunitySection.vue
new file mode 100644
index 00000000..9104befa
--- /dev/null
+++ b/.vitepress/theme/components/landing/4. community-section/CommunitySection.vue
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/5. sponsor-section/SponsorSection.vue b/.vitepress/theme/components/landing/5. sponsor-section/SponsorSection.vue
new file mode 100644
index 00000000..b6980337
--- /dev/null
+++ b/.vitepress/theme/components/landing/5. sponsor-section/SponsorSection.vue
@@ -0,0 +1,224 @@
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/6. get-started-section/GetStartedSection.vue b/.vitepress/theme/components/landing/6. get-started-section/GetStartedSection.vue
new file mode 100644
index 00000000..8e0f9a7f
--- /dev/null
+++ b/.vitepress/theme/components/landing/6. get-started-section/GetStartedSection.vue
@@ -0,0 +1,291 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
使用 Vite 开始构建
+
+ 准备好迎接一个能跟上您思维速度的开发环境
+
+
开始
+
+
+
+
+
+
diff --git a/.vitepress/theme/components/landing/common/SvgNode.vue b/.vitepress/theme/components/landing/common/SvgNode.vue
new file mode 100644
index 00000000..1bb35a5a
--- /dev/null
+++ b/.vitepress/theme/components/landing/common/SvgNode.vue
@@ -0,0 +1,214 @@
+
+
+
+
+
+
+
+ {{ props.label }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vitepress/theme/composables/sponsor.ts b/.vitepress/theme/composables/sponsor.ts
index b6a98ce1..9fa0ebee 100644
--- a/.vitepress/theme/composables/sponsor.ts
+++ b/.vitepress/theme/composables/sponsor.ts
@@ -1,4 +1,4 @@
-import { ref, onMounted } from 'vue'
+import { onMounted, onUnmounted, ref } from 'vue'
interface Sponsors {
special: Sponsor[]
@@ -13,16 +13,73 @@ interface Sponsor {
name: string
img: string
url: string
+ /**
+ * Expects to also have an **inversed** image with `-dark` postfix.
+ */
+ hasDark?: true
}
// shared data across instances so we load only once.
-const data = ref()
+const data = ref<{ tier: string; size: string; items: Sponsor[] }[]>()
const dataHost = 'https://sponsors.vuejs.org'
const dataUrl = `${dataHost}/vite.json`
+export const voidZero = {
+ name: 'VoidZero',
+ url: 'https://voidzero.dev',
+ img: '/voidzero.svg',
+} satisfies Sponsor
+
+const viteSponsors: Pick = {
+ special: [
+ // sponsors patak-dev
+ {
+ name: 'Bolt',
+ url: 'https://bolt.new',
+ img: '/bolt.svg',
+ },
+ // sponsors antfu
+ {
+ name: 'NuxtLabs',
+ url: 'https://nuxtlabs.com',
+ img: '/nuxtlabs.svg',
+ },
+ ],
+ gold: [
+ // now automated via sponsors.vuejs.org too
+ ],
+}
+
+function toggleDarkLogos() {
+ if (data.value) {
+ const isDark = document.documentElement.classList.contains('dark')
+ data.value.forEach(({ items }) => {
+ items.forEach((s: Sponsor) => {
+ if (s.hasDark) {
+ s.img = isDark
+ ? s.img.replace(/(\.\w+)$/, '-dark$1')
+ : s.img.replace(/-dark(\.\w+)$/, '$1')
+ }
+ })
+ })
+ }
+}
+
export function useSponsor() {
onMounted(async () => {
+ const ob = new MutationObserver((list) => {
+ for (const m of list) {
+ if (m.attributeName === 'class') {
+ toggleDarkLogos()
+ }
+ }
+ })
+ ob.observe(document.documentElement, { attributes: true })
+ onUnmounted(() => {
+ ob.disconnect()
+ })
+
if (data.value) {
return
}
@@ -31,31 +88,48 @@ export function useSponsor() {
const json = await result.json()
data.value = mapSponsors(json)
+ toggleDarkLogos()
})
return {
- data
+ data,
}
}
function mapSponsors(sponsors: Sponsors) {
return [
{
- tier: 'Platinum Sponsor',
+ tier: '合作伙伴',
+ size: 'big',
+ items: viteSponsors['special'],
+ },
+ {
+ tier: '铂金赞助商',
size: 'big',
- items: mapImgPath(sponsors['platinum'])
+ items: mapImgPath(sponsors['platinum']),
},
{
- tier: 'Gold Sponsors',
+ tier: '黄金赞助商',
size: 'medium',
- items: mapImgPath(sponsors['gold'])
- }
+ items: [...mapImgPath(sponsors['gold']), ...viteSponsors['gold']],
+ },
]
}
+const viteSponsorNames = new Set(
+ Object.values(viteSponsors).flatMap((sponsors) =>
+ sponsors.map((s) => s.name),
+ ),
+)
+
+/**
+ * Map Vue/Vite sponsors data to objects and filter out Vite-specific sponsors
+ */
function mapImgPath(sponsors: Sponsor[]) {
- return sponsors.map((sponsor) => ({
- ...sponsor,
- img: `${dataHost}/images/${sponsor.img}`
- }))
+ return sponsors
+ .filter((sponsor) => !viteSponsorNames.has(sponsor.name))
+ .map((sponsor) => ({
+ ...sponsor,
+ img: `${dataHost}/images/${sponsor.img}`,
+ }))
}
diff --git a/.vitepress/theme/composables/useCardAnimation.ts b/.vitepress/theme/composables/useCardAnimation.ts
new file mode 100644
index 00000000..13e1f6a8
--- /dev/null
+++ b/.vitepress/theme/composables/useCardAnimation.ts
@@ -0,0 +1,107 @@
+import { type Ref, onMounted, onUnmounted, ref } from 'vue'
+import { gsap } from 'gsap'
+import { ScrollTrigger } from 'gsap/dist/ScrollTrigger'
+
+gsap.registerPlugin(ScrollTrigger)
+
+/**
+ * A custom hook for animating a card element.
+ *
+ * @param {HTMLElement | string} el - The element or selector for the element to be animated
+ * @param {() => GSAPTimeline} animation - A function that returns a GSAP timeline for the animation
+ * @param {object} options - Options for the animation
+ */
+export function useCardAnimation(
+ el: HTMLElement | string,
+ animation: (() => GSAPTimeline) | undefined = undefined,
+ options?: {
+ /**
+ * A flag to indicate whether the animation should only run once, and not reset once complete.
+ */
+ once?: boolean
+ },
+) {
+ /**
+ * The GSAP timeline for this animation.
+ */
+ let timeline: GSAPTimeline | null
+
+ /**
+ * A flag to indicate whether the card is currently active or not.
+ * May be inactive while the animation is still finishing up, due to CSS transitions.
+ */
+ const isCardActive: Ref = ref(false)
+
+ /**
+ * An internal flag to prevent multiple animations from running at the same time.
+ */
+ const isAnimationRunning: Ref = ref(false)
+
+ /**
+ * Starts the card's animation, managing the lifecycle internally to prevent multiple animations from running at the same time.
+ */
+ const startAnimation = () => {
+ if (isAnimationRunning.value) {
+ return
+ } else {
+ isAnimationRunning.value = true
+ isCardActive.value = true
+ }
+ if (timeline) {
+ timeline.kill()
+ }
+ if (!animation) {
+ return
+ }
+ timeline = gsap.timeline({
+ onComplete: () => {
+ if (!options?.once) {
+ isCardActive.value = false
+ setTimeout(() => {
+ isAnimationRunning.value = false
+ }, 3000)
+ }
+ },
+ })
+ timeline.add(animation())
+ }
+
+ /**
+ * The ScrollTrigger instance for this card.
+ */
+ let scrollTriggerInstance: ScrollTrigger | null = null
+
+ /**
+ * Trigger's the card's animation automatically on mobile devices (no hover method)
+ */
+ onMounted(() => {
+ if (window.innerWidth < 768) {
+ scrollTriggerInstance = ScrollTrigger.create({
+ trigger: el,
+ start: 'top 60%',
+ onEnter: () => {
+ startAnimation()
+ },
+ })
+ }
+ })
+
+ /**
+ * Remove the ScrollTrigger and GSAP timeline instances when the component is unmounted
+ */
+ onUnmounted(() => {
+ if (scrollTriggerInstance) {
+ scrollTriggerInstance.kill()
+ scrollTriggerInstance = null
+ }
+ if (timeline) {
+ timeline.kill()
+ timeline = null
+ }
+ })
+
+ return {
+ startAnimation,
+ isCardActive,
+ }
+}
diff --git a/.vitepress/theme/composables/useSlideIn.ts b/.vitepress/theme/composables/useSlideIn.ts
new file mode 100644
index 00000000..e41cd898
--- /dev/null
+++ b/.vitepress/theme/composables/useSlideIn.ts
@@ -0,0 +1,19 @@
+import { nextTick, onMounted } from 'vue'
+import { gsap } from 'gsap'
+
+export function useSlideIn(el: HTMLElement | string) {
+ onMounted(async () => {
+ await nextTick(() => {
+ gsap.to(el, {
+ x: 0,
+ duration: 1,
+ ease: 'power3.out',
+ scrollTrigger: {
+ trigger: el,
+ start: 'top 100%',
+ once: true,
+ },
+ })
+ })
+ })
+}
diff --git a/.vitepress/theme/custom.css b/.vitepress/theme/custom.css
index a9383986..36374b47 100644
--- a/.vitepress/theme/custom.css
+++ b/.vitepress/theme/custom.css
@@ -57,6 +57,7 @@
background: var(--c-brand);
color: white;
border-radius: 10px;
+ vertical-align: middle;
}
#wwads-container {
diff --git a/.vitepress/theme/index.ts b/.vitepress/theme/index.ts
index c1e67d28..9e212533 100644
--- a/.vitepress/theme/index.ts
+++ b/.vitepress/theme/index.ts
@@ -1,20 +1,31 @@
import { h } from 'vue'
-import Theme from 'vitepress/theme'
-import HomeSponsors from './components/HomeSponsors.vue'
+import type { Theme } from 'vitepress'
+import DefaultTheme from 'vitepress/theme'
+import TwoslashFloatingVue from '@shikijs/vitepress-twoslash/client'
+import '@shikijs/vitepress-twoslash/style.css'
+import './styles/vars.css'
+import './styles/landing.css'
import AsideSponsors from './components/AsideSponsors.vue'
import SvgImage from './components/SvgImage.vue'
-import './styles/vars.css'
+import WwAds from './components/WwAds.vue'
+import ReleaseTag from './components/ReleaseTag.vue'
import './custom.css'
+import YouTubeVideo from './components/YouTubeVideo.vue'
+import 'virtual:group-icons.css'
export default {
- ...Theme,
+ extends: DefaultTheme,
Layout() {
- return h(Theme.Layout, null, {
- 'home-features-after': () => h(HomeSponsors),
- 'aside-ads-before': () => h(AsideSponsors)
+ return h(DefaultTheme.Layout, null, {
+ 'aside-outline-after': () => h(WwAds),
+ 'aside-ads-before': () => h(AsideSponsors),
})
},
enhanceApp({ app }) {
app.component('SvgImage', SvgImage)
- }
-}
+ app.component('ReleaseTag', ReleaseTag)
+ app.component('YouTubeVideo', YouTubeVideo)
+ app.use(TwoslashFloatingVue)
+ },
+} satisfies Theme
+
diff --git a/.vitepress/theme/styles/landing.css b/.vitepress/theme/styles/landing.css
new file mode 100644
index 00000000..1e919af1
--- /dev/null
+++ b/.vitepress/theme/styles/landing.css
@@ -0,0 +1,230 @@
+/* /////////////////////// */
+/* Landing Page CSS Styles */
+/* /////////////////////// */
+
+html:has(.landing) {
+ --vp-c-bg: #101010;
+
+ background-color: #101010;
+
+ body {
+ background-color: #101010;
+ }
+}
+
+.landing {
+ overflow-x: hidden;
+ background-color: #101010;
+
+ * {
+ -webkit-font-smoothing: antialiased !important;
+ -moz-osx-font-smoothing: grayscale !important;
+ text-rendering: optimizeLegibility !important;
+ }
+
+ /* /////////////////// */
+ /* VitePress Overrides */
+ /* /////////////////// */
+
+ .VPNavBar,
+ .VPNavBar:not(.top) {
+ background: transparent !important;
+
+ @media (min-width: 768px) {
+ backdrop-filter: blur(10px);
+ background: rgba(15, 15, 15, 0.8) !important;
+ border-bottom: 1px solid #262626 !important;
+ }
+
+ .content-body {
+ background: none !important;
+ transition: none;
+ }
+ }
+
+ .VPNavBar *:not(.wrapper *) {
+ transition: none;
+ }
+
+ .VPFooter {
+ border-top: 1px solid #262626 !important;
+ background: radial-gradient(circle at top center, #0f151a 30%, #000000 80%);
+ }
+
+ .VPHome {
+ padding-bottom: 0 !important;
+ margin-bottom: 0 !important;
+ }
+
+ /* /////////////// */
+ /* Force Dark Mode */
+ /* /////////////// */
+
+ .VPNavBarAppearance {
+ display: none;
+ }
+
+ .VPMenu .translations + .group {
+ display: none;
+ }
+
+ .VPNavScreenAppearance {
+ visibility: hidden;
+ }
+
+ .social-links::before {
+ margin-left: 0 !important;
+ }
+
+ /* ////////// */
+ /* Typography */
+ /* ////////// */
+
+ h1 {
+ text-align: center;
+ font-family: 'Manrope', sans-serif;
+ font-style: normal;
+ font-weight: 600;
+ background: linear-gradient(
+ 180deg,
+ #fff 0%,
+ rgba(255, 255, 255, 0.31) 100%
+ );
+ background-clip: text;
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ text-wrap: balance;
+ cursor: default;
+ font-size: 44px;
+ line-height: 120%;
+ letter-spacing: -0.88px;
+ padding: 0 20px;
+ margin-bottom: 15px;
+
+ @media (min-width: 768px) {
+ font-size: 64px;
+ line-height: 81px;
+ letter-spacing: -1.28px;
+ }
+
+ @media (min-width: 1025px) {
+ font-size: 72px;
+ letter-spacing: -1.44px;
+ padding-bottom: 8px; /* Fix for hanging descender on "g" in "tooling" */
+ }
+ }
+
+ h2 {
+ display: block;
+ width: fit-content;
+ font-family: Manrope, sans-serif;
+ font-size: 32px;
+ font-style: normal;
+ font-weight: 600;
+ line-height: 120%;
+ letter-spacing: -0.64px;
+ cursor: default;
+ text-wrap: balance;
+ padding: 0 20px;
+
+ @media (min-width: 768px) {
+ font-size: 44px;
+ letter-spacing: -0.88px;
+ }
+ }
+
+ h3 {
+ color: #a9a9a9;
+ text-align: center;
+ font-family: Inter, sans-serif;
+ font-size: 20px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 150%;
+ letter-spacing: -0.4px;
+ max-width: 500px;
+ text-wrap: balance;
+ cursor: default;
+ margin-bottom: 25px;
+ padding: 0 20px;
+ }
+
+ /* /////// */
+ /* Buttons */
+ /* /////// */
+
+ .btn {
+ display: flex;
+ padding: 10px 18px;
+ justify-content: center;
+ align-items: center;
+ gap: 8px;
+ border-radius: 8px;
+ color: #fff;
+ font-family: Inter, sans-serif;
+ font-size: 16px;
+ font-style: normal;
+ font-weight: 500;
+ line-height: 24px;
+ text-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
+ transition: all 0.2s ease-in-out;
+ width: fit-content;
+
+ &:hover {
+ transform: translate3d(0, -2px, 0);
+ }
+
+ &.btn--primary {
+ position: relative;
+ background:
+ radial-gradient(
+ 141.42% 141.42% at 100% 0%,
+ rgba(255, 255, 255, 0.4) 0%,
+ rgba(255, 255, 255, 0) 100%
+ ),
+ radial-gradient(
+ 140.35% 140.35% at 100% 94.74%,
+ #bd34fe 0%,
+ rgba(189, 52, 254, 0) 100%
+ ),
+ radial-gradient(
+ 89.94% 89.94% at 18.42% 15.79%,
+ #41d1ff 0%,
+ rgba(65, 209, 255, 0) 100%
+ );
+ box-shadow: 0 1px 0 0 rgba(255, 255, 255, 0.75) inset;
+
+ &:hover {
+ background:
+ radial-gradient(
+ 141.42% 141.42% at 100% 0%,
+ rgba(255, 255, 255, 0.5) 0%,
+ rgba(255, 255, 255, 0) 100%
+ ),
+ radial-gradient(
+ 140.35% 140.35% at 100% 94.74%,
+ #bd34fe 0%,
+ rgba(189, 52, 254, 0) 100%
+ ),
+ radial-gradient(
+ 89.94% 89.94% at 18.42% 15.79%,
+ #41d1ff 0%,
+ rgba(65, 209, 255, 0) 100%
+ );
+ box-shadow: 0 1.5px 0 0 rgba(255, 255, 255, 0.8) inset;
+ }
+ }
+
+ &.btn--outline {
+ border: 1px solid rgba(255, 255, 255, 0.2);
+
+ &:hover {
+ border: 1px solid rgba(255, 255, 255, 0.4);
+ }
+ }
+
+ &.btn--rounded {
+ border-radius: 100px;
+ }
+ }
+}
diff --git a/.vitepress/theme/styles/vars.css b/.vitepress/theme/styles/vars.css
index 8022a97b..9c73cf8f 100644
--- a/.vitepress/theme/styles/vars.css
+++ b/.vitepress/theme/styles/vars.css
@@ -18,48 +18,16 @@
:root {
--vp-button-brand-border: var(--vp-c-brand-light);
- --vp-button-brand-text: var(--vp-c-text-dark-1);
+ --vp-button-brand-text: var(--vp-c-white);
--vp-button-brand-bg: var(--vp-c-brand);
--vp-button-brand-hover-border: var(--vp-c-brand-light);
- --vp-button-brand-hover-text: var(--vp-c-text-dark-1);
+ --vp-button-brand-hover-text: var(--vp-c-white);
--vp-button-brand-hover-bg: var(--vp-c-brand-light);
--vp-button-brand-active-border: var(--vp-c-brand-light);
- --vp-button-brand-active-text: var(--vp-c-text-dark-1);
+ --vp-button-brand-active-text: var(--vp-c-white);
--vp-button-brand-active-bg: var(--vp-button-brand-bg);
}
-/**
- * Component: Home
- * -------------------------------------------------------------------------- */
-
-:root {
- --vp-home-hero-name-color: transparent;
- --vp-home-hero-name-background: -webkit-linear-gradient(
- 120deg,
- #bd34fe 30%,
- #41d1ff
- );
-
- --vp-home-hero-image-background-image: linear-gradient(
- -45deg,
- #bd34fe 50%,
- #47caff 50%
- );
- --vp-home-hero-image-filter: blur(40px);
-}
-
-@media (min-width: 640px) {
- :root {
- --vp-home-hero-image-filter: blur(56px);
- }
-}
-
-@media (min-width: 960px) {
- :root {
- --vp-home-hero-image-filter: blur(72px);
- }
-}
-
/**
* Component: Custom Block
* -------------------------------------------------------------------------- */
@@ -82,6 +50,7 @@
.DocSearch {
--docsearch-primary-color: var(--vp-c-brand) !important;
+ --docsearch-container-background: rgba(0, 0, 0, 0.7);
}
/**
@@ -114,3 +83,23 @@
.dark .vp-doc .custom-block a {
transition: color 0.25s;
}
+
+.vp-sponsor.aside .vp-sponsor-grid.mini .vp-sponsor-grid-image {
+ max-width: 124px;
+}
+
+.vp-sponsor-grid.big .vp-sponsor-grid-image {
+ max-height: 56px;
+}
+
+.vp-sponsor-grid.mini .vp-sponsor-grid-image[alt='Bit'] {
+ max-height: 48px;
+}
+
+.vp-sponsor-grid.xmini .vp-sponsor-grid-image[alt='JetBrains'] {
+ max-height: 54px;
+}
+
+.vp-sponsor-grid.medium .vp-sponsor-grid-image[alt='JetBrains'] {
+ max-height: 100px;
+}
diff --git a/.vitepress/tsconfig.json b/.vitepress/tsconfig.json
new file mode 100644
index 00000000..d6ac8578
--- /dev/null
+++ b/.vitepress/tsconfig.json
@@ -0,0 +1,13 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "strict": true,
+ "noImplicitOverride": true,
+ "noUnusedLocals": true,
+ "esModuleInterop": true,
+ "noEmit": true
+ },
+ "exclude": ["cache", "dist"]
+}
diff --git a/.vitepress/utils/fetchReleaseTag.js b/.vitepress/utils/fetchReleaseTag.js
deleted file mode 100644
index 0003b5cd..00000000
--- a/.vitepress/utils/fetchReleaseTag.js
+++ /dev/null
@@ -1,12 +0,0 @@
-export function fetchReleaseTag() {
- return fetch('https://api.github.com/repos/vitejs/docs-cn/releases/latest')
- .then((res) => res.json())
- .then((json) => json.tag_name ?? '')
- .then(releaseTag => {
- const tagLineParagragh = document.querySelector('div.VPHero.has-image.VPHomeHero > div > div.main > p.tagline')
- const docsReleaseTagSpan = document.createElement('samp')
- docsReleaseTagSpan.classList.add('docs-cn-github-release-tag')
- docsReleaseTagSpan.innerText = releaseTag
- tagLineParagragh?.appendChild(docsReleaseTagSpan)
- })
-}
diff --git a/.vitepress/utils/frontmatter-service.js b/.vitepress/utils/frontmatter-service.js
index b9ed983a..2b695cb8 100644
--- a/.vitepress/utils/frontmatter-service.js
+++ b/.vitepress/utils/frontmatter-service.js
@@ -1,6 +1,7 @@
-const fs = require('fs')
-const matter = require('gray-matter')
-const { extend, isEmpty: _isEmpty } = require('lodash')
+import fs from 'node:fs'
+import matter from 'gray-matter'
+import _ from 'lodash'
+
// gray-matter is a dep for vitepress,
// no need to specify that in package.json
@@ -21,7 +22,7 @@ class FrontMatterService {
}
isEmpty() {
- return _isEmpty(this.matter.data)
+ return _._isEmpty(this.matter.data)
}
/** @param{(data: string) => void} callback */
@@ -48,7 +49,7 @@ class FrontMatterService {
/** @param {Record} src */
extend(src) {
- extend(this.matter.data, src)
+ _.extend(this.matter.data, src)
return this
}
@@ -63,4 +64,4 @@ class FrontMatterService {
}
}
-module.exports = new FrontMatterService()
+export default new FrontMatterService()
diff --git a/.vitepress/utils/useReleaseTag.ts b/.vitepress/utils/useReleaseTag.ts
new file mode 100644
index 00000000..2cd51836
--- /dev/null
+++ b/.vitepress/utils/useReleaseTag.ts
@@ -0,0 +1,15 @@
+import { onMounted, ref } from 'vue'
+
+export function useReleaseTag() {
+ const releaseTag = ref('')
+
+ onMounted(async () => {
+ const result = await fetch('https://api.github.com/repos/vitejs/docs-cn/releases/latest')
+ const json = await result.json()
+ releaseTag.value = json?.tag_name ?? ''
+ })
+
+ return {
+ releaseTag
+ }
+}
diff --git a/.vitepress/vite-env.d.ts b/.vitepress/vite-env.d.ts
new file mode 100644
index 00000000..11f02fe2
--- /dev/null
+++ b/.vitepress/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 18603fe4..35eb1a4c 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -3,5 +3,9 @@
"editor.tabSize": 2,
"prettier.singleQuote": true,
"prettier.semi": false,
- "prettier.trailingComma": "none"
+ "prettier.trailingComma": "none",
+ "cSpell.words": [
+ "Rollup",
+ "Vite"
+ ]
}
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..cbe5ad16
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,437 @@
+Attribution-NonCommercial-ShareAlike 4.0 International
+
+=======================================================================
+
+Creative Commons Corporation ("Creative Commons") is not a law firm and
+does not provide legal services or legal advice. Distribution of
+Creative Commons public licenses does not create a lawyer-client or
+other relationship. Creative Commons makes its licenses and related
+information available on an "as-is" basis. Creative Commons gives no
+warranties regarding its licenses, any material licensed under their
+terms and conditions, or any related information. Creative Commons
+disclaims all liability for damages resulting from their use to the
+fullest extent possible.
+
+Using Creative Commons Public Licenses
+
+Creative Commons public licenses provide a standard set of terms and
+conditions that creators and other rights holders may use to share
+original works of authorship and other material subject to copyright
+and certain other rights specified in the public license below. The
+following considerations are for informational purposes only, are not
+exhaustive, and do not form part of our licenses.
+
+ Considerations for licensors: Our public licenses are
+ intended for use by those authorized to give the public
+ permission to use material in ways otherwise restricted by
+ copyright and certain other rights. Our licenses are
+ irrevocable. Licensors should read and understand the terms
+ and conditions of the license they choose before applying it.
+ Licensors should also secure all rights necessary before
+ applying our licenses so that the public can reuse the
+ material as expected. Licensors should clearly mark any
+ material not subject to the license. This includes other CC-
+ licensed material, or material used under an exception or
+ limitation to copyright. More considerations for licensors:
+ wiki.creativecommons.org/Considerations_for_licensors
+
+ Considerations for the public: By using one of our public
+ licenses, a licensor grants the public permission to use the
+ licensed material under specified terms and conditions. If
+ the licensor's permission is not necessary for any reason--for
+ example, because of any applicable exception or limitation to
+ copyright--then that use is not regulated by the license. Our
+ licenses grant only permissions under copyright and certain
+ other rights that a licensor has authority to grant. Use of
+ the licensed material may still be restricted for other
+ reasons, including because others have copyright or other
+ rights in the material. A licensor may make special requests,
+ such as asking that all changes be marked or described.
+ Although not required by our licenses, you are encouraged to
+ respect those requests where reasonable. More considerations
+ for the public:
+ wiki.creativecommons.org/Considerations_for_licensees
+
+=======================================================================
+
+Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
+Public License
+
+By exercising the Licensed Rights (defined below), You accept and agree
+to be bound by the terms and conditions of this Creative Commons
+Attribution-NonCommercial-ShareAlike 4.0 International Public License
+("Public License"). To the extent this Public License may be
+interpreted as a contract, You are granted the Licensed Rights in
+consideration of Your acceptance of these terms and conditions, and the
+Licensor grants You such rights in consideration of benefits the
+Licensor receives from making the Licensed Material available under
+these terms and conditions.
+
+
+Section 1 -- Definitions.
+
+ a. Adapted Material means material subject to Copyright and Similar
+ Rights that is derived from or based upon the Licensed Material
+ and in which the Licensed Material is translated, altered,
+ arranged, transformed, or otherwise modified in a manner requiring
+ permission under the Copyright and Similar Rights held by the
+ Licensor. For purposes of this Public License, where the Licensed
+ Material is a musical work, performance, or sound recording,
+ Adapted Material is always produced where the Licensed Material is
+ synched in timed relation with a moving image.
+
+ b. Adapter's License means the license You apply to Your Copyright
+ and Similar Rights in Your contributions to Adapted Material in
+ accordance with the terms and conditions of this Public License.
+
+ c. BY-NC-SA Compatible License means a license listed at
+ creativecommons.org/compatiblelicenses, approved by Creative
+ Commons as essentially the equivalent of this Public License.
+
+ d. Copyright and Similar Rights means copyright and/or similar rights
+ closely related to copyright including, without limitation,
+ performance, broadcast, sound recording, and Sui Generis Database
+ Rights, without regard to how the rights are labeled or
+ categorized. For purposes of this Public License, the rights
+ specified in Section 2(b)(1)-(2) are not Copyright and Similar
+ Rights.
+
+ e. Effective Technological Measures means those measures that, in the
+ absence of proper authority, may not be circumvented under laws
+ fulfilling obligations under Article 11 of the WIPO Copyright
+ Treaty adopted on December 20, 1996, and/or similar international
+ agreements.
+
+ f. Exceptions and Limitations means fair use, fair dealing, and/or
+ any other exception or limitation to Copyright and Similar Rights
+ that applies to Your use of the Licensed Material.
+
+ g. License Elements means the license attributes listed in the name
+ of a Creative Commons Public License. The License Elements of this
+ Public License are Attribution, NonCommercial, and ShareAlike.
+
+ h. Licensed Material means the artistic or literary work, database,
+ or other material to which the Licensor applied this Public
+ License.
+
+ i. Licensed Rights means the rights granted to You subject to the
+ terms and conditions of this Public License, which are limited to
+ all Copyright and Similar Rights that apply to Your use of the
+ Licensed Material and that the Licensor has authority to license.
+
+ j. Licensor means the individual(s) or entity(ies) granting rights
+ under this Public License.
+
+ k. NonCommercial means not primarily intended for or directed towards
+ commercial advantage or monetary compensation. For purposes of
+ this Public License, the exchange of the Licensed Material for
+ other material subject to Copyright and Similar Rights by digital
+ file-sharing or similar means is NonCommercial provided there is
+ no payment of monetary compensation in connection with the
+ exchange.
+
+ l. Share means to provide material to the public by any means or
+ process that requires permission under the Licensed Rights, such
+ as reproduction, public display, public performance, distribution,
+ dissemination, communication, or importation, and to make material
+ available to the public including in ways that members of the
+ public may access the material from a place and at a time
+ individually chosen by them.
+
+ m. Sui Generis Database Rights means rights other than copyright
+ resulting from Directive 96/9/EC of the European Parliament and of
+ the Council of 11 March 1996 on the legal protection of databases,
+ as amended and/or succeeded, as well as other essentially
+ equivalent rights anywhere in the world.
+
+ n. You means the individual or entity exercising the Licensed Rights
+ under this Public License. Your has a corresponding meaning.
+
+
+Section 2 -- Scope.
+
+ a. License grant.
+
+ 1. Subject to the terms and conditions of this Public License,
+ the Licensor hereby grants You a worldwide, royalty-free,
+ non-sublicensable, non-exclusive, irrevocable license to
+ exercise the Licensed Rights in the Licensed Material to:
+
+ a. reproduce and Share the Licensed Material, in whole or
+ in part, for NonCommercial purposes only; and
+
+ b. produce, reproduce, and Share Adapted Material for
+ NonCommercial purposes only.
+
+ 2. Exceptions and Limitations. For the avoidance of doubt, where
+ Exceptions and Limitations apply to Your use, this Public
+ License does not apply, and You do not need to comply with
+ its terms and conditions.
+
+ 3. Term. The term of this Public License is specified in Section
+ 6(a).
+
+ 4. Media and formats; technical modifications allowed. The
+ Licensor authorizes You to exercise the Licensed Rights in
+ all media and formats whether now known or hereafter created,
+ and to make technical modifications necessary to do so. The
+ Licensor waives and/or agrees not to assert any right or
+ authority to forbid You from making technical modifications
+ necessary to exercise the Licensed Rights, including
+ technical modifications necessary to circumvent Effective
+ Technological Measures. For purposes of this Public License,
+ simply making modifications authorized by this Section 2(a)
+ (4) never produces Adapted Material.
+
+ 5. Downstream recipients.
+
+ a. Offer from the Licensor -- Licensed Material. Every
+ recipient of the Licensed Material automatically
+ receives an offer from the Licensor to exercise the
+ Licensed Rights under the terms and conditions of this
+ Public License.
+
+ b. Additional offer from the Licensor -- Adapted Material.
+ Every recipient of Adapted Material from You
+ automatically receives an offer from the Licensor to
+ exercise the Licensed Rights in the Adapted Material
+ under the conditions of the Adapter's License You apply.
+
+ c. No downstream restrictions. You may not offer or impose
+ any additional or different terms or conditions on, or
+ apply any Effective Technological Measures to, the
+ Licensed Material if doing so restricts exercise of the
+ Licensed Rights by any recipient of the Licensed
+ Material.
+
+ 6. No endorsement. Nothing in this Public License constitutes or
+ may be construed as permission to assert or imply that You
+ are, or that Your use of the Licensed Material is, connected
+ with, or sponsored, endorsed, or granted official status by,
+ the Licensor or others designated to receive attribution as
+ provided in Section 3(a)(1)(A)(i).
+
+ b. Other rights.
+
+ 1. Moral rights, such as the right of integrity, are not
+ licensed under this Public License, nor are publicity,
+ privacy, and/or other similar personality rights; however, to
+ the extent possible, the Licensor waives and/or agrees not to
+ assert any such rights held by the Licensor to the limited
+ extent necessary to allow You to exercise the Licensed
+ Rights, but not otherwise.
+
+ 2. Patent and trademark rights are not licensed under this
+ Public License.
+
+ 3. To the extent possible, the Licensor waives any right to
+ collect royalties from You for the exercise of the Licensed
+ Rights, whether directly or through a collecting society
+ under any voluntary or waivable statutory or compulsory
+ licensing scheme. In all other cases the Licensor expressly
+ reserves any right to collect such royalties, including when
+ the Licensed Material is used other than for NonCommercial
+ purposes.
+
+
+Section 3 -- License Conditions.
+
+Your exercise of the Licensed Rights is expressly made subject to the
+following conditions.
+
+ a. Attribution.
+
+ 1. If You Share the Licensed Material (including in modified
+ form), You must:
+
+ a. retain the following if it is supplied by the Licensor
+ with the Licensed Material:
+
+ i. identification of the creator(s) of the Licensed
+ Material and any others designated to receive
+ attribution, in any reasonable manner requested by
+ the Licensor (including by pseudonym if
+ designated);
+
+ ii. a copyright notice;
+
+ iii. a notice that refers to this Public License;
+
+ iv. a notice that refers to the disclaimer of
+ warranties;
+
+ v. a URI or hyperlink to the Licensed Material to the
+ extent reasonably practicable;
+
+ b. indicate if You modified the Licensed Material and
+ retain an indication of any previous modifications; and
+
+ c. indicate the Licensed Material is licensed under this
+ Public License, and include the text of, or the URI or
+ hyperlink to, this Public License.
+
+ 2. You may satisfy the conditions in Section 3(a)(1) in any
+ reasonable manner based on the medium, means, and context in
+ which You Share the Licensed Material. For example, it may be
+ reasonable to satisfy the conditions by providing a URI or
+ hyperlink to a resource that includes the required
+ information.
+ 3. If requested by the Licensor, You must remove any of the
+ information required by Section 3(a)(1)(A) to the extent
+ reasonably practicable.
+
+ b. ShareAlike.
+
+ In addition to the conditions in Section 3(a), if You Share
+ Adapted Material You produce, the following conditions also apply.
+
+ 1. The Adapter's License You apply must be a Creative Commons
+ license with the same License Elements, this version or
+ later, or a BY-NC-SA Compatible License.
+
+ 2. You must include the text of, or the URI or hyperlink to, the
+ Adapter's License You apply. You may satisfy this condition
+ in any reasonable manner based on the medium, means, and
+ context in which You Share Adapted Material.
+
+ 3. You may not offer or impose any additional or different terms
+ or conditions on, or apply any Effective Technological
+ Measures to, Adapted Material that restrict exercise of the
+ rights granted under the Adapter's License You apply.
+
+
+Section 4 -- Sui Generis Database Rights.
+
+Where the Licensed Rights include Sui Generis Database Rights that
+apply to Your use of the Licensed Material:
+
+ a. for the avoidance of doubt, Section 2(a)(1) grants You the right
+ to extract, reuse, reproduce, and Share all or a substantial
+ portion of the contents of the database for NonCommercial purposes
+ only;
+
+ b. if You include all or a substantial portion of the database
+ contents in a database in which You have Sui Generis Database
+ Rights, then the database in which You have Sui Generis Database
+ Rights (but not its individual contents) is Adapted Material,
+ including for purposes of Section 3(b); and
+
+ c. You must comply with the conditions in Section 3(a) if You Share
+ all or a substantial portion of the contents of the database.
+
+For the avoidance of doubt, this Section 4 supplements and does not
+replace Your obligations under this Public License where the Licensed
+Rights include other Copyright and Similar Rights.
+
+
+Section 5 -- Disclaimer of Warranties and Limitation of Liability.
+
+ a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
+ EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
+ AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
+ ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
+ IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
+ WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
+ ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
+ KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
+ ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
+
+ b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
+ TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
+ NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
+ INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
+ COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
+ USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
+ DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
+ IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
+
+ c. The disclaimer of warranties and limitation of liability provided
+ above shall be interpreted in a manner that, to the extent
+ possible, most closely approximates an absolute disclaimer and
+ waiver of all liability.
+
+
+Section 6 -- Term and Termination.
+
+ a. This Public License applies for the term of the Copyright and
+ Similar Rights licensed here. However, if You fail to comply with
+ this Public License, then Your rights under this Public License
+ terminate automatically.
+
+ b. Where Your right to use the Licensed Material has terminated under
+ Section 6(a), it reinstates:
+
+ 1. automatically as of the date the violation is cured, provided
+ it is cured within 30 days of Your discovery of the
+ violation; or
+
+ 2. upon express reinstatement by the Licensor.
+
+ For the avoidance of doubt, this Section 6(b) does not affect any
+ right the Licensor may have to seek remedies for Your violations
+ of this Public License.
+
+ c. For the avoidance of doubt, the Licensor may also offer the
+ Licensed Material under separate terms or conditions or stop
+ distributing the Licensed Material at any time; however, doing so
+ will not terminate this Public License.
+
+ d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
+ License.
+
+
+Section 7 -- Other Terms and Conditions.
+
+ a. The Licensor shall not be bound by any additional or different
+ terms or conditions communicated by You unless expressly agreed.
+
+ b. Any arrangements, understandings, or agreements regarding the
+ Licensed Material not stated herein are separate from and
+ independent of the terms and conditions of this Public License.
+
+
+Section 8 -- Interpretation.
+
+ a. For the avoidance of doubt, this Public License does not, and
+ shall not be interpreted to, reduce, limit, restrict, or impose
+ conditions on any use of the Licensed Material that could lawfully
+ be made without permission under this Public License.
+
+ b. To the extent possible, if any provision of this Public License is
+ deemed unenforceable, it shall be automatically reformed to the
+ minimum extent necessary to make it enforceable. If the provision
+ cannot be reformed, it shall be severed from this Public License
+ without affecting the enforceability of the remaining terms and
+ conditions.
+
+ c. No term or condition of this Public License will be waived and no
+ failure to comply consented to unless expressly agreed to by the
+ Licensor.
+
+ d. Nothing in this Public License constitutes or may be interpreted
+ as a limitation upon, or waiver of, any privileges and immunities
+ that apply to the Licensor or You, including from the legal
+ processes of any jurisdiction or authority.
+
+=======================================================================
+
+Creative Commons is not a party to its public
+licenses. Notwithstanding, Creative Commons may elect to apply one of
+its public licenses to material it publishes and in those instances
+will be considered the “Licensor.” The text of the Creative Commons
+public licenses is dedicated to the public domain under the CC0 Public
+Domain Dedication. Except for the limited purpose of indicating that
+material is shared under a Creative Commons public license or as
+otherwise permitted by the Creative Commons policies published at
+creativecommons.org/policies, Creative Commons does not authorize the
+use of the trademark "Creative Commons" or any other trademark or logo
+of Creative Commons without its prior written consent including,
+without limitation, in connection with any unauthorized modifications
+to any of its public licenses or any other arrangements,
+understandings, or agreements concerning use of licensed material. For
+the avoidance of doubt, this paragraph does not form part of the
+public licenses.
+
+Creative Commons may be contacted at creativecommons.org.
diff --git a/README.md b/README.md
index 0026f745..80246af6 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,11 @@
> ### 敬请所有读者注意
>
> - 原则上这里只进行英文版对应的翻译工作,如果觉得原文有改进之处,或任何不仅针对中文版,而受益所有语言版本的想法,建议直接在英文版仓库讨论。
-> - **原则上这里不适合讨论 Vite 的使用问题**,建议相关问题在 Vite 的 [issues 区](https://github.com/vitejs/vite/issues)、[Vite 官方讨论区](https://chat.vitejs.dev/) 或各大主流技术社区讨论,以便得到更多帮助和更充分的讨论。
+> - **原则上这里不适合讨论 Vite 的使用问题**,建议相关问题在 Vite 的 [issues 区](https://github.com/vitejs/vite/issues)、[Vite 官方讨论区](https://chat.vite.dev/) 或各大主流技术社区讨论,以便得到更多帮助和更充分的讨论。
-
-
+
+
@@ -14,7 +14,7 @@
-
+
@@ -23,7 +23,7 @@
> Vite:下一代前端开发与构建工具
- 💡 极速的开发服务器启动
-- ⚡️ 轻量快速的热模块重载(HMR)
+- ⚡️ 轻量快速的模块热替换(HMR)
- 🛠️ 丰富的功能
- 📦 自带优化的构建
- 🔩 通用的插件接口
@@ -33,7 +33,7 @@ Vite (法语意为 “迅速”,发音 /vit/)是一种全新的前端构
## 📝 如何参与贡献
-目前 Vite 中文文档处于 v3 beta 版本,内容 **每日** 根据英文文档同步更新。
+目前 Vite 中文文档处于 v6 版本,内容 **每日** 根据英文文档同步更新。
**工作流介绍:** 英文文档的所在 [请点击此链接](https://github.com/vitejs/vite/tree/main/docs),我们会每天拉取英文版文档内容的更新到 sync-docs 分支,并由印记中文 bot 自动发起 Pull Request,解决 Git 冲突并翻译内容。
@@ -56,4 +56,16 @@ $ pnpm dev
## 版权声明
-本仓库所包含的中文翻译内容(即所有 `.md` 文件),其版权为 Vite 官方中文翻译团队所有。除官方中文文档 [cn.vitejs.dev](https://cn.vitejs.dev) 之外,不得在其它域名下进行未经授权的转载或部署。
+ 本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 (CC BY-NC-SA 4.0) 进行许可。
+
+## 贡献者统计
+
+> 统计规则:所有通过 Pull Request 产生了对 `main` 分支 commit 的贡献者。
+>
+> 头像图生成逻辑参见:[github-contributor-svg-generator](https://github.com/ShenQingchuan/github-contributor-svg-generator)
+
+
+
+
+
+
diff --git a/_data/blog.data.ts b/_data/blog.data.ts
new file mode 100644
index 00000000..39d45ec2
--- /dev/null
+++ b/_data/blog.data.ts
@@ -0,0 +1,40 @@
+import { createContentLoader } from 'vitepress'
+
+interface Post {
+ title: string
+ url: string
+ date: {
+ time: number
+ string: string
+ }
+}
+
+declare const data: Post[]
+export { data }
+
+export default createContentLoader('blog/*.md', {
+ // excerpt: true,
+ transform(raw): Post[] {
+ return raw
+ .map(({ url, frontmatter }) => ({
+ title: frontmatter.head.find((e) => e[1].property === 'og:title')[1]
+ .content,
+ url,
+ date: formatDate(frontmatter.date),
+ }))
+ .sort((a, b) => b.date.time - a.date.time)
+ },
+})
+
+function formatDate(raw: string): Post['date'] {
+ const date = new Date(raw)
+ date.setUTCHours(12)
+ return {
+ time: +date,
+ string: date.toLocaleDateString('en-US', {
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric',
+ }),
+ }
+}
diff --git a/_data/team.js b/_data/team.js
index 3d83c1fd..50d2339f 100644
--- a/_data/team.js
+++ b/_data/team.js
@@ -5,65 +5,126 @@ export const core = [
title: 'Creator',
org: 'Vue.js',
orgLink: 'https://vuejs.org/',
- desc: '独立开源开发者,Vue.js & Vite 作者',
+ desc: 'Independent open source developer, creator of Vue.js and Vite.',
links: [
{ icon: 'github', link: 'https://github.com/yyx990803' },
- { icon: 'twitter', link: 'https://twitter.com/youyuxi' }
+ { icon: 'x', link: 'https://x.com/youyuxi' },
+ { icon: 'bluesky', link: 'https://bsky.app/profile/evanyou.me' },
],
- sponsor: 'https://github.com/sponsors/yyx990803'
+ sponsor: 'https://github.com/sponsors/yyx990803',
},
{
avatar: 'https://www.github.com/patak-dev.png',
name: 'Patak',
- title: '合作伙伴',
+ title: 'A collaborative being',
org: 'StackBlitz',
orgLink: 'https://stackblitz.com/',
- desc: 'Vite 核心团队成员,Vue 团队成员',
+ desc: 'Core team member of Vite. Team member of Vue.',
links: [
{ icon: 'github', link: 'https://github.com/patak-dev' },
- { icon: 'twitter', link: 'https://twitter.com/patak_dev' }
+ { icon: 'bluesky', link: 'https://bsky.app/profile/patak.dev' },
+ { icon: 'mastodon', link: 'https://elk.zone/m.webtoo.ls/@patak' },
],
- sponsor: 'https://github.com/sponsors/patak-dev'
+ sponsor: 'https://github.com/sponsors/patak-dev',
},
{
avatar: 'https://www.github.com/antfu.png',
name: 'Anthony Fu',
- title: '极富热情的开源开发者',
+ title: 'A fanatical open sourceror',
org: 'NuxtLabs',
orgLink: 'https://nuxtlabs.com/',
- desc: 'Vite & Vue 核心团队成员,在 NuxtLabs 工作',
+ desc: 'Core team member of Vite & Vue. Working at NuxtLabs.',
links: [
{ icon: 'github', link: 'https://github.com/antfu' },
- { icon: 'twitter', link: 'https://twitter.com/antfu7' }
+ { icon: 'bluesky', link: 'https://bsky.app/profile/antfu.me' },
+ { icon: 'mastodon', link: 'https://elk.zone/m.webtoo.ls/@antfu' },
],
- sponsor: 'https://github.com/sponsors/antfu'
+ sponsor: 'https://github.com/sponsors/antfu',
},
{
- avatar: 'https://github.com/sodatea.png',
- name: '蒋豪群',
- title: '开发者',
- org: 'Vue.js',
- orgLink: 'https://vuejs.org/',
- desc: 'Vite/Vite 核心团队成员,全职开源开发者',
+ avatar: 'https://github.com/bluwy.png',
+ name: 'Bjorn Lu',
+ title: 'Open Source Developer',
+ desc: 'Building tools for fun.',
links: [
- { icon: 'github', link: 'https://github.com/sodatea' },
- { icon: 'twitter', link: 'https://twitter.com/haoqunjiang' }
+ { icon: 'github', link: 'https://github.com/bluwy' },
+ { icon: 'bluesky', link: 'https://bsky.app/profile/bluwy.me' },
+ { icon: 'twitter', link: 'https://twitter.com/bluwyoo' },
+ { icon: 'mastodon', link: 'https://elk.zone/m.webtoo.ls/@bluwy' },
],
- sponsor: 'https://github.com/sponsors/sodatea'
+ sponsor: 'https://bjornlu.com/sponsor',
},
{
- avatar: 'https://github.com/Shinigami92.png',
- name: 'Shinigami',
- title: '维护者',
- org: 'Faker',
- orgLink: 'https://fakerjs.dev',
- desc: '热衷于 TypeScript 的爱好者,广泛使用 Vue SPA 和 pug。',
+ avatar: 'https://github.com/sapphi-red.png',
+ name: 'green',
+ title: 'Web Developer',
+ desc: 'Vite core team member. Call me sapphi or green or midori ;)',
links: [
- { icon: 'github', link: 'https://github.com/Shinigami92' },
- { icon: 'twitter', link: 'https://twitter.com/Shini_92' }
+ { icon: 'github', link: 'https://github.com/sapphi-red' },
+ { icon: 'bluesky', link: 'https://bsky.app/profile/sapphi.red' },
+ { icon: 'twitter', link: 'https://twitter.com/sapphi_red' },
+ { icon: 'mastodon', link: 'https://elk.zone/m.webtoo.ls/@sapphi_red' },
+ ],
+ sponsor: 'https://github.com/sponsors/sapphi-red',
+ },
+ {
+ avatar: 'https://github.com/ArnaudBarre.png',
+ name: 'Arnaud Barré',
+ title: 'Frontend Developer',
+ desc: 'Passionate by tooling around TypeScript and React.',
+ links: [
+ { icon: 'github', link: 'https://github.com/ArnaudBarre' },
+ {
+ icon: 'bluesky',
+ link: 'https://bsky.app/profile/arnaud-barre.bsky.social',
+ },
+ { icon: 'mastodon', link: 'https://elk.zone/m.webtoo.ls/@ArnaudBarre' },
+ ],
+ sponsor: 'https://github.com/sponsors/ArnaudBarre',
+ },
+ {
+ avatar: 'https://github.com/dominikg.png',
+ name: 'Dominik G.',
+ title: 'Resident CI Expert',
+ desc: 'Team Member of Vite and Svelte',
+ links: [
+ { icon: 'github', link: 'https://github.com/dominikg' },
+ { icon: 'mastodon', link: 'https://elk.zone/m.webtoo.ls/@dominikg' },
+ ],
+ sponsor: 'https://github.com/sponsors/dominikg',
+ },
+ {
+ avatar: 'https://github.com/sheremet-va.png',
+ name: 'Vladimir',
+ title: 'Core team member of Vitest & Vite',
+ desc: 'An open source fullstack developer',
+ links: [
+ { icon: 'github', link: 'https://github.com/sheremet-va' },
+ { icon: 'bluesky', link: 'https://bsky.app/profile/erus.dev' },
+ { icon: 'mastodon', link: 'https://elk.zone/m.webtoo.ls/@sheremet_va' },
],
- sponsor: 'https://github.com/sponsors/Shinigami92'
+ sponsor: 'https://github.com/sponsors/sheremet-va',
},
+ {
+ avatar: 'https://github.com/hi-ogawa.png',
+ name: 'Hiroshi Ogawa',
+ title: 'Team Member of Vitest & Vite',
+ desc: 'Open source enthusiast',
+ links: [
+ { icon: 'github', link: 'https://github.com/hi-ogawa' },
+ { icon: 'bluesky', link: 'https://bsky.app/profile/hiogawa.bsky.social' },
+ ],
+ sponsor: 'https://github.com/sponsors/hi-ogawa',
+ },
+ {
+ avatar: 'https://github.com/btea.png',
+ name: 'btea',
+ title: 'Web Developer',
+ links: [{ icon: 'github', link: 'https://github.com/btea' }],
+ },
+]
+
+export const emeriti = [
{
avatar: 'https://i.imgur.com/KMed6rQ.jpeg',
name: 'Alec Larson',
@@ -71,41 +132,22 @@ export const core = [
desc: 'Dabbling in social ecommerce, meta frameworks, and board games',
links: [
{ icon: 'github', link: 'https://github.com/aleclarson' },
- { icon: 'twitter', link: 'https://twitter.com/retropragma' }
+ { icon: 'x', link: 'https://x.com/retropragma' },
+ {
+ icon: 'bluesky',
+ link: 'https://bsky.app/profile/retropragma.bsky.social',
+ },
],
- sponsor: 'https://github.com/sponsors/aleclarson'
- },
- {
- avatar: 'https://github.com/bluwy.png',
- name: 'Bjorn Lu',
- title: '前端开发者',
- desc: 'Svelte & Vite 团队成员',
- links: [
- { icon: 'github', link: 'https://github.com/bluwy' },
- { icon: 'twitter', link: 'https://twitter.com/bluwyoo' }
- ],
- sponsor: 'https://bjornlu.com/sponsor'
},
{
avatar: 'https://github.com/poyoho.png',
name: 'yoho',
- title: '前端开发者',
- desc: 'Vite 团队成员',
+ title: 'Frontend Developer',
+ desc: 'Frontend. Vite team member.',
links: [
{ icon: 'github', link: 'https://github.com/poyoho' },
- { icon: 'twitter', link: 'https://twitter.com/yoho_po' }
- ]
- },
- {
- avatar: 'https://github.com/sapphi-red.png',
- name: 'green',
- title: 'Web 开发者',
- desc: 'Vite 团队成员。(你可以叫我 sapphi、green(翠) 或者 midori)',
- links: [
- { icon: 'github', link: 'https://github.com/sapphi-red' },
- { icon: 'twitter', link: 'https://twitter.com/sapphi_red' }
+ { icon: 'x', link: 'https://x.com/yoho_po' },
],
- sponsor: 'https://github.com/sponsors/sapphi-red'
},
{
avatar: 'https://github.com/ygj6.png',
@@ -114,8 +156,8 @@ export const core = [
desc: 'Vue & Vite 团队成员',
links: [
{ icon: 'github', link: 'https://github.com/ygj6' },
- { icon: 'twitter', link: 'https://twitter.com/ygj_66' }
- ]
+ { icon: 'x', link: 'https://x.com/ygj_66' },
+ ],
},
{
avatar: 'https://github.com/Niputi.png',
@@ -125,12 +167,10 @@ export const core = [
desc: 'Web/Javascript 爱好者',
links: [
{ icon: 'github', link: 'https://github.com/Niputi' },
- { icon: 'twitter', link: 'https://twitter.com/Niputi_' }
- ]
- }
-]
-
-export const emeriti = [
+ { icon: 'x', link: 'https://x.com/Niputi_' },
+ { icon: 'bluesky', link: 'https://bsky.app/profile/niputi.bsky.social' },
+ ],
+ },
{
avatar: 'https://github.com/underfin.png',
name: 'underfin',
@@ -141,14 +181,43 @@ export const emeriti = [
avatar: 'https://github.com/GrygrFlzr.png',
name: 'GrygrFlzr',
title: '开发者',
- links: [{ icon: 'github', link: 'https://github.com/GrygrFlzr' }]
+ links: [
+ { icon: 'github', link: 'https://github.com/GrygrFlzr' },
+ { icon: 'bluesky', link: 'https://bsky.app/profile/bsky.cybeast.dev' },
+ ],
},
{
avatar: 'https://github.com/nihalgonsalves.png',
name: 'Nihal Gonsalves',
title: '高级软件工程师',
links: [{ icon: 'github', link: 'https://github.com/nihalgonsalves' }]
- }
+ },
+ {
+ avatar: 'https://github.com/Shinigami92.png',
+ name: 'Shinigami',
+ title: 'Senior Frontend Engineer',
+ org: 'Faker',
+ orgLink: 'https://fakerjs.dev',
+ desc: 'Passionate TypeScript enthusiast working extensively with Vue SPA.',
+ links: [
+ { icon: 'github', link: 'https://github.com/Shinigami92' },
+ { icon: 'mastodon', link: 'https://elk.zone/mas.to/@Shini92' },
+ ],
+ },
+ {
+ avatar: 'https://github.com/haoqunjiang.png',
+ name: 'Haoqun Jiang',
+ title: 'Core Team Member',
+ org: 'Vue.js',
+ orgLink: 'https://vuejs.org/',
+ desc: 'Curator of best practices for Vue.js tooling',
+ links: [
+ { icon: 'github', link: 'https://github.com/haoqunjiang' },
+ { icon: 'bluesky', link: 'https://bsky.app/profile/haoqun.dev' },
+ { icon: 'mastodon', link: 'https://elk.zone/m.webtoo.ls/@haoqun' },
+ ],
+ sponsor: 'https://github.com/sponsors/haoqunjiang',
+ },
]
export const cnTranslator = [
diff --git a/blog.md b/blog.md
new file mode 100644
index 00000000..0310c699
--- /dev/null
+++ b/blog.md
@@ -0,0 +1,13 @@
+---
+sidebar: false
+editLink: false
+outline: false
+---
+
+
+
+# Vite 博客的最新消息 {#latest-from-the-vite-blog}
+
+
diff --git a/blog/announcing-vite2.md b/blog/announcing-vite2.md
index f764ab06..705dedc8 100644
--- a/blog/announcing-vite2.md
+++ b/blog/announcing-vite2.md
@@ -1,9 +1,28 @@
---
+title: Announcing Vite 2.0
+author:
+ - name: The Vite Team
sidebar: false
+date: 2021-02-16
+head:
+ - - meta
+ - property: og:type
+ content: website
+ - - meta
+ - property: og:title
+ content: Announcing Vite 2.0
+ - - meta
+ - property: og:url
+ content: https://vite.dev/blog/announcing-vite2
+ - - meta
+ - property: og:description
+ content: Vite 2 Release Announcement
---
# Vite 2.0 发布了 {#announcing-vite-2-0}
+_February 16, 2021_ - Check out the [Vite 3.0 announcement](./announcing-vite3.md)
+
@@ -14,7 +33,7 @@ Vite(法语意思是 “快”,发音为 `/vit/`,类似 veet)是一种
想知道 Vite 有多快?看看这个[视频比较](https://twitter.com/amasad/status/1355379680275128321), 在 Repl.it 上从零启动一个基于 Vite 的 React 应用,浏览器页面加载完毕的时候,基于 CRA(`create-react-app`)的应用甚至还没有安装完依赖。
-如果你还没听说过 Vite 到底是什么,可以到 [这里](/guide/why) 了解一下项目的设计初衷。如果你想要了解 Vite 跟其它一些类似的工具有什么区别,可以参考这里的 [对比](/guide/comparisons)。
+如果你还没听说过 Vite 到底是什么,可以到 [这里](/guide/why) 了解一下项目的设计初衷。如果你想要了解 Vite 跟其它一些类似的工具有什么区别,可以参考这里的 [对比](https://v5.vite.dev/guide/comparisons.html)。
## 2.0 带来了什么 {#whats-new-in-2-0}
@@ -46,7 +65,7 @@ Vite 将 CSS 看作模块系统中的一等公民,并且内置了以下支持
### 服务端渲染(SSR)支持 {#server-side-rendering-ssr-support}
-Vite 2.0 提供 [实验性的 SSR 支持](/guide/ssr)。Vite 提供了灵活的 API,以便于在开发过程中直接通过 Node.js 高效率地加载和更新 ESM 的源码(几乎与服务端的 HMR 一致),并自动外部化与 CommonJS 兼容的依赖关系,以提高开发和 SSR 的构建速度。生产环境下,服务器可以和 Vite 完全解耦。基于 Vite SSR 的架构也可以很方便的做静态预渲染(SSG)。
+Vite 2.0 提供 [实验性的 SSR 支持](/guide/ssr)。Vite 提供了灵活的 API,以便于在开发过程中直接通过 Node.js 高效率地加载和更新 ESM 的源码(几乎与服务端的 HMR 一致),并自动外部化与 CommonJS 兼容的依赖关系,以提高开发和 SSR 的构建速度。生产环境下,服务器可以和 Vite 完全解耦。基于 Vite SSR 的架构也可以很方便的做静态预渲染(SSG)。
Vite SSR 会作为一个底层功能,而我们期待看到更高层级的框架在此基础上的应用。
@@ -62,4 +81,4 @@ Vite 默认只支持原生支持 ESM 的现代浏览器,但可以通过官方
npm init @vitejs/app
```
-然后,你可以阅读 [指引文档](/guide/) 了解 Vite 提供了哪些开箱即用的功能,也可以在 [GitHub](https://github.com/vitejs/vite) 上查看源码,关注我们的 [Twitter](https://twitter.com/vite_js) 以了解最新的进展,或与其他 Vite 用户在 [Discord](http://chat.vitejs.dev/) 上一起讨论。
+然后,你可以阅读 [指引文档](/guide/) 了解 Vite 提供了哪些开箱即用的功能,也可以在 [GitHub](https://github.com/vitejs/vite) 上查看源码,关注我们的 [Twitter](https://twitter.com/vite_js) 以了解最新的进展,或与其他 Vite 用户在 [Discord](http://chat.vite.dev/) 上一起讨论。
diff --git a/blog/announcing-vite3.md b/blog/announcing-vite3.md
index 7f727f73..efb3be87 100644
--- a/blog/announcing-vite3.md
+++ b/blog/announcing-vite3.md
@@ -1,4 +1,8 @@
---
+title: Vite 3.0 is out!
+author:
+ name: The Vite Team
+date: 2022-07-23
sidebar: false
head:
- - meta
@@ -9,10 +13,10 @@ head:
content: Announcing Vite 3
- - meta
- property: og:image
- content: https://vitejs.dev/og-image-announcing-vite3.png
+ content: https://vite.dev/og-image-announcing-vite3.png
- - meta
- property: og:url
- content: https://vitejs.dev/blog/announcing-vite3
+ content: https://vite.dev/blog/announcing-vite3
- - meta
- property: og:description
content: Vite 3 Release Announcement
@@ -23,7 +27,9 @@ head:
# Vite 3.0 is out!
-In February last year, [Evan You](https://twitter.com/youyuxi) released Vite 2. Since then, its adoption has grown non-stop, reaching more than 1 million npm downloads per week. A sprawling ecosystem rapidly formed after the release. Vite is powering a renewed innovation race in Web frameworks. [Nuxt 3](https://v3.nuxtjs.org/) uses Vite by default. [SvelteKit](https://kit.svelte.dev/), [Astro](https://astro.build/), [Hydrogen](https://hydrogen.shopify.dev/), and [SolidStart](https://docs.solidjs.com/start) are all built with Vite. [Laravel has now decided to use Vite by default](https://laravel.com/docs/9.x/vite). [Vite Ruby](https://vite-ruby.netlify.app/) shows how Vite can improve Rails DX. [Vitest](https://vitest.dev) is making strides as a Vite-native alternative to Jest. Vite is behind [Cypress](https://docs.cypress.io/guides/component-testing/writing-your-first-component-test) and [Playwright](https://playwright.dev/docs/test-components)'s new Component Testing features, Storybook has [Vite as an official builder](https://github.com/storybookjs/builder-vite). And [the list goes on](https://patak.dev/vite/ecosystem.html). Maintainers from most of these projects got involved in improving the Vite core itself, working closely with the Vite [team](https://vitejs.dev/team) and other contributors.
+_July 23, 2022_ - Check out the [Vite 4.0 announcement](./announcing-vite4.md)
+
+In February last year, [Evan You](https://twitter.com/youyuxi) released Vite 2. Since then, its adoption has grown non-stop, reaching more than 1 million npm downloads per week. A sprawling ecosystem rapidly formed after the release. Vite is powering a renewed innovation race in Web frameworks. [Nuxt 3](https://v3.nuxtjs.org/) uses Vite by default. [SvelteKit](https://kit.svelte.dev/), [Astro](https://astro.build/), [Hydrogen](https://hydrogen.shopify.dev/), and [SolidStart](https://docs.solidjs.com/quick-start) are all built with Vite. [Laravel has now decided to use Vite by default](https://laravel.com/docs/9.x/vite). [Vite Ruby](https://vite-ruby.netlify.app/) shows how Vite can improve Rails DX. [Vitest](https://vitest.dev) is making strides as a Vite-native alternative to Jest. Vite is behind [Cypress](https://docs.cypress.io/guides/component-testing/writing-your-first-component-test) and [Playwright](https://playwright.dev/docs/test-components)'s new Component Testing features, Storybook has [Vite as an official builder](https://github.com/storybookjs/builder-vite). And [the list goes on](https://patak.dev/vite/ecosystem.html). Maintainers from most of these projects got involved in improving the Vite core itself, working closely with the Vite [team](https://vite.dev/team) and other contributors.

@@ -32,26 +38,26 @@ Today, 16 months from the v2 launch we are happy to announce the release of Vite
Quick links:
- [Docs](/)
-- [Migration Guide](/guide/migration)
+- [Migration Guide](https://v3.vite.dev/guide/migration.html)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md#300-2022-07-13)
-If you are new to Vite, we recommend reading the [Why Vite Guide](https://vitejs.dev/guide/why.html). Then check out [the Getting Started](https://vitejs.dev/guide/) and [Features guide](https://vitejs.dev/guide/features) to see what Vite provides out of the box. As usual, contributions are welcome at [GitHub](https://github.com/vitejs/vite). More than [600 collaborators](https://github.com/vitejs/vite/graphs/contributors) have helped improve Vite so far. Follow the updates on [Twitter](https://twitter.com/vite_js), or join discussions with other Vite users on our [Discord chat server](http://chat.vitejs.dev/).
+If you are new to Vite, we recommend reading the [Why Vite Guide](https://vite.dev/guide/why.html). Then check out [the Getting Started](https://vite.dev/guide/) and [Features guide](https://vite.dev/guide/features) to see what Vite provides out of the box. As usual, contributions are welcome at [GitHub](https://github.com/vitejs/vite). More than [600 collaborators](https://github.com/vitejs/vite/graphs/contributors) have helped improve Vite so far. Follow the updates on [Twitter](https://twitter.com/vite_js), or join discussions with other Vite users on our [Discord chat server](http://chat.vite.dev/).
## New Documentation
-Go to [vitejs.dev](https://vitejs.dev) to enjoy the new v3 docs. Vite is now using the new [VitePress](https://vitepress.vuejs.org) default theme, with a stunning dark mode between other features.
+Go to [vite.dev](https://vite.dev) to enjoy the new v3 docs. Vite is now using the new [VitePress](https://vitepress.vuejs.org) default theme, with a stunning dark mode between other features.
-[](https://vitejs.dev)
+[](https://vite.dev)
Several projects in the ecosystem have already migrated to it (see [Vitest](https://vitest.dev), [vite-plugin-pwa](https://vite-plugin-pwa.netlify.app/), and [VitePress](https://vitepress.vuejs.org/) itself).
-If you need to access the Vite 2 docs, they will remain online at [v2.vitejs.dev](https://v2.vitejs.dev). There is also a new [main.vitejs.dev](https://main.vitejs.dev) subdomain, where each commit to Vite’s main branch is auto deployed. This is useful when testing beta versions or contributing to the core’s development.
+If you need to access the Vite 2 docs, they will remain online at [v2.vite.dev](https://v2.vite.dev). There is also a new [main.vite.dev](https://main.vite.dev) subdomain, where each commit to Vite’s main branch is auto deployed. This is useful when testing beta versions or contributing to the core’s development.
There is also now an official Spanish translation, that has been added to the previous Chinese and Japanese translations:
-- [简体中文](https://cn.vitejs.dev/)
-- [日本語](https://ja.vitejs.dev/)
-- [Español](https://es.vitejs.dev/)
+- [简体中文](https://cn.vite.dev/)
+- [日本語](https://ja.vite.dev/)
+- [Español](https://es.vite.dev/)
## Create Vite Starter Templates
@@ -179,7 +185,7 @@ Learn more in the [WebAssembly guide](/guide/features.html#webassembly)
### ESM SSR Build by Default
-Most SSR frameworks in the ecosystem were already using ESM builds. So, Vite 3 makes ESM the default format for SSR builds. This allows us to streamline previous [SSR externalization heuristics](https://vitejs.dev/guide/ssr.html#ssr-externals), externalizing dependencies by default.
+Most SSR frameworks in the ecosystem were already using ESM builds. So, Vite 3 makes ESM the default format for SSR builds. This allows us to streamline previous [SSR externalization heuristics](https://vite.dev/guide/ssr.html#ssr-externals), externalizing dependencies by default.
### Improved Relative Base Support
@@ -193,7 +199,7 @@ There are other deploy scenarios where this isn't enough. For example, if the ge
### Esbuild Deps Optimization at Build Time (Experimental)
-One of the main differences between dev and build time is how Vite handles dependencies. During build time, [`@rollup/plugin-commonjs`](https://github.com/rollup/plugins/tree/master/packages/commonjs) is used to allow importing CJS only dependencies (like React). When using the dev server, esbuild is used instead to pre-bundle and optimize dependencies, and an inline interop scheme is applied while transforming user code importing CJS deps. During the development of Vite 3, we introduced the changes needed to also allow the use of [esbuild to optimize dependencies during build time](/guide/migration.html#using-esbuild-deps-optimization-at-build-time). [`@rollup/plugin-commonjs`](https://github.com/rollup/plugins/tree/master/packages/commonjs) can then be avoided, making dev and build time work in the same way.
+One of the main differences between dev and build time is how Vite handles dependencies. During build time, [`@rollup/plugin-commonjs`](https://github.com/rollup/plugins/tree/master/packages/commonjs) is used to allow importing CJS only dependencies (like React). When using the dev server, esbuild is used instead to pre-bundle and optimize dependencies, and an inline interop scheme is applied while transforming user code importing CJS deps. During the development of Vite 3, we introduced the changes needed to also allow the use of [esbuild to optimize dependencies during build time](https://v3.vite.dev/guide/migration.html#using-esbuild-deps-optimization-at-build-time). [`@rollup/plugin-commonjs`](https://github.com/rollup/plugins/tree/master/packages/commonjs) can then be avoided, making dev and build time work in the same way.
Given that Rollup v3 will be out in the next months, and we're going to follow up with another Vite major, we've decided to make this mode optional to reduce v3 scope and give Vite and the ecosystem more time to work out possible issues with the new CJS interop approach during build time. Frameworks may switch to using esbuild deps optimization during build time by default at their own pace before Vite 4.
@@ -211,7 +217,7 @@ Vite cares about its publish and install footprint; a fast installation of a new
| Vite 3.0.0 | 3.05MB | 17.8MB |
| Reduction | -30% | -7% |
-In part, this reduction was possible by making some dependencies that most users weren't needing optional. First, [Terser](https://github.com/terser/terser) is no longer installed by default. This dependency was no longer needed since we already made esbuild the default minifier for both JS and CSS in Vite 2. If you use `build.minify: 'terser'`, you'll need to install it (`npm add -D terser`). We also moved [node-forge](https://github.com/digitalbazaar/forge) out of the monorepo, implementing support for automatic https certificate generation as a new plugin: [`@vitejs/plugin-basic-ssl`](/guide/migration.html#automatic-https-certificate-generation). Since this feature only creates untrusted certificates that are not added to the local store, it didn't justify the added size.
+In part, this reduction was possible by making some dependencies that most users weren't needing optional. First, [Terser](https://github.com/terser/terser) is no longer installed by default. This dependency was no longer needed since we already made esbuild the default minifier for both JS and CSS in Vite 2. If you use `build.minify: 'terser'`, you'll need to install it (`npm add -D terser`). We also moved [node-forge](https://github.com/digitalbazaar/forge) out of the monorepo, implementing support for automatic https certificate generation as a new plugin: [`@vitejs/plugin-basic-ssl`](https://v3.vite.dev/guide/migration.html#automatic-https-certificate-generation). Since this feature only creates untrusted certificates that are not added to the local store, it didn't justify the added size.
## Bug Fixing
@@ -228,7 +234,7 @@ A triaging marathon was spearheaded by [@bluwyoo](https://twitter.com/bluwyoo),
- The Modern Browser Baseline now targets browsers which support the [native ES Modules](https://caniuse.com/es6-module), [native ESM dynamic import](https://caniuse.com/es6-module-dynamic-import), and [`import.meta`](https://caniuse.com/mdn-javascript_operators_import_meta) features.
- JS file extensions in SSR and library mode now use a valid extension (`js`, `mjs`, or `cjs`) for output JS entries and chunks based on their format and the package type.
-Learn more in the [Migration Guide](/guide/migration).
+Learn more in the [Migration Guide](https://v3.vite.dev/guide/migration.html).
## Upgrades to Vite Core
@@ -239,7 +245,7 @@ While working towards Vite 3, we also improved the contributing experience for c
- Vite upgraded to [pnpm 7](https://pnpm.io/), following the rest of the ecosystem.
- Playgrounds have been moved to [`/playgrounds`](https://github.com/vitejs/vite/tree/main/playground) out of packages directory.
- The packages and playgrounds are now `"type": "module"`.
-- Plugins are now bundled using [unbuild](https://github.com/unjs/unbuild), and [plugin-vue-jsx](https://github.com/vitejs/vite/tree/main/packages/plugin-vue-jsx) and [plugin-legacy](https://github.com/vitejs/vite/tree/main/packages/plugin-legacy) were moved to TypeScript.
+- Plugins are now bundled using [unbuild](https://github.com/unjs/unbuild), and [plugin-vue-jsx](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue-jsx) and [plugin-legacy](https://github.com/vitejs/vite/tree/main/packages/plugin-legacy) were moved to TypeScript.
## The Ecosystem is Ready for v3
@@ -267,4 +273,4 @@ We'll take the following months to ensure a smooth transition for all the projec
The Rollup team is [working on its next major](https://twitter.com/lukastaegert/status/1544186847399743488), to be released in the following months. Once the Rollup plugins ecosystem has time to update, we'll follow up with a new Vite major. This will give us another opportunity to introduce more significant changes this year, which we could take to stabilize some of the experimental features introduced in this release.
-If you are interested in helping improve Vite, the best way to get on board is to help with triaging issues. Join [our Discord](https://chat.vitejs.dev) and look for the `#contributing` channel. Or get involved in our `#docs`, `#help` others, or create plugins. We are just getting started. There are many open ideas to keep improving Vite's DX.
+If you are interested in helping improve Vite, the best way to get on board is to help with triaging issues. Join [our Discord](https://chat.vite.dev) and look for the `#contributing` channel. Or get involved in our `#docs`, `#help` others, or create plugins. We are just getting started. There are many open ideas to keep improving Vite's DX.
diff --git a/blog/announcing-vite4-3.md b/blog/announcing-vite4-3.md
new file mode 100644
index 00000000..b725308b
--- /dev/null
+++ b/blog/announcing-vite4-3.md
@@ -0,0 +1,90 @@
+---
+title: Vite 4.3 is out!
+author:
+ name: The Vite Team
+date: 2023-04-20
+sidebar: false
+head:
+ - - meta
+ - property: og:type
+ content: website
+ - - meta
+ - property: og:title
+ content: Announcing Vite 4.3
+ - - meta
+ - property: og:image
+ content: https://vite.dev/og-image-announcing-vite4-3.png
+ - - meta
+ - property: og:url
+ content: https://vite.dev/blog/announcing-vite4-3
+ - - meta
+ - property: og:description
+ content: Vite 4.3 Release Announcement
+ - - meta
+ - name: twitter:card
+ content: summary_large_image
+---
+
+# Vite 4.3 is out!
+
+_April 20, 2023_
+
+
+
+Quick links:
+
+- Docs: [English](/), [简体中文](https://cn.vite.dev/), [日本語](https://ja.vite.dev/), [Español](https://es.vite.dev/), [Português](https://pt.vite.dev/)
+- [Vite 4.3 Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md#430-2023-04-20)
+
+## Performance Improvements
+
+In this minor, we focused on improving the dev server performance. The resolve logic got streamlined, improving hot paths and implementing smarter caching for finding `package.json`, TS config files, and resolved URL in general.
+
+You can read a detailed walkthrough of the performance work done in this blog post by one of Vite Contributors: [How we made Vite 4.3 faaaaster 🚀](https://sun0day.github.io/blog/vite/why-vite4_3-is-faster.html).
+
+This sprint resulted in speed improvements across the board compared to Vite 4.2.
+
+These are the performance improvements as measured by [sapphi-red/performance-compare](https://github.com/sapphi-red/performance-compare), which tests an app with 1000 React Components cold and warm dev server startup time as well as HMR times for a root and a leaf component:
+
+| **Vite (babel)** | Vite 4.2 | Vite 4.3 | Improvement |
+| :----------------- | --------: | -------: | ----------: |
+| **dev cold start** | 17249.0ms | 5132.4ms | -70.2% |
+| **dev warm start** | 6027.8ms | 4536.1ms | -24.7% |
+| **Root HMR** | 46.8ms | 26.7ms | -42.9% |
+| **Leaf HMR** | 27.0ms | 12.9ms | -52.2% |
+
+| **Vite (swc)** | Vite 4.2 | Vite 4.3 | Improvement |
+| :----------------- | --------: | -------: | ----------: |
+| **dev cold start** | 13552.5ms | 3201.0ms | -76.4% |
+| **dev warm start** | 4625.5ms | 2834.4ms | -38.7% |
+| **Root HMR** | 30.5ms | 24.0ms | -21.3% |
+| **Leaf HMR** | 16.9ms | 10.0ms | -40.8% |
+
+
+
+
+
+You can read more information about the benchmark [here](https://gist.github.com/sapphi-red/25be97327ee64a3c1dce793444afdf6e). Specs and Versions for this performance run:
+
+- CPU: Ryzen 9 5900X, Memory: DDR4-3600 32GB, SSD: WD Blue SN550 NVME SSD
+- Windows 10 Pro 21H2 19044.2846
+- Node.js 18.16.0
+- Vite and React Plugin versions
+ - Vite 4.2 (babel): Vite 4.2.1 + plugin-react 3.1.0
+ - Vite 4.3 (babel): Vite 4.3.0 + plugin-react 4.0.0-beta.1
+ - Vite 4.2 (swc): Vite 4.2.1 + plugin-react-swc 3.2.0
+ - Vite 4.3 (swc): Vite 4.3.0 + plugin-react-swc 3.3.0
+
+Early adopters have also reported seeing 1.5x-2x dev startup time improvement on real apps while testing the Vite 4.3 beta. We'd love to know the results for your apps.
+
+## Profiling
+
+We'll continue to work on Vite's performance. We're working on an official [Benchmark tool](https://github.com/vitejs/vite-benchmark) for Vite that let us get performance metrics for each Pull Request.
+
+And [vite-plugin-inspect](https://github.com/antfu/vite-plugin-inspect) now has more performance-related features to help you identify which plugins or middlewares are the bottleneck for your applications.
+
+Using `vite --profile` (and then pressing `p`) once the page loads will save a CPU profile of the dev server startup. You can open them in an app as [speedscope](https://www.speedscope.app/) to identify performance issues. And you can share your findings with the Vite Team in a [Discussion](https://github.com/vitejs/vite/discussions) or in [Vite's Discord](https://chat.vite.dev).
+
+## Next Steps
+
+We decided to do a single Vite Major this year aligning with the [EOL of Node.js 16](https://endoflife.date/nodejs) in September, dropping support for both Node.js 14 and 16 in it. If you would like to get involved, we started a [Vite 5 Discussion](https://github.com/vitejs/vite/discussions/12466) to gather early feedback.
diff --git a/blog/announcing-vite4.md b/blog/announcing-vite4.md
new file mode 100644
index 00000000..9f574f54
--- /dev/null
+++ b/blog/announcing-vite4.md
@@ -0,0 +1,140 @@
+---
+title: Vite 4.0 is out!
+author:
+ name: The Vite Team
+date: 2022-12-09
+sidebar: false
+head:
+ - - meta
+ - property: og:type
+ content: website
+ - - meta
+ - property: og:title
+ content: Announcing Vite 4
+ - - meta
+ - property: og:image
+ content: https://vite.dev/og-image-announcing-vite4.png
+ - - meta
+ - property: og:url
+ content: https://vite.dev/blog/announcing-vite4
+ - - meta
+ - property: og:description
+ content: Vite 4 Release Announcement
+ - - meta
+ - name: twitter:card
+ content: summary_large_image
+---
+
+# Vite 4.0 is out!
+
+_December 9, 2022_ - Check out the [Vite 5.0 announcement](./announcing-vite5.md)
+
+Vite 3 [was released](./announcing-vite3.md) five months ago. npm downloads per week have gone from 1 million to 2.5 million since then. The ecosystem has matured too, and continues to grow. In this year's [Jamstack Conf survey](https://twitter.com/vite_js/status/1589665610119585793), usage among the community jumped from 14% to 32% while keeping a high 9.7 satisfaction score. We saw the stable releases of [Astro 1.0](https://astro.build/), [Nuxt 3](https://v3.nuxtjs.org/), and other Vite-powered frameworks that are innovating and collaborating: [SvelteKit](https://kit.svelte.dev/), [Solid Start](https://www.solidjs.com/blog/introducing-solidstart), [Qwik City](https://qwik.builder.io/qwikcity/overview/). Storybook announced first-class support for Vite as one of its main features for [Storybook 7.0](https://storybook.js.org/blog/first-class-vite-support-in-storybook/). Deno now [supports Vite](https://www.youtube.com/watch?v=Zjojo9wdvmY). [Vitest](https://vitest.dev) adoption is exploding, it will soon represent half of Vite's npm downloads. Nx is also investing in the ecosystem, and [officially supports Vite](https://nx.dev/packages/vite).
+
+[](https://viteconf.org/2022/replay)
+
+As a showcase of the growth Vite and related projects have experienced, the Vite ecosystem gathered on October 11th at [ViteConf 2022](https://viteconf.org/2022/replay). We saw representatives from the main web framework and tools tell stories of innovation and collaboration. And in a symbolic move, the Rollup team choose that exact day to release [Rollup 3](https://cn.rollupjs.org).
+
+Today, the Vite [team](https://vite.dev/team) with the help of our ecosystem partners, is happy to announce the release of Vite 4, powered during build time by Rollup 3. We've worked with the ecosystem to ensure a smooth upgrade path for this new major. Vite is now using [Rollup 3](https://github.com/vitejs/vite/issues/9870), which allowed us to simplify Vite's internal asset handling and has many improvements. See the [Rollup 3 release notes here](https://github.com/rollup/rollup/releases/tag/v3.0.0).
+
+
+
+Quick links:
+
+- [Docs](/)
+- [Migration Guide](https://v4.vite.dev/guide/migration.html)
+- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md#400-2022-12-09)
+
+Docs in other languages:
+
+- [简体中文](https://cn.vite.dev/)
+- [日本語](https://ja.vite.dev/)
+- [Español](https://es.vite.dev/)
+
+If you recently started using Vite, we suggest reading the [Why Vite Guide](https://vite.dev/guide/why.html) and checking out [the Getting Started](https://vite.dev/guide/) and [Features guide](https://vite.dev/guide/features). If you want to get involved, contributions are welcome at [GitHub](https://github.com/vitejs/vite). Almost [700 collaborators](https://github.com/vitejs/vite/graphs/contributors) have contributed to Vite. Follow the updates on [Twitter](https://twitter.com/vite_js) and [Mastodon](https://webtoo.ls/@vite), or join collaborate with others on our [Discord community](http://chat.vite.dev/).
+
+## Start playing with Vite 4
+
+Use `pnpm create vite` to scaffold a Vite project with your preferred framework, or open a started template online to play with Vite 4 using [vite.new](https://vite.new).
+
+You can also run `pnpm create vite-extra` to get access to templates from other frameworks and runtimes (Solid, Deno, SSR, and library starters). `create vite-extra` templates are also available when you run `create vite` under the `Others` option.
+
+Note that Vite starter templates are intended to be used as a playground to test Vite with different frameworks. When building your next project, we recommend reaching out to the starters recommended by each framework. Some frameworks now redirect in `create vite` to their starters too (`create-vue` and `Nuxt 3` for Vue, and `SvelteKit` for Svelte).
+
+## New React plugin using SWC during development
+
+[SWC](https://swc.rs/) is now a mature replacement for [Babel](https://babeljs.io/), especially in the context of React projects. SWC's React Fast Refresh implementation is a lot faster than Babel, and for some projects, it is now a better alternative. From Vite 4, two plugins are available for React projects with different tradeoffs. We believe that both approaches are worth supporting at this point, and we'll continue to explore improvements to both plugins in the future.
+
+### @vitejs/plugin-react
+
+[@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react) is a plugin that uses esbuild and Babel, achieving fast HMR with a small package footprint and the flexibility of being able to use the Babel transform pipeline.
+
+### @vitejs/plugin-react-swc (new)
+
+[@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) is a new plugin that uses esbuild during build, but replaces Babel with SWC during development. For big projects that don't require non-standard React extensions, cold start and Hot Module Replacement (HMR) can be significantly faster.
+
+## Browser Compatibility
+
+The modern browser build now targets `safari14` by default for wider ES2020 compatibility. This means that modern builds can now use [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) and that the [nullish coalescing operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing) isn't transpiled anymore. If you need to support older browsers, you can add [`@vitejs/plugin-legacy`](https://github.com/vitejs/vite/tree/main/packages/plugin-legacy) as usual.
+
+## Importing CSS as a String
+
+In Vite 3, importing the default export of a `.css` file could introduce a double loading of CSS.
+
+```ts
+import cssString from './global.css'
+```
+
+This double loading could occur since a `.css` file will be emitted and it's likely that the CSS string will also be used by the application code — for example, injected by the framework runtime. From Vite 4, the `.css` default export [has been deprecated](https://github.com/vitejs/vite/issues/11094). The `?inline` query suffix modifier needs to be used in this case, as that doesn't emit the imported `.css` styles.
+
+```ts
+import stuff from './global.css?inline'
+```
+
+Learn more in the [Migration Guide](https://v4.vite.dev/guide/migration.html).
+
+## Environment Variables
+
+Vite now uses `dotenv` 16 and `dotenv-expand` 9 (previously `dotenv` 14 and `dotenv-expand` 5). If you have a value including `#` or `` ` ``, you will need to wrap them with quotes.
+
+```diff
+-VITE_APP=ab#cd`ef
++VITE_APP="ab#cd`ef"
+```
+
+For more details, see the [`dotenv`](https://github.com/motdotla/dotenv/blob/master/CHANGELOG.md) and [`dotenv-expand` changelog](https://github.com/motdotla/dotenv-expand/blob/master/CHANGELOG.md).
+
+## Other Features
+
+- CLI Shortcuts (press `h` during dev to see them all) ([#11228](https://github.com/vitejs/vite/pull/11228))
+- Support for patch-package when pre bundling dependencies ([#10286](https://github.com/vitejs/vite/issues/10286))
+- Cleaner build logs output ([#10895](https://github.com/vitejs/vite/issues/10895)) and switch to `kB` to align with browser dev tools ([#10982](https://github.com/vitejs/vite/issues/10982))
+- Improved error messages during SSR ([#11156](https://github.com/vitejs/vite/issues/11156))
+
+## Reduced Package Size
+
+Vite cares about its footprint, to speed up installation, especially in the use case of playgrounds for documentation and reproductions. And once more, this major brings improvements in Vite's package size. Vite 4 install size is 23% smaller compared to vite 3.2.5 (14.1 MB vs 18.3 MB).
+
+## Upgrades to Vite Core
+
+[Vite Core](https://github.com/vitejs/vite) and [vite-ecosystem-ci](https://github.com/vitejs/vite-ecosystem-ci) continue to evolve to provide a better experience to maintainers and collaborators and to ensure that Vite development scales to cope with the growth in the ecosystem.
+
+### Framework plugins out of core
+
+[`@vitejs/plugin-vue`](https://github.com/vitejs/vite-plugin-vue) and [`@vitejs/plugin-react`](https://github.com/vitejs/vite-plugin-react) have been part of Vite core monorepo since the first versions of Vite. This helped us to get a close feedback loop when making changes as we were getting both Core and the plugins tested and released together. With [vite-ecosystem-ci](https://github.com/vitejs/vite-ecosystem-ci) we can get this feedback with these plugins developed on independent repositories, so from Vite 4, [they have been moved out of the Vite core monorepo](https://github.com/vitejs/vite/pull/11158). This is meaningful for Vite's framework-agnostic story and will allow us to build independent teams to maintain each of the plugins. If you have bugs to report or features to request, please create issues on the new repositories moving forward: [`vitejs/vite-plugin-vue`](https://github.com/vitejs/vite-plugin-vue) and [`vitejs/vite-plugin-react`](https://github.com/vitejs/vite-plugin-react).
+
+### vite-ecosystem-ci improvements
+
+[vite-ecosystem-ci](https://github.com/vitejs/vite-ecosystem-ci) extends Vite's CI by providing on-demand status reports on the state of the CIs of [most major downstream projects](https://github.com/vitejs/vite-ecosystem-ci/tree/main/tests). We run vite-ecosystem-ci three times a week against Vite's main branch and receive timely reports before introducing a regression. Vite 4 will soon be compatible with most projects using Vite, which already prepared branches with the needed changes and will be releasing them in the next few days. We are also able to run vite-ecosystem-ci on-demand on PRs using `/ecosystem-ci run` in a comment, allowing us to know [the effect of changes](https://github.com/vitejs/vite/pull/11269#issuecomment-1343365064) before they hit main.
+
+## Acknowledgments
+
+Vite 4 wouldn't be possible without uncountable hours of work by Vite contributors, many of them maintainers of downstream projects and plugins, and the efforts of the [Vite Team](/team). All of us have worked together to improve Vite's DX once more, for every framework and app using it. We're grateful to be able to improve a common base for such a vibrant ecosystem.
+
+We're also thankful to individuals and companies sponsoring the Vite team, and companies investing directly in Vite's future: [@antfu7](https://twitter.com/antfu7)'s work on Vite and the ecosystem is part of his job at [Nuxt Labs](https://nuxtlabs.com/), [Astro](https://astro.build) is funding [@bluwyoo](https://twitter.com/bluwyoo)'s' Vite core work, and [StackBlitz](https://stackblitz.com/) hires [@patak_dev](https://twitter.com/patak_dev) to work full time on Vite.
+
+## Next steps
+
+Our immediate focus would be on triaging newly opened issues to avoid disruption by possible regressions. If you would like to get involved and help us improve Vite, we suggest starting with issues triaging. Join [our Discord](https://chat.vite.dev) and reach out on the `#contributing` channel. Polish our `#docs` story, and `#help` others. We need to continue to build a helpful and welcoming community for the next wave of users, as Vite's adoption continues to grow.
+
+There are a lot of open fronts to keep improving the DX of everyone that has chosen Vite to power their frameworks and develop their apps. Onwards!
diff --git a/blog/announcing-vite5-1.md b/blog/announcing-vite5-1.md
new file mode 100644
index 00000000..bbb24a8e
--- /dev/null
+++ b/blog/announcing-vite5-1.md
@@ -0,0 +1,134 @@
+---
+title: Vite 5.1 is out!
+author:
+ name: The Vite Team
+date: 2024-02-08
+sidebar: false
+head:
+ - - meta
+ - property: og:type
+ content: website
+ - - meta
+ - property: og:title
+ content: Announcing Vite 5.1
+ - - meta
+ - property: og:image
+ content: https://vite.dev/og-image-announcing-vite5-1.png
+ - - meta
+ - property: og:url
+ content: https://vite.dev/blog/announcing-vite5-1
+ - - meta
+ - property: og:description
+ content: Vite 5.1 Release Announcement
+ - - meta
+ - name: twitter:card
+ content: summary_large_image
+---
+
+# Vite 5.1 is out!
+
+_February 8, 2024_
+
+
+
+Vite 5 [was released](./announcing-vite5.md) last November, and it represented another big leap for Vite and the ecosystem. A few weeks ago we celebrated 10 million weekly npm downloads and 900 contributors to the Vite repo. Today, we're excited to announce the release of Vite 5.1.
+
+Quick links: [Docs](/), [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md#510-2024-02-08)
+
+Docs in other languages: [简体中文](https://cn.vite.dev/), [日本語](https://ja.vite.dev/), [Español](https://es.vite.dev/), [Português](https://pt.vite.dev/), [한국어](https://ko.vite.dev/), [Deutsch](https://de.vite.dev/)
+
+Try Vite 5.1 online in StackBlitz: [vanilla](https://vite.new/vanilla-ts), [vue](https://vite.new/vue-ts), [react](https://vite.new/react-ts), [preact](https://vite.new/preact-ts), [lit](https://vite.new/lit-ts), [svelte](https://vite.new/svelte-ts), [solid](https://vite.new/solid-ts), [qwik](https://vite.new/qwik-ts).
+
+If you're new to Vite, we suggest reading first the [Getting Started](/guide/) and [Features](/guide/features) guides.
+
+To stay up to date, follow us on [X](https://x.com/vite_js) or [Mastodon](https://webtoo.ls/@vite).
+
+## Vite Runtime API
+
+Vite 5.1 adds experimental support for a new Vite Runtime API. It allows running any code by processing it with Vite plugins first. It is different from `server.ssrLoadModule` because the runtime implementation is decoupled from the server. This lets library and framework authors implement their own layer of communication between the server and the runtime. This new API is intended to replace Vite's current SSR primitives once it is stable.
+
+The new API brings many benefits:
+
+- Support for HMR during SSR.
+- It is decoupled from the server, so there is no limit on how many clients can use a single server - every client has its own module cache (you can even communicate with it how you want - using message channel/fetch call/direct function call/websocket).
+- It doesn't depend on any node/bun/deno built-in APIs, so it can run in any environment.
+- It's easy to integrate with tools that have their own mechanism to run code (you can provide a runner to use `eval` instead of `new AsyncFunction` for example).
+
+The initial idea [was proposed by Pooya Parsa](https://github.com/nuxt/vite/pull/201) and implemented by [Anthony Fu](https://github.com/antfu) as the [vite-node](https://github.com/vitest-dev/vitest/tree/main/packages/vite-node#readme) package to [power Nuxt 3 Dev SSR](https://antfu.me/posts/dev-ssr-on-nuxt) and later also used as the base for [Vitest](https://vitest.dev). So the general idea of vite-node has been battle-tested for quite some time now. This is a new iteration of the API by [Vladimir Sheremet](https://github.com/sheremet-va), who had already re-implemented vite-node in Vitest and took the learnings to make the API even more powerful and flexible when adding it to Vite Core. The PR was one year in the makings, you can see the evolution and discussions with ecosystem maintainers [here](https://github.com/vitejs/vite/issues/12165).
+
+::: info
+The Vite Runtime API evolved into the Module Runner API, released in Vite 6 as part of the [Environment API](/guide/api-environment).
+:::
+
+## Features
+
+### Improved support for `.css?url`
+
+Import CSS files as URLs now works reliably and correctly. This was the last remaining hurdle in Remix's move to Vite. See ([#15259](https://github.com/vitejs/vite/issues/15259)).
+
+### `build.assetsInlineLimit` now supports a callback
+
+Users can now [provide a callback](/config/build-options.html#build-assetsinlinelimit) that returns a boolean to opt-in or opt-out of inlining for specific assets. If `undefined` is returned, the default logic applies. See ([#15366](https://github.com/vitejs/vite/issues/15366)).
+
+### Improved HMR for circular import
+
+In Vite 5.0, accepted modules within circular imports always triggered a full page reload even if they can be handled fine in the client. This is now relaxed to allow HMR to apply without a full page reload, but if any error happens during HMR, the page will be reloaded. See ([#15118](https://github.com/vitejs/vite/issues/15118)).
+
+### Support `ssr.external: true` to externalize all SSR packages
+
+Historically, Vite externalizes all packages except for linked packages. This new option can be used to force externalize all packages including linked packages too. This is handy in tests within monorepos where we want to emulate the usual case of all packages externalized, or when using `ssrLoadModule` to load an arbitrary file and we want to always external packages as we don't care about HMR. See ([#10939](https://github.com/vitejs/vite/issues/10939)).
+
+### Expose `close` method in the preview server
+
+The preview server now exposes a `close` method, which will properly teardown the server including all opened socket connections. See ([#15630](https://github.com/vitejs/vite/issues/15630)).
+
+## Performance improvements
+
+Vite keeps getting faster with each release, and Vite 5.1 is packed with performance improvements. We measured the loading time for 10K modules (25 level deep tree) using [vite-dev-server-perf](https://github.com/yyx990803/vite-dev-server-perf) for all minor versions from Vite 4.0. This is a good benchmark to measure the effect of Vite's bundle-less approach. Each module is a small TypeScript file with a counter and imports to other files in the tree, so this mostly measuring the time it takes to do the requests a separate modules. In Vite 4.0, loading 10K modules took 8 seconds on a M1 MAX. We had a breakthrough in [Vite 4.3 were we focused on performance](./announcing-vite4-3.md), and we were able to load them in 6.35 seconds. In Vite 5.1, we managed to do another performance leap. Vite is now serving the 10K modules in 5.35 seconds.
+
+
+
+The results of this benchmark run on Headless Puppeteer and are a good way to compare versions. They don't represent the time as experienced by users though. When running the same 10K modules in an Incognito window is Chrome, we have:
+
+| 10K Modules | Vite 5.0 | Vite 5.1 |
+| --------------------- | :------: | :------: |
+| Loading time | 2892ms | 2765ms |
+| Loading time (cached) | 2778ms | 2477ms |
+| Full reload | 2003ms | 1878ms |
+| Full reload (cached) | 1682ms | 1604ms |
+
+### Run CSS preprocessors in threads
+
+Vite now has opt-in support for running CSS preprocessors in threads. You can enable it using [`css.preprocessorMaxWorkers: true`](/config/shared-options.html#css-preprocessormaxworkers). For a Vuetify 2 project, dev startup time was reduced by 40% with this feature enabled. There is [performance comparison for others setups in the PR](https://github.com/vitejs/vite/pull/13584#issuecomment-1678827918). See ([#13584](https://github.com/vitejs/vite/issues/13584)). [Give Feedback](https://github.com/vitejs/vite/discussions/15835).
+
+### New options to improve server cold starts
+
+You can set `optimizeDeps.holdUntilCrawlEnd: false` to switch to a new strategy for deps optimization that may help in big projects. We're considering switching to this strategy by default in the future. [Give Feedback](https://github.com/vitejs/vite/discussions/15834). ([#15244](https://github.com/vitejs/vite/issues/15244))
+
+### Faster resolving with cached checks
+
+The `fs.cachedChecks` optimization is now enabled by default. In Windows, `tryFsResolve` was ~14x faster with it, and resolving ids overall got a ~5x speed up in the triangle benchmark. ([#15704](https://github.com/vitejs/vite/issues/15704))
+
+### Internal performance improvements
+
+The dev server had several incremental performance gains. A new middleware to short-circuit on 304 ([#15586](https://github.com/vitejs/vite/issues/15586)). We avoided `parseRequest` in hot paths ([#15617](https://github.com/vitejs/vite/issues/15617)). Rollup is now properly lazy loaded ([#15621](https://github.com/vitejs/vite/issues/15621))
+
+## Deprecations
+
+We continue to reduce Vite's API surface where possible to make the project maintainable long term.
+
+### Deprecated `as` option in `import.meta.glob`
+
+The standard moved to [Import Attributes](https://github.com/tc39/proposal-import-attributes), but we don't plan to replace `as` with a new option at this point. Instead, it is recommended that the user switches to `query`. See ([#14420](https://github.com/vitejs/vite/issues/14420)).
+
+### Removed experimental build-time pre-bundling
+
+Build-time pre-bundling, an experimental feature added in Vite 3, is removed. With Rollup 4 switching its parser to native, and Rolldown being worked on, both the performance and the dev-vs-build inconsistency story for this feature are no longer valid. We want to continue improving dev/build consistency, and have concluded that using Rolldown for "prebundling during dev" and "production builds" is the better bet moving forward. Rolldown may also implement caching in a way that is a lot more efficient during build than deps prebundling. See ([#15184](https://github.com/vitejs/vite/issues/15184)).
+
+## Get Involved
+
+We are grateful to the [900 contributors to Vite Core](https://github.com/vitejs/vite/graphs/contributors), and the maintainers of plugins, integrations, tools, and translations that keeps pushing the ecosystem forward. If you're enjoying Vite, we invite you to participate and help us. Check out our [Contributing Guide](https://github.com/vitejs/vite/blob/main/CONTRIBUTING.md), and jump into [triaging issues](https://github.com/vitejs/vite/issues), [reviewing PRs](https://github.com/vitejs/vite/pulls), answering questions at [GitHub Discussions](https://github.com/vitejs/vite/discussions) and helping others in the community in [Vite Land](https://chat.vite.dev).
+
+## Acknowledgments
+
+Vite 5.1 is possible thanks to our community of contributors, maintainers in the ecosystem, and the [Vite Team](/team). A shout out to the individuals and companies sponsoring Vite development. [StackBlitz](https://stackblitz.com/), [Nuxt Labs](https://nuxtlabs.com/), and [Astro](https://astro.build) for hiring Vite team members. And also to the sponsors on [Vite's GitHub Sponsors](https://github.com/sponsors/vitejs), [Vite's Open Collective](https://opencollective.com/vite), and [Evan You's GitHub Sponsors](https://github.com/sponsors/yyx990803).
diff --git a/blog/announcing-vite5.md b/blog/announcing-vite5.md
new file mode 100644
index 00000000..e15ead42
--- /dev/null
+++ b/blog/announcing-vite5.md
@@ -0,0 +1,110 @@
+---
+title: Vite 5.0 is out!
+author:
+ name: The Vite Team
+date: 2023-11-16
+sidebar: false
+head:
+ - - meta
+ - property: og:type
+ content: website
+ - - meta
+ - property: og:title
+ content: Announcing Vite 5
+ - - meta
+ - property: og:image
+ content: https://vite.dev/og-image-announcing-vite5.png
+ - - meta
+ - property: og:url
+ content: https://vite.dev/blog/announcing-vite5
+ - - meta
+ - property: og:description
+ content: Vite 5 Release Announcement
+ - - meta
+ - name: twitter:card
+ content: summary_large_image
+---
+
+# Vite 5.0 发布了!{#vite-5-0-is-out}
+
+_2023年11月16日_
+
+
+
+Vite 4 发布了将近一年,它为生态系统奠定了坚实的基础。每周的 npm 下载量从250万增加到了750万,因为项目不断在共享基础设施上构建。各种框架不断创新,除了 [Astro](https://astro.build/)、[Nuxt](https://nuxt.com/)、[SvelteKit](https://kit.svelte.dev/)、[Solid Start](https://www.solidjs.com/blog/introducing-solidstart)、[Qwik City](https://qwik.builder.io/qwikcity/overview/) 等等之外,我们看到新的框架加入并使生态系统变得更加强大。[RedwoodJS](https://redwoodjs.com/) 和 [Remix](https://remix.run/) 转向 Vite 为 React 生态系统的进一步采用铺平了道路。[Vitest](https://vitest.dev) 的增长速度甚至比 Vite 还要快。其团队一直在努力工作,并将很快 [发布 Vitest 1.0](https://github.com/vitest-dev/vitest/issues/3596)。当与其他工具一起使用时,如 [Storybook](https://storybook.js.org)、[Nx](https://nx.dev) 和 [Playwright](https://playwright.dev),Vite 的故事不断改善,环境也是如此,Vite 的开发在 [Deno](https://deno.com) 和 [Bun](https://bun.sh) 中都可以工作。
+
+一个月前,我们举办了第二届 [ViteConf](https://viteconf.org/23/replay),由 [StackBlitz](https://stackblitz.com) 主办。像去年一样,生态系统中的大多数项目聚在一起分享想法,并保持连接以持续扩展共同体。我们也看到新的组件补充了元框架工具包,比如 [Volar](https://volarjs.dev/) 和 [Nitro](https://nitro.build/)。Rollup 团队在同一天发布了 [Rollup 4](https://cn.rollupjs.org),这是去年 Lukas 开创的传统。
+
+六个月前,Vite 4.3 [发布了](./announcing-vite4.md)。这个版本显著改善了开发服务器的性能。但是,还有很大的改进空间。在 ViteConf 上,[Evan You 揭示了 Vite 的长期计划,即着手开发 Rolldown](https://www.youtube.com/watch?v=hrdwQHoAp0M),这是 Rollup 的 Rust 版本,具有兼容的 API。一旦准备就绪,我们打算在 Vite Core 中使用它,以执行 Rollup 和 esbuild 的任务。这将意味着构建性能的提升(随着我们将 Vite 本身的性能敏感部分转移到 Rust,开发性能也将在以后提升),以及减少开发和构建之间的不一致性。Rolldown 目前处于早期阶段,团队正准备在年底之前开源代码库。敬请期待!
+
+今天,我们在 Vite 的道路上又迈出了一个重要的里程碑。Vite [团队](/team)、[贡献者](https://github.com/vitejs/vite/graphs/contributors) 和生态系统合作伙伴,很高兴地宣布发布 Vite 5。Vite 现在使用 [Rollup 4](https://github.com/vitejs/vite/pull/14508),这已经是构建性能的重大提升。而且还有一些新选项可以改进你的开发服务器性能。
+
+Vite 5 的重点是清理 API(删除已弃用的功能)并简化几个功能,解决了长期存在的问题,例如切换 `define` 以使用正确的 AST 替换而不是正则表达式。我们还在继续采取措施未来证明 Vite(现在需要 Node.js 18+,并且已经 [弃用了 CJS Node API](/guide/migration#deprecate-cjs-node-api))。
+
+快速链接:
+
+- [文档](/)
+- [迁移指南](/guide/migration)
+- [变更日志](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md#500-2023-11-16)
+
+其他语言的文档:
+
+- [简体中文](https://cn.vite.dev/)
+- [日本語](https://ja.vite.dev/)
+- [Español](https://es.vite.dev/)
+- [Português](https://pt.vite.dev/)
+- [한국어](https://ko.vite.dev/)
+- [Deutsch](https://de.vite.dev/)(新增翻译!)
+
+如果你是 Vite 的新用户,我们建议你先阅读 [入门指南](/guide/) 和 [功能](/guide/features) 指南。
+
+我们感谢超过 [850 位对 Vite Core 作出贡献的贡献者](https://github.com/vitejs/vite/graphs/contributors),以及 Vite 插件、集成、工具和翻译的维护者和贡献者,他们帮助我们达到了这一里程碑。我们鼓励你参与进来,继续与我们一起改进 Vite。你可以在我们的 [贡献指南](https://github.com/vitejs/vite/blob/main/CONTRIBUTING.md) 中了解更多信息。要开始,我们建议你 [处理问题](https://github.com/vitejs/vite/issues),[审查 PR](https://github.com/vitejs/vite/pulls),基于开放的问题发送失败的测试 PR,并在 [讨论](https://github.com/vitejs/vite/discussions) 和 Vite Land 的 [帮助论坛](https://discord.com/channels/804011606160703521/1019670660856942652) 中帮助其他人。你会在这个过程中学到很多,并顺利地进一步为项目做出贡献。如果你有疑问,请加入我们的 [Discord 社区](http://chat.vite.dev/),并在 [#contributing 频道](https://discord.com/channels/804011606160703521/804439875226173480) 上打个招呼。
+
+要保持最新,请关注我们在 [X](https://twitter.com/vite_js) 或 [Mastodon](https://webtoo.ls/@vite) 上的动态。
+
+## 使用 Vite 5 快速开始 {#quick-start-with-vite-5}
+
+使用 `pnpm create vite` 来创建一个 Vite 项目,并选择你喜欢的框架,或者通过在线的模板使用 [vite.new](https://vite.new/) 来体验 Vite 5。你也可以运行 `pnpm create vite-extra` 来获取其他框架和运行时的模板(如 Solid、Deno、SSR 和库的起始模板)。当你在 `Others` 选项下运行 `create vite` 时,`create vite-extra` 的模板也是可用的。
+
+请注意,Vite 起始模板旨在用作测试 Vite 与不同框架的沙盒。在构建下一个项目时,我们建议使用每个框架推荐的起始模板。一些框架现在在 `create vite` 中也重定向到它们的起始模板(Vue 的 `create-vue` 和 `Nuxt 3`,以及 Svelte 的 `SvelteKit`)。
+
+## Node.js 支持 {#node-js-support}
+
+Vite 不再支持已达到 EOL 的 Node.js 14 / 16 / 17 / 19。现在需要 Node.js 18 / 20+。
+
+## 性能方面 {#performance}
+
+除了 Rollup 4 的构建性能改进之外,现在还有一个新指南,帮助你识别和修复常见的性能问题,网址为 [https://vite.dev/guide/performance](/guide/performance)。
+
+Vite 5 还引入了 [server.warmup](/guide/performance.html#warm-up-frequently-used-files),这是一个新功能,用于改善启动时间。它允许你定义一个模块列表,在服务器启动时应预先转换。当使用 [`--open` 或 `server.open`](/config/server-options.html#server-open) 时,Vite 还将自动预热你的应用程序的入口点或提供的要打开的 URL。
+
+## 主要变化 {#main-changes}
+
+- [Vite is now powered by Rollup 4](/guide/migration#rollup-4)
+- [The CJS Node API has been deprecated](/guide/migration#deprecate-cjs-node-api)
+- [Rework `define` and `import.meta.env.*` replacement strategy](/guide/migration#rework-define-and-import-meta-env-replacement-strategy)
+- [SSR externalized modules value now matches production](/guide/migration#ssr-externalized-modules-value-now-matches-production)
+- [`worker.plugins` is now a function](/guide/migration#worker-plugins-is-now-a-function)
+- [Allow path containing `.` to fallback to index.html](/guide/migration#allow-path-containing-to-fallback-to-index-html)
+- [Align dev and preview HTML serving behavior](/guide/migration#align-dev-and-preview-html-serving-behaviour)
+- [Manifest files are now generated in `.vite` directory by default](/guide/migration#manifest-files-are-now-generated-in-vite-directory-by-default)
+- [CLI shortcuts require an additional `Enter` press](/guide/migration#cli-shortcuts-require-an-additional-enter-press)
+- [Update `experimentalDecorators` and `useDefineForClassFields` TypeScript behavior](/guide/migration#update-experimentaldecorators-and-usedefineforclassfields-typescript-behaviour)
+- [Remove `--https` flag and `https: true`](/guide/migration#remove-https-flag-and-https-true)
+- [Remove `resolvePackageEntry` and `resolvePackageData` APIs](/guide/migration#remove-resolvepackageentry-and-resolvepackagedata-apis)
+- [Removes previously deprecated APIs](/guide/migration#removed-deprecated-apis)
+- [Read more about advanced changes affecting plugin and tool authors](/guide/migration#advanced)
+
+## 迁移到 Vite 5 {#migrating-to-vite-5}
+
+我们与生态系统合作伙伴合作,确保平稳迁移到这个新的主要版本。再次感谢 [vite-ecosystem-ci](https://www.youtube.com/watch?v=7L4I4lDzO48),它对我们进行更大胆的改变并避免回退起到了关键作用。我们很高兴看到其他生态系统采用类似的方案,以改善其项目与下游维护者之间的协作。
+
+对于大多数项目来说,升级到 Vite 5 应该是直截了当的。但我们建议在升级之前查看 [详细的迁移指南](/guide/migration)。
+
+你可以在 [Vite 5 变更日志](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md#500-2023-11-16) 中找到对 Vite 核心的全面变更列表。
+
+## 致谢 {#acknowledgments}
+
+Vite 5 是我们社区的贡献者、下游维护者、插件作者和 [Vite 团队](/team) 长时间工作的结果。特别感谢 [Bjorn Lu](https://twitter.com/bluwyoo) 在这个主要版本的发布过程中的领导。
+
+我们还要感谢个人和公司对 Vite 开发的赞助。[StackBlitz](https://stackblitz.com/)、[Nuxt Labs](https://nuxtlabs.com/) 和 [Astro](https://astro.build/) 继续通过雇佣 Vite 团队成员来投资 Vite。向 [Vite](https://github.com/sponsors/vitejs)、[Vite 的 Open Collective](https://opencollective.com/vite) 和 [Evan You](https://github.com/sponsors/yyx990803) 的赞助者表示感谢。特别感谢 [Remix](https://remix.run/) 成为金牌赞助商,并在转向 Vite 后回馈社区。
diff --git a/blog/announcing-vite6.md b/blog/announcing-vite6.md
new file mode 100644
index 00000000..5cbc5a70
--- /dev/null
+++ b/blog/announcing-vite6.md
@@ -0,0 +1,115 @@
+---
+title: Vite 6.0 is out!
+author:
+ name: The Vite Team
+date: 2024-11-26
+sidebar: false
+head:
+ - - meta
+ - property: og:type
+ content: website
+ - - meta
+ - property: og:title
+ content: Announcing Vite 6
+ - - meta
+ - property: og:image
+ content: https://vite.dev/og-image-announcing-vite6.png
+ - - meta
+ - property: og:url
+ content: https://vite.dev/blog/announcing-vite6
+ - - meta
+ - property: og:description
+ content: Vite 6 Release Announcement
+ - - meta
+ - name: twitter:card
+ content: summary_large_image
+---
+
+# Vite 6.0 发布了! {#vite-6-0-is-out}
+
+_2024年11月26日_
+
+
+
+今天,Vite 迎来了发展历程中的重要里程碑。我们很高兴地宣布,Vite 6 正式发布了!这一重大版本的发布离不开 Vite [团队](/team)、[贡献者](https://github.com/vitejs/vite/graphs/contributors) 以及整个生态系统合作伙伴的共同努力。
+
+过去一年中,Vite 的采用率持续增长,自 Vite 5 发布以来,npm 每周下载量从 750 万次跃升至 1700 万次。[Vitest](https://vitest.dev) 不仅越来越受用户欢迎,还开始形成自己的生态系统。例如,[Storybook](https://storybook.js.org) 推出了由 Vitest 支持的全新测试功能。
+
+Vite 生态系统也迎来了一批新成员,包括 [TanStack Start](https://tanstack.com/start)、[One](https://onestack.dev/)、[Ember](https://emberjs.com/) 等框架。Web 开发领域的创新速度日益加快,[Astro](https://astro.build/)、[Nuxt](https://nuxt.com/)、[SvelteKit](https://kit.svelte.dev/)、[Solid Start](https://www.solidjs.com/blog/introducing-solidstart)、[Qwik City](https://qwik.builder.io/qwikcity/overview)、[RedwoodJS](https://redwoodjs.com/)、[React Router](https://reactrouter.com/) 等项目都在不断推陈出新。
+
+Vite 已被 OpenAI、Google、Apple、Microsoft、NASA、Shopify、Cloudflare、GitLab、Reddit 和 Linear 等众多知名公司采用。两个月前,我们创建了一份 [使用 Vite 的公司列表](https://github.com/vitejs/companies-using-vite)。令人欣喜的是,许多开发者提交 PR 将他们的公司添加到列表中。回首 Vite 诞生至今,我们共同打造的生态系统增长速度之快,实在令人难以置信。
+
+
+
+### 加速 Vite 生态系统 {#speeding-up-the-vite-ecosystem}
+
+上个月,[StackBlitz](https://stackblitz.com) 再次主办了第三届 [ViteConf](https://viteconf.org/24/replay),吸引了整个社区的广泛参与。这是迄今为止规模最大的 Vite 会议,生态系统中的各路开发者齐聚一堂。Evan You 正式宣布成立 [VoidZero](https://staging.voidzero.dev/posts/announcing-voidzero-inc),这是一家致力于为 JavaScript 生态系统构建开源、高性能和统一开发工具链的公司。VoidZero 推出了 [Rolldown](https://rolldown.rs) 和 [Oxc](https://oxc.rs),他们的团队正在加紧准备这些工具以供 Vite 采用。想了解 Vite 未来如何借助 Rust 实现更强大的性能,不妨观看 Evan 的主题演讲。
+
+
+
+[Stackblitz](https://stackblitz.com) 推出了 [bolt.new](https://bolt.new),这是一个结合了 Claude 和 WebContainers 的 Remix 应用,允许你使用提示语、编辑、运行和部署全栈应用。Nate Weiner 宣布了 [One](https://onestack.dev/),一个新的 Vite 驱动的 Web 和原生 React 框架。Storybook 展示了他们最新由 Vitest 驱动的 [测试功能](https://youtu.be/8t5wxrFpCQY?si=PYZoWKf-45goQYDt)。还有更多精彩内容。我们建议你观看 [全部 43 场演讲](https://www.youtube.com/playlist?list=PLqGQbXn_GDmnObDzgjUF4Krsfl6OUKxtp)。演讲者们付出了巨大努力,分享了每个项目的最新进展。
+
+Vite 还更新了主页和域名。请记得将你的链接更新为新的 [vite.dev](https://vite.dev) 域名。新设计和实现由 VoidZero 完成,正是他们制作了自己的网站。特别感谢 [Vicente Rodriguez](https://bento.me/rmoon) 和 [Simon Le Marchant](https://marchantweb.com/) 的贡献。
+
+### Vite 6 的到来 {#the-next-vite-major-is-here}
+
+Vite 6 是自 Vite 2 以来最重要的主要版本发布。我们渴望与生态系统合作,通过新的 API 继续扩展我们的共享资源,并一如既往地提供一个更完善的构建基础。
+
+快速链接:
+
+- [英文文档](https://vite.dev)
+- 翻译版本:[简体中文](/)、[日本語](https://ja.vite.dev/)、[Español](https://es.vite.dev/)、[Português](https://pt.vite.dev/)、[한국어](https://ko.vite.dev/)、[Deutsch](https://de.vite.dev/)
+- [迁移指南](/guide/migration)
+- [GitHub 更新日志](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md#600-2024-11-26)
+
+如果你是 Vite 的新用户,我们建议首先阅读 [入门指南](/guide/) 和 [功能介绍](/guide/features) 部分。
+
+我们要感谢超过 [1000 位 Vite Core 贡献者](https://github.com/vitejs/vite/graphs/contributors) 以及 Vite 插件、集成、工具和翻译的维护者和贡献者,他们帮助我们打造了这个新的主要版本。我们也邀请你参与进来,帮助我们改进整个生态系统的 Vite。了解更多信息,请参阅我们的 [贡献指南](https://github.com/vitejs/vite/blob/main/CONTRIBUTING.md)。
+
+如果准备开始的话,我们建议可以帮助 [分类问题](https://github.com/vitejs/vite/issues)、[审查 PR](https://github.com/vitejs/vite/pulls)、根据开放问题发送失败的测试 PR,并在[讨论](https://github.com/vitejs/vite/discussions) 和 Vite Land 的 [帮助论坛](https://discord.com/channels/804011606160703521/1019670660856942652) 中帮助他人。如果你想与我们交流,请加入我们的 [Discord 社区](http://chat.vite.dev/) 并在 [#贡献频道](https://discord.com/channels/804011606160703521/804439875226173480) 中打个招呼。
+
+有关 Vite 生态系统和 Vite Core 的最新消息,请关注我们的 [Bluesky](https://bsky.app/profile/vite.dev)、[X](https://twitter.com/vite_js) 或 [Mastodon](https://webtoo.ls/@vite)。
+
+### 开始使用 Vite 6 {#getting-started-with-vite-6}
+
+你可以使用 `pnpm create vite` 快速搭建一个 Vite 应用,使用你喜欢的框架,或在线体验 Vite 6,访问 [vite.new](https://vite.new)。你还可以运行 `pnpm create vite-extra` 以获取其他框架和运行时(Solid、Deno、SSR 和库起始模板)的模板。当你在 `create vite` 下选择 `Others` 选项时,也可以使用 `create vite-extra` 模板。
+
+Vite 启动模板旨在作为测试 Vite 与不同框架结合的演练场。在构建下一个项目时,你可以试着使用每个框架推荐的启动模板。`create vite` 还提供了一些框架的快捷设置,如 `create-vue`、`Nuxt 3`、`SvelteKit`、`Remix`、`Analog` 和 `Angular`。
+
+### Node.js 支持 {#node-js-support}
+
+Vite 6 与 Vite 5 类似,支持 Node.js 18、20 和 22+。Node.js 21 的支持已被移除。Vite 在旧版本的 Node.js [生命周期终止](https://endoflife.date/nodejs) (EOL)后停止支持。Node.js 18 EOL 在 2025 年 4 月底,届时我们可能会发布一个新主要版本以提高所需的 Node.js 版本。
+
+### 实验性环境 API {#experimental-environment-api}
+
+Vite 正在通过新的环境 API 变得更加灵活。这些新 API 将允许框架作者提供更接近生产环境的开发体验,并为生态系统共享新的构建模块。如果你正在构建一个 SPA,使用 Vite 的单一客户端环境,一切将如以往一样工作。即使对于自定义 SSR 应用,Vite 6 也向后兼容。环境 API 的主要目标受众是框架作者。
+
+对于感兴趣的终端用户,[Sapphi](https://github.com/sapphi-red) 撰写了一篇很好的 [环境 API 介绍](https://green.sapphi.red/blog/increasing-vites-potential-with-the-environment-api) 指南。这是一个很好的起点,帮助你理解我们为何努力使 Vite 更加灵活。
+
+如果你是框架作者或 Vite 插件维护者,并希望利用新 API,你可以在 [环境 API 指南](https://main.vite.dev/guide/api-environment) 中了解更多信息。
+
+我们要感谢所有参与定义和实现新 API 的伙伴。这个故事始于 Vite 2 采用了由 [Rich Harris](https://github.com/Rich-Harris) 和 [SvelteKit](https://svelte.dev/docs/kit) 团队开创的无打包 SSR 开发方案。Vite 的 SSR 转换随后启发了 [Anthony Fu](https://github.com/antfu/) 和 [Pooya Parsa](https://github.com/pi0) 创建 vite-node 并改进 [Nuxt 的开发 SSR 方案](https://antfu.me/posts/dev-ssr-on-nuxt)。Anthony 之后使用 vite-node 为 [Vitest](https://vitest.dev) 提供支持,而 [Vladimir Sheremet](https://github.com/sheremet-va) 在维护 Vitest 的过程中也在不断改进它。2023 年初,Vladimir 开始将 vite-node 上游合并到 Vite Core 中,一年后我们在 Vite 5.1 中将其作为 Runtime API 发布。来自生态系统合作伙伴(特别感谢 Cloudflare 团队)的反馈推动我们对 Vite 的环境进行更雄心勃勃的重构。你可以在 [Patak 的 ViteConf 24 演讲](https://www.youtube.com/watch?v=WImor3HDyqU?si=EZ-rFJn4pDW3tUvp) 中了解更多关于这个故事的信息。
+
+Vite 团队的每个人都参与了新 API 的定义,该 API 是与生态系统中许多项目的反馈共同设计的。感谢所有参与者!如果你正在基于 Vite 构建框架、插件或工具,我们鼓励你参与进来。新 API 是实验性的。我们将与生态系统合作,审查新 API 的使用方式,并在下一个主要版本中稳定它们。如果你想提问或反馈意见,这里有一个 [开放的 GitHub 讨论](https://github.com/vitejs/vite/discussions/16358)。
+
+## 主要变化 {#main-changes}
+
+- [`resolve.conditions` 默认值](/guide/migration#default-value-for-resolve-conditions)
+- [JSON 序列化](/guide/migration#json-stringify)
+- [在 HTML 元素中扩展对资源引用的支持](/guide/migration#extended-support-of-asset-references-in-html-elements)
+- [postcss-load-config](/guide/migration#postcss-load-config)
+- [Sass 现在默认使用现代 API](/guide/migration#sass-now-uses-modern-api-by-default)
+- [在"库"模式下自定义 CSS 输出文件名](/guide/migration#customize-css-output-file-name-in-library-mode)
+- [以及更多仅影响少数用户的更改](/guide/migration#advanced)
+
+此外,还有一个新的 [破坏性变更](/changes/) 页面,列出了 Vite 中所有计划的、正在考虑的和过去的更改。
+
+## 迁移到 Vite 6 {#migrating-to-vite-6}
+
+对于大多数项目,升级到 Vite 6 应该是很直接的,但我们建议在升级前查看 [详细的迁移指南](/guide/migration)。
+
+完整的更改列表请参见 [Vite 6 更新日志](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md#500-2024-11-26)。
+
+## 致谢 {#acknowledgments}
+
+Vite 6 的发布离不开我们社区贡献者、下游维护者、插件作者和 [Vite 团队](/team) 的辛勤工作。我们感谢所有支持 Vite 开发的个人和公司。Vite 由 [VoidZero](https://voidzero.dev) 与 [StackBlitz](https://stackblitz.com/)、[Nuxt Labs](https://nuxtlabs.com/) 和 [Astro](https://astro.build) 合作呈现。特别感谢 [Vite 的 GitHub 赞助者](https://github.com/sponsors/vitejs) 和 [Vite 的 Open Collective](https://opencollective.com/vite) 上的赞助者。
diff --git a/blog/announcing-vite7.md b/blog/announcing-vite7.md
new file mode 100644
index 00000000..f9f77168
--- /dev/null
+++ b/blog/announcing-vite7.md
@@ -0,0 +1,97 @@
+---
+title: Vite 7.0 is out!
+author:
+ name: The Vite Team
+date: 2025-06-24
+sidebar: false
+head:
+ - - meta
+ - property: og:type
+ content: website
+ - - meta
+ - property: og:title
+ content: Announcing Vite 7
+ - - meta
+ - property: og:image
+ content: https://vite.dev/og-image-announcing-vite7.png
+ - - meta
+ - property: og:url
+ content: https://vite.dev/blog/announcing-vite7
+ - - meta
+ - property: og:description
+ content: Vite 7 Release Announcement
+ - - meta
+ - name: twitter:card
+ content: summary_large_image
+---
+
+# Vite 7.0 发布了! {#vite-7-0-is-out}
+
+_2025年6月24日_
+
+
+
+我们很高兴与大家分享 Vite 7 的发布!从 Evan You 向 Vite 仓库提交第一次 commit 至今已经过去 5 年了,当时没有人能预料到前端生态会发生如此巨大的变化。如今,大多数现代前端框架和工具正在协同工作,构建在 Vite 共享的基础设施之上。通过更高层次的共享,它们能够以更快的速度进行创新。Vite 现在每周被下载 3100 万次,在上次重大版本发布后的七个月内增长了 1400 万次下载量。
+
+今年,我们将迈出几个重要的步伐。首先,[ViteConf](https://viteconf.org) 将首次以线下形式举办!Vite 生态系统将于 10 月 9-10 日在阿姆斯特丹齐聚一堂!本次活动由 [JSWorld](https://jsworldconference.com/) 联合 [Bolt](https://bolt.new)、[VoidZero](https://voidzero.dev) 和 Vite 核心团队共同组织!我们已经成功举办过三届精彩的[ViteConf 线上活动](https://www.youtube.com/@viteconf/playlists),现在迫不及待地想要与大家面对面交流。欢迎查看演讲嘉宾名单并前往 [ViteConf 官网](https://viteconf.org) 获取门票信息。
+
+此外,[VoidZero](https://voidzero.dev/posts/announcing-voidzero-inc) 继续在构建面向 JavaScript 生态系统的开源统一开发工具链的使命中取得重大进展。在过去一年里,VoidZero 团队一直在开发 [Rolldown](https://rolldown.rs/) —— 一个基于 Rust 的下一代打包工具(bundler),作为现代化 Vite 核心的更广泛努力的一部分。你现在就可以通过使用 `rolldown-vite` 包来体验基于 Rolldown 的 Vite,替代默认的 `vite` 包。它是一个即插即用的替代方案,未来 Rolldown 将成为 Vite 的默认打包工具。切换后可以显著减少你的构建时间,尤其是对于较大的项目而言。更多信息请参阅 [Rolldown-Vite 宣布博文](https://voidzero.dev/posts/announcing-rolldown-vite) 和我们的 [迁移指南](https://vite.dev/rolldown)。
+
+通过 VoidZero 与 [NuxtLabs](https://nuxtlabs.com/) 的合作,Anthony Fu 正在致力于开发 Vite DevTools。它将为所有基于 Vite 的项目和框架提供更深入且富有洞察力的调试与分析功能。你可以阅读 [VoidZero 与 NuxtLabs 联手打造 Vite DevTools 的博客文章](https://voidzero.dev/posts/voidzero-nuxtlabs-vite-devtools) 了解更多信息。
+
+快速链接:
+
+- [英文文档](https://vite.dev)
+- 新增翻译:[فارسی](https://fa.vite.dev/)
+- 翻译版本:[简体中文](/)、[日本語](https://ja.vite.dev/)、[Español](https://es.vite.dev/)、[Português](https://pt.vite.dev/)、[한국어](https://ko.vite.dev/)、[Deutsch](https://de.vite.dev/)
+- [迁移指南](/guide/migration)
+- [GitHub 更新日志](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
+
+使用 [vite.new](https://vite.new) 在线体验 Vite 7,或者通过运行 `pnpm create vite` 在本地使用你偏好的框架搭建 Vite 项目。更多信息请查看[入门指南](/guide/)。
+
+我们诚邀你加入我们,帮助我们改进 Vite(加入超过 [1.1K 位 Vite Core 贡献者](https://github.com/vitejs/vite/graphs/contributors))、我们的依赖项、插件以及生态系统中的项目。了解更多信息,请参阅我们的[贡献指南](https://github.com/vitejs/vite/blob/main/CONTRIBUTING.md)。
+
+一个好的入门方法包括:[整理问题](https://github.com/vitejs/vite/issues)、[审阅 PR](https://github.com/vitejs/vite/pulls)、基于未解决问题提交测试 PR,或在 [讨论区](https://github.com/vitejs/vite/discussions) 以及 Vite Land 的 [帮助论坛](https://discord.com/channels/804011606160703521/1019670660856942652) 中为他人提供帮助。如有任何疑问,欢迎加入我们的 [Discord 社区](http://chat.vite.dev/),并在 [#contributing 频道](https://discord.com/channels/804011606160703521/804439875226173480) 中与我们交流。
+
+通过关注我们在 [Bluesky](https://bsky.app/profile/vite.dev)、[X(原 Twitter)](https://twitter.com/vite_js) 或 [Mastodon](https://webtoo.ls/@vite),保持更新并与更多基于 Vite 构建的开发者建立联系。
+
+## Node.js 支持 {#node-js-support}
+
+Vite 现在要求使用 Node.js 20.19+ 或 22.12+。由于 Node.js 18 已于 2025 年 4 月底达到[生命周期终点(EOL)](https://endoflife.date/nodejs),我们已不再支持该版本。
+
+我们要求使用这些新的 Node.js 版本范围,以确保 Node.js 可以无需启用标志即可支持 `require(esm)`。这使我们能够仅以 ESM 格式发布 Vite 7.0,同时不会阻止 CJS 模块通过 `require` 调用 Vite 的 JavaScript API。有关当前 ESM 在生态系统中的发展状况的详细分析,请查看 Anthony Fu 的文章 [《迈向纯 ESM》](https://antfu.me/posts/move-on-to-esm-only)。
+
+## 默认浏览器兼容性目标已更改为 Baseline Widely Available {#default-browser-target-changed-to-baseline-widely-available}
+
+[Baseline](https://web-platform-dx.github.io/web-features/) 为我们提供了明确的信息,指出了哪些 Web 平台特性在当今主流浏览器中可用。Baseline Widely Available,表示该功能已经十分成熟,可在多种设备和浏览器版本中正常工作,并且在各浏览器中至少已支持 30 个月。
+
+在 Vite 7 中,默认浏览器目标将从 `'modules'` 更改为新的默认值:`'baseline-widely-available'`。每当我们发布一个重大版本时,所支持的浏览器列表都会更新,以匹配与“Baseline Widely Available”特性兼容的最低浏览器版本。Vite 7.0 中 `build.target` 的默认浏览器值变化如下:
+
+- Chrome 87 → 107
+- Edge 88 → 107
+- Firefox 78 → 104
+- Safari 14.0 → 16.0
+
+这一变化为未来版本的浏览器兼容性带来了更高的可预测性。
+
+## Vitest {#vitest}
+
+对于 Vitest 用户而言,Vite 7.0 从 Vitest 3.2 开始得到支持。你可以阅读 [Vitest 3.2 发布博客](https://vitest.dev/blog/vitest-3-2.html),了解更多关于 Vitest 团队如何持续改进 Vite 测试功能的内容。
+
+## Environment API {#environment-api}
+
+Vite 6 是自 Vite 2 以来最具意义的一次重大发布,它通过 [全新的实验性 Environment API](https://vite.dev/blog/announcing-vite6.html#experimental-environment-api) 引入了多项新功能。我们暂时将这些新 API 保持为实验性状态,以便生态系统逐步评估它们在各类项目中的适用性并提供反馈。如果你正在基于 Vite 构建项目,我们鼓励你尝试使用这些新 API,并通过[此开放讨论话题](https://github.com/vitejs/vite/discussions/16358) 向我们提供你的使用反馈。
+
+在 Vite 7 中,我们新增了一个 `buildApp` 钩子,使插件能够协调环境的构建过程。详情请参阅[面向框架的 Environment API 指南](/guide/api-environment-frameworks.html#environments-during-build)。
+
+我们要感谢那些一直在测试新 API 并帮助我们稳定新功能的团队。例如,Cloudflare 团队宣布了其 Cloudflare Vite 插件的 1.0 版本发布,并正式支持 React Router v7。他们的插件展示了 Environment API 在运行时提供者方面的潜力。要了解更多关于他们的实现方式和未来计划,请查看文章 [“Just use Vite”… with the Workers runtime](https://blog.cloudflare.com/introducing-the-cloudflare-vite-plugin/)。
+
+## 迁移到 Vite 7 {#migrating-to-vite-7}
+
+从 Vite 6 升级到 Vite 7 应该是一次平滑的体验。我们移除了已弃用的功能,例如 Sass 的旧版 API 支持以及 `splitVendorChunkPlugin`,这些改动不会影响你的项目。我们仍然建议你在升级前查看[详细的迁移指南](/guide/migration)。
+
+所有变更的完整列表请见 [Vite 7 更新日志](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)。
+
+## 致谢 {#acknowledgments}
+
+Vite 7 由 [Vite 团队](/team) 在广大贡献者、下游维护者和插件开发者的帮助下精心打造而成。我们特别感谢 [sapphi-red](https://github.com/sapphi-red),以表彰他在 `rolldown-vite` 和本次发布中做出的出色工作。Vite 由 [VoidZero](https://voidzero.dev) 打造,并得到了 [Bolt](https://bolt.new) 和 [Nuxt Labs](https://nuxtlabs.com) 的合作支持。我们还要感谢我们的赞助商,包括 [Vite 的 GitHub 赞助计划](https://github.com/sponsors/vitejs) 和 [Vite 的 Open Collective 页面](https://opencollective.com/vite) 上的支持者。
diff --git a/changes/hotupdate-hook.md b/changes/hotupdate-hook.md
new file mode 100644
index 00000000..509bc435
--- /dev/null
+++ b/changes/hotupdate-hook.md
@@ -0,0 +1,122 @@
+# HMR `hotUpdate` 插件钩子 {#hmr-hotupdate-plugin-hook}
+
+::: tip 反馈
+可以在 [环境 API 讨论](https://github.com/vitejs/vite/discussions/16358) 中向我们提供反馈
+:::
+
+我们计划废弃 `handleHotUpdate` 插件钩子,转而使用能够感知 [环境 API](/guide/api-environment.md) 的 [`hotUpdate` 钩子](/guide/api-environment#the-hotupdate-hook),并通过 `create` 和 `delete` 来处理额外的监听事件。
+
+影响范围:`Vite 插件作者`
+
+::: warning 即将废弃
+`hotUpdate` 钩子最初在 `v6.0` 版本中引入。我们计划在未来的 major 版本中废弃 `handleHotUpdate` 钩子。我们目前还不建议你停止使用 `handleHotUpdate`。如果你想尝试并向我们提供反馈,你可以在你的 vite 配置文件中将 `future.removePluginHookHandleHotUpdate` 设置为 `"warn"`。
+:::
+
+## 动机 {#motivation}
+
+[`handleHotUpdate` 钩子](/guide/api-plugin.md#handlehotupdate) 可以让你执行自定义的模块热替换(HMR)更新处理。在 `HmrContext` 中,可以传入一个需要更新的模块列表。
+
+```ts
+interface HmrContext {
+ file: string
+ timestamp: number
+ modules: Array
+ read: () => string | Promise
+ server: ViteDevServer
+}
+```
+
+`handleHotUpdate` 钩子在所有环境中只调用一次,传入的模块只有来自客户端和 SSR 环境的混合信息。一旦框架开始使用自定义环境,就需要一个新的钩子为每个环境调用。
+
+新的 `hotUpdate` 钩子的工作方式与 `handleHotUpdate` 一样,但是它会在每个环境中被调用,并且会接收一个新的 `HotUpdateOptions` 实例:
+
+```ts
+interface HotUpdateOptions {
+ type: 'create' | 'update' | 'delete'
+ file: string
+ timestamp: number
+ modules: Array
+ read: () => string | Promise
+ server: ViteDevServer
+}
+```
+
+你可以像在其他插件钩子中一样,通过 `this.environment` 来访问当前的开发环境。现在,`modules` 列表只包含来自当前环境的模块节点。每个环境更新都可以定义不同的更新策略。
+
+这个钩子也会在处理额外的监听事件时被调用,而不仅仅是在 `'update'` 事件中。你可以使用 `type` 来区分这些事件。
+
+## 迁移指南 {#migration-guide}
+
+过滤并缩小受影响的模块列表,使 HMR 更加准确。
+
+```js
+handleHotUpdate({ modules }) {
+ return modules.filter(condition)
+}
+
+// 迁移至:
+
+hotUpdate({ modules }) {
+ return modules.filter(condition)
+}
+```
+
+返回一个空数组并执行完全重载:
+
+```js
+handleHotUpdate({ server, modules, timestamp }) {
+ // 手动使模块失效
+ const invalidatedModules = new Set()
+ for (const mod of modules) {
+ server.moduleGraph.invalidateModule(
+ mod,
+ invalidatedModules,
+ timestamp,
+ true
+ )
+ }
+ server.ws.send({ type: 'full-reload' })
+ return []
+}
+
+// 迁移至:
+
+hotUpdate({ modules, timestamp }) {
+ // 手动使模块失效
+ const invalidatedModules = new Set()
+ for (const mod of modules) {
+ this.environment.moduleGraph.invalidateModule(
+ mod,
+ invalidatedModules,
+ timestamp,
+ true
+ )
+ }
+ this.environment.hot.send({ type: 'full-reload' })
+ return []
+}
+```
+
+返回一个空数组并通过向客户端发送自定义事件来执行完全自定义的 HMR 处理:
+
+```js
+handleHotUpdate({ server }) {
+ server.ws.send({
+ type: 'custom',
+ event: 'special-update',
+ data: {}
+ })
+ return []
+}
+
+// 迁移至:
+
+hotUpdate() {
+ this.environment.hot.send({
+ type: 'custom',
+ event: 'special-update',
+ data: {}
+ })
+ return []
+}
+```
diff --git a/changes/index.md b/changes/index.md
new file mode 100644
index 00000000..b5392af7
--- /dev/null
+++ b/changes/index.md
@@ -0,0 +1,27 @@
+# 破坏性变更 {#breaking-changes}
+
+Vite 中的破坏性变更列表,包括 API 废弃、移除和变更。在你的 Vite 配置中,大多数下面的变更可以使用 [`future` 选项](/config/shared-options.html#future) 进行选择。
+
+## 计划中 {#planned}
+
+这些变更计划在 Vite 的下一个主要版本中进行。我们会通过废弃或使用警告来尽可能地引导你,同时我们也正在联系框架、插件的作者以及用户来实施这些变更。
+
+- _目前还没有计划中的变更_
+
+## 考虑中 {#considering}
+
+这些变更正在考虑中,通常是希望改进当前使用模式的实验性 API。由于这里并未列出所有的变更,所以请访问 [Vite GitHub Discussions 中的 Experimental 标签](https://github.com/vitejs/vite/discussions/categories/feedback?discussions_q=label%3Aexperimental+category%3AFeedback) 来查看完整的列表。
+
+我们目前还不建议你切换到这些 API。我们将它们包含在 Vite 中是为了帮助我们收集反馈。请查看这些提案,并在每个提案相关联的 GitHub Discussions 中告诉我们它们在你的使用场景中的表现如何。
+
+- [钩子函数中的 `this.environment`](/changes/this-environment-in-hooks)
+- [HMR `hotUpdate` 插件钩子](/changes/hotupdate-hook)
+- [迁移到基于环境的API](/changes/per-environment-apis)
+- [使用 `ModuleRunner` API 进行服务端渲染](/changes/ssr-using-modulerunner)
+- [构建过程中的共享插件](/changes/shared-plugins-during-build)
+
+## 历史 {#past}
+
+以下的变更已经被实施或者撤销。在当前的主要版本中,它们已经不再相关。
+
+- _目前还没有历史的变更_
diff --git a/changes/per-environment-apis.md b/changes/per-environment-apis.md
new file mode 100644
index 00000000..f384ed9a
--- /dev/null
+++ b/changes/per-environment-apis.md
@@ -0,0 +1,33 @@
+# 迁移到基于环境的API {#move-to-per-environment-apis}
+
+::: tip 反馈
+可以在 [环境 API 讨论](https://github.com/vitejs/vite/discussions/16358) 中向我们提供反馈
+:::
+
+`ViteDevServer` 中与 module graph 和 modules transforms 相关的多个 API 已移至 `DevEnvironment` 实例。
+
+影响范围:`Vite 插件作者`
+
+::: warning 即将废弃
+`环境`实例首次在 `v6.0` 中引入。计划在未来的 major 版本中废弃现在的 `server.moduleGraph` 和其他方法。我们不建议你现在就放弃 server 方法。要识别你的使用情况,请在你的 vite 配置中设置以下。
+
+```ts
+future: {
+ removeServerModuleGraph: 'warn',
+ removeServerTransformRequest: 'warn',
+}
+```
+
+:::
+
+## 动机 {#motivation}
+
+在 Vite v5 及之前的版本中,一个 Vite 开发服务器总是有两个环境(`client` 和 `ssr`)。`server.moduleGraph` 混合了来自这两个环境的模块。节点通过 `clientImportedModules` 和 `ssrImportedModules` 列表连接(但每种环境只维护一个 `importers` 列表)。转换后的模块由一个 `id` 和一个 `ssr` 布尔值表示。该布尔值需要传递给 API,例如 `server.moduleGraph.getModuleByUrl(url, ssr)` 和 `server.transformRequest(url, { ssr })`。
+
+在 Vite v6 中,现在可以创建任意数量的自定义环境(`client`, `ssr`, `edge`等)。单一的 `ssr` 布尔值已经不够用了。我们没有将 API 改为 `server.transformRequest(url, { environment })`,而是将这些方法移到了环境实例中,这样就可以在没有 Vite dev 服务器的情况下调用这些方法。
+
+## 迁移指南 {#migration-guide}
+
+- `server.moduleGraph` -> [`environment.moduleGraph`](/guide/api-environment-instances#separate-module-graphs)
+- `server.transformRequest(url, ssr)` -> `environment.transformRequest(url)`
+- `server.warmupRequest(url, ssr)` -> `environment.warmupRequest(url)`
diff --git a/changes/shared-plugins-during-build.md b/changes/shared-plugins-during-build.md
new file mode 100644
index 00000000..3e5d243a
--- /dev/null
+++ b/changes/shared-plugins-during-build.md
@@ -0,0 +1,81 @@
+# 构建过程中的共享插件 {#shared-plugins-during-build}
+
+::: tip 反馈
+可以在 [环境 API 讨论](https://github.com/vitejs/vite/discussions/16358) 中向我们提供反馈
+:::
+
+查看 [构建过程中的共享插件](/guide/api-environment-plugins.md#shared-plugins-during-build).
+
+影响范围:`Vite 插件作者`
+
+::: warning 未来默认值更改
+`builder.sharedConfigBuild` 最初在 `v6.0` 版本中被引入。你可以将它设置为 `true`,以此来检查你的插件与共享配置是如何配合工作的。一旦插件生态系统准备就绪,我们希望能得到关于在未来的主要版本中改变默认设置的反馈。
+:::
+
+## 动机 {#motivation}
+
+调整开发和构建插件管道。
+
+## 迁移指南 {#migration-guide}
+
+为实现跨环境共享插件,插件状态必须以当前环境为关键。以下形式的插件将计算所有环境中已转换模块的数量。
+
+```js
+function CountTransformedModulesPlugin() {
+ let transformedModules
+ return {
+ name: 'count-transformed-modules',
+ buildStart() {
+ transformedModules = 0
+ },
+ transform(id) {
+ transformedModules++
+ },
+ buildEnd() {
+ console.log(transformedModules)
+ },
+ }
+}
+```
+
+如果我们想要计算每个环境中已转换模块的数量,我们需要维护一个映射表。
+
+```js
+function PerEnvironmentCountTransformedModulesPlugin() {
+ const state = new Map()
+ return {
+ name: 'count-transformed-modules',
+ perEnvironmentStartEndDuringDev: true,
+ buildStart() {
+ state.set(this.environment, { count: 0 })
+ }
+ transform(id) {
+ state.get(this.environment).count++
+ },
+ buildEnd() {
+ console.log(this.environment.name, state.get(this.environment).count)
+ }
+ }
+}
+```
+
+为了简化这种模式,Vite 导出了一个 `perEnvironmentState` 助手:
+
+```js
+function PerEnvironmentCountTransformedModulesPlugin() {
+ const state = perEnvironmentState<{ count: number }>(() => ({ count: 0 }))
+ return {
+ name: 'count-transformed-modules',
+ perEnvironmentStartEndDuringDev: true,
+ buildStart() {
+ state(this).count = 0
+ }
+ transform(id) {
+ state(this).count++
+ },
+ buildEnd() {
+ console.log(this.environment.name, state(this).count)
+ }
+ }
+}
+```
diff --git a/changes/ssr-using-modulerunner.md b/changes/ssr-using-modulerunner.md
new file mode 100644
index 00000000..623d8e0e
--- /dev/null
+++ b/changes/ssr-using-modulerunner.md
@@ -0,0 +1,21 @@
+# 使用 ModuleRunner API 进行服务端渲染 {#ssr-using-modulerunner-api}
+
+::: tip 反馈
+可以在 [环境 API 讨论](https://github.com/vitejs/vite/discussions/16358) 中向我们提供反馈
+:::
+
+`server.ssrLoadModule` 已被从 [Module Runner](/guide/api-environment#modulerunner) 导入所取代。
+
+影响范围:`Vite 插件作者`
+
+::: warning 即将废弃
+`ModuleRunner` 最初在 `v6.0` 版本中被引入。我们计划在未来的主要版本中废弃 `server.ssrLoadModule`。如果想识别你的使用情况,可以在你的 vite 配置文件中将 `future.removeSsrLoadModule` 设置为 `"warn"`。
+:::
+
+## 动机 {#motivation}
+
+`server.ssrLoadModule(url)` 仅允许在 `ssr` 环境中导入模块,并且只能在与 Vite 开发服务器相同的进程中执行这些模块。对于具有自定义环境的应用程序,每个环境都关联一个 `ModuleRunner`,该模块可能在单独的线程或进程中运行。为了导入模块,我们现在使用 `moduleRunner.import(url)`。
+
+## 迁移指南 {#migration-guide}
+
+请查看 [用于框架的环境 API 指南](../guide/api-environment-frameworks.md)。
diff --git a/changes/this-environment-in-hooks.md b/changes/this-environment-in-hooks.md
new file mode 100644
index 00000000..6e1d8d29
--- /dev/null
+++ b/changes/this-environment-in-hooks.md
@@ -0,0 +1,43 @@
+# 钩子函数中的 this.environment {#this-environment-in-hooks}
+
+::: tip 反馈
+可以在 [环境 API 讨论](https://github.com/vitejs/vite/discussions/16358) 中向我们提供反馈
+:::
+
+在 Vite 6 版本之前,只有两个环境是可用的:`client` 和 `ssr`。在 `resolveId`、`load` 和 `transform` 中的 `options.ssr` 插件钩子参数,允许插件的作者在处理插件钩子中的模块时区分这两个环境。在 Vite 6 版本中,一个 Vite 应用可以根据需要定义任意数量的命名环境。我们在插件的上下文中引入了 `this.environment`,以便在钩子中与当前模块的环境进行交互。
+
+影响范围:`Vite 插件作者`
+
+::: warning 即将废弃
+`this.environment` 最初在 `v6.0` 版本中被引入。我们计划在未来的 major 版本中废弃 `options.ssr`。到那时,我们会开始建议你将你的插件迁移到新的 API。如果想识别你的使用情况,可以在你的 vite 配置文件中将 `future.removePluginHookSsrArgument` 设置为 `"warn"`。
+:::
+
+## 动机 {#motivation}
+
+`this.environment` 不仅可以让插件钩子实现知道当前的环境名称,还可以让它访问到环境配置选项、模块图信息和转换管道(`environment.config`、`environment.moduleGraph`、`environment.transformRequest()`)。在上下文中可以使用环境实例,这让插件的作者可以避免依赖整个开发服务器(通常是在通过 `configureServer` 钩子启动时进行缓存)。
+
+## 迁移指南 {#migration-guide}
+
+对于现有的插件,如果想要快速迁移,可以在 `resolveId`、`load` 和 `transform` 钩子中,将 `options.ssr` 参数替换为 `this.environment.config.consumer === 'server'`:
+
+```ts
+import { Plugin } from 'vite'
+
+export function myPlugin(): Plugin {
+ return {
+ name: 'my-plugin',
+ resolveId(id, importer, options) {
+ const isSSR = options.ssr // [!code --]
+ const isSSR = this.environment.config.consumer === 'server' // [!code ++]
+
+ if (isSSR) {
+ // SSR 特有逻辑
+ } else {
+ // 客户端特有逻辑
+ }
+ },
+ }
+}
+```
+
+对于更稳定、长期的实现,插件钩子应该处理 [多个环境](/guide/api-environment-plugins.html#accessing-the-current-environment-in-hooks),并使用细粒度的环境选项,而不是依赖于环境的名称。
diff --git a/config/build-options.md b/config/build-options.md
index edcb795b..b95f8e16 100644
--- a/config/build-options.md
+++ b/config/build-options.md
@@ -1,30 +1,27 @@
# 构建选项 {#build-options}
-## build.target {#build-target}
+除非另有说明,本节中的选项仅适用于构建。
+
+## build.target
- **类型:** `string | string[]`
-- **默认:** `'modules'`
+- **默认:** `'baseline-widely-available'`
- **相关内容:** [浏览器兼容性](/guide/build#browser-compatibility)
-设置最终构建的浏览器兼容目标。默认值是一个 Vite 特有的值——`'modules'`,这是指 [支持原生 ES 模块](https://caniuse.com/es6-module)、[原生 ESM 动态导入](https://caniuse.com/es6-module-dynamic-import) 和 [`import.meta`](https://caniuse.com/mdn-javascript_operators_import_meta) 的浏览器。
-
-另一个特殊值是 “esnext” —— 即假设有原生动态导入支持,并且将会转译得尽可能小:
+最终软件包的浏览器兼容性目标。默认值是 Vite 的一个特殊值 `'baseline-widely-available'`,该值针对的是包含在 2025 年 5 月 1 日广泛可用的 [Baseline](https://web-platform-dx.github.io/web-features/) 中的浏览器。具体来说,它是 `['chrome107', 'edge107', 'firefox104', 'safari16']`。
-- 如果 [`build.minify`](#build-minify) 选项为 `'terser'`, `'esnext'` 将会强制降级为 `'es2019'`。
-- 其他情况下将完全不会执行转译。
+另一个特殊值是 `'esnext'` —— 即假设有原生动态导入支持,并只执行最低限度的转译。
转换过程将会由 esbuild 执行,并且此值应该是一个合法的 [esbuild 目标选项](https://esbuild.github.io/api/#target)。自定义目标也可以是一个 ES 版本(例如:`es2015`)、一个浏览器版本(例如:`chrome58`)或是多个目标组成的一个数组。
注意:如果代码包含不能被 `esbuild` 安全地编译的特性,那么构建将会失败。查看 [esbuild 文档](https://esbuild.github.io/content-types/#javascript) 获取更多细节。
-## build.polyfillModulePreload {#build-polyfillmodulepreload}
+## build.modulePreload {#build-modulepreload}
-- **类型:** `boolean`
-- **默认值:** `true`
+- **类型:** `boolean | { polyfill?: boolean, resolveDependencies?: ResolveModulePreloadDependenciesFn }`
+- **默认值:** `{ polyfill: true }`
-用于决定是否自动注入 [module preload 的 polyfill](https://guybedford.com/es-module-preloading-integrity#modulepreload-polyfill).
-
-如果设置为 `true`,此 polyfill 会被自动注入到每个 `index.html` 入口的 proxy 模块中。如果是通过 `build.rollupOptions.input` 将构建配置为使用非 html 的自定义入口,那么则需要在你自定义入口中手动引入 polyfill:
+默认情况下,一个 [模块预加载 polyfill](https://guybedford.com/es-module-preloading-integrity#modulepreload-polyfill) 会被自动注入。该 polyfill 会自动注入到每个 `index.html` 入口的的代理模块中。如果构建通过 `build.rollupOptions.input` 被配置为了使用非 HTML 入口的形式,那么必须要在你的自定义入口中手动引入该 polyfill:
```js
import 'vite/modulepreload-polyfill'
@@ -32,6 +29,51 @@ import 'vite/modulepreload-polyfill'
注意:此 polyfill **不适用于** [Library 模式](/guide/build#library-mode)。如果你需要支持不支持动态引入的浏览器,你应该避免在你的库中使用此选项。
+此 polyfill 可以通过 `{ polyfill: false }` 来禁用。
+
+每个动态导入要预加载的块列表将由 Vite 计算。默认情况下,在载入这些依赖时,会使用一个包含 `base` 的绝对路径。如果 `base` 是相对路径(`''` 或者 `'./'`),解析时则会使用 `import.meta.url`,以避免出现依赖于最终部署基路径的绝对路径。
+
+目前有一个实验性功能支持使用 `resolveDependencies` 函数对依赖项列表及其路径进行细粒度控制。可以在这里 [提供反馈](https://github.com/vitejs/vite/discussions/13841)。它期望接收一个 `ResolveModulePreloadDependenciesFn` 类型的函数:
+
+```ts
+type ResolveModulePreloadDependenciesFn = (
+ url: string,
+ deps: string[],
+ context: {
+ hostId: string
+ hostType: 'html' | 'js'
+ },
+) => string[]
+```
+
+`resolveDependencies` 函数会在每次动态导入时被调用,并包含其依赖的 chunk 列表。同时,它也会在入口 HTML 文件中导入每个 chunk 时被调用。你可以返回一个新的依赖数组,其中可以过滤掉或注入更多的依赖,或修改它们的路径。`deps` 路径是相对于 `build.outDir` 的。返回值应是对于 `build.outDir` 的相对路径。
+
+```js twoslash
+/** @type {import('vite').UserConfig} */
+const config = {
+ // prettier-ignore
+ build: {
+// ---cut-before---
+modulePreload: {
+ resolveDependencies: (filename, deps, { hostId, hostType }) => {
+ return deps.filter(condition)
+ },
+},
+// ---cut-after---
+ },
+}
+```
+
+解析得到的依赖路径可以再在之后使用 [`experimental.renderBuiltUrl`](../guide/build.md#advanced-base-options) 更改。
+
+## build.polyfillModulePreload {#build-polyfillmodulepreload}
+
+- **类型:** `boolean`
+- **默认:** `true`
+- **已废弃** 请使用 `build.modulePreload.polyfill` 替代
+
+是否自动注入一个 [模块预加载 polyfill](https://guybedford.com/es-module-preloading-integrity#modulepreload-polyfill)。
+
## build.outDir {#build-outdir}
- **类型:** `string`
@@ -44,16 +86,18 @@ import 'vite/modulepreload-polyfill'
- **类型:** `string`
- **默认:** `assets`
-指定生成静态资源的存放路径(相对于 `build.outDir`)。
+指定生成静态资源的存放路径(相对于 `build.outDir`)。在 [库模式](/guide/build#library-mode) 下不能使用。
## build.assetsInlineLimit {#build-assetsinlinelimit}
-- **类型:** `number`
-- **默认:** `4096` (4kb)
+- **类型:** `number` | `((filePath: string, content: Buffer) => boolean | undefined)`
+- **默认:** `4096` (4 KiB)
小于此阈值的导入或引用资源将内联为 base64 编码,以避免额外的 http 请求。设置为 `0` 可以完全禁用此项。
-Git LFS 占位符会自动排除在内联之外,因为它们不包含它们所表示的文件的内容。
+如果传入了一个回调函数,可以通过返回一个布尔值来选择是否加入。如果没有返回任何内容,那么就会应用默认的逻辑。
+
+Git LFS 占位符会自动排除在内联之外,因为它们不包含其所表示的文件的内容。
:::tip 注意
如果你指定了 `build.lib`,那么 `build.assetsInlineLimit` 将被忽略,无论文件大小或是否为 Git LFS 占位符,资源都会被内联。
@@ -64,7 +108,7 @@ Git LFS 占位符会自动排除在内联之外,因为它们不包含它们所
- **类型:** `boolean`
- **默认:** `true`
-启用/禁用 CSS 代码拆分。当启用时,在异步 chunk 中导入的 CSS 将内联到异步 chunk 本身,并在其被加载时插入。
+启用/禁用 CSS 代码拆分。当启用时,在异步 chunk 中导入的 CSS 将内联到异步 chunk 本身,并在其被加载时一并获取。
如果禁用,整个项目中的所有 CSS 将被提取到一个 CSS 文件中。
@@ -72,10 +116,10 @@ Git LFS 占位符会自动排除在内联之外,因为它们不包含它们所
如果指定了 `build.lib`,`build.cssCodeSplit` 会默认为 `false`。
:::
-## build.cssTarget
+## build.cssTarget {#build-csstarget}
- **类型:** `string | string[]`
-- **默认值:** 与 [`build.target`](/config/#build-target) 一致
+- **默认值:** 与 [`build.target`](#build-target) 一致
此选项允许用户为 CSS 的压缩设置一个不同的浏览器 target,此处的 target 并非是用于 JavaScript 转写目标。
@@ -83,18 +127,25 @@ Git LFS 占位符会自动排除在内联之外,因为它们不包含它们所
最直观的示例是当你要兼容的场景是安卓微信中的 webview 时,它支持大多数现代的 JavaScript 功能,但并不支持 [CSS 中的 `#RGBA` 十六进制颜色符号](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#rgb_colors)。
这种情况下,你需要将 `build.cssTarget` 设置为 `chrome61`,以防止 vite 将 `rgba()` 颜色转化为 `#RGBA` 十六进制符号的形式。
+## build.cssMinify {#build-cssminify}
+
+- **类型:** `boolean | 'esbuild' | 'lightningcss'`
+- **默认:** 对于客户端,与 [`build.minify`](#build-minify) 相同;对于 SSR,为 `'esbuild'`
+
+此选项允许用户覆盖 CSS 最小化压缩的配置,而不是使用默认的 `build.minify`,这样你就可以单独配置 JS 和 CSS 的最小化压缩方式。Vite 默认使用 `esbuild` 来最小化 CSS。将此选项设置为 `'lightningcss'` 可以改用 [Lightning CSS](https://lightningcss.dev/minification.html) 进行压缩。设置为该项,便可以使用 [`css.lightningcss`](./shared-options.md#css-lightningcss) 选项来进行配置。
+
## build.sourcemap {#build-sourcemap}
- **类型:** `boolean | 'inline' | 'hidden'`
- **默认:** `false`
-构建后是否生成 source map 文件。如果为 `true`,将会创建一个独立的 source map 文件。如果为 `'inline'`,source map 将作为一个 data URI 附加在输出文件中。`'hidden'` 的工作原理与 `'true'` 相似,只是 bundle 文件中相应的注释将不被保留。
+构建后是否生成 source map 文件。如果为 `true`,将会创建一个独立的 source map 文件。如果为 `'inline'`,source map 将作为一个 data URI 附加在输出文件中。`'hidden'` 的工作原理与 `true` 相似,只是 bundle 文件中相应的注释将不被保留。
## build.rollupOptions {#build-rollupoptions}
-- **类型:** [`RollupOptions`](https://rollupjs.org/guide/en/#big-list-of-options)
+- **类型:** [`RollupOptions`](https://cn.rollupjs.org/configuration-options/)
-自定义底层的 Rollup 打包配置。这与从 Rollup 配置文件导出的选项相同,并将与 Vite 的内部 Rollup 选项合并。查看 [Rollup 选项文档](https://rollupjs.org/guide/en/#big-list-of-options) 获取更多细节。
+自定义底层的 Rollup 打包配置。这与从 Rollup 配置文件导出的选项相同,并将与 Vite 的内部 Rollup 选项合并。查看 [Rollup 选项文档](https://cn.rollupjs.org/configuration-options/) 获取更多细节。
## build.commonjsOptions {#build-commonjsoptions}
@@ -111,10 +162,28 @@ Git LFS 占位符会自动排除在内联之外,因为它们不包含它们所
## build.lib {#build-lib}
-- **类型:** `{ entry: string, name?: string, formats?: ('es' | 'cjs' | 'umd' | 'iife')[], fileName?: string | ((format: ModuleFormat) => string) }`
+- **类型:** `{ entry: string | string[] | { [entryAlias: string]: string }, name?: string, formats?: ('es' | 'cjs' | 'umd' | 'iife')[], fileName?: string | ((format: ModuleFormat, entryName: string) => string), cssFileName?: string }`
- **相关内容:** [库模式](/guide/build#library-mode)
-构建为库。`entry` 是必须的因为库不能使用 HTML 作为入口。`name` 则是暴露的全局变量,在 `formats` 包含 `'umd'` 或 `'iife'` 时是必须的。默认 `formats` 是 `['es', 'umd']` 。`fileName` 是输出的包文件名,默认 `fileName` 是 `package.json` 的 `name` 选项,同时,它还可以被定义为参数为 `format` 的函数。
+以库的形式构建。`entry` 是必需的,因为库不能使用 HTML 作为入口。`name` 是暴露的全局变量,当 `formats` 包括 `'umd'` 或 `'iife'` 时必须使用。默认的 `formats` 为 `['es'、'umd']`,如果使用多个入口,则为 `['es'、'cjs']`。
+
+`fileName` 是软件包输出文件的名称,默认为 `package.json` 中的 `"name"`。它也可以定义为以 `format` 和 `entryName` 为参数的函数,并返回文件名。
+
+如果软件包导入了 CSS,`cssFileName` 可用于指定 CSS 输出文件的名称。如果设置为字符串,则默认值与 `fileName` 相同,否则也会返回到 `package.json` 中的 `"name"`。
+
+```js twoslash [vite.config.js]
+import { defineConfig } from 'vite'
+
+export default defineConfig({
+ build: {
+ lib: {
+ entry: ['src/main.js'],
+ fileName: (format, entryName) => `my-lib-${entryName}.${format}.js`,
+ cssFileName: 'my-lib-style',
+ },
+ },
+})
+```
## build.manifest {#build-manifest}
@@ -122,7 +191,9 @@ Git LFS 占位符会自动排除在内联之外,因为它们不包含它们所
- **默认:** `false`
- **相关内容:** [后端集成](/guide/backend-integration)
-当设置为 `true`,构建后将会生成 `manifest.json` 文件,包含了没有被 hash 过的资源文件名和 hash 后版本的映射。可以为一些服务器框架渲染时提供正确的资源引入链接。当该值为一个字符串时,它将作为 manifest 文件的名字。
+是否生成一个 manifest 文件,包含了没有被 hash 过的资源文件名和 hash 后版本的映射,然后服务器框架可使用该映射来呈现正确的资源引入链接。
+
+当值为字符串时,将用作相对于 `build.outDir` 的 manifest 文件路径。设置为 `true` 时,路径将是 `.vite/manifest.json`。
## build.ssrManifest {#build-ssrmanifest}
@@ -130,20 +201,36 @@ Git LFS 占位符会自动排除在内联之外,因为它们不包含它们所
- **默认值:** `false`
- **相关链接:** [服务端渲染](/guide/ssr)
-当设置为 `true` 时,构建也将生成 SSR 的 manifest 文件,以确定生产中的样式链接与资产预加载指令。当该值为一个字符串时,它将作为 manifest 文件的名字。
+是否生成 SSR 的 manifest 文件,以确定生产中的样式链接与资源预加载指令。
+
+当值为字符串时,将用作相对于 `build.outDir` 的 manifest 文件路径。设置为 `true` 时,路径将是 `.vite/ssr-manifest.json`。
## build.ssr {#build-ssr}
- **类型:** `boolean | string`
-- **默认值:** `undefined`
-- **相关链接:** [Server-Side Rendering](/guide/ssr)
+- **默认值:** `false`
+- **相关链接:** [服务端渲染](/guide/ssr)
生成面向 SSR 的构建。此选项的值可以是字符串,用于直接定义 SSR 的入口,也可以为 `true`,但这需要通过设置 `rollupOptions.input` 来指定 SSR 的入口。
+## build.emitAssets
+
+- **类型:** `boolean`
+- **默认:** `false`
+
+在非客户端的构建过程中,静态资源并不会被输出,因为我们默认它们会作为客户端构建的一部分被输出。这个选项允许框架在其他环境的构建中强制输出这些资源。而将这些资源合并起来则是框架在构建后步骤中的责任。
+
+## build.ssrEmitAssets
+
+- **类型:** `boolean`
+- **默认:** `false`
+
+在 SSR 构建期间,静态资源不会被输出,因为它们通常被认为是客户端构建的一部分。这个选项允许框架强制在客户端和 SSR 构建中都输出它们。将静态资源在构建后合并是框架的责任。一旦环境 API 稳定,这个选项将被 `build.emitAssets` 替代。
+
## build.minify {#build-minify}
- **类型:** `boolean | 'terser' | 'esbuild'`
-- **默认:** `'esbuild'`
+- **默认:** 客户端构建默认为`'esbuild'`,SSR构建默认为 `false`
设置为 `false` 可以禁用最小化混淆,或是用来指定使用哪种混淆器。默认为 [Esbuild](https://github.com/evanw/esbuild),它比 terser 快 20-40 倍,压缩率只差 1%-2%。[Benchmarks](https://github.com/privatenumber/minification-benchmarks)
@@ -161,6 +248,8 @@ npm add -D terser
传递给 Terser 的更多 [minify 选项](https://terser.org/docs/api-reference#minify-options)。
+此外,你还可以传递一个 `maxWorkers: number` 选项来指定最大的工作线程数。默认为 CPU 核心数减 1。
+
## build.write {#build-write}
- **类型:** `boolean`
@@ -175,6 +264,13 @@ npm add -D terser
默认情况下,若 `outDir` 在 `root` 目录下,则 Vite 会在构建时清空该目录。若 `outDir` 在根目录之外则会抛出一个警告避免意外删除掉重要的文件。可以设置该选项来关闭这个警告。该功能也可以通过命令行参数 `--emptyOutDir` 来使用。
+## build.copyPublicDir {#build-copypublicdir}
+
+- **类型:** `boolean`
+- **默认:** `true`
+
+默认情况下,Vite 会在构建阶段将 `publicDir` 目录中的所有文件复制到 `outDir` 目录中。可以通过设置该选项为 `false` 来禁用该行为。
+
## build.reportCompressedSize {#build-reportcompressedsize}
- **类型:** `boolean`
@@ -187,11 +283,11 @@ npm add -D terser
- **类型:** `number`
- **默认:** `500`
-规定触发警告的 chunk 大小。(以 kbs 为单位)
+规定触发警告的 chunk 大小。(以 kB 为单位)。它将与未压缩的 chunk 大小进行比较,因为 [JavaScript 大小本身与执行时间相关](https://v8.dev/blog/cost-of-javascript-2019)。
## build.watch {#build-watch}
-- **类型:** [`WatcherOptions`](https://rollupjs.org/guide/en/#watch-options)`| null`
+- **类型:** [`WatcherOptions`](https://cn.rollupjs.org/configuration-options/#watch)`| null`
- **默认:** `null`
设置为 `{}` 则会启用 rollup 的监听器。对于只在构建阶段或者集成流程使用的插件很常用。
diff --git a/config/dep-optimization-options.md b/config/dep-optimization-options.md
index 00ddfdaf..ae19813b 100644
--- a/config/dep-optimization-options.md
+++ b/config/dep-optimization-options.md
@@ -2,13 +2,15 @@
- **相关内容:** [依赖预构建](/guide/dep-pre-bundling)
-## optimizeDeps.entries {#optimizedeps-entries}
+除非另有说明,本节中的选项仅适用于依赖优化器,该优化器仅在开发环境中使用。
+
+## optimizeDeps.entries
- **类型:** `string | string[]`
默认情况下,Vite 会抓取你的 `index.html` 来检测需要预构建的依赖项(忽略了`node_modules`、`build.outDir`、`__tests__` 和 `coverage`)。如果指定了 `build.rollupOptions.input`,Vite 将转而去抓取这些入口点。
-如果这两者都不合你意,则可以使用此选项指定自定义条目——该值需要遵循 [fast-glob 模式](https://github.com/mrmlnc/fast-glob#basic-syntax) ,或者是相对于 Vite 项目根目录的匹配模式数组。当显式声明了 `optimizeDeps.entries` 时默认只有 `node_modules` 和 `build.outDir` 文件夹会被忽略。如果还需忽略其他文件夹,你可以在模式列表中使用以 `!` 为前缀的、用来匹配忽略项的模式。
+如果这两者都不合你意,则可以使用此选项指定自定义条目——该值需要遵循 [tinyglobby 模式](https://github.com/SuperchupuDev/tinyglobby) ,或者是相对于 Vite 项目根目录的匹配模式数组。当显式声明了 `optimizeDeps.entries` 时默认只有 `node_modules` 和 `build.outDir` 文件夹会被忽略。如果还需忽略其他文件夹,你可以在模式列表中使用以 `!` 为前缀的、用来匹配忽略项的模式。对于明确包含字符串 `node_modules` 的模式,不会忽略 `node_modules`。
## optimizeDeps.exclude {#optimizedeps-exclude}
@@ -19,11 +21,13 @@
:::warning CommonJS
CommonJS 的依赖不应该排除在优化外。如果一个 ESM 依赖被排除在优化外,但是却有一个嵌套的 CommonJS 依赖,则应该为该 CommonJS 依赖添加 `optimizeDeps.include`。例如:
-```js
+```js twoslash
+import { defineConfig } from 'vite'
+// ---cut---
export default defineConfig({
optimizeDeps: {
- include: ['esm-dep > cjs-dep']
- }
+ include: ['esm-dep > cjs-dep'],
+ },
})
```
@@ -35,11 +39,33 @@ export default defineConfig({
默认情况下,不在 `node_modules` 中的,链接的包不会被预构建。使用此选项可强制预构建链接的包。
-## optimizeDeps.esbuildOptions {#optimizedeps-esbuildoptions}
+**实验性:** 如果你使用的是一个有很多深层导入的库,你也可以指定一个尾部的 glob 模式来一次性地预构建所有深层导入。这将避免在使用新的深层导入时不断地预构建。可以在此 [提供反馈](https://github.com/vitejs/vite/discussions/15833)。例如:
+
+```js twoslash
+import { defineConfig } from 'vite'
+// ---cut---
+export default defineConfig({
+ optimizeDeps: {
+ include: ['my-lib/components/**/*.vue'],
+ },
+})
+```
+
+## optimizeDeps.esbuildOptions {#optimizedeps-esbuild-options}
-- **类型:** [`EsbuildBuildOptions`](https://esbuild.github.io/api/#simple-options)
+- **类型:** [`Omit`](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys)`<`[`EsbuildBuildOptions`](https://esbuild.github.io/api/#general-options)`,
+| 'bundle'
+| 'entryPoints'
+| 'external'
+| 'write'
+| 'watch'
+| 'outdir'
+| 'outfile'
+| 'outbase'
+| 'outExtension'
+| 'metafile'>`
-在部署扫描和优化过程中传递给 esbuild 的选项。
+在依赖扫描和优化过程中传递给 esbuild 的选项。
某些选项进行了省略,因为修改它们与 Vite 的优化方案并不兼容。
@@ -51,3 +77,40 @@ export default defineConfig({
- **类型:** `boolean`
设置为 `true` 可以强制依赖预构建,而忽略之前已经缓存过的、已经优化过的依赖。
+
+## optimizeDeps.noDiscovery {#optimizedeps-no-discovery}
+
+- **类型:** `boolean`
+- **默认:** `false`
+
+设置为 true 时,自动依赖项发现将被禁用,并且仅优化 `optimizeDeps.include` 中列出的依赖项。在开发过程中,仅 CJS 依赖项必须存在于 `optimizeDeps.include` 中。
+
+## optimizeDeps.holdUntilCrawlEnd
+
+- **实验性:** [提供反馈](https://github.com/vitejs/vite/discussions/15834)
+- **类型:** `boolean`
+- **默认:** `true`
+
+当该功能被启用时,系统会在冷启动时保持第一个优化的依赖结果,直到所有的静态导入都被检索完毕。这样可以避免因为发现新的依赖项而触发新的公共 chunk 生成,从而需要刷新整个页面。如果通过扫描和在 `include` 中明确定义的方式能找到所有的依赖项,那么最好关闭这个功能,这样浏览器可以并行处理更多的请求。
+
+## optimizeDeps.disabled {#optimizedeps-disabled}
+
+- **已废弃**
+- **实验性:** [提供反馈](https://github.com/vitejs/vite/discussions/13839)
+- **类型:** `boolean | 'build' | 'dev'`
+- **默认:** `'build'`
+
+此选项已被弃用。从 Vite 5.1 版本开始,构建过程中对依赖项的预打包已经被移除。将 `optimizeDeps.disabled` 设置为 `true` 或 `'dev'` 将会禁用优化器,配置为 `false` 或 `'build'` 将会在开发模式下启用优化器。
+
+如果你想完全禁用优化器,可以设置 `optimizeDeps.noDiscovery: true` 来禁止自动发现依赖项,并保持 `optimizeDeps.include` 未定义或为空。
+
+:::warning
+在构建过程中优化依赖项是一个 **实验性** 的功能。尝试这种策略的项目也会使用 `build.commonjsOptions: { include: [] }` 来移除 `@rollup/plugin-commonjs`。如果你这样做,将会有一个警告提示你在打包时需要重新启用它,以支持仅使用 CJS 的包。
+:::
+
+## optimizeDeps.needsInterop
+
+- **实验性**
+- **类型:** `string[]`
+
+当导入这些依赖项时,会强制 ESM 转换。Vite 能够正确检测到依赖项是否需要转换处理(interop),因此通常不需要使用此选项。然而,不同的依赖项组合可能导致其中一些包以不同方式预构建。将这些包添加到 `needsInterop` 中可以通过避免重新加载整个页面来加快冷启动速度。如果某个依赖项符合此情况,Vite 将抛出警告,建议你在配置中添加该包名。
diff --git a/config/index.md b/config/index.md
index 18d66690..a0e9815c 100644
--- a/config/index.md
+++ b/config/index.md
@@ -1,19 +1,20 @@
-# 配置 Vite {#configuring-vite}
+---
+title: 配置 Vite
+---
-## 配置文件 {#config-file}
+# 配置 Vite {#configuring-vite}
-当以命令行方式运行 `vite` 时,Vite 会自动解析 [项目根目录](/guide/#index-html-and-project-root) 下名为 `vite.config.js` 的文件。
+当以命令行方式运行 `vite` 时,Vite 会自动解析 [项目根目录](/guide/#index-html-and-project-root) 下名为 `vite.config.js` 的配置文件(也支持其他 JS 和 TS 扩展名)。
最基础的配置文件是这样的:
-```js
-// vite.config.js
+```js [vite.config.js]
export default {
// 配置选项
}
```
-注意:即使项目没有在 `package.json` 中开启 `type: "module"`,Vite 也支持在配置文件中使用 ESM 语法。这种情况下,配置文件会在被加载前自动进行预处理。
+注意:即使项目没有在 `package.json` 中开启 `"type": "module"`,Vite 也支持在配置文件中使用 ESM 语法。这种情况下,配置文件会在被加载前自动进行预处理。
你可以显式地通过 `--config` 命令行选项指定一个配置文件(相对于 `cwd` 路径进行解析)
@@ -21,6 +22,12 @@ export default {
vite --config my-config.js
```
+::: tip 加载配置文件
+默认情况下,Vite 使用 `esbuild` 将配置文件打包到临时文件中并加载它。这可能会在 monorepo 中导入 TypeScript 文件时引发问题。如果你遇到了这种方法问题,可以通过指定 `--configLoader runner` 以改用 [module runner](/guide/api-environment-runtimes.html#modulerunner),它不会创建临时配置并将动态转换任何文件。请注意,module runner 不支持配置文件中的 CJS,但外部 CJS 包应该可以正常工作。
+
+另外,如果你正在使用支持TypeScript的环境(例如 `node --experimental-strip-types`),或者只编写纯 JavaScript 代码,你可以指定 `--configLoader native` 以使用环境的本机运行时加载配置文件。请注意,配置文件导入的模块的更新不会被检测到,因此不会自动重启 Vite 服务器。
+:::
+
## 配置智能提示 {#config-intellisense}
因为 Vite 本身附带 TypeScript 类型,所以你可以通过 IDE 和 jsdoc 的配合来实现智能提示:
@@ -42,14 +49,24 @@ export default defineConfig({
})
```
-Vite 也直接支持 TS 配置文件。你可以在 `vite.config.ts` 中使用 `defineConfig` 工具函数。
+Vite 也直接支持 TypeScript 配置文件。你可以在 `vite.config.ts` 中使用上述的 `defineConfig` 工具函数,或者 `satisfies` 运算符:
+
+```ts
+import type { UserConfig } from 'vite'
+
+export default {
+ // ...
+} satisfies UserConfig
+```
## 情景配置 {#conditional-config}
-如果配置文件需要基于(`dev`/`serve` 或 `build`)命令或者不同的 [模式](/guide/env-and-mode) 来决定选项,亦或者是一个 SSR 构建(`ssrBuild`),则可以选择导出这样一个函数:
+如果配置文件需要基于(`serve` 或 `build`)命令或者不同的 [模式](/guide/env-and-mode#modes) 来决定选项,亦或者是一个 SSR 构建(`isSsrBuild`)、一个正在预览的构建产物(`isPreview`),则可以选择导出这样一个函数:
-```js
-export default defineConfig(({ command, mode, ssrBuild }) => {
+```js twoslash
+import { defineConfig } from 'vite'
+// ---cut---
+export default defineConfig(({ command, mode, isSsrBuild, isPreview }) => {
if (command === 'serve') {
return {
// dev 独有配置
@@ -63,15 +80,17 @@ export default defineConfig(({ command, mode, ssrBuild }) => {
})
```
-需要注意的是,在 Vite 的 API 中,在开发环境下 `command` 的值为 `serve`(在 CLI 中, `vite dev` 和 `vite serve` 是 `vite` 的别名),而在生产环境下为 `build`(`vite build`)。
+需要注意的是,在 Vite 的 API 中,在开发环境下 `command` 的值为 `serve`(在 CLI 中, `vite dev` 和 `vite serve` 是 [`vite`](/guide/cli#vite) 的别名),而在生产环境下为 `build`([`vite build`](/guide/cli#vite-build))。
-`ssrBuild` 仍是实验性的。它只在构建过程中可用,而不是一个更通用的 `ssr` 标志,因为在开发过程中,我们唯一的服务器会共享处理 SSR 和非 SSR 请求的配置。某些工具可能没有区分浏览器和 SSR 两种构建目标的命令,那么这个值可能是 `undefined`,因此需要采用显式的比较表达式。
+`isSsrBuild` 和 `isPreview` 是额外的可选标志,用于区分 `build` 和 `serve` 命令的类型。一些加载 Vite 配置的工具可能不支持这些标志,而会传递 `undefined`。因此,建议使用 `true` 和 `false` 的显式比较。
## 异步配置 {#async-config}
-如果配置需要调用一个异步函数,也可以转而导出一个异步函数:
+如果配置需要调用一个异步函数,也可以转而导出一个异步函数。这个异步函数也可以通过 `defineConfig` 传递,以便获得更好的智能提示:
-```js
+```js twoslash
+import { defineConfig } from 'vite'
+// ---cut---
export default defineConfig(async ({ command, mode }) => {
const data = await asyncFunction()
return {
@@ -80,24 +99,41 @@ export default defineConfig(async ({ command, mode }) => {
})
```
-### 环境变量 {#environment-variables}
+## 在配置中使用环境变量 {#using-environment-variables-in-config}
环境变量通常可以从 `process.env` 获得。
注意 Vite 默认是不加载 `.env` 文件的,因为这些文件需要在执行完 Vite 配置后才能确定加载哪一个,举个例子,`root` 和 `envDir` 选项会影响加载行为。不过当你的确需要时,你可以使用 Vite 导出的 `loadEnv` 函数来加载指定的 `.env` 文件。
-```js
+```js twoslash
import { defineConfig, loadEnv } from 'vite'
-export default defineConfig(({ command, mode }) => {
+export default defineConfig(({ mode }) => {
// 根据当前工作目录中的 `mode` 加载 .env 文件
- // 设置第三个参数为 '' 来加载所有环境变量,而不管是否有 `VITE_` 前缀。
+ // 设置第三个参数为 '' 来加载所有环境变量,而不管是否有
+ // `VITE_` 前缀。
const env = loadEnv(mode, process.cwd(), '')
return {
// vite 配置
define: {
- __APP_ENV__: env.APP_ENV
- }
+ __APP_ENV__: JSON.stringify(env.APP_ENV),
+ },
}
})
```
+
+## 在 VS Code 上调试配置文件 {#debugging-the-config-file-on-vs-code}
+
+在默认的 `--configLoader bundle` 行为下,Vite 会将生成的临时配置文件写入 `node_modules/.vite-temp` 文件夹,在 Vite 配置文件中设置断点调试时会出现文件未找到的错误。要修复该问题,请在 `.vscode/settings.json` 中添加以下配置:
+
+```json
+{
+ "debug.javascript.terminalOptions": {
+ "resolveSourceMapLocations": [
+ "${workspaceFolder}/**",
+ "!**/node_modules/**",
+ "**/node_modules/.vite-temp/**"
+ ]
+ }
+}
+```
diff --git a/config/preview-options.md b/config/preview-options.md
index 0cb88058..94acd3f0 100644
--- a/config/preview-options.md
+++ b/config/preview-options.md
@@ -1,9 +1,11 @@
# 预览选项 {#preview-options}
-## preview.host {#preview-host}
+除非另有说明,本节中的选项仅适用于预览。
+
+## preview.host
- **类型:** `string | boolean`
-- **默认:** [`server.host`](#server_host)
+- **默认:** [`server.host`](./server-options#server-host)
为开发服务器指定 ip 地址。
设置为 `0.0.0.0` 或 `true` 会监听所有地址,包括局域网和公共地址。
@@ -17,6 +19,15 @@
:::
+## preview.allowedHosts
+
+- **类型:** `string | true`
+- **默认:** [`server.allowedHosts`](./server-options#server-allowedhosts)
+
+Vite 允许响应的主机名。
+
+查看 [`server.allowedHosts`](./server-options#server-allowedhosts) 以获取更多详细信息。
+
## preview.port {#preview-port}
- **类型:** `number`
@@ -29,41 +40,43 @@
```js
export default defineConfig({
server: {
- port: 3030
+ port: 3030,
},
preview: {
- port: 8080
- }
+ port: 8080,
+ },
})
```
## preview.strictPort {#preview-strictport}
- **类型:** `boolean`
-- **默认:** [`server.strictPort`](#server_strictport)
+- **默认:** [`server.strictPort`](./server-options#server-strictport)
设置为 `true` 时,如果端口已被使用,则直接退出,而不会再进行后续端口的尝试。
## preview.https {#preview-https}
-- **类型:** `boolean | https.ServerOptions`
-- **默认:** [`server.https`](#server_https)
+- **类型:** `https.ServerOptions`
+- **默认:** [`server.https`](./server-options#server-https)
-启用 TLS + HTTP/2。注意,只有在与 [`server.proxy` 选项](#server-proxy) 同时使用时,才会降级为 TLS。
+启用 TLS + HTTP/2。
-该值也可以传递给 `https.createServer()` 的 [options 对象](https://nodejs.org/api/https.html#https_https_createserver_options_requestlistener)。
+有关更多详细信息,请参阅 [`server.https`](./server-options#server-https)。
## preview.open {#preview-open}
- **类型:** `boolean | string`
-- **默认:** [`server.open`](#server_open)
+- **默认:** [`server.open`](./server-options#server-open)
开发服务器启动时,自动在浏览器中打开应用程序。当该值为字符串时,它将被用作 URL 的路径名。如果你想在你喜欢的某个浏览器打开该开发服务器,你可以设置环境变量 `process.env.BROWSER` (例如 `firefox`)。欲了解更多细节,请参阅 [`open` 包的源码](https://github.com/sindresorhus/open#app)。
+`BROWSER` 和 `BROWSER_ARGS` 是两个特殊的环境变量,你可以在 `.env` 文件中设置它们用以配置本选项。查看 [`open` 这个包](https://github.com/sindresorhus/open#app) 了解更多详情。
+
## preview.proxy {#preview-proxy}
- **类型:** `Record`
-- **默认:** [`server.proxy`](#server_proxy)
+- **默认:** [`server.proxy`](./server-options#server-proxy)
为开发服务器配置自定义代理规则。其值的结构为 `{ key: options }` 的对象。如果 key 以 `^` 开头,它将被识别为 `RegExp`,其中 `configure` 选项可用于访问代理实例。
@@ -72,9 +85,11 @@ export default defineConfig({
## preview.cors {#preview-cors}
- **类型:** `boolean | CorsOptions`
-- **默认:** [`server.cors`](#server_proxy)
+- **默认:** [`server.cors`](./server-options#server-cors)
+
+为预览服务器配置 CORS。
-为开发服务器配置 CORS。此功能默认启用并支持任何来源。可传递一个 [options 对象](https://github.com/expressjs/cors) 来进行配置,或者传递 `false` 来禁用此行为。
+请查看 [`server.cors`](./server-options#server-cors) 了解更多细节。
## preview.headers {#preview-headers}
diff --git a/config/server-options.md b/config/server-options.md
index d9796676..ff174e21 100644
--- a/config/server-options.md
+++ b/config/server-options.md
@@ -1,6 +1,8 @@
# 开发服务器选项 {#server-options}
-## server.host {#server-host}
+除非另有说明,本节中的选项仅适用于开发环境。
+
+## server.host
- **类型:** `string | boolean`
- **默认:** `'localhost'`
@@ -16,12 +18,11 @@
第一种情况是 `localhost` 被使用了。Node.js 在 v17 以下版本中默认会对 DNS 解析地址的结果进行重新排序。当访问 `localhost` 时,浏览器使用 DNS 来解析地址,这个地址可能与 Vite 正在监听的地址不同。当地址不一致时,Vite 会打印出来。
-你可以设置 [`dns.setDefaultResultOrder('verbatim')`](https://nodejs.org/api/dns.html#dns_dns_setdefaultresultorder_order) 来禁用这个重新排序的行为。Vite 将会将改地址打印为 `localhost`。
+你可以设置 [`dns.setDefaultResultOrder('verbatim')`](https://nodejs.org/api/dns.html#dns_dns_setdefaultresultorder_order) 来禁用这个重新排序的行为。Vite 会将地址打印为 `localhost`。
-```js
-// vite.config.js
+```js twoslash [vite.config.js]
import { defineConfig } from 'vite'
-import dns from 'dns'
+import dns from 'node:dns'
dns.setDefaultResultOrder('verbatim')
@@ -34,7 +35,45 @@ export default defineConfig({
:::
-## server.port {#server-port}
+::: tip 在 WSL2 中通过 LAN 访问开发服务器
+
+当你在 WSL2 运行 Vite 时,仅设置 `host: true` 来从局域网访问服务器是不够的。
+请看 [WSL 相关文档](https://learn.microsoft.com/en-us/windows/wsl/networking#accessing-a-wsl-2-distribution-from-your-local-area-network-lan) 了解更多细节。
+
+:::
+
+## server.allowedHosts
+
+- **类型:** `string[] | true`
+- **默认:** `[]`
+
+Vite允许响应的主机名。
+默认情况下,允许 `localhost` 及其下的所有 `.localhost` 域名和所有 IP 地址。
+使用 HTTPS 时,将跳过此检查。
+
+如果设置的字符串以 `.` 开头,则允许该主机名本身(不带 `.`)以及该主机名下的所有子域名。例如,`.example.com` 将允许 `example.com`、`foo.example.com` 和 `foo.bar.example.com`。如果设置为 `true`,服务器将被允许响应任何主机的请求。
+
+::: details 哪些主机可以安全添加?
+
+你控制其解析 IP 地址的主机可以安全地添加到允许的主机列表中。
+
+例如,如果你拥有域名 `vite.dev`,你可以将 `vite.dev` 和 `.vite.dev` 添加到列表中。如果你不拥有该域名且无法信任该域名的所有者,则不应添加它。
+
+特别是,你绝不能将顶级域名(如 `.com`)添加到列表中。这是因为任何人都可以购买域名 `example.com` 并控制其解析的 IP 地址。
+
+:::
+
+::: danger
+
+将 `server.allowedHosts` 设置为 `true` 允许任何网站通过 DNS 重绑定攻击向你的开发服务器发送请求,从而使它们能够下载你的源代码和内容。我们建议始终使用显式的允许主机列表。有关更多详细信息,请参阅 [GHSA-vg6x-rcgg-rjx6](https://github.com/vitejs/vite/security/advisories/GHSA-vg6x-rcgg-rjx6)。
+
+:::
+
+::: details 通过环境变量配置
+你可以设置环境变量 `__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS` 来添加额外允许的服务器端口。
+:::
+
+## server.port
- **类型:** `number`
- **默认值:** `5173`
@@ -49,11 +88,11 @@ export default defineConfig({
## server.https {#server-https}
-- **类型:** `boolean | https.ServerOptions`
+- **类型:** `https.ServerOptions`
-启用 TLS + HTTP/2。注意:当 [`server.proxy` 选项](#server-proxy) 也被使用时,将会仅使用 TLS。
+启用 TLS + HTTP/2。该值是传递给 `https.createServer()` 的 [options 对象](https://nodejs.org/api/https.html#https_https_createserver_options_requestlistener)。
-这个值也可以是一个传递给 `https.createServer()` 的 [选项对象](https://nodejs.org/api/https.html#https_https_createserver_options_requestlistener)。
+请注意,仅当同时使用 [`server.proxy` 选项](#server-proxy) 时,才会降级为 TLS。
需要一个合法可用的证书。对基本使用的配置需求来说,你可以添加 [@vitejs/plugin-basic-ssl](https://github.com/vitejs/vite-plugin-basic-ssl) 到项目插件中,它会自动创建和缓存一个自签名的证书。但我们推荐你创建和使用你自己的证书。
@@ -61,15 +100,17 @@ export default defineConfig({
- **类型:** `boolean | string`
-在开发服务器启动时自动在浏览器中打开应用程序。当此值为字符串时,会被用作 URL 的路径名。若你想指定喜欢的浏览器打开服务器,你可以设置环境变量 `process.env.BROWSER`(例如:`firefox`)。查看 [这个 `open` 包](https://github.com/sindresorhus/open#app) 获取更多细节。
+开发服务器启动时,自动在浏览器中打开应用程序。当该值为字符串时,它将被用作 URL 的路径名。如果你想在你喜欢的某个浏览器打开该开发服务器,你可以设置环境变量 `process.env.BROWSER` (例如 `firefox`)。你还可以设置 `process.env.BROWSER_ARGS` 来传递额外的参数(例如 `--incognito`)。
+
+`BROWSER` 和 `BROWSER_ARGS` 都是特殊的环境变量,你可以将它们放在 `.env` 文件中进行设置,欲了解更多打开浏览器的更多内部细节,请参阅 [`open` 包的源码](https://github.com/sindresorhus/open#app)。
**示例:**
```js
export default defineConfig({
server: {
- open: '/docs/index.html'
- }
+ open: '/docs/index.html',
+ },
})
```
@@ -77,9 +118,11 @@ export default defineConfig({
- **类型:** `Record`
-为开发服务器配置自定义代理规则。期望接收一个 `{ key: options }` 对象。如果 key 值以 `^` 开头,将会被解释为 `RegExp`。`configure` 可用于访问 proxy 实例。
+为开发服务器配置自定义代理规则。期望接收一个 `{ key: options }` 对象。任何请求路径以 key 值开头的请求将被代理到对应的目标。如果 key 值以 `^` 开头,将被识别为 `RegExp`。`configure` 选项可用于访问 proxy 实例。如果请求匹配任何配置的代理规则,该请求将不会被 Vite 转换。
-使用 [`http-proxy`](https://github.com/http-party/node-http-proxy)。完整选项详见 [此处](https://github.com/http-party/node-http-proxy#options).
+请注意,如果使用了非相对的 [基础路径 `base`](/config/shared-options.md#base),则必须在每个 key 值前加上该 `base`。
+
+继承自 [`http-proxy`](https://github.com/http-party/node-http-proxy#options)。完整选项详见 [此处](https://github.com/vitejs/vite/blob/main/packages/vite/src/node/server/middlewares/proxy.ts#L13)。
在某些情况下,你可能也想要配置底层的开发服务器。(例如添加自定义的中间件到内部的 [connect](https://github.com/senchalabs/connect) 应用中)为了实现这一点,你需要编写你自己的 [插件](/guide/using-plugins.html) 并使用 [configureServer](/guide/api-plugin.html#configureserver) 函数。
@@ -89,19 +132,25 @@ export default defineConfig({
export default defineConfig({
server: {
proxy: {
- // 字符串简写写法
+ // 字符串简写写法:
+ // http://localhost:5173/foo
+ // -> http://localhost:4567/foo
'/foo': 'http://localhost:4567',
- // 选项写法
+ // 带选项写法:
+ // http://localhost:5173/api/bar
+ // -> http://jsonplaceholder.typicode.com/bar
'/api': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
- rewrite: (path) => path.replace(/^\/api/, '')
+ rewrite: (path) => path.replace(/^\/api/, ''),
},
- // 正则表达式写法
+ // 正则表达式写法:
+ // http://localhost:5173/fallback/
+ // -> http://jsonplaceholder.typicode.com/
'^/fallback/.*': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
- rewrite: (path) => path.replace(/^\/fallback/, '')
+ rewrite: (path) => path.replace(/^\/fallback/, ''),
},
// 使用 proxy 实例
'/api': {
@@ -111,21 +160,33 @@ export default defineConfig({
// proxy 是 'http-proxy' 的实例
}
},
- // Proxying websockets or socket.io
+ // 代理 websockets 或 socket.io 写法:
+ // ws://localhost:5173/socket.io
+ // -> ws://localhost:5174/socket.io
+ // 在使用 `rewriteWsOrigin` 时要特别谨慎,因为这可能会让
+ // 代理服务器暴露在 CSRF 攻击之下
'/socket.io': {
- target: 'ws://localhost:3000',
- ws: true
- }
- }
- }
+ target: 'ws://localhost:5174',
+ ws: true,
+ rewriteWsOrigin: true,
+ },
+ },
+ },
})
```
## server.cors {#server-cors}
- **类型:** `boolean | CorsOptions`
+- **默认:** `{ origin: /^https?:\/\/(?:(?:[^:]+\.)?localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/ }` (允许 localhost、`127.0.0.1` 和 `::1`)
-为开发服务器配置 CORS。默认启用并允许任何源,传递一个 [选项对象](https://github.com/expressjs/cors) 来调整行为或设为 `false` 表示禁用。
+为开发服务器配置 CORS。传递一个 [选项对象](https://github.com/expressjs/cors#configuration-options) 来调整行为,或设置为 `true` 来允许任何源。
+
+::: danger
+
+将 `server.cors` 设置为 `true` 允许任何网站向你的开发服务器发送请求并下载你的源代码和内容。我们建议始终使用显式的允许来源列表。
+
+:::
## server.headers {#server-headers}
@@ -141,6 +202,8 @@ export default defineConfig({
设置 `server.hmr.overlay` 为 `false` 可以禁用开发服务器错误的屏蔽。
+`protocol` 是用于设置 HMR 连接使用的 WebSocket 协议的选项,可以是 `ws`(WebSocket)或者 `wss`(WebSocket Secure)。
+
`clientPort` 是一个高级选项,只在客户端的情况下覆盖端口,这允许你为 websocket 提供不同的端口,而并非在客户端代码中查找。如果需要在 dev-server 情况下使用 SSL 代理,这非常有用。
当 `server.hmr.server` 被定义后,Vite 将会通过所提供的的服务器来处理 HMR 连接。如果不是在中间件模式下,Vite 将尝试通过已有服务器处理 HMR 连接。这在使用自签证书或想通过网络在某端口暴露 Vite 的情况下,非常有用。
@@ -152,7 +215,7 @@ export default defineConfig({
在默认配置下, 在 Vite 之前的反向代理应该支持代理 WebSocket。如果 Vite HMR 客户端连接 WebSocket 失败,该客户端将兜底为绕过反向代理、直接连接 WebSocket 到 Vite HMR 服务器:
```
-Direct websocket connection fallback. Check out https://vitejs.dev/config/server-options.html#server-hmr to remove the previous connection error.
+Direct websocket connection fallback. Check out https://vite.dev/config/server-options.html#server-hmr to remove the previous connection error.
```
当该兜底策略偶然地可以被忽略时,这条报错将会出现在浏览器中。若要通过直接绕过反向代理来避免此错误,你可以:
@@ -163,56 +226,69 @@ Direct websocket connection fallback. Check out https://vitejs.dev/config/server
:::
-## server.watch {#server-watch}
+## server.warmup
+
+- **类型:** `{ clientFiles?: string[], ssrFiles?: string[] }`
+- **相关:** [预热常用文件](/guide/performance.html#warm-up-frequently-used-files)
-- **类型:** `object`
+提前转换和缓存文件以进行预热。可以在服务器启动时提高初始页面加载速度,并防止转换瀑布。
-传递给 [chokidar](https://github.com/paulmillr/chokidar#api) 的文件系统监听器选项。
+`clientFiles` 是仅在客户端使用的文件,而 `ssrFiles` 是仅在服务端渲染中使用的文件。它们接受相对于 `root` 的文件路径数组或 [`tinyglobby`](https://github.com/SuperchupuDev/tinyglobby) 模式。
-Vite 服务器默认会忽略对 `.git/` 和 `node_modules/` 目录的监听。如果你需要对 `node_modules/` 内的包进行监听,你可以为 `server.watch.ignored` 赋值一个取反的 glob 模式,例如:
+请确保只添加经常使用的文件,以免在启动时过载 Vite 开发服务器。
```js
export default defineConfig({
server: {
- watch: {
- ignored: ['!**/node_modules/your-package-name/**']
- }
+ warmup: {
+ clientFiles: ['./src/components/*.vue', './src/utils/big-utils.js'],
+ ssrFiles: ['./src/server/modules/*.js'],
+ },
},
- // 被监听的包必须被排除在优化之外,
- // 以便它能出现在依赖关系图中并触发热更新。
- optimizeDeps: {
- exclude: ['your-package-name']
- }
})
```
+## server.watch {#server-watch}
+
+- **类型:** `object | null`
+
+文件系统监视器选项传递给 [chokidar](https://github.com/paulmillr/chokidar/tree/3.6.0#api)。
+
+Vite 服务器的文件监听器默认会监听 `root` 目录,同时会跳过 `.git/`、`node_modules/`、`test-results/`, 以及 Vite 的 `cacheDir` 和 `build.outDir` 这些目录。当监听到文件更新时,Vite 会应用 HMR 并且只在需要时更新页面。
+
+如果设置为 `null`,则不会监视任何文件。`server.watcher` 将提供兼容的事件发射器,但调用 `add` 或 `unwatch` 将不起作用。
+
+::: warning 监听 `node_modules` 中的文件
+
+目前没有可行的方式来监听 `node_modules` 中的文件。若要了解更多详情和可能的临时替代方案,你可以关注 [issue #8619](https://github.com/vitejs/vite/issues/8619)。
+
+:::
+
::: warning 在 Windows Linux 子系统(WSL)上使用 Vite
-当需要再 Windows Subsystem for Linux (WSL) 2 上运行 Vite 时,如果项目文件夹位于 Windows 文件系统中,你需要将此选项设置为 `{ usePolling: true }`。这是由于 Windows 文件系统的 [WSL2 限制](https://github.com/microsoft/WSL/issues/4739) 造成的。
+当需要在 Windows Subsystem for Linux (WSL) 2 上运行 Vite 时,如果项目文件夹位于 Windows 文件系统中,你需要将此选项设置为 `{ usePolling: true }`。这是由于 Windows 文件系统的 [WSL2 限制](https://github.com/microsoft/WSL/issues/4739) 造成的。
要解决这一问题,你可以采取以下两种办法之一:
- **推荐**:使用 WSL2 应用来编辑你的文件
- 同时我们推荐将你的项目移出 Windows 文件系统,从 WSL2 访问 Windows 文件系统非常慢。移除这一开销将大大提升性能表现。
- 设置 `{ usePolling: true }`
- - 注意 [`usePolling` 会导致高 CPU 占用率](https://github.com/paulmillr/chokidar#performance)
+ - 注意 [`usePolling` 会导致高 CPU 占用率](https://github.com/paulmillr/chokidar/tree/3.6.0#performance)
:::
## server.middlewareMode {#server-middlewaremode}
-- **类型:** `'ssr' | 'html'`
-
-以中间件模式创建 Vite 服务器。(不含 HTTP 服务器)
+- **类型:** `boolean`
+- **默认值:** `false`
-- `'ssr'` 将禁用 Vite 自身的 HTML 服务逻辑,因此你应该手动为 `index.html` 提供服务。
-- `'html'` 将启用 Vite 自身的 HTML 服务逻辑。
+以中间件模式创建 Vite 服务器。
-- **相关:** [SSR - 设置开发服务器](/guide/ssr#setting-up-the-dev-server)
+- **相关:** [appType](./shared-options#apptype),[SSR - 设置开发服务器](/guide/ssr#setting-up-the-dev-server)
- **示例:**
-```js
+```js twoslash
import express from 'express'
import { createServer as createViteServer } from 'vite'
@@ -221,27 +297,24 @@ async function createServer() {
// 以中间件模式创建 Vite 服务器
const vite = await createViteServer({
- server: { middlewareMode: 'ssr' }
+ server: { middlewareMode: true },
+ appType: 'custom',
+ // 不引入 Vite 默认的 HTML 处理中间件
})
// 将 vite 的 connect 实例作中间件使用
app.use(vite.middlewares)
app.use('*', async (req, res) => {
- // 如果 `middlewareMode` 是 `'ssr'`,应在此为 `index.html` 提供服务.
- // 如果 `middlewareMode` 是 `'html'`,则此处无需手动服务 `index.html`
- // 因为 Vite 自会接管
+ // 由于 `appType` 的值是 `'custom'`,因此应在此处提供响应。
+ // 请注意:如果 `appType` 值为 `'spa'` 或 `'mpa'`,Vite 会包含
+ // 处理 HTML 请求和 404 的中间件,因此用户中间件应该在
+ // Vite 的中间件之前添加,以确保其生效。
})
}
createServer()
```
-## server.base {#server-base}
-
-- **类型:** `string | undefined`
-
-在 HTTP 请求中预留此文件夹,用于代理 Vite 作为子文件夹时使用。应该以 `/` 字符开始和结束。
-
## server.fs.strict {#server-fs-strict}
- **类型:** `boolean`
@@ -255,6 +328,8 @@ createServer()
限制哪些文件可以通过 `/@fs/` 路径提供服务。当 `server.fs.strict` 设置为 true 时,访问这个目录列表外的文件将会返回 403 结果。
+可以提供目录和文件。
+
Vite 将会搜索此根目录下潜在工作空间并作默认使用。一个有效的工作空间应符合以下几个条件,否则会默认以 [项目 root 目录](/guide/#index-html-and-project-root) 作备选方案。
- 在 `package.json` 中包含 `workspaces` 字段
@@ -268,7 +343,7 @@ Vite 将会搜索此根目录下潜在工作空间并作默认使用。一个有
export default defineConfig({
server: {
fs: {
- // 可以为项目根目录的上一级提供服务
+ // 允许为项目根目录的上一级提供服务
allow: ['..']
}
}
@@ -287,31 +362,64 @@ export default defineConfig({
// 搜索工作区的根目录
searchForWorkspaceRoot(process.cwd()),
// 自定义规则
- '/path/to/custom/allow'
- ]
- }
- }
+ '/path/to/custom/allow_directory',
+ '/path/to/custom/allow_file.demo',
+ ],
+ },
+ },
})
```
## server.fs.deny {#server-fs-deny}
- **类型:** `string[]`
+- **默认:** `['.env', '.env.*', '*.{crt,pem}', '**/.git/**']`
-用于限制 Vite 开发服务器提供敏感文件的黑名单。
+用于限制 Vite 开发服务器提供敏感文件的黑名单。这会比 [`server.fs.allow`](#server-fs-allow) 选项的优先级更高。同时还支持 [picomatch 模式](https://github.com/micromatch/picomatch#globbing-features)。
-默认为 `['.env', '.env.*', '*.{pem,crt}']`。
+::: tip NOTE
+
+此黑名单不适用于[公共目录](/guide/assets.md#the-public-directory)。公共目录中的所有文件均未经任何过滤,因为它们会在构建过程中直接复制到输出目录。
+
+:::
## server.origin {#server-origin}
- **类型:** `string`
-用于定义开发调试阶段生成资产的 origin。
+用于定义开发调试阶段生成资源的 origin。
```js
export default defineConfig({
server: {
- origin: 'http://127.0.0.1:8080'
- }
+ origin: 'http://127.0.0.1:8080',
+ },
})
```
+
+## server.sourcemapIgnoreList {#server-sourcemapignorelist}
+
+- **类型:** `false | (sourcePath: string, sourcemapPath: string) => boolean`
+- **默认:** `(sourcePath) => sourcePath.includes('node_modules')`
+
+是否忽略服务器 sourcemap 中的源文件,用于填充 [`x_google_ignoreList` source map 扩展](https://developer.chrome.com/articles/x-google-ignore-list/)。
+
+对开发服务器来说 `server.sourcemapIgnoreList` 等价于 [`build.rollupOptions.output.sourcemapIgnoreList`](https://cn.rollupjs.org/configuration-options/#output-sourcemapignorelist)。两个配置选项之间的区别在于,rollup 函数使用相对路径调用 `sourcePath`,而 `server.sourcemapIgnoreList` 使用绝对路径调用。在开发过程中,大多数模块的映射和源文件位于同一个文件夹中,因此 `sourcePath` 的相对路径就是文件名本身。在这些情况下,使用绝对路径更加方便。
+
+默认情况下,它会排除所有包含 `node_modules` 的路径。你可以传递 `false` 来禁用此行为,或者为了获得完全的控制,可以传递一个函数,该函数接受源路径和 sourcemap 的路径,并返回是否忽略源路径。
+
+```js
+export default defineConfig({
+ server: {
+ // 这是默认值,它将把所有路径中含有 node_modules 的文件
+ // 添加到忽略列表中。
+ sourcemapIgnoreList(sourcePath, sourcemapPath) {
+ return sourcePath.includes('node_modules')
+ },
+ },
+})
+```
+
+::: tip 注意
+需要单独设置 [`server.sourcemapIgnoreList`](#server-sourcemapignorelist) 和 [`build.rollupOptions.output.sourcemapIgnoreList`](https://cn.rollupjs.org/configuration-options/#output-sourcemapignorelist)。`server.sourcemapIgnoreList` 是一个仅适用于服务端的配置,并不从定义好的 rollup 选项中获得其默认值。
+:::
diff --git a/config/shared-options.md b/config/shared-options.md
index d4c38dc6..8e549864 100644
--- a/config/shared-options.md
+++ b/config/shared-options.md
@@ -1,6 +1,8 @@
-# 共享配置 {#shared-options}
+# 共享选项 {#shared-options}
-## root {#root}
+除非另有说明,本节中的选项适用于所有开发、构建和预览。
+
+## root
- **类型:** `string`
- **默认:** `process.cwd()`
@@ -13,11 +15,12 @@
- **类型:** `string`
- **默认:** `/`
+- **相关:** [`server.origin`](/config/server-options.md#server-origin)
开发或生产环境服务的公共基础路径。合法的值包括以下几种:
- 绝对 URL 路径名,例如 `/foo/`
-- 完整的 URL,例如 `https://foo.com/`
+- 完整的 URL,例如 `https://bar.com/foo/ `(域名部分在开发环境中不会被使用,因此该值与 `/foo/` 相同)
- 空字符串或 `./`(用于嵌入形式的开发)
更多信息详见 [公共基础路径](/guide/build#public-base-path)。
@@ -33,24 +36,25 @@
## define {#define}
-- **类型:** `Record`
+- **类型:** `Record`
定义全局常量替换方式。其中每项在开发环境下会被定义在全局,而在构建时被静态替换。
-- 从 `2.0.0-beta.70` 开始,string 值会以原始表达式形式使用,所以如果定义了一个字符串常量,它需要被显式地打引号。(例如使用 `JSON.stringify`)
-
-- 为了与 [esbuild 的行为](https://esbuild.github.io/api/#define)保持一致,表达式必须为一个 JSON 对象(null、boolean、number、string、数组或对象),亦或是一个单独的标识符。
+Vite 使用 [esbuild define](https://esbuild.github.io/api/#define) 来进行替换,因此值的表达式必须是一个包含 JSON 可序列化值(null、boolean、number、string、array 或 object)或单一标识符的字符串。对于非字符串值,Vite 将自动使用 `JSON.stringify` 将其转换为字符串。
-- 替换只会在匹配到周围不是其他字母、数字、`_` 或 `$` 时执行。
-
-::: warning
-因为它是不经过任何语法分析,直接替换文本实现的,所以我们建议只对 CONSTANTS 使用 `define`。
+**示例:**
-例如,`process.env.FOO` 和 `__APP_VERSION__` 就非常适合。但 `process` 或 `global` 不应使用此选项。变量相关应使用 shim 或 polyfill 代替。
-:::
+```js
+export default defineConfig({
+ define: {
+ __APP_VERSION__: JSON.stringify('v1.0.0'),
+ __API_URL__: 'window.__backend_api_url',
+ },
+})
+```
::: tip NOTE
-对于使用 TypeScript 的开发者来说,请确保在 `env.d.ts` 或 `vite-env.d.ts` 文件中添加类型声明,以获得类型检查以及代码提示。
+对于使用 TypeScript 的开发者来说,请确保在 `vite-env.d.ts` 文件中添加类型声明,以获得类型检查以及代码提示。
示例:
@@ -61,21 +65,7 @@ declare const __APP_VERSION__: string
:::
-::: tip NOTE
-由于开发模式和构建模式实现 `define` 的差异性,我们应该避免采用一些可能导致不一致的用例。
-
-例如:
-
-```js
-const obj = {
- __NAME__, // 不要以缩写形式定义对象属性
- __KEY__: value // 不要定义对象的 key
-}
-```
-
-:::
-
-## plugins {#plugins}
+## plugins
- **类型:** `(Plugin | Plugin[] | Promise)[]`
@@ -86,7 +76,7 @@ const obj = {
- **类型:** `string | false`
- **默认:** `"public"`
-作为静态资源服务的文件夹。该目录中的文件在开发期间在 `/` 处提供,并在构建期间复制到 `outDir` 的根目录,并且始终按原样提供或复制而无需进行转换。该值可以是文件系统的绝对路径,也可以是相对于项目的根目录的相对路径。
+作为静态资源服务的文件夹。该目录中的文件在开发期间在 `/` 处提供,并在构建期间复制到 `outDir` 的根目录,并且始终按原样提供或复制而无需进行转换。该值可以是文件系统的绝对路径,也可以是相对于项目根目录的相对路径。
将 `publicDir` 设定为 `false` 可以关闭此项功能。
@@ -111,7 +101,7 @@ const obj = {
更高级的自定义解析方法可以通过 [插件](/guide/api-plugin) 实现。
::: warning 在 SSR 中使用
-如果你已经为 [SSR 外部化的依赖](/guide/ssr.md#ssr-externals) 配置了别名,你可能想要为真实的 `node_modules` 包配别名. [Yarn](https://classic.yarnpkg.com/en/docs/cli/add/#toc-yarn-add-alias) 和 [pnpm](https://pnpm.js.org/en/aliases) 都支持通过 `npm:` 前缀配置别名。
+如果你已经为 [SSR 外部化的依赖](/guide/ssr.md#ssr-externals) 配置了别名,你可能想要为真实的 `node_modules` 包配别名。[Yarn](https://classic.yarnpkg.com/en/docs/cli/add/#toc-yarn-add-alias) 和 [pnpm](https://pnpm.io/aliases/) 都支持通过 `npm:` 前缀配置别名。
:::
## resolve.dedupe {#resolve-dedupe}
@@ -124,9 +114,10 @@ const obj = {
对于服务端渲染构建,配置项 `build.rollupOptions.output` 为 ESM 构建输出时去重过程将不工作。一个替代方案是先使用 CJS 构建输出,直到 ESM 在插件中有了更好的模块加载支持。
:::
-## resolve.conditions
+## resolve.conditions {#resolve-conditions}
- **类型:** `string[]`
+- **默认:** `['module', 'browser', 'development|production']` (`defaultClientConditions`)
解决程序包中 [情景导出](https://nodejs.org/api/packages.html#packages_conditional_exports) 时的其他允许条件。
@@ -145,23 +136,21 @@ const obj = {
在这里,`import` 和 `require` 被称为“情景”。情景可以嵌套,并且应该从最特定的到最不特定的指定。
-Vite 有一个“允许的情景”列表,并且会匹配列表中第一个情景。默认允许的情景是:`import`,`module`,`browser`,`default` 和基于当前情景为 `production/development`。`resolve.conditions` 配置项使得我们可以指定其他允许的情景。
+`development|production` 是一个特殊值,根据 `process.env.NODE_ENV` 的值替换为 `production` 或 `development` 。如果 `process.env.NODE_ENV === 'production'`,则替换为 `production`,否则替换为 `development`。
-:::warning 解决子路径导出问题
-导出以“/”结尾的 key 已被 Node 弃用,可能无法正常工作。请联系包的作者改为使用 [`*` 子路径模式](https://nodejs.org/api/packages.html#package-entry-points)。
-:::
+请注意,如果符合要求,`import`,`require`,`default` 始终会被应用。
## resolve.mainFields {#resolve-mainfields}
- **类型:** `string[]`
-- **默认:** `['module', 'jsnext:main', 'jsnext']`
+- **默认:** `['browser', 'module', 'jsnext:main', 'jsnext']` (`defaultClientMainFields`)
-`package.json` 中,在解析包的入口点时尝试的字段列表。注意:这比从 `exports` 字段解析的情景导出优先级低:如果一个入口点从 `exports` 成功解析,`resolve.mainFields` 将被忽略。
+`package.json` 中,在解析包的入口点时尝试的字段列表。注意:这比从 `exports` 字段解析的情景导出优先级低:如果一个入口起点从 `exports` 成功解析,`resolve.mainFields` 将被忽略。
## resolve.extensions {#resolve-extensions}
- **类型:** `string[]`
-- **默认:** `['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json']`
+- **默认:** `['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json']`
导入时想要省略的扩展名列表。注意,**不** 建议忽略自定义导入类型的扩展名(例如:`.vue`),因为它会影响 IDE 和类型支持。
@@ -175,41 +164,59 @@ Vite 有一个“允许的情景”列表,并且会匹配列表中第一个情
- **相关:** [esbuild#preserve-symlinks](https://esbuild.github.io/api/#preserve-symlinks),[webpack#resolve.symlinks
](https://webpack.js.org/configuration/resolve/#resolvesymlinks)
-## css.modules {#css-modules}
+## html.cspNonce
-- **类型:**
+- **类型:** `string`
+- **相关:** [内容安全策略(CSP)](/guide/features#content-security-policy-csp)
-```ts
-interface CSSModulesOptions {
- scopeBehaviour?: 'global' | 'local'
- globalModulePaths?: RegExp[]
- generateScopedName?:
- | string
- | ((name: string, filename: string, css: string) => string)
- hashPrefix?: string
- /**
- * 默认:null
- */
- localsConvention?:
- | 'camelCase'
- | 'camelCaseOnly'
- | 'dashes'
- | 'dashesOnly'
- | null
-}
-```
+一个在生成脚本或样式标签时会用到的 nonce 值占位符。设置此值还会生成一个带有 nonce 值的 meta 标签。
+
+## css.modules
+
+- **类型:**
+ ```ts
+ interface CSSModulesOptions {
+ getJSON?: (
+ cssFileName: string,
+ json: Record,
+ outputFileName: string,
+ ) => void
+ scopeBehaviour?: 'global' | 'local'
+ globalModulePaths?: RegExp[]
+ exportGlobals?: boolean
+ generateScopedName?:
+ | string
+ | ((name: string, filename: string, css: string) => string)
+ hashPrefix?: string
+ /**
+ * default: undefined
+ */
+ localsConvention?:
+ | 'camelCase'
+ | 'camelCaseOnly'
+ | 'dashes'
+ | 'dashesOnly'
+ | ((
+ originalClassName: string,
+ generatedClassName: string,
+ inputFile: string,
+ ) => string)
+ }
+ ```
配置 CSS modules 的行为。选项将被传递给 [postcss-modules](https://github.com/css-modules/postcss-modules)。
+当使用 [Lightning CSS](../guide/features.md#lightning-css) 时,该选项不会产生任何效果。如果要启用该选项,则应该使用 [`css.lightningcss.cssModules`](https://lightningcss.dev/css-modules.html) 来替代。
+
## css.postcss {#css-postcss}
- **类型:** `string | (postcss.ProcessOptions & { plugins?: postcss.AcceptedPlugin[] })`
内联的 PostCSS 配置(格式同 `postcss.config.js`),或者一个(默认基于项目根目录的)自定义的 PostCSS 配置路径。
-对内联的 POSTCSS 配置,它期望接收与 `postcss.config.js` 一致的格式。但对于 `plugins` 属性有些特别,只接收使用 [数组格式](https://github.com/postcss/postcss-load-config/blob/main/README.md#array)。
+对内联的 PostCSS 配置,它期望接收与 `postcss.config.js` 一致的格式。但对于 `plugins` 属性有些特别,只接收使用 [数组格式](https://github.com/postcss/postcss-load-config/blob/main/README.md#array)。
-搜索是使用 [postcss-load-config](https://github.com/postcss/postcss-load-config) 完成的,只有被支持的文件名才会被加载。
+搜索是使用 [postcss-load-config](https://github.com/postcss/postcss-load-config) 完成的,只有被支持的文件名才会被加载。默认情况下,不会搜索工作区根目录(或 [项目根目录](/guide/#index-html-and-project-root),如果未找到工作区)之外的配置文件。如有必要,您可以指定根目录之外的自定义路径来加载特定的配置文件。
注意:如果提供了该内联配置,Vite 将不会搜索其他 PostCSS 配置源。
@@ -217,31 +224,119 @@ interface CSSModulesOptions {
- **类型:** `Record`
-指定传递给 CSS 预处理器的选项。文件扩展名用作选项的键,例如:
+指定传递给 CSS 预处理器的选项。文件扩展名用作选项的键。每个预处理器支持的选项可以在它们各自的文档中找到:
+
+- `sass`/`scss`:
+- 如果已安装,则使用 `sass-embedded`,否则使用 `sass`。为了获得最佳性能,建议安装 `sass-embedded` 包。
+ - [Options](https://sass-lang.com/documentation/js-api/interfaces/stringoptions/)
+- `less`: [选项](https://lesscss.org/usage/#less-options).
+- `styl`/`stylus`: 仅支持 [`define`](https://stylus-lang.com/docs/js.html#define-name-node),可以作为对象传递。
+
+**示例:**
```js
export default defineConfig({
css: {
preprocessorOptions: {
- scss: {
- additionalData: `$injectedColor: orange;`
+ less: {
+ math: 'parens-division',
},
styl: {
- additionalData: `$injectedColor ?= orange`
- }
- }
- }
+ define: {
+ $specialColor: new stylus.nodes.RGBA(51, 197, 255, 1),
+ },
+ },
+ scss: {
+ importers: [
+ // ...
+ ],
+ },
+ },
+ },
+})
+```
+
+### css.preprocessorOptions[extension].additionalData
+
+- **类型:** `string | ((source: string, filename: string) => (string | { content: string; map?: SourceMap }))`
+
+该选项可以用来为每一段样式内容添加额外的代码。但是要注意,如果你添加的是实际的样式而不仅仅是变量,那这些样式在最终的产物中会重复。
+
+**示例:**
+
+```js
+export default defineConfig({
+ css: {
+ preprocessorOptions: {
+ scss: {
+ additionalData: `$injectedColor: orange;`,
+ },
+ },
+ },
})
```
+## css.preprocessorMaxWorkers
+
+- **类型:** `number | true`
+- **默认:** `true`
+
+指定 CSS 预处理器可以使用的最大线程数。`true` 表示最多为 CPU 数量减 1。当设置为 `0` 时,Vite 将不会创建任何工作线程,而是在主线程中运行预处理器。
+
+根据预处理器选项,即使此选项未设置为 `0`,Vite 也可能会在主线程上运行预处理器。
+
## css.devSourcemap {#css-devsourcemap}
-- **实验性**
+- **实验性:** [提供反馈](https://github.com/vitejs/vite/discussions/13845)
- **类型:** `boolean`
- **默认:** `false`
在开发过程中是否启用 sourcemap。
+## css.transformer
+
+- **实验性:** [提供反馈](https://github.com/vitejs/vite/discussions/13835)
+- **类型:** `'postcss' | 'lightningcss'`
+- **默认:** `'postcss'`
+
+该选项用于选择用于 CSS 处理的引擎。详细信息请查看 [Lightning CSS](../guide/features.md#lightning-css)。
+
+::: info 重复的 `@import`
+需要注意的是,postcss(postcss-import)处理重复 `@import` 的行为与浏览器是不同的。详情请参考 [postcss/postcss-import#462](https://github.com/postcss/postcss-import/issues/462)。
+:::
+
+## css.lightningcss
+
+- **实验性:** [提供反馈](https://github.com/vitejs/vite/discussions/13835)
+- **类型:**
+
+```js
+import type {
+ CSSModulesConfig,
+ Drafts,
+ Features,
+ NonStandard,
+ PseudoClasses,
+ Targets,
+} from 'lightningcss'
+```
+
+```js
+{
+ targets?: Targets
+ include?: Features
+ exclude?: Features
+ drafts?: Drafts
+ nonStandard?: NonStandard
+ pseudoClasses?: PseudoClasses
+ unusedSymbols?: string[]
+ cssModules?: CSSModulesConfig,
+ // ...
+}
+```
+
+该选项用于配置 Lightning CSS。有关完整的转换选项,请参阅 [Lightning CSS 仓库](https://github.com/parcel-bundler/lightningcss/blob/master/node/index.d.ts)。
+
## json.namedExports {#json-namedexports}
- **类型:** `boolean`
@@ -251,25 +346,25 @@ export default defineConfig({
## json.stringify {#json-stringify}
-- **类型:** `boolean`
-- **默认:** `false`
+- **类型:** `boolean | 'auto'`
+- **默认:** `'auto'`
若设置为 `true`,导入的 JSON 会被转换为 `export default JSON.parse("...")`,这样会比转译成对象字面量性能更好,尤其是当 JSON 文件较大的时候。
-开启此项,则会禁用按名导入。
+如果设置为 `'auto'`,只有当 [数据大于 10kB 时](https://v8.dev/blog/cost-of-javascript-2019#json:~:text=A%20good%20rule%20of%20thumb%20is%20to%20apply%20this%20technique%20for%20objects%20of%2010%20kB%20or%20larger),才会对数据进行字符串化处理。
## esbuild {#esbuild}
- **类型:** `ESBuildOptions | false`
-`ESBuildOptions` 继承自 [esbuild 转换选项](https://esbuild.github.io/api/#transform-api)。最常见的用例是自定义 JSX:
+`ESBuildOptions` 继承自 [esbuild 转换选项](https://esbuild.github.io/api/#transform)。最常见的用例是自定义 JSX:
```js
export default defineConfig({
esbuild: {
jsxFactory: 'h',
- jsxFragment: 'Fragment'
- }
+ jsxFragment: 'Fragment',
+ },
})
```
@@ -280,8 +375,8 @@ export default defineConfig({
```js
export default defineConfig({
esbuild: {
- jsxInject: `import React from 'react'`
- }
+ jsxInject: `import React from 'react'`,
+ },
})
```
@@ -306,7 +401,7 @@ export default defineConfig({
```js
export default defineConfig({
- assetsInclude: ['**/*.gltf']
+ assetsInclude: ['**/*.gltf'],
})
```
@@ -316,6 +411,40 @@ export default defineConfig({
调整控制台输出的级别,默认为 `'info'`。
+## customLogger {#customlogger}
+
+- **类型:**
+ ```ts
+ interface Logger {
+ info(msg: string, options?: LogOptions): void
+ warn(msg: string, options?: LogOptions): void
+ warnOnce(msg: string, options?: LogOptions): void
+ error(msg: string, options?: LogErrorOptions): void
+ clearScreen(type: LogType): void
+ hasErrorLogged(error: Error | RollupError): boolean
+ hasWarned: boolean
+ }
+ ```
+
+使用自定义 logger 记录消息。可以使用 Vite 的 `createLogger` API 获取默认的 logger 并对其进行自定义,例如,更改消息或过滤掉某些警告。
+
+```ts twoslash
+import { createLogger, defineConfig } from 'vite'
+
+const logger = createLogger()
+const loggerWarn = logger.warn
+
+logger.warn = (msg, options) => {
+ // 忽略空 CSS 文件的警告
+ if (msg.includes('vite:css') && msg.includes(' is empty')) return
+ loggerWarn(msg, options)
+}
+
+export default defineConfig({
+ customLogger: logger,
+})
+```
+
## clearScreen {#clearscreen}
- **类型:** `boolean`
@@ -325,10 +454,10 @@ export default defineConfig({
## envDir {#envdir}
-- **类型:** `string`
+- **类型:** `string | false`
- **默认:** `root`
-用于加载 `.env` 文件的目录。可以是一个绝对路径,也可以是相对于项目根的路径。
+用于加载 `.env` 文件的目录。可以是一个绝对路径,也可以是相对于项目根的路径。设置为 `false` 将禁用 `.env` 文件的加载。
关于环境文件的更多信息,请参见 [这里](/guide/env-and-mode#env-files)。
@@ -337,21 +466,39 @@ export default defineConfig({
- **类型:** `string | string[]`
- **默认:** `VITE_`
-以 `envPrefix` 开头的环境变量会通过 import.meta.env 暴露在你的客户端源码中。
+以 `envPrefix` 开头的环境变量会通过 `import.meta.env` 暴露在你的客户端源码中。
:::warning 安全注意事项
`envPrefix` 不应被设置为空字符串 `''`,这将暴露你所有的环境变量,导致敏感信息的意外泄漏。 检测到配置为 `''` 时 Vite 将会抛出错误.
+
+如果你想暴露一个不含前缀的变量,可以使用 [define](#define) 选项:
+
+```js
+define: {
+ 'import.meta.env.ENV_VARIABLE': JSON.stringify(process.env.ENV_VARIABLE)
+}
+```
+
:::
-## appType
+## appType {#apptype}
- **类型:** `'spa' | 'mpa' | 'custom'`
- **默认:** `'spa'`
无论你的应用是一个单页应用(SPA)还是一个 [多页应用(MPA)](../guide/build#multi-page-app),亦或是一个定制化应用(SSR 和自定义 HTML 处理的框架):
-- `'spa'`:包含 SPA 回退中间件以及在预览中将 [sirv](https://github.com/lukeed/sirv) 配置为 `single: true`
-- `'mpa'`:仅包含非 SPA HTML 中间件
+- `'spa'`:包含 HTML 中间件以及使用 SPA 回退。在预览中将 [sirv](https://github.com/lukeed/sirv) 配置为 `single: true`
+- `'mpa'`:包含 HTML 中间件
- `'custom'`:不包含 HTML 中间件
要了解更多,请查看 Vite 的 [SSR 指引](/guide/ssr#vite-cli)。相关内容:[`server.middlewareMode`](./server-options#server-middlewaremode)。
+
+## future
+
+- **类型:** `Record`
+- **默认:** [破坏性变更](/changes/)
+
+启用未来的重大变更,为顺利迁移到 Vite 的下一个主要版本做好准备。随着新功能的开发,这个列表可能会随时进行更新、添加或移除。
+
+请查看 [破坏性变更](/changes/) 页面,了解可能的选项详情。
diff --git a/config/ssr-options.md b/config/ssr-options.md
index ee5fa0f3..0c132ed5 100644
--- a/config/ssr-options.md
+++ b/config/ssr-options.md
@@ -1,18 +1,28 @@
# SSR 选项 {#ssr-options}
-## ssr.external {#ssr-external}
+除非另有说明,本节中的选项适用于开发和构建。
-- **类型:** `string[]`
+## ssr.external
+
+- **类型:** `string[] | true`
- **相关:** [SSR 外部化](/guide/ssr#ssr-externals)
-列出的是要为 SSR 强制外部化的依赖。
+这个选项可以将指定的依赖项和它们传递的依赖项进行外部化,以供服务端渲染(SSR)使用。默认情况下,所有的依赖项都会被外部化,除了那些被链接的依赖项(为了HMR)。如果希望将这些软链接的依赖项也外部化,你可以将其名称传给这个选项。
+
+如果这个选项设置为 `true`,那么所有的依赖项,包括被链接的依赖项,都将被外部化。
+
+需要注意的是,如果在该选项明确列出了一些依赖项(使用 `string[]` 类型),那么其将始终被优先考虑,即使它们也在 `ssr.noExternal` 中被列出(无论使用何种类型)。
## ssr.noExternal {#ssr-noexternal}
- **类型:** `string | RegExp | (string | RegExp)[] | true`
- **相关:** [SSR 外部化](/guide/ssr#ssr-externals)
-列出的是防止被 SSR 外部化依赖项。如果设为 `true`,将没有依赖被外部化。
+这个选项可以防止列出的依赖项在服务端渲染(SSR)时被外部化,这些依赖项将会在构建过程中被打包。默认情况下,只有软链接的依赖项不会被外部化(这是为了HMR)。如果你希望将软链接的依赖项也外部化,可以将其名称传给 `ssr.external` 选项。
+
+如果这个选项设置为 `true`,那么没有任何依赖项会被外部化。然而,如果你在 `ssr.external` 中明确列出了一些依赖项(使用 `string[]` 类型),那么这些依赖项可以优先被外部化。如果设置了 `ssr.target: 'node'`,那么 Node.js 的内置模块也会被默认外部化。
+
+需要注意的是,如果 `ssr.noExternal: true` 和 `ssr.external: true` 都被设置了,那么 `ssr.noExternal` 将优先生效,没有任何依赖项会被外部化。
## ssr.target
@@ -21,10 +31,32 @@
SSR 服务器的构建目标。
-## ssr.format
+## ssr.resolve.conditions {#ssr-resolve-conditions}
+
+- **类型:** `string[]`
+- **默认:** `['module', 'node', 'development|production']`(`defaultServerConditions`) (当 `ssr.target === 'webworker'` 时为 `['module', 'browser', 'development|production']` (`defaultClientConditions`) )
+- **相关:** [解析情景](./shared-options.md#resolve-conditions)
+
+这些条件会在插件管道中使用,并且只会影响 SSR 构建期间的非外部化依赖项。使用 `ssr.resolve.externalConditions` 来影响外部化导入。
+
+## ssr.resolve.externalConditions {#ssr-resolve-externalconditions}
+
+- **类型:** `string[]`
+- **默认:** `['node']`
+
+在对外部化的直接依赖项(由 Vite 导入的外部依赖项)进行 SSR 导入(包括 `ssrLoadModule`)期间所使用的条件。
+
+:::tip
+
+使用该选项时,请确保在开发和构建中使用 [`--conditions` flag](https://nodejs.org/docs/latest/api/cli.html#-c-condition---conditionscondition) 以相同的值运行 Node,以获得一致的行为。
+
+例如,当设置 `['node', 'custom']` 时,应该在 dev 中运行 `NODE_OPTIONS='--conditions custom' vite`,在 build 后运行 `NODE_OPTIONS="--conditions custom" node ./dist/server.js`。
+
+:::
-- **实验性**
-- **类型:** `'esm' | 'cjs'`
-- **默认:** `esm`
+## ssr.resolve.mainFields
-SSR 服务器的构建语法格式。从 Vite v3 开始,SSR 构建默认生成 ESM 格式。设置为 `'cjs'` 可以构建为 CJS 格式,但不推荐这样做。这个选项被标记为实验性的,以便给用户更多时间更新到 ESM。CJS 构建需要复杂的外部化启发式,但在 ESM 格式中则不需要。
+- **类型:** `string[]`
+- **默认:** `['module', 'jsnext:main', 'jsnext']`
+
+在解析一个包的入口文件时,会尝试使用 `package.json` 中的字段列表。请注意,这些字段的优先级低于从条件导出解析的 `exports` 字段:如果能从 `exports` 字段成功解析出入口文件,那么 main 字段将会被忽略。此设置仅影响未外部化的依赖项。
diff --git a/config/worker-options.md b/config/worker-options.md
index 540038a4..fe954b59 100644
--- a/config/worker-options.md
+++ b/config/worker-options.md
@@ -1,20 +1,23 @@
# Worker 选项 {#worker-options}
+除非另有说明,本节中的选项适用于所有开发、构建和预览。
+
## worker.format
- **类型:** `'es' | 'iife'`
-- **默认:** `iife`
+- **默认:** `'iife'`
worker 打包时的输出类型。
## worker.plugins
-- **类型:** [`(Plugin | Plugin[])[]`](./shared-options#plugins)
+- **类型:** [`() => (Plugin | Plugin[])[]`](./shared-options#plugins)
-应用于 worker 打包的 Vite 插件。注意 [config.plugins](./shared-options#plugins) 不会应用于 worker,而是应该在这里配置所用到的插件。
+应用于 worker 打包的 Vite 插件。注意 [config.plugins](./shared-options#plugins) 仅会在开发(dev)阶段应用于 worker,若要配置在构建(build)阶段应用于 worker 的插件则应该在本选项这里配置。
+该函数应返回新的插件实例,因为它们在并行的 rollup worker 构建中使用。因此,在 `config` 钩子中修改 `config.worker` 选项将被忽略。
## worker.rollupOptions
-- **类型:** [`RollupOptions`](https://rollupjs.org/guide/en/#big-list-of-options)
+- **类型:** [`RollupOptions`](https://cn.rollupjs.org/configuration-options/)
用于打包 worker 的 Rollup 配置项。
diff --git a/guide/api-environment-frameworks.md b/guide/api-environment-frameworks.md
new file mode 100644
index 00000000..4765d250
--- /dev/null
+++ b/guide/api-environment-frameworks.md
@@ -0,0 +1,338 @@
+# 用于框架的环境 API {#environment-api-for-frameworks}
+
+:::warning 实验性
+环境 API 仍处于实验阶段。我们仍将在主要版本之间保持 API 的稳定性,以便生态系统进行实验和构建。我们计划在下游项目有时间试验并验证新功能后,在未来的主要版本中稳定这些新 API(可能包含重大更改)。
+
+资料:
+
+- [反馈讨论](https://github.com/vitejs/vite/discussions/16358) 我们在此处收集新 API 的反馈。
+- [环境 API PR](https://github.com/vitejs/vite/pull/16471) 新 API 在此处被实现并进行了审查。
+
+请与我们分享您的反馈。
+:::
+
+## 环境和框架 {#environments-and-frameworks}
+
+隐式的 `ssr` 环境和其他非客户端环境在开发过程中默认使用 `RunnableDevEnvironment`。虽然这要求运行时与 Vite 服务器运行的环境相同,但这与 `ssrLoadModule` 类似,允许框架迁移并为其 SSR 开发方案启用模块热替换(HMR)。你可以使用 `isRunnableDevEnvironment` 函数来保护任何可运行的环境。
+
+```ts
+export class RunnableDevEnvironment extends DevEnvironment {
+ public readonly runner: ModuleRunner
+}
+
+class ModuleRunner {
+ /**
+ * 要执行的 URL。
+ * 可以接受文件路径,服务器路径,或者相对于根路径的 id。
+ * 返回一个实例化的模块(和 ssrLoadModule 中的一样)
+ */
+ public async import(url: string): Promise>
+ /**
+ * 其他的 ModuleRunner 方法...
+ */
+}
+
+if (isRunnableDevEnvironment(server.environments.ssr)) {
+ await server.environments.ssr.runner.import('/entry-point.js')
+}
+```
+
+:::warning
+只有在第一次使用时,`runner` 才会被加载。请注意,当通过调用 `process.setSourceMapsEnabled` 或在不支持的情况下重写 `Error.prepareStackTrace` 创建 `runner` 时,Vite 会启用源映射支持。
+:::
+
+那些通过 [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch) 与它们的运行环境进行交互的框架可以使用 `FetchableDevEnvironment`,它提供了一种标准化的方式来通过 `handleRequest` 方法处理请求:
+
+```ts
+import {
+ createServer,
+ createFetchableDevEnvironment,
+ isFetchableDevEnvironment,
+} from 'vite'
+
+const server = await createServer({
+ server: { middlewareMode: true },
+ appType: 'custom',
+ environments: {
+ custom: {
+ dev: {
+ createEnvironment(name, config) {
+ return createFetchableDevEnvironment(name, config, {
+ handleRequest(request: Request): Promise | Response {
+ // 处理请求并返回响应
+ },
+ })
+ },
+ },
+ },
+ },
+})
+
+// 现在,任何使用环境 API 的人都可以调用 `dispatchFetch`
+if (isFetchableDevEnvironment(server.environments.custom)) {
+ const response: Response = await server.environments.custom.dispatchFetch(
+ new Request('/request-to-handle'),
+ )
+}
+```
+
+:::warning
+Vite 会检查 `dispatchFetch` 方法的输入和输出:请求必须是全局 `Request` 类的一个实例,而响应必须是全局 `Response` 类的一个实例。如果不满足这些条件,Vite 将会抛出一个 `TypeError`。
+
+尽管 `FetchableDevEnvironment` 是作为一个类来实现的,但请注意,Vite 团队可能会随时更改它,因为其被视为实现细节部分。
+:::
+
+## 默认 `RunnableDevEnvironment` {#default-runnabledevenvironment}
+
+假设我们有一个配置为中间件模式的 Vite 服务器,如 [SSR 设置指南](/guide/ssr#setting-up-the-dev-server) 所述,我们可以使用环境 API 来实现 SSR 中间件。请记住,它不必命名为 `ssr`,因此在本例中我们将其命名为 `server`。错误处理部分已省略。
+
+```js
+import fs from 'node:fs'
+import path from 'node:path'
+import { fileURLToPath } from 'node:url'
+import { createServer } from 'vite'
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url))
+
+const viteServer = await createServer({
+ server: { middlewareMode: true },
+ appType: 'custom',
+ environments: {
+ server: {
+ // 默认情况下,模块与 vite 开发服务器在同一进程中运行
+ },
+ },
+})
+
+// 在 TypeScript 中,你可能需要将这个转换为 RunnableDevEnvironment,或者
+// 使用 "isRunnableDevEnvironment" 来保护对运行器的访问
+const serverEnvironment = viteServer.environments.server
+
+app.use('*', async (req, res, next) => {
+ const url = req.originalUrl
+
+ // 1. 读取 index.html
+ const indexHtmlPath = path.resolve(__dirname, 'index.html')
+ let template = fs.readFileSync(indexHtmlPath, 'utf-8')
+
+ // 2. 应用 Vite HTML 转换。这将注入 Vite HMR 客户端,
+ // 并应用来自 Vite 插件的 HTML 转换,例如
+ // @vitejs/plugin-react 提供的全局前置代码
+ template = await viteServer.transformIndexHtml(url, template)
+
+ // 3. 加载服务器入口文件。import(url) 自动将
+ // ESM 源代码转换为 Node.js 可用的代码!
+ // 不需要打包,并且提供全面的 HMR 支持。
+ const { render } = await serverEnvironment.runner.import(
+ '/src/entry-server.js',
+ )
+
+ // 4. 渲染应用的 HTML。将假设 entry-server.js 导出的
+ // `render` 函数调用了对应框架的 SSR API,
+ // 例如 ReactDOMServer.renderToString()
+ const appHtml = await render(url)
+
+ // 5. 将应用渲染的 HTML 注入到模板中。
+ const html = template.replace(``, appHtml)
+
+ // 6. 发送渲染后的 HTML 回去。
+ res.status(200).set({ 'Content-Type': 'text/html' }).end(html)
+})
+```
+
+## 运行时无关的 SSR {#runtime-agnostic-ssr}
+
+由于 `RunnableDevEnvironment` 只能用于在与 Vite 服务器相同的运行时中运行代码,它需要一个可以运行 Vite 服务器的运行时(即与 Node.js 兼容的运行时)。这意味着您需要使用原始的 `DevEnvironment` 来使其对运行时无关。
+
+:::info `FetchableDevEnvironment` 提议
+
+最初的提议是在 `DevEnvironment` 类上有一个 `run` 方法,该方法将允许消费者通过使用 `transport` 选项在运行器端调用一个导入。在我们的测试中,我们发现 API 还不够通用,以至于我们暂时不开始推荐它。目前,我们正在寻求对 [`FetchableDevEnvironment` 提议](https://github.com/vitejs/vite/discussions/18191) 的反馈。
+
+:::
+
+`RunnableDevEnvironment` 有一个 `runner.import` 函数,返回模块的值。但是这个函数在原始的 `DevEnvironment` 中不可用,并且需要将使用 Vite 的 API 和用户模块的代码解耦。
+
+例如,下面的例子中,使用 Vite API 的代码使用了用户模块的值:
+
+```ts
+// 使用 Vite API 的代码
+import { createServer } from 'vite'
+
+const server = createServer()
+const ssrEnvironment = server.environment.ssr
+const input = {}
+
+const { createHandler } = await ssrEnvironment.runner.import('./entrypoint.js')
+const handler = createHandler(input)
+const response = handler(new Request('/'))
+
+// -------------------------------------
+// ./entrypoint.js
+export function createHandler(input) {
+ return function handler(req) {
+ return new Response('hello')
+ }
+}
+```
+
+如果你的代码可以在与用户模块相同的运行时中运行(即,它不依赖于 Node.js 特定的 API),你可以使用虚拟模块。这种方法避免了从使用 Vite API 的代码中获取值的需求。
+
+```ts
+// 使用 Vite API 的代码
+import { createServer } from 'vite'
+
+const server = createServer({
+ plugins: [
+ // 处理 `virtual:entrypoint` 的插件
+ {
+ name: 'virtual-module',
+ /* 插件实现 */
+ },
+ ],
+})
+const ssrEnvironment = server.environment.ssr
+const input = {}
+
+// 使用每个环境工厂暴露的函数来运行代码
+// 检查每个环境工厂提供了什么
+if (ssrEnvironment instanceof RunnableDevEnvironment) {
+ ssrEnvironment.runner.import('virtual:entrypoint')
+} else if (ssrEnvironment instanceof CustomDevEnvironment) {
+ ssrEnvironment.runEntrypoint('virtual:entrypoint')
+} else {
+ throw new Error(`Unsupported runtime for ${ssrEnvironment.name}`)
+}
+
+// -------------------------------------
+// virtual:entrypoint
+const { createHandler } = await import('./entrypoint.js')
+const handler = createHandler(input)
+const response = handler(new Request('/'))
+
+// -------------------------------------
+// ./entrypoint.js
+export function createHandler(input) {
+ return function handler(req) {
+ return new Response('hello')
+ }
+}
+```
+
+例如,如果你想在用户模块上调用 `transformIndexHtml`,你可以使用以下插件:
+
+```ts {13-21}
+function vitePluginVirtualIndexHtml(): Plugin {
+ let server: ViteDevServer | undefined
+ return {
+ name: vitePluginVirtualIndexHtml.name,
+ configureServer(server_) {
+ server = server_
+ },
+ resolveId(source) {
+ return source === 'virtual:index-html' ? '\0' + source : undefined
+ },
+ async load(id) {
+ if (id === '\0' + 'virtual:index-html') {
+ let html: string
+ if (server) {
+ this.addWatchFile('index.html')
+ html = fs.readFileSync('index.html', 'utf-8')
+ html = await server.transformIndexHtml('/', html)
+ } else {
+ html = fs.readFileSync('dist/client/index.html', 'utf-8')
+ }
+ return `export default ${JSON.stringify(html)}`
+ }
+ return
+ },
+ }
+}
+```
+
+如果你的代码需要 Node.js API,你可以使用 `hot.send` 从用户模块与使用 Vite API 的代码进行通信。但是,请注意,这种方式在构建过程后可能无法以相同的方式工作。
+
+```ts
+// 使用 Vite API 的代码
+import { createServer } from 'vite'
+
+const server = createServer({
+ plugins: [
+ // 处理 `virtual:entrypoint` 的插件
+ {
+ name: 'virtual-module',
+ /* 插件实现 */
+ },
+ ],
+})
+const ssrEnvironment = server.environment.ssr
+const input = {}
+
+// 使用每个环境工厂暴露的函数来运行代码
+// 检查每个环境工厂提供了什么
+if (ssrEnvironment instanceof RunnableDevEnvironment) {
+ ssrEnvironment.runner.import('virtual:entrypoint')
+} else if (ssrEnvironment instanceof CustomDevEnvironment) {
+ ssrEnvironment.runEntrypoint('virtual:entrypoint')
+} else {
+ throw new Error(`Unsupported runtime for ${ssrEnvironment.name}`)
+}
+
+const req = new Request('/')
+
+const uniqueId = 'a-unique-id'
+ssrEnvironment.send('request', serialize({ req, uniqueId }))
+const response = await new Promise((resolve) => {
+ ssrEnvironment.on('response', (data) => {
+ data = deserialize(data)
+ if (data.uniqueId === uniqueId) {
+ resolve(data.res)
+ }
+ })
+})
+
+// -------------------------------------
+// virtual:entrypoint
+const { createHandler } = await import('./entrypoint.js')
+const handler = createHandler(input)
+
+import.meta.hot.on('request', (data) => {
+ const { req, uniqueId } = deserialize(data)
+ const res = handler(req)
+ import.meta.hot.send('response', serialize({ res: res, uniqueId }))
+})
+
+const response = handler(new Request('/'))
+
+// -------------------------------------
+// ./entrypoint.js
+export function createHandler(input) {
+ return function handler(req) {
+ return new Response('hello')
+ }
+}
+```
+
+## 构建过程中的环境 {#environments-during-build}
+
+在命令行接口中,调用 `vite build` 和 `vite build --ssr` 仍将只构建客户端和仅 ssr 环境以保证向后兼容性。
+
+当 `builder` 为 `undefined` 时(或者调用 `vite build --app`)时,`vite build` 将选择构建整个应用。这将在未来的主要版本中成为默认设置。将创建一个 `ViteBuilder` 实例(构建时等同于 `ViteDevServer`),用于为生产环境构建所有配置的环境。默认情况下,环境的构建按照 `environments` 记录的顺序依次运行。框架或用户可以进一步配置环境的构建方式,使用:
+
+```js
+export default {
+ builder: {
+ buildApp: async (builder) => {
+ const environments = Object.values(builder.environments)
+ return Promise.all(
+ environments.map((environment) => builder.build(environment)),
+ )
+ },
+ },
+}
+```
+
+插件还可以定义一个 `buildApp` 钩子。顺序 `'pre'` 和 `'null'` 在配置的 `builder.buildApp` 之前执行,顺序 `'post'` 钩子在其之后执行。`environment.isBuilt` 可用于检查环境是否已被构建。
+
+## 环境无关的代码 {#environment-agnostic-code}
+
+大部分情况,当前的 `environment` 实例会作为正在运行代码的上下文中的一部分,所以通过 `server.environments` 来访问它们的需求应该很少。例如,在插件钩子内部,环境是作为 `PluginContext` 的一部分暴露出来的,所以可以使用 `this.environment` 来访问它。参见 [用于插件的环境 API](./api-environment-plugins.md) 了解如何构建对环境敏感的插件。
diff --git a/guide/api-environment-instances.md b/guide/api-environment-instances.md
new file mode 100644
index 00000000..d755dc27
--- /dev/null
+++ b/guide/api-environment-instances.md
@@ -0,0 +1,209 @@
+# 使用 `Environment` 实例 {#using-environment-instances}
+
+:::warning 实验性
+环境 API 仍处于实验阶段。我们仍将在主要版本之间保持 API 的稳定性,以便生态系统进行实验和构建。我们计划在下游项目有时间试验并验证新功能后,在未来的主要版本中稳定这些新 API(可能包含重大更改)。
+
+资料:
+
+- [反馈讨论](https://github.com/vitejs/vite/discussions/16358) 我们在此处收集新 API 的反馈。
+- [环境 API PR](https://github.com/vitejs/vite/pull/16471) 新 API 在此处被实现并进行了审查。
+
+请与我们分享您的反馈。
+:::
+
+## 访问环境 {#accessing-the-environments}
+在开发阶段,可以使用 `server.environments` 来访问开发服务器中的可用环境:
+
+```js
+// 创建服务器,或通过 configureServer 钩子来获取
+const server = await createServer(/* 选项 */)
+
+const clientEnvironment = server.environments.client
+clientEnvironment.transformRequest(url)
+console.log(server.environments.ssr.moduleGraph)
+```
+
+你也可以从插件中访问当前环境。更多详情请参见 [针对插件的环境 API](./api-environment-plugins.md#accessing-the-current-environment-in-hooks)。
+
+## `DevEnvironment` 类 {#devenvironment-class}
+
+在开发阶段,每个环境都是 `DevEnvironment` 类的一个实例:
+
+```ts
+class DevEnvironment {
+ /**
+ * 环境在 Vite 服务器中的唯一标识符。
+ * 默认情况下,Vite 暴露 'client' 和 'ssr' 环境。
+ */
+ name: string
+ /**
+ * 用于在目标运行时的关联模块运行器中
+ * 发送和接收消息的通信通道。
+ */
+ hot: NormalizedHotChannel
+ /**
+ * 模块节点的图,包含处理过的模块之间的
+ * 导入关系和处理代码的缓存结果。
+ */
+ moduleGraph: EnvironmentModuleGraph
+ /**
+ * 为此环境解析的插件,包括使用按环境的
+ * `create` 钩子创建的插件。
+ */
+ plugins: Plugin[]
+ /**
+ * 允许通过环境插件管道解析、加载
+ * 和转换代码。
+ */
+ pluginContainer: EnvironmentPluginContainer
+ /**
+ * 为此环境解析的配置选项。服务器全局范围内的选项
+ * 作为所有环境的默认值,并可以被覆盖(解析条件、
+ * 外部依赖、优化的依赖)。
+ */
+ config: ResolvedConfig & ResolvedDevEnvironmentOptions
+
+ constructor(
+ name: string,
+ config: ResolvedConfig,
+ context: DevEnvironmentContext,
+ )
+
+ /**
+ * 解析 URL 到一个 id,加载它,并使用插件管道
+ * 处理代码。模块图也会被更新。
+ */
+ async transformRequest(url: string): Promise
+
+ /**
+ * 注册一个低优先级处理的请求。这对于避免瀑布效应
+ * 非常有用。Vite 服务器有关于其他请求导入模块的
+ * 信息,因此它可以预热模块图,使得当模块被请求时
+ * 已经处理完毕。
+ */
+ async warmupRequest(url: string): Promise
+}
+```
+
+其中 `DevEnvironmentContext`是:
+
+```ts
+interface DevEnvironmentContext {
+ hot: boolean
+ transport?: HotChannel | WebSocketServer
+ options?: EnvironmentOptions
+ remoteRunner?: {
+ inlineSourceMap?: boolean
+ }
+ depsOptimizer?: DepsOptimizer
+}
+```
+
+`TransformResult` 是:
+
+```ts
+interface TransformResult {
+ code: string
+ map: SourceMap | { mappings: '' } | null
+ etag?: string
+ deps?: string[]
+ dynamicDeps?: string[]
+}
+```
+
+Vite 服务器中的环境实例允许你使用 `environment.transformRequest(url)` 方法处理一个 URL。这个函数将使用插件管道将 `url` 解析为模块 `id`,加载它(从文件系统读取文件或通过实现虚拟模块的插件),然后转换代码。在转换模块时,将通过创建或更新相应的模块节点,在环境模块图中记录导入和其他元数据。处理完成后,转换结果也存储在模块中。
+
+:::info transformRequest 命名
+在这个提议的当前版本中,我们使用 `transformRequest(url)` 和 `warmupRequest(url)`,这样对于习惯于 Vite 当前 API 的用户来说,会更容易讨论和理解。在发布之前,我们也可以借此机会审查这些命名。例如,可以命名为 `environment.processModule(url)` 或 `environment.loadModule(url)`,借鉴于 Rollup 的插件钩子中的 `context.load(id)`。目前,我们认为保留当前的名称并推迟这个讨论是更好的选择。
+:::
+
+## 独立的模块图 {#separate-module-graphs}
+
+每个环境都有一个独立的模块图。所有模块图都有相同的签名,因此可以实现通用算法来爬取或查询图,而无需依赖环境。`hotUpdate` 是一个很好的例子。当一个文件被修改时,将使用每个环境的模块图来发现受影响的模块,并为每个环境独立执行 HMR。
+
+::: info
+Vite v5 有一个混合的客户端和 SSR 模块图。给定一个未处理的或无效的节点,无法知道它对应的是客户端、SSR 还是两者都有的环境。模块节点有一些带有前缀的属性,如 `clientImportedModules` 和 `ssrImportedModules`(以及 `importedModules`,返回两者的并集)。`importers` 包含了每个模块节点的客户端和 SSR 环境的所有导入者。模块节点还有 `transformResult` 和 `ssrTransformResult`。存在一个向后兼容层允许生态系统从已弃用的 `server.moduleGraph` 迁移过来。
+:::
+
+每个模块都由一个 `EnvironmentModuleNode` 实例表示。模块可能在图中被注册,但尚未被处理(在这种情况下,`transformResult` 将为 `null`)。在模块处理后,`importers` 和 `importedModules` 也会被更新。
+
+```ts
+class EnvironmentModuleNode {
+ environment: string
+
+ url: string
+ id: string | null = null
+ file: string | null = null
+
+ type: 'js' | 'css'
+
+ importers = new Set()
+ importedModules = new Set()
+ importedBindings: Map> | null = null
+
+ info?: ModuleInfo
+ meta?: Record
+ transformResult: TransformResult | null = null
+
+ acceptedHmrDeps = new Set()
+ acceptedHmrExports: Set | null = null
+ isSelfAccepting?: boolean
+ lastHMRTimestamp = 0
+ lastInvalidationTimestamp = 0
+}
+```
+
+`environment.moduleGraph` 是 `EnvironmentModuleGraph` 的一个实例:
+
+```ts
+export class EnvironmentModuleGraph {
+ environment: string
+
+ urlToModuleMap = new Map()
+ idToModuleMap = new Map()
+ etagToModuleMap = new Map()
+ fileToModulesMap = new Map>()
+
+ constructor(
+ environment: string,
+ resolveId: (url: string) => Promise,
+ )
+
+ async getModuleByUrl(
+ rawUrl: string,
+ ): Promise
+
+ getModuleById(id: string): EnvironmentModuleNode | undefined
+
+ getModulesByFile(file: string): Set | undefined
+
+ onFileChange(file: string): void
+
+ onFileDelete(file: string): void
+
+ invalidateModule(
+ mod: EnvironmentModuleNode,
+ seen: Set = new Set(),
+ timestamp: number = monotonicDateNow(),
+ isHmr: boolean = false,
+ ): void
+
+ invalidateAll(): void
+
+ async ensureEntryFromUrl(
+ rawUrl: string,
+ setIsSelfAccepting = true,
+ ): Promise
+
+ createFileOnlyEntry(file: string): EnvironmentModuleNode
+
+ async resolveUrl(url: string): Promise
+
+ updateModuleTransformResult(
+ mod: EnvironmentModuleNode,
+ result: TransformResult | null,
+ ): void
+
+ getModuleByEtag(etag: string): EnvironmentModuleNode | undefined
+}
+```
diff --git a/guide/api-environment-plugins.md b/guide/api-environment-plugins.md
new file mode 100644
index 00000000..dd67b55e
--- /dev/null
+++ b/guide/api-environment-plugins.md
@@ -0,0 +1,248 @@
+# 用于插件的环境 API {#environment-api-for-plugins}
+
+:::warning 实验性
+环境 API 仍处于实验阶段。我们仍将在主要版本之间保持 API 的稳定性,以便生态系统进行实验和构建。我们计划在下游项目有时间试验并验证新功能后,在未来的主要版本中稳定这些新 API(可能包含重大更改)。
+
+资料:
+
+- [反馈讨论](https://github.com/vitejs/vite/discussions/16358) 我们在此处收集新 API 的反馈。
+- [环境 API PR](https://github.com/vitejs/vite/pull/16471) 新 API 在此处被实现并进行了审查。
+
+请与我们分享您的反馈。
+:::
+
+## 在钩子中访问当前环境 {#accessing-the-current-environment-in-hooks}
+
+在 Vite 6之前,由于只有两个环境(`client` 和 `ssr`),一个 `ssr` 布尔值足以在 Vite API 中识别当前环境。插件钩子在最后的选项参数中接收一个 `ssr` 布尔值,多个 API 也期望通过一个可选的 `ssr` 参数来正确地将模块关联到对应的环境(例如 `server.moduleGraph.getModuleByUrl(url, { ssr })`)。
+
+随着可配置的环境出现,我们现在有了一种统一的方法来在插件中访问它们的选项和实例。插件钩子现在在其上下文中暴露 `this.environment`,以前期望 `ssr` 布尔值的 API 现在被限定到正确的环境(例如 `environment.moduleGraph.getModuleByUrl(url)`)。
+
+Vite 服务器有一个共享的插件管道,但在处理模块时,它总是在给定环境的上下文中进行。`environment` 实例在插件上下文中可用。
+
+插件可以使用 `environment` 实例根据环境的配置(可通过 `environment.config` 访问)来改变模块的处理方式。
+
+```ts
+ transform(code, id) {
+ console.log(this.environment.config.resolve.conditions)
+ }
+```
+
+## 使用钩子注册新环境 {#registering-new-environments-using-hooks}
+
+插件可以在 `config` 钩子中添加新环境(例如,为了有一个专门用于 [RSC](https://react.dev/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components) 的模块图):
+
+```ts
+ config(config: UserConfig) {
+ config.environments.rsc ??= {}
+ }
+```
+
+一个空对象就足以注册环境,默认值则来自于根级别的环境配置。
+
+## 使用钩子配置环境 {#configuring-environment-using-hooks}
+
+当 `config` 钩子正在运行时,我们还不知道完整的环境列表,而且环境可以受到来自根级别环境配置的默认值或通过 `config.environments` 记录明确影响。
+插件应使用 `config` 钩子设置默认值。要配置每个环境,可以使用新的 `configEnvironment` 钩子。此钩子会为每个环境调用,并传入其部分解析的配置,包括最终默认值的解析。
+
+```ts
+ configEnvironment(name: string, options: EnvironmentOptions) {
+ if (name === 'rsc') {
+ options.resolve.conditions = // ...
+```
+
+## `hotUpdate` 钩子 {#the-hotupdate-hook}
+
+- **类型:** `(this: { environment: DevEnvironment }, options: HotUpdateOptions) => Array | void | Promise | void>`
+- **查看:** [HMR API](./api-hmr)
+
+`hotUpdate` 钩子允许插件为特定环境执行自定义的 HMR 更新处理。当一个文件发生变化时,会按照 `server.environments` 中的顺序为每个环境依次运行 HMR 算法,因此 `hotUpdate` 钩子会被多次调用。这个钩子会接收一个带有以下签名的上下文对象:
+
+```ts
+interface HotUpdateOptions {
+ type: 'create' | 'update' | 'delete'
+ file: string
+ timestamp: number
+ modules: Array
+ read: () => string | Promise
+ server: ViteDevServer
+}
+```
+
+- `this.environment` 是当前正在处理文件更新的模块执行环境。
+
+- `modules` 是由于文件更改而受影响的此环境中的模块的数组。它是一个数组,因为一个文件可能映射到多个服务的模块(例如 Vue SFCs)。
+
+- `read` 是一个异步读取函数,返回文件的内容。这是因为,在某些系统上,文件更改回调可能在编辑器完成文件更新之前触发得太快,直接的 `fs.readFile` 将返回空内容。传入的读取函数规范化了这种行为。
+
+可以选择钩子用于:
+
+- 过滤和缩小受影响的模块列表,使 HMR 更准确。
+
+- 返回一个空数组并执行完全重载:
+
+ ```js
+ hotUpdate({ modules, timestamp }) {
+ if (this.environment.name !== 'client')
+ return
+
+ // 手动使模块失效
+ const invalidatedModules = new Set()
+ for (const mod of modules) {
+ this.environment.moduleGraph.invalidateModule(
+ mod,
+ invalidatedModules,
+ timestamp,
+ true
+ )
+ }
+ this.environment.hot.send({ type: 'full-reload' })
+ return []
+ }
+ ```
+
+- 返回一个空数组并通过向客户端发送自定义事件来执行完全自定义的 HMR 处理:
+
+ ```js
+ hotUpdate() {
+ if (this.environment.name !== 'client')
+ return
+
+ this.environment.hot.send({
+ type: 'custom',
+ event: 'special-update',
+ data: {}
+ })
+ return []
+ }
+ ```
+
+ 客户端代码应使用 [HMR API](./api-hmr) 注册相应的处理程序(这可以通过相同插件的 `transform` 钩子注入):
+
+ ```js
+ if (import.meta.hot) {
+ import.meta.hot.on('special-update', (data) => {
+ // 执行自定义更新
+ })
+ }
+ ```
+
+## 插件中的基于环境的状态 {#per-environment-state-in-plugins}
+
+鉴于相同的插件实例会被用于不同的环境,插件的状态需要以 `this.environment` 作为键来存储。这与生态系统中已使用的模式相同,即使用 `ssr` 布尔值作为键来避免混合客户端和 SSR 模块状态的方式。可以使用 `Map` 来分别为每个环境保存其对应的状态。注意:为了保持向后兼容性,在未设置 `perEnvironmentStartEndDuringDev: true` 标志时,`buildStart` 和 `buildEnd` 仅会针对客户端环境被调用。
+
+```js
+function PerEnvironmentCountTransformedModulesPlugin() {
+ const state = new Map()
+ return {
+ name: 'count-transformed-modules',
+ perEnvironmentStartEndDuringDev: true,
+ buildStart() {
+ state.set(this.environment, { count: 0 })
+ },
+ transform(id) {
+ state.get(this.environment).count++
+ },
+ buildEnd() {
+ console.log(this.environment.name, state.get(this.environment).count)
+ }
+ }
+}
+```
+
+## 基于环境的插件 {#per-environment-plugins}
+
+插件可以使用 `applyToEnvironment` 函数来定义它适用的环境。
+
+```js
+const UnoCssPlugin = () => {
+ // 共享的全局状态
+ return {
+ buildStart() {
+ // 使用 WeakMap 初始化每个环境状态
+ // 使用 this.environment
+ },
+ configureServer() {
+ // 正常使用全局钩子
+ },
+ applyToEnvironment(environment) {
+ // 如果此插件应在此环境中激活,则返回 true
+ // 或返回一个新插件来替代它。
+ // 如果不使用这个 hook,则插件在所有环境中都是激活的
+ },
+ resolveId(id, importer) {
+ // 只对此插件适用的环境进行调用
+ },
+ }
+}
+```
+
+如果一个插件没有环境感知功能,并且其状态没有基于当前环境进行区分,`applyToEnvironment` 钩子可以轻松地将其设置为针对每个环境工作。
+
+```js
+import { nonShareablePlugin } from 'non-shareable-plugin'
+
+export default defineConfig({
+ plugins: [
+ {
+ name: 'per-environment-plugin',
+ applyToEnvironment(environment) {
+ return nonShareablePlugin({ outputName: environment.name })
+ },
+ },
+ ],
+})
+```
+
+Vite 输出了一个 `perEnvironmentPlugin` 助手,以简化这些不需要其他钩子的情况:
+
+```js
+import { nonShareablePlugin } from 'non-shareable-plugin'
+
+export default defineConfig({
+ plugins: [
+ perEnvironmentPlugin('per-environment-plugin', (environment) =>
+ nonShareablePlugin({ outputName: environment.name }),
+ ),
+ ],
+})
+```
+
+`applyToEnvironment` 钩子在配置时调用,目前在 `configResolved` 之后调用,因为生态系统中的项目正在修改其中的插件。未来,环境插件解析可能会移至 `configResolved` 之前。
+
+## 构建钩子中的环境 {#environment-in-build-hooks}
+
+与开发期间一样,插件钩子在构建期间也接收环境实例,取代了 `ssr` 布尔值。
+这同样适用于 `renderChunk`、`generateBundle` 和其他仅在构建时使用的钩子。
+
+## 构建期间的共享插件 {#shared-plugins-during-build}
+
+在 Vite 6 之前,插件管道在开发和构建期间的工作方式不同:
+
+- **开发期间:** 插件是共享的
+- **构建期间:** 插件对每个环境是隔离的(在不同的进程中:`vite build` 然后 `vite build --ssr`)。
+
+这迫使框架通过写入文件系统的清单文件在 `client` 构建和 `ssr` 构建之间共享状态。在 Vite 6 中,我们现在在单个进程中构建所有环境,因此插件管道和环境间通信的方式可以与开发对齐。
+
+在未来的主要版本,我们可以实现完全一致:
+
+- **在开发和构建期间:** 插件是共享的,并可以 [根据环境进行过滤](#per-environment-plugins)
+
+在构建期间还会共享一个单一的 `ResolvedConfig` 实例,允许在整个应用构建过程中进行缓存,类似于我们在开发期间使用 `WeakMap` 的方式。
+
+对于 Vite 6,我们需要做一个较小的改动以保持向后兼容。生态系统插件当前使用 `config.build` 而不是 `environment.config.build` 来访问配置,因此我们需要默认为每个环境创建一个新的 `ResolvedConfig`。项目可以通过设置 `builder.sharedConfigBuild` 为 `true` 来选择共享完整的配置和插件管道。
+
+此选项最初仅适用于一小部分项目,因此插件作者可以通过将 `sharedDuringBuild` 标志设置为 `true` 来选择特定插件在构建期间共享。这可以很容易地共享常规插件的状态:
+
+```js
+function myPlugin() {
+ // 在开发和构建中的所有环境之间共享状态
+ const sharedState = ...
+ return {
+ name: 'shared-plugin',
+ transform(code, id) { ... },
+
+ // 选择在所有环境中使用单个实例
+ sharedDuringBuild: true,
+ }
+}
+```
diff --git a/guide/api-environment-runtimes.md b/guide/api-environment-runtimes.md
new file mode 100644
index 00000000..be763ea6
--- /dev/null
+++ b/guide/api-environment-runtimes.md
@@ -0,0 +1,394 @@
+# 用于运行时的环境 API {#environment-api-for-runtimes}
+
+:::warning 实验性
+环境 API 仍处于实验阶段。我们仍将在主要版本之间保持 API 的稳定性,以便生态系统进行实验和构建。我们计划在下游项目有时间试验并验证新功能后,在未来的主要版本中稳定这些新 API(可能包含重大更改)。
+
+资料:
+
+- [反馈讨论](https://github.com/vitejs/vite/discussions/16358) 我们在此处收集新 API 的反馈。
+- [环境 API PR](https://github.com/vitejs/vite/pull/16471) 新 API 在此处被实现并进行了审查。
+
+请与我们分享您的反馈。
+:::
+
+## 环境工厂 {#environment-factories}
+
+环境工厂(Environments factory)旨在由环境提供者(如 Cloudflare)实现,而不是由终端用户实现。环境工厂返回一个 `EnvironmentOptions`,用于在开发和构建环境中使用目标运行时的最常见情况。默认环境选项也可以设置,因此用户无需手动配置。
+
+```ts
+function createWorkerdEnvironment(
+ userConfig: EnvironmentOptions,
+): EnvironmentOptions {
+ return mergeConfig(
+ {
+ resolve: {
+ conditions: [
+ /*...*/
+ ],
+ },
+ dev: {
+ createEnvironment(name, config) {
+ return createWorkerdDevEnvironment(name, config, {
+ hot: true,
+ transport: customHotChannel(),
+ })
+ },
+ },
+ build: {
+ createEnvironment(name, config) {
+ return createWorkerdBuildEnvironment(name, config)
+ },
+ },
+ },
+ userConfig,
+ )
+}
+```
+
+配置文件可以写为:
+
+```js
+import { createWorkerdEnvironment } from 'vite-environment-workerd'
+
+export default {
+ environments: {
+ ssr: createWorkerdEnvironment({
+ build: {
+ outDir: '/dist/ssr',
+ },
+ }),
+ rsc: createWorkerdEnvironment({
+ build: {
+ outDir: '/dist/rsc',
+ },
+ }),
+ },
+}
+```
+
+并且框架可以使用带有 workerd 运行时的环境来执行以下操作:
+
+```js
+const ssrEnvironment = server.environments.ssr
+```
+
+## 创建新的环境工厂 {#creating-a-new-environment-factory}
+
+Vite 开发服务器默认暴露两个环境:一个 `client` 环境和一个 `ssr` 环境。客户端环境默认是浏览器环境,模块运行器(module runner)通过将虚拟模块 `/@vite/client` 导入客户端应用来实现。SSR 环境默认在与 Vite 服务器相同的 Node 运行时中运行,允许应用服务器在开发期间使用完整的 HMR 支持来渲染请求。
+
+转换后的源代码称为模块(module),在每个环境中处理的模块之间的关系保存在模块图中。这些模块的转换代码被发送到与每个环境关联的运行时以执行。当一个模块在运行时中被执行时,它的导入模块将被请求,从而触发模块图的一部分处理。
+
+Vite 模块运行器允许首先使用 Vite 插件处理代码来运行任何代码。它不同于 `server.ssrLoadModule`,因为运行器实现与服务器解耦。这允许库和框架作者实现 Vite 服务器与运行器之间的通信层。浏览器通过服务器 Web Socket 和 HTTP 请求与其对应的环境通信。Node 模块运行器可以直接通过函数调用处理模块,因为它在同一进程中运行。其他环境可以通过连接到 JS 运行时(如 workerd)或 Worker 线程(如 Vitest)来运行模块。
+
+此功能的目标之一是提供一个可定制的 API 来处理和运行代码。用户可以使用暴露的基础组件创建新的环境工厂。
+
+```ts
+import { DevEnvironment, HotChannel } from 'vite'
+
+function createWorkerdDevEnvironment(
+ name: string,
+ config: ResolvedConfig,
+ context: DevEnvironmentContext
+) {
+ const connection = /* ... */
+ const transport: HotChannel = {
+ on: (listener) => { connection.on('message', listener) },
+ send: (data) => connection.send(data),
+ }
+
+ const workerdDevEnvironment = new DevEnvironment(name, config, {
+ options: {
+ resolve: { conditions: ['custom'] },
+ ...context.options,
+ },
+ hot: true,
+ transport,
+ })
+ return workerdDevEnvironment
+}
+```
+
+## `ModuleRunner`
+
+一个模块运行器在目标运行时中实例化。下一节中的所有 API 都从 `vite/module-runner` 导入,除非另有说明。这个导出入口文件尽可能保持轻量,仅导出创建模块运行器所需的最小部分。
+
+**类型签名:**
+
+```ts
+export class ModuleRunner {
+ constructor(
+ public options: ModuleRunnerOptions,
+ public evaluator: ModuleEvaluator = new ESModulesEvaluator(),
+ private debug?: ModuleRunnerDebugger,
+ ) {}
+ /**
+ * 要执行的 URL。
+ * 可以是文件路径,服务器路径,或者相对于根路径的 id
+ */
+ public async import(url: string): Promise
+ /**
+ * 清除所有缓存,包括 HMR 监听器
+ */
+ public clearCache(): void
+ /**
+ * 清除所有缓存,移除所有 HMR 监听器,并重置源映射支持
+ * 此方法不会停止 HMR 连接
+ */
+ public async close(): Promise
+ /**
+ * 如果通过调用 `close()` 关闭了运行器,则返回 `true`
+ */
+ public isClosed(): boolean
+}
+```
+
+`ModuleRunner` 中的模块评估器负责执行代码。Vite 默认导出 `ESModulesEvaluator`,它使用 `new AsyncFunction` 来执行代码。如果你的 JavaScript 运行时不支持不安全的运行,你可以提供你自己的实现。
+
+模块运行器暴露了 `import` 方法。当 Vite 服务器触发 `full-reload` HMR 事件时,所有受影响的模块将被重新执行。请注意,当这种情况发生时,模块运行器不会更新 `exports` 对象(会覆盖它),如果你依赖于拥有最新的 `exports` 对象,你需要再次运行 `import` 或从 `evaluatedModules` 中获取模块。
+
+**使用示例:**
+
+```js
+import { ModuleRunner, ESModulesEvaluator } from 'vite/module-runner'
+import { transport } from './rpc-implementation.js'
+
+const moduleRunner = new ModuleRunner(
+ {
+ transport,
+ },
+ new ESModulesEvaluator(),
+)
+
+await moduleRunner.import('/src/entry-point.js')
+```
+
+## `ModuleRunnerOptions`
+
+```ts twoslash
+import type {
+ InterceptorOptions as InterceptorOptionsRaw,
+ ModuleRunnerHmr as ModuleRunnerHmrRaw,
+ EvaluatedModules,
+} from 'vite/module-runner'
+import type { Debug } from '@type-challenges/utils'
+
+type InterceptorOptions = Debug
+type ModuleRunnerHmr = Debug
+/** 见下文 */
+type ModuleRunnerTransport = unknown
+
+// ---cut---
+interface ModuleRunnerOptions {
+ /**
+ * 一组与服务器通信的方法
+ */
+ transport: ModuleRunnerTransport
+ /**
+ * 配置如何解析源映射。
+ * 如果 `process.setSourceMapsEnabled` 可用,首选 `node`
+ * 否则,它将默认使用 `prepareStackTrace`,这将
+ * 覆盖 `Error.prepareStackTrace` 方法
+ * 你可以提供一个对象来配置如何解析
+ * 未被 Vite 处理的文件的内容和其源映射
+ */
+ sourcemapInterceptor?:
+ | false
+ | 'node'
+ | 'prepareStackTrace'
+ | InterceptorOptions
+ /**
+ * 禁用 HMR 或配置 HMR 选项
+ *
+ * @default true
+ */
+ hmr?: boolean | ModuleRunnerHmr
+ /**
+ * 自定义模块缓存。如果未提供,它将创建一个单独的模块缓存给
+ * 每个模块运行器实例
+ */
+ evaluatedModules?: EvaluatedModules
+}
+```
+
+## `ModuleEvaluator`
+
+**类型签名:**
+
+```ts twoslash
+import type { ModuleRunnerContext as ModuleRunnerContextRaw } from 'vite/module-runner'
+import type { Debug } from '@type-challenges/utils'
+
+type ModuleRunnerContext = Debug
+
+// ---cut---
+export interface ModuleEvaluator {
+ /**
+ * 转换后代码中前缀行的数量。
+ */
+ startOffset?: number
+ /**
+ * 运行由 Vite 转换的代码。
+ * @param context 函数上下文
+ * @param code 转换后的代码
+ * @param id 用于获取模块的 ID
+ */
+ runInlinedModule(
+ context: ModuleRunnerContext,
+ code: string,
+ id: string,
+ ): Promise
+ /**
+ * 运行外部化的模块
+ * @param file 外部模块的文件 URL
+ */
+ runExternalModule(file: string): Promise
+}
+```
+
+Vite 默认导出了实现此接口的 `ESModulesEvaluator`。它使用 `new AsyncFunction` 来执行代码,因此,如果代码有内联源映射,它应该包含 [2 行的偏移](https://tc39.es/ecma262/#sec-createdynamicfunction) 以适应新增的行。这是由 `ESModulesEvaluator` 自动完成的。自定义评估器不会添加额外的行。
+
+## `ModuleRunnerTransport` {#modulerunnertransport}
+
+**类型签名:**
+
+```ts twoslash
+import type { ModuleRunnerTransportHandlers } from 'vite/module-runner'
+/** 一个对象 */
+type HotPayload = unknown
+// ---cut---
+interface ModuleRunnerTransport {
+ connect?(handlers: ModuleRunnerTransportHandlers): Promise | void
+ disconnect?(): Promise | void
+ send?(data: HotPayload): Promise | void
+ invoke?(data: HotPayload): Promise<{ result: any } | { error: any }>
+ timeout?: number
+}
+```
+
+通过 RPC 或直接调用函数与环境通信的传输对象。如果未执行 `invoke` 方法,则必须执行 `send` 方法和 `connect` 方法。Vite 将在内部构建 `invoke` 方法。
+
+你需要将它与服务器上的 `HotChannel` 实例结合起来,就像本例中在工作线程中创建模块运行程序一样:
+
+::: code-group
+
+```js [worker.js]
+import { parentPort } from 'node:worker_threads'
+import { fileURLToPath } from 'node:url'
+import { ESModulesEvaluator, ModuleRunner } from 'vite/module-runner'
+
+/** @type {import('vite/module-runner').ModuleRunnerTransport} */
+const transport = {
+ connect({ onMessage, onDisconnection }) {
+ parentPort.on('message', onMessage)
+ parentPort.on('close', onDisconnection)
+ },
+ send(data) {
+ parentPort.postMessage(data)
+ },
+}
+
+const runner = new ModuleRunner(
+ {
+ transport,
+ },
+ new ESModulesEvaluator(),
+)
+```
+
+```js [server.js]
+import { BroadcastChannel } from 'node:worker_threads'
+import { createServer, RemoteEnvironmentTransport, DevEnvironment } from 'vite'
+
+function createWorkerEnvironment(name, config, context) {
+ const worker = new Worker('./worker.js')
+ const handlerToWorkerListener = new WeakMap()
+
+ const workerHotChannel = {
+ send: (data) => worker.postMessage(data),
+ on: (event, handler) => {
+ if (event === 'connection') return
+
+ const listener = (value) => {
+ if (value.type === 'custom' && value.event === event) {
+ const client = {
+ send(payload) {
+ worker.postMessage(payload)
+ },
+ }
+ handler(value.data, client)
+ }
+ }
+ handlerToWorkerListener.set(handler, listener)
+ worker.on('message', listener)
+ },
+ off: (event, handler) => {
+ if (event === 'connection') return
+ const listener = handlerToWorkerListener.get(handler)
+ if (listener) {
+ worker.off('message', listener)
+ handlerToWorkerListener.delete(handler)
+ }
+ },
+ }
+
+ return new DevEnvironment(name, config, {
+ transport: workerHotChannel,
+ })
+}
+
+await createServer({
+ environments: {
+ worker: {
+ dev: {
+ createEnvironment: createWorkerEnvironment,
+ },
+ },
+ },
+})
+```
+
+:::
+
+使用 HTTP 请求在运行程序和服务器之间进行通信的另一个示例:
+
+```ts
+import { ESModulesEvaluator, ModuleRunner } from 'vite/module-runner'
+
+export const runner = new ModuleRunner(
+ {
+ transport: {
+ async invoke(data) {
+ const response = await fetch(`http://my-vite-server/invoke`, {
+ method: 'POST',
+ body: JSON.stringify(data),
+ })
+ return response.json()
+ },
+ },
+ hmr: false, // disable HMR as HMR requires transport.connect
+ },
+ new ESModulesEvaluator(),
+)
+
+await runner.import('/entry.js')
+```
+
+在这种情况下,可以使用 `NormalizedHotChannel` 中的 `handleInvoke` 方法:
+
+```ts
+const customEnvironment = new DevEnvironment(name, config, context)
+
+server.onRequest((request: Request) => {
+ const url = new URL(request.url)
+ if (url.pathname === '/invoke') {
+ const payload = (await request.json()) as HotPayload
+ const result = customEnvironment.hot.handleInvoke(payload)
+ return new Response(JSON.stringify(result))
+ }
+ return Response.error()
+})
+```
+
+但请注意,要支持 HMR,必须使用 `send` 和 `connect` 方法。`send` 方法通常在触发自定义事件时调用(如`import.meta.hot.send("my-event")`)。
+
+Vite 从主入口导出 `createServerHotChannel`,以支持 Vite SSR 期间的 HMR。
diff --git a/guide/api-environment.md b/guide/api-environment.md
new file mode 100644
index 00000000..9ac04207
--- /dev/null
+++ b/guide/api-environment.md
@@ -0,0 +1,140 @@
+# 环境 API {#environment-api}
+
+:::warning 实验性
+环境 API 仍处于实验阶段。我们仍将在主要版本之间保持 API 的稳定性,以便生态系统进行实验和构建。我们计划在下游项目有时间试验并验证新功能后,在未来的主要版本中稳定这些新 API(可能包含重大更改)。
+
+资料:
+
+- [反馈讨论](https://github.com/vitejs/vite/discussions/16358) 我们在此处收集新 API 的反馈。
+- [环境 API PR](https://github.com/vitejs/vite/pull/16471) 新 API 在此处被实现并进行了审查。
+
+请与我们分享您的反馈。
+:::
+
+## 引入环境概念 {#formalizing-environments}
+
+Vite 6 正式引入了环境(Environments)的概念。在 Vite 5 之前,有两个隐式环境(`client`,以及可选的 `ssr`)。新的环境 API 允许用户和框架作者根据他们的应用在生产环境中的工作方式创建尽可能多的环境。这些新的功能需要大规模的内部重构,而我们也已经在保持向后兼容性上做出了很大的努力。Vite 6 的初始目标是尽可能平滑地将整个生态系统迁移到新的主要版本,直到有足够的用户已经迁移,并且框架和插件作者已经验证了新的设计后,再采用这些新的实验性 API。
+
+## 缩小构建和开发模式间的差距 {#closing-the-gap-between-build-and-dev}
+
+对于简单的 SPA/MPA,配置中不会暴露任何与环境有关的新 API。在内部,Vite 会将选项应用于 `client` 环境,但在配置 Vite 时无需了解这一概念。Vite 5 中的配置和行为应能在此无缝运行。
+
+当我们移动到一个典型的服务器端渲染(SSR)应用程序时,我们将有两个环境:
+
+- `client`: 在浏览器中运行应用程序。
+- `ssr`: 在 node(或其他服务器运行时)中运行应用程序,渲染页面后再发送到浏览器。
+
+在开发过程中,Vite 会在与 Vite 开发服务器相同的 Node 进程中执行服务器代码,从而接近生产环境。不过,服务器也有可能在其他 JS 运行时中运行,如 [Cloudflare 的 workerd](https://github.com/cloudflare/workerd),它们有不同的限制。现代应用程序也可能在两个以上的环境中运行,例如浏览器、节点服务器和边缘服务器。Vite 5 无法正确表示这些环境。
+
+Vite 6 允许用户在构建和开发过程中配置应用程序,以映射其所有环境。在开发期间,一个 Vite 开发服务器现在可用于在多个不同环境中同时运行代码。应用程序源代码仍由 Vite 开发服务器进行转换。在共享 HTTP 服务器、中间件、解析配置和插件管道的基础上,Vite 开发服务器现在拥有一组独立的开发环境。每个开发环境的配置都尽可能与生产环境相匹配,并连接到执行代码的开发运行时(对于 Workerd,服务器代码现在可以在本地 miniflare 中运行)。在客户端,浏览器导入并执行代码。在其他环境中,模块运行程序会获取并评估转换后的代码。
+
+
+
+## 环境配置 {#environments-configuration}
+
+对于 SPA/MPA,配置与 Vite 5 类似。在内部,这些选项用于配置 `client` 环境。
+
+```js
+export default defineConfig({
+ build: {
+ sourcemap: false,
+ },
+ optimizeDeps: {
+ include: ['lib'],
+ },
+})
+```
+
+这一点很重要,因为我们希望 Vite 保持平易近人,避免在需要时才公开新概念。
+
+如果应用程序由多个环境组成,则可以使用 `environments` 配置选项显式配置这些环境。
+
+```js
+export default {
+ build: {
+ sourcemap: false,
+ },
+ optimizeDeps: {
+ include: ['lib'],
+ },
+ environments: {
+ server: {},
+ edge: {
+ resolve: {
+ noExternal: true,
+ },
+ },
+ },
+}
+```
+
+如果没有明确说明,环境将继承已配置的顶级配置选项(例如,新的 `server` 和 `edge` 环境将继承 `build.sourcemap: false` 选项)。少数顶级选项(如 `optimizeDeps`)仅适用于 `client` 环境,因为它们在默认应用于服务器环境时效果不佳。也可以通过 `environments.client` 明确配置 `client` 环境,但我们建议使用顶级选项进行配置,以便在添加新环境时客户端配置保持不变。
+
+`EnvironmentOptions` 接口公开所有每个环境选项。有些环境选项适用于 `build` 和 `dev`,如 `resolve`。还有 `DevEnvironmentOptions` 和 `BuildEnvironmentOptions` 用于开发和构建特定选项(如 `dev.warmup` 或 `build.outDir`)。一些选项(例如`optimizeDeps`)仅适用于 dev,但为了向后兼容,它保留为顶层而不是嵌套在`dev`中。
+
+```ts
+interface EnvironmentOptions {
+ define?: Record
+ resolve?: EnvironmentResolveOptions
+ optimizeDeps: DepOptimizationOptions
+ consumer?: 'client' | 'server'
+ dev: DevOptions
+ build: BuildOptions
+}
+```
+
+`UserConfig` 接口从 `EnvironmentOptions` 接口扩展而来,允许通过 `environments` 选项配置客户端和其他环境的默认值。在开发过程中,名为 `ssr` 的 `client` 和服务器环境始终存在。这允许与 `server.ssrLoadModule(url)` 和 `server.moduleGraph` 向后兼容。在构建期间,`client` 环境始终存在,而 `ssr` 环境仅在明确配置时才存在(使用 `environments.ssr` 或为了向后兼容而使用 `build.ssr`)。应用程序不需要为其 SSR 环境使用 `ssr` 名称,例如,它可以将其命名为 `server`。
+
+```ts
+interface UserConfig extends EnvironmentOptions {
+ environments: Record
+ // 其他选项
+}
+```
+
+请注意,一旦环境 API 稳定, `ssr` 顶级属性将被废弃。该选项的作用与 `environments` 相同,但针对的是默认的 `ssr` 环境,而且只允许配置一小部分选项。
+
+## 自定义环境实例 {#custom-environment-instances}
+
+底层 API 配置已可用,因此可以支持为运行时提供环境。这些环境还可以生成其他进程或线程,以便在更接近生产环境的运行时间内运行开发模块。
+
+```js
+import { customEnvironment } from 'vite-environment-provider'
+
+export default {
+ build: {
+ outDir: '/dist/client',
+ },
+ environments: {
+ ssr: customEnvironment({
+ build: {
+ outDir: '/dist/ssr',
+ },
+ }),
+ },
+}
+```
+
+## 向后兼容性 {#backward-compatibility}
+
+当前的 Vite 服务器 API 尚未被弃用,并且与 Vite 5 向后兼容。新的环境 API 是实验性的。
+
+`server.moduleGraph` 返回客户端和服务器端渲染(ssr)模块图的混合视图。所有其方法都将返回向后兼容的混合模块节点。对于传递给 `handleHotUpdate` 的模块节点,也使用相同的方案。
+
+我们不建议现在就切换到环境 API。我们的目标是在插件不需要维护两个版本之前,让大部分用户基础采用 Vite 6。查看未来破坏性更改部分以获取未来弃用和升级路径的信息:
+
+- [钩子函数中的 `this.environment`](/changes/this-environment-in-hooks)
+- [HMR `hotUpdate` 插件钩子](/changes/hotupdate-hook)
+- [迁移到基于环境的API](/changes/per-environment-apis)
+- [使用 `ModuleRunner` API 进行服务端渲染](/changes/ssr-using-modulerunner)
+- [构建过程中的共享插件](/changes/shared-plugins-during-build)
+
+## 目标用户 {#target-users}
+
+本指南为终端用户提供了关于环境的基本概念。
+
+插件作者可以使用更一致的 API 与当前环境配置进行交互。如果你正在基于 Vite 进行开发,[环境 API 插件指南](./api-environment-plugins.md) 描述了扩展插件 API 如何支持多个自定义环境。
+
+框架可以自行决定在不同层次上暴露环境。如果你是框架作者,请继续阅读 [环境 API 框架指南](./api-environment-frameworks.md),以了解环境 API 编程方面的内容。
+
+对于运行时提供者,[环境 API 运行时指南](./api-environment-runtimes.md) 解释了如何提供自定义环境供框架和用户使用。
diff --git a/guide/api-hmr.md b/guide/api-hmr.md
index 778d4d2f..ce5cd505 100644
--- a/guide/api-hmr.md
+++ b/guide/api-hmr.md
@@ -8,15 +8,18 @@
Vite 通过特殊的 `import.meta.hot` 对象暴露手动 HMR API。
-```ts
+```ts twoslash
+import type { ModuleNamespace } from 'vite/types/hot.d.ts'
+import type {
+ CustomEventName,
+ InferCustomEventPayload,
+} from 'vite/types/customEvent.d.ts'
+
+// ---cut---
interface ImportMeta {
readonly hot?: ViteHotContext
}
-type ModuleNamespace = Record & {
- [Symbol.toStringTag]: 'Module'
-}
-
interface ViteHotContext {
readonly data: any
@@ -25,19 +28,25 @@ interface ViteHotContext {
accept(dep: string, cb: (mod: ModuleNamespace | undefined) => void): void
accept(
deps: readonly string[],
- cb: (mods: Array) => void
+ cb: (mods: Array) => void,
): void
dispose(cb: (data: any) => void): void
- decline(): void
- invalidate(): void
+ prune(cb: (data: any) => void): void
+ invalidate(message?: string): void
- // `InferCustomEventPayload` provides types for built-in Vite events
- on(
+ on(
event: T,
- cb: (payload: InferCustomEventPayload) => void
+ cb: (payload: InferCustomEventPayload) => void,
+ ): void
+ off(
+ event: T,
+ cb: (payload: InferCustomEventPayload) => void,
+ ): void
+ send(
+ event: T,
+ data?: InferCustomEventPayload,
): void
- send(event: T, data?: InferCustomEventPayload): void
}
```
@@ -51,17 +60,26 @@ if (import.meta.hot) {
}
```
-## `hot.accept(cb)` {#hot-acceptcb}
+## TypeScript 的智能提示 {#intellisense-for-typescript}
+Vite 在 [`vite/client.d.ts`](https://github.com/vitejs/vite/blob/main/packages/vite/client.d.ts) 中为 `import.meta.hot` 提供了类型定义。你可以在 `src` 目录中创建一个 `vite-env.d.ts`,以便 TypeScript 获取类型定义:
+
+```ts [vite-env.d.ts]
+///
+```
+
+## `hot.accept(cb)` {#hot-accept-cb}
要接收模块自身,应使用 `import.meta.hot.accept`,参数为接收已更新模块的回调函数:
-```js
+```js twoslash
+import 'vite/client'
+// ---cut---
export const count = 1
if (import.meta.hot) {
import.meta.hot.accept((newModule) => {
if (newModule) {
- // newModule is undefined when SyntaxError happened
+ // 当语法错误发生时,newModule 是 undefined
console.log('updated: count is now ', newModule.count)
}
})
@@ -70,15 +88,21 @@ if (import.meta.hot) {
“接受” 热更新的模块被认为是 **HMR 边界**。
-请注意,Vite 的 HMR 实际上并不替换最初导入的模块:如果 HMR 边界模块从某个依赖重新导出其导入,则它应负责更新这些重新导出的模块(这些导出必须使用 `let`)。此外,从边界模块向上的导入者将不会收到更新。
+Vite 的 HMR 实际上并不替换最初导入的模块:如果一个 HMR 边界模块重新导出来自依赖项的导入,则它应负责更新这些重新导出的模块(这些导出必须使用 `let`)。此外,从边界模块向上的导入者将不会收到更新。这种简化的 HMR 实现对于大多数开发用例来说已经足够了,同时允许我们跳过生成代理模块的昂贵工作。
-这种简化的 HMR 实现对于大多数开发用例来说已经足够了,同时允许我们跳过生成代理模块的昂贵工作。
+Vite 要求这个函数的调用在源代码中显示为 `import.meta.hot.accept(`(对空格敏感),这样模块才能接受更新。这是 Vite 为使模块支持 HMR 而进行的静态分析的一个要求。
-## `hot.accept(deps, cb)`
+## `hot.accept(deps, cb)` {#hot-accept-deps-cb}
模块也可以接受直接依赖项的更新,而无需重新加载自身:
-```js
+```js twoslash
+// @filename: /foo.d.ts
+export declare const foo: () => void
+
+// @filename: /example.js
+import 'vite/client'
+// ---cut---
import { foo } from './foo.js'
foo()
@@ -93,17 +117,20 @@ if (import.meta.hot) {
import.meta.hot.accept(
['./foo.js', './bar.js'],
([newFooModule, newBarModule]) => {
- // 回调函数接收一个更新后模块的数组
+ // 只有当所更新的模块非空时,回调函数接收一个数组
+ // 如果更新不成功(例如语法错误),则该数组为空
}
)
}
```
-## `hot.dispose(cb)`
+## `hot.dispose(cb)` {#hot-dispose-cb}
一个接收自身的模块或一个期望被其他模块接收的模块可以使用 `hot.dispose` 来清除任何由其更新副本产生的持久副作用:
-```js
+```js twoslash
+import 'vite/client'
+// ---cut---
function setupSideEffect() {}
setupSideEffect()
@@ -115,17 +142,60 @@ if (import.meta.hot) {
}
```
+## `hot.prune(cb)` {#hot-prune-cb}
+
+注册一个回调,当模块在页面上不再被导入时调用。与 `hot.dispose` 相比,如果源代码更新时自行清理了副作用,你只需要在模块从页面上被删除时,使用此方法进行清理。Vite 目前在 `.css` 导入上使用此方法。
+
+```js twoslash
+import 'vite/client'
+// ---cut---
+function setupOrReuseSideEffect() {}
+
+setupOrReuseSideEffect()
+
+if (import.meta.hot) {
+ import.meta.hot.prune((data) => {
+ // 清理副作用
+ })
+}
+```
+
## `hot.data` {#hot-data}
`import.meta.hot.data` 对象在同一个更新模块的不同实例之间持久化。它可以用于将信息从模块的前一个版本传递到下一个版本。
+注意,不支持对 `data` 本身的重新赋值。相反,你应该对 `data` 对象的属性进行突变,以便保留从其他处理程序添加的信息。
+
+```js twoslash
+import 'vite/client'
+// ---cut---
+// ok
+import.meta.hot.data.someValue = 'hello'
+
+// 不支持
+import.meta.hot.data = { someValue: 'hello' }
+```
+
## `hot.decline()` {#hot-decline}
-调用 `import.meta.hot.decline()` 表示此模块不可热更新,如果在传播 HMR 更新时遇到此模块,浏览器应该执行完全重新加载。
+目前是一个空操作并暂留用于向后兼容。若有新的用途设计可能在未来会发生变更。要指明某模块是不可热更新的,请使用 `hot.invalidate()`。
-## `hot.invalidate()` {#hot-invalidate}
+## `hot.invalidate(message?: string)` {#hot-invalidate}
-现在调用 `import.meta.hot.invalidate()` 只是重新加载页面。
+一个接收自身的模块可以在运行时意识到它不能处理 HMR 更新,因此需要将更新强制传递给导入者。通过调用 `import.meta.hot.invalidate()`,HMR 服务将使调用方的导入失效,就像调用方不是接收自身的一样。这会同时在浏览器控制台和命令行中打印出一条信息,你可以传入这条信息,对发生失效的原因给予一些上下文。
+
+请注意,你应该总是调用 `import.meta.hot.accept`,即使你打算随后立即调用 `invalidate`,否则 HMR 客户端将不会监听未来对接收自身模块的更改。为了清楚地表达你的意图,我们建议在 `accept` 回调中调用 `invalidate`,例如:
+
+```js twoslash
+import 'vite/client'
+// ---cut---
+import.meta.hot.accept((module) => {
+ // 你可以使用新的模块实例来决定是否使其失效。
+ if (cannotHandleUpdate(module)) {
+ import.meta.hot.invalidate()
+ }
+})
+```
## `hot.on(event, cb)` {#hot-onevent-cb}
@@ -134,16 +204,30 @@ if (import.meta.hot) {
以下 HMR 事件由 Vite 自动触发:
- `'vite:beforeUpdate'` 当更新即将被应用时(例如,一个模块将被替换)
+- `'vite:afterUpdate'` 当更新已经被应用时(例如,一个模块已被替换)
- `'vite:beforeFullReload'` 当完整的重载即将发生时
- `'vite:beforePrune'` 当不再需要的模块即将被剔除时
+- `'vite:invalidate'` 当使用 `import.meta.hot.invalidate()` 使一个模块失效时
- `'vite:error'` 当发生错误时(例如,语法错误)
+- `'vite:ws:disconnect'` 当 WebSocket 连接丢失时
+- `'vite:ws:connect'` 当 WebSocket 重新建立连接时
自定义 HMR 事件可以由插件发送。更多细节详见 [handleHotUpdate](./api-plugin#handleHotUpdate)。
-## `hot.send(event, data)`
+## `hot.off(event, cb)` {#hot-offevent-cb}
+
+从事件监听器中移除回调函数。
+
+## `hot.send(event, data)` {#hot-send-event-data}
发送自定义事件到 Vite 开发服务器。
如果在连接前调用,数据会先被缓存、等到连接建立好后再发送。
-查看 [客户端与服务器的数据交互](/guide/api-plugin.html#client-server-communication) 一节获取更多细节。
+查看 [客户端与服务端间通信](/guide/api-plugin.html#client-server-communication) 以及 [自定义事件的 TypeScript 类型定义指南](/guide/api-plugin.html#typescript-for-custom-events) 章节获取更多细节。
+
+## 推荐阅读 {#further-reading}
+
+如果你想深入了解如何使用 HMR API,以及它的内部运作机制,可以参考以下资源:
+
+- [热模块替换其实很简单](https://bjornlu.com/blog/hot-module-replacement-is-easy)
diff --git a/guide/api-javascript.md b/guide/api-javascript.md
index bae9ba3b..699c120d 100644
--- a/guide/api-javascript.md
+++ b/guide/api-javascript.md
@@ -1,6 +1,6 @@
# JavaScript API {#javascript-api}
-Vite 的 JavaScript API 是完全类型化的,我们推荐使用 TypeScript 或者在 VS Code 中启用 JS 类型检查来利用智能提示和类型校验。
+Vite 的 JavaScript API 是完全类型化的,我们推荐使用 TypeScript 或者在 VS Code 中启用 JS 类型检查来利用智能提示和类型签名。
## `createServer` {#createserver}
@@ -12,29 +12,64 @@ async function createServer(inlineConfig?: InlineConfig): Promise
**使用示例:**
-```js
-import { fileURLToPath } from 'url'
+```ts twoslash
+import { fileURLToPath } from 'node:url'
import { createServer } from 'vite'
const __dirname = fileURLToPath(new URL('.', import.meta.url))
-;(async () => {
- const server = await createServer({
- // 任何合法的用户配置选项,加上 `mode` 和 `configFile`
- configFile: false,
- root: __dirname,
- server: {
- port: 1337
- }
- })
- await server.listen()
-
- server.printUrls()
-})()
+const server = await createServer({
+ // 任何合法的用户配置选项,加上 `mode` 和 `configFile`
+ configFile: false,
+ root: __dirname,
+ server: {
+ port: 1337,
+ },
+})
+await server.listen()
+
+server.printUrls()
+server.bindCLIShortcuts({ print: true })
```
::: tip 注意
-当在同一个 Node.js 进程中使用 `createServer` 和 `build` 时,两个函数都依赖于 `process.env.``NODE_ENV` 才可正常工作,而这个环境变量又依赖于 `mode` 配置项。为了避免行为冲突,请在这两个 API 传入参数 `development` 字段中设置 `process.env.``NODE_ENV` 或者 `mode` 配置项,或者你也可以生成另一个子进程,分别运行这两个 API。
+当在同一个 Node.js 进程中使用 `createServer` 和 `build` 时,两个函数都依赖于 `process.env.NODE_ENV` 才可正常工作,而这个环境变量又依赖于 `mode` 配置项。为了避免行为冲突,请在使用这两个 API 时为 `process.env.NODE_ENV` 或者 `mode` 配置项、字段设置参数值 `development`,或者你也可以生成另一个子进程,分别运行这两个 API。
+:::
+
+::: tip 注意
+当使用 [中间件模式](/config/server-options.md#server-middlewaremode) 与 [WebSocket 代理配置](/config/server-options.md#server-proxy) 时,父 http 服务器应该在 `middlewareMode` 中提供,以正确绑定代理。
+
+
+示例
+
+```ts twoslash
+import http from 'http'
+import { createServer } from 'vite'
+
+const parentServer = http.createServer() // or express, koa, etc.
+
+const vite = await createServer({
+ server: {
+ // 开启中间件模式
+ middlewareMode: {
+ // 提供父 http 服务器以代理 WebSocket
+ server: parentServer,
+ },
+ proxy: {
+ '/ws': {
+ target: 'ws://localhost:3000',
+ // Proxying WebSocket
+ ws: true,
+ },
+ },
+ },
+})
+
+// @noErrors: 2339
+parentServer.use(vite.middlewares)
+```
+
+
:::
## `InlineConfig` {#inlineconfig}
@@ -42,7 +77,6 @@ const __dirname = fileURLToPath(new URL('.', import.meta.url))
`InlineConfig` 接口扩展了 `UserConfig` 并添加了以下属性:
- `configFile`:指明要使用的配置文件。如果没有设置,Vite 将尝试从项目根目录自动解析。设置为 `false` 可以禁用自动解析功能。
-- `envFile`:设置为 `false` 时,则禁用 `.env` 文件。
## `ResolvedConfig` {#resolvedconfig}
@@ -73,8 +107,9 @@ interface ViteDevServer {
*/
httpServer: http.Server | null
/**
- * chokidar 监听器实例
- * https://github.com/paulmillr/chokidar#api
+ * chokidar 监听器实例。如果 `config.server.watch` 被设置为 `null`,
+ * 它不会监听任何文件,并且调用 `add` 或 `unwatch` 将不起作用。
+ * https://github.com/paulmillr/chokidar/tree/3.6.0#api
*/
watcher: FSWatcher
/**
@@ -90,8 +125,8 @@ interface ViteDevServer {
*/
moduleGraph: ModuleGraph
/**
- * Vite CLI 会打印出来的被解析的 URL。在中间件模式下、或是
- * 在 `server.listen` 调用之前会是 null
+ * Vite 在 CLI 上打印的已解析的 URL(经 URL 编码处理)。
+ * 在中间件模式下或服务器未监听任何端口时,返回 `null`。
*/
resolvedUrls: ResolvedServerUrls | null
/**
@@ -100,23 +135,32 @@ interface ViteDevServer {
*/
transformRequest(
url: string,
- options?: TransformOptions
+ options?: TransformOptions,
): Promise
/**
* 应用 Vite 内建 HTML 转换和任意插件 HTML 转换
*/
- transformIndexHtml(url: string, html: string): Promise
+ transformIndexHtml(
+ url: string,
+ html: string,
+ originalUrl?: string,
+ ): Promise
/**
* 加载一个给定的 URL 作为 SSR 的实例化模块
*/
ssrLoadModule(
url: string,
- options?: { fixStacktrace?: boolean }
+ options?: { fixStacktrace?: boolean },
): Promise>
/**
* 解决 ssr 错误堆栈信息
*/
ssrFixStacktrace(e: Error): void
+ /**
+ * 触发模块图中某个模块的 HMR。你可以使用 `server.moduleGraph`
+ * API 来检索要重新加载的模块。如果 `hmr` 是 `false`,则不进行任何操作
+ */
+ reloadModule(module: ModuleNode): Promise
/**
* 启动服务器
*/
@@ -131,39 +175,53 @@ interface ViteDevServer {
* 停止服务器
*/
close(): Promise
+ /**
+ * 绑定 CLI 快捷键
+ */
+ bindCLIShortcuts(options?: BindCLIShortcutsOptions): void
+ /**
+ * 调用 `await server.waitForRequestsIdle(id)` 会等待所有的静态导入
+ * 都被处理完。如果这个函数是从一个加载或转换的插件钩子中被调用的,那么你需要
+ * 把 id 作为参数传入,以避免死锁。在模块图的第一个静态导入部分被处理之后
+ * 调用这个函数,它将立即返回。
+ * @实验性
+ */
+ waitForRequestsIdle: (ignoredId?: string) => Promise
}
```
+:::info
+`waitForRequestsIdle` 的设计初衷是作为一种应急措施,以改善那些无法按照 Vite 开发服务器按需加载特性来实现的功能的开发体验。像 Tailwind 这样的工具可以在启动期间使用它,以便在应用代码被加载之前延迟生成应用的 CSS 类,从而避免样式的闪烁变化。当这个函数在加载或转换钩子中被使用,并且使用的是默认的 HTTP1 服务器时,六个 http 通道中的一个将被阻塞,直到服务器处理完所有的静态导入。Vite 的依赖优化器目前使用这个函数来避免在缺少依赖项时进行全页刷新,它通过延迟加载预打包的依赖项,直到从静态导入的源收集到所有的导入依赖项。在未来的主要版本中,Vite 可能会采取不同的策略,将 `optimizeDeps.crawlUntilStaticImports: false` 设置为默认值,以避免在大型应用程序在冷启动期间出现性能下降。
+:::
+
## `build` {#build}
-**类型校验:**
+**类型签名:**
```ts
async function build(
- inlineConfig?: InlineConfig
+ inlineConfig?: InlineConfig,
): Promise
```
**使用示例:**
-```js
-import path from 'path'
-import { fileURLToPath } from 'url'
+```ts twoslash [vite.config.js]
+import path from 'node:path'
+import { fileURLToPath } from 'node:url'
import { build } from 'vite'
const __dirname = fileURLToPath(new URL('.', import.meta.url))
-;(async () => {
- await build({
- root: path.resolve(__dirname, './project'),
- base: '/foo/',
- build: {
- rollupOptions: {
- // ...
- }
- }
- })
-})()
+await build({
+ root: path.resolve(__dirname, './project'),
+ base: '/foo/',
+ build: {
+ rollupOptions: {
+ // ...
+ },
+ },
+})
```
## `preview` {#preview}
@@ -176,34 +234,73 @@ async function preview(inlineConfig?: InlineConfig): Promise
**示例用法:**
-```js
+```ts twoslash
import { preview } from 'vite'
-;(async () => {
- const previewServer = await preview({
- // 任何有效的用户配置项,将加上 `mode` 和 `configFile`
- preview: {
- port: 8080,
- open: true
- }
- })
-
- previewServer.printUrls()
-})()
+
+const previewServer = await preview({
+ // 任何合法的用户配置选项,加上 `mode` 和 `configFile`
+ preview: {
+ port: 8080,
+ open: true,
+ },
+})
+
+previewServer.printUrls()
+previewServer.bindCLIShortcuts({ print: true })
+```
+
+## `PreviewServer`
+
+```ts
+interface PreviewServer {
+ /**
+ * 解析后的 vite 配置对象
+ */
+ config: ResolvedConfig
+ /**
+ * 一个 connect 应用实例。
+ * - 可用作将自定义中间件附加到预览服务器上。
+ * - 还可用作自定义 HTTP 服务器的处理函数
+ * 或作为任何 connect 风格的 Node.js 框架的中间件
+ *
+ * https://github.com/senchalabs/connect#use-middleware
+ */
+ middlewares: Connect.Server
+ /**
+ * 原生 Node http 服务器实例
+ */
+ httpServer: http.Server
+ /**
+ * Vite 在 CLI 上打印的已解析的 URL(经 URL 编码处理)。
+ * 在服务器未监听任何端口时,返回 `null`。
+ */
+ resolvedUrls: ResolvedServerUrls | null
+ /**
+ * 打印服务器 URL
+ */
+ printUrls(): void
+ /**
+ * 设置 CLI 快捷键
+ */
+ bindCLIShortcuts(options?: BindCLIShortcutsOptions): void
+}
```
## `resolveConfig` {#resolveconfig}
-**类型校验:**
+**类型签名:**
```ts
async function resolveConfig(
inlineConfig: InlineConfig,
command: 'build' | 'serve',
- defaultMode = 'development'
+ defaultMode = 'development',
+ defaultNodeEnv = 'development',
+ isPreview = false,
): Promise
```
-该 `command` 值在开发环境(即 CLI 命令 `vite`、`vite dev` 和 `vite serve`) 为 `serve`。
+该 `command` 值在开发环境和预览环境 为 `serve`,而在构建环境是 `build`。
## `mergeConfig`
@@ -213,12 +310,35 @@ async function resolveConfig(
function mergeConfig(
defaults: Record,
overrides: Record,
- isRoot = true
+ isRoot = true,
): Record
```
深度合并两份配置。`isRoot` 代表着 Vite 配置被合并的层级。举个例子,如果你是要合并两个 `build` 选项请设为 `false`。
+::: tip NOTE
+`mergeConfig` 只接受对象形式的配置。如果有一个回调形式的配置,应该在将其传递给 `mergeConfig` 之前先调用该回调函数,将其转换成对象形式。
+
+你可以使用 `defineConfig` 工具函数将回调形式的配置与另一个配置合并:
+
+```ts twoslash
+import {
+ defineConfig,
+ mergeConfig,
+ type UserConfigFnObject,
+ type UserConfig,
+} from 'vite'
+declare const configAsCallback: UserConfigFnObject
+declare const configAsObject: UserConfig
+
+// ---cut---
+export default defineConfig((configEnv) =>
+ mergeConfig(configAsCallback(configEnv), configAsObject),
+)
+```
+
+:::
+
## `searchForWorkspaceRoot`
**类型签名:**
@@ -226,7 +346,7 @@ function mergeConfig(
```ts
function searchForWorkspaceRoot(
current: string,
- root = searchForPackageRoot(current)
+ root = searchForPackageRoot(current),
): string
```
@@ -247,7 +367,7 @@ function searchForWorkspaceRoot(
function loadEnv(
mode: string,
envDir: string,
- prefixes: string | string[] = 'VITE_'
+ prefixes: string | string[] = 'VITE_',
): Record
```
@@ -276,7 +396,7 @@ async function transformWithEsbuild(
code: string,
filename: string,
options?: EsbuildTransformOptions,
- inMap?: object
+ inMap?: object,
): Promise
```
@@ -291,7 +411,8 @@ async function loadConfigFromFile(
configEnv: ConfigEnv,
configFile?: string,
configRoot: string = process.cwd(),
- logLevel?: LogLevel
+ logLevel?: LogLevel,
+ customLogger?: Logger,
): Promise<{
path: string
config: UserConfig
@@ -300,3 +421,30 @@ async function loadConfigFromFile(
```
手动通过 esbuild 加载一份 Vite 配置。
+
+## `preprocessCSS`
+
+- **实验性:** [提供反馈](https://github.com/vitejs/vite/discussions/13815)
+
+**类型签名:**
+
+```ts
+async function preprocessCSS(
+ code: string,
+ filename: string,
+ config: ResolvedConfig,
+): Promise
+
+interface PreprocessCSSResult {
+ code: string
+ map?: SourceMapInput
+ modules?: Record
+ deps?: Set
+}
+```
+
+预处理 `.css`、`.scss`、`.sass`、`.less`、`.styl` 和 `.stylus` 文件,将它们转化为纯 CSS,这样就可以在浏览器中使用或者被其他工具解析了。这和 [内置的 CSS 预处理器](/guide/features#css-pre-processors) 很像,如果你使用了这个功能,则必须安装相应的预处理器。
+
+使用哪个预处理器是根据 `filename` 的扩展名来推断的。如果 `filename` 以 `.module.{ext}` 结尾,那么它就会被推断为 [CSS module](https://github.com/css-modules/css-modules),返回的结果会包含一个 `modules` 对象,这个对象将原始的类名映射到转换后的类名。
+
+需要注意的是,预处理不会解析 `url()` 或 `image-set()` 中的 URL。
diff --git a/guide/api-plugin.md b/guide/api-plugin.md
index c030aa2b..305d09da 100644
--- a/guide/api-plugin.md
+++ b/guide/api-plugin.md
@@ -2,13 +2,13 @@
Vite 插件扩展了设计出色的 Rollup 接口,带有一些 Vite 独有的配置项。因此,你只需要编写一个 Vite 插件,就可以同时为开发环境和生产环境工作。
-**推荐在阅读下面的章节之前,首先阅读下 [Rollup 插件文档](https://rollupjs.org/guide/en/#plugin-development)**
+**推荐在阅读下面的章节之前,首先阅读下 [Rollup 插件文档](https://cn.rollupjs.org/plugin-development/)**
## 致插件创作者 {#authoring-a-plugin}
Vite 努力秉承开箱即用的原则,因此在创作一款新插件前,请确保已经阅读过 [Vite 的功能指南](/guide/features),避免重复劳作。同时还应查看社区是否存在可用插件,包括 [兼容 Rollup 的插件](https://github.com/rollup/awesome) 以及 [Vite 的专属插件](https://github.com/vitejs/awesome-vite#plugins)。
-当创作插件时,你可以在 `vite.config.js` 中直接使用它。没必要直接为它创建一个新的 package。当你发现某个插件在你项目中很有用时,可以考虑 [在社区中](https://chat.vitejs.dev) 将其与他人分享。
+当创作插件时,你可以在 `vite.config.js` 中直接使用它。没必要直接为它创建一个新的 package。当你发现某个插件在你项目中很有用时,可以考虑 [在社区中](https://chat.vite.dev) 将其与他人分享。
::: tip
在学习、调试或创作插件时,我们建议在你的项目中引入 [vite-plugin-inspect](https://github.com/antfu/vite-plugin-inspect)。 它可以帮助你检查 Vite 插件的中间状态。安装后,你可以访问 `localhost:5173/__inspect/` 来检查你项目的模块和栈信息。请查阅 [vite-plugin-inspect 文档](https://github.com/antfu/vite-plugin-inspect) 中的安装说明。
@@ -17,7 +17,7 @@ Vite 努力秉承开箱即用的原则,因此在创作一款新插件前,请
## 约定 {#conventions}
-如果插件不使用 Vite 特有的钩子,可以作为 [兼容 Rollup 的插件](#rollup-plugin-compatibility) 来实现,推荐使用 [Rollup 插件名称约定](https://rollupjs.org/guide/en/#conventions)。
+如果插件不使用 Vite 特有的钩子,可以作为 [兼容 Rollup 的插件](#rollup-plugin-compatibility) 来实现,推荐使用 [Rollup 插件名称约定](https://cn.rollupjs.org/plugin-development/#conventions)。
- Rollup 插件应该有一个带 `rollup-plugin-` 前缀、语义清晰的名称。
- 在 package.json 中包含 `rollup-plugin` 和 `vite-plugin` 关键字。
@@ -42,13 +42,12 @@ Vite 努力秉承开箱即用的原则,因此在创作一款新插件前,请
用户会将插件添加到项目的 `devDependencies` 中并使用数组形式的 `plugins` 选项配置它们。
-```js
-// vite.config.js
+```js [vite.config.js]
import vitePlugin from 'vite-plugin-feature'
import rollupPlugin from 'rollup-plugin-feature'
export default defineConfig({
- plugins: [vitePlugin(), rollupPlugin()]
+ plugins: [vitePlugin(), rollupPlugin()],
})
```
@@ -66,13 +65,12 @@ export default function framework(config) {
}
```
-```js
-// vite.config.js
+```js [vite.config.js]
import { defineConfig } from 'vite'
import framework from 'vite-plugin-framework'
export default defineConfig({
- plugins: [framework()]
+ plugins: [framework()],
})
```
@@ -98,7 +96,7 @@ export default function myPlugin() {
map: null // 如果可行将提供 source map
}
}
- }
+ },
}
}
```
@@ -127,7 +125,7 @@ export default function myPlugin() {
if (id === resolvedVirtualModuleId) {
return `export const msg = "from virtual module"`
}
- }
+ },
}
}
```
@@ -146,27 +144,31 @@ console.log(msg)
## 通用钩子 {#universal-hooks}
-在开发中,Vite 开发服务器会创建一个插件容器来调用 [Rollup 构建钩子](https://rollupjs.org/guide/en/#build-hooks),与 Rollup 如出一辙。
+在开发中,Vite 开发服务器会创建一个插件容器来调用 [Rollup 构建钩子](https://cn.rollupjs.org/plugin-development/#build-hooks),与 Rollup 如出一辙。
以下钩子在服务器启动时被调用:
-- [`options`](https://rollupjs.org/guide/en/#options)
-- [`buildStart`](https://rollupjs.org/guide/en/#buildstart)
+- [`options`](https://cn.rollupjs.org/plugin-development/#options)
+- [`buildStart`](https://cn.rollupjs.org/plugin-development/#buildstart)
以下钩子会在每个传入模块请求时被调用:
-- [`resolveId`](https://rollupjs.org/guide/en/#resolveid)
-- [`load`](https://rollupjs.org/guide/en/#load)
-- [`transform`](https://rollupjs.org/guide/en/#transform)
+- [`resolveId`](https://cn.rollupjs.org/plugin-development/#resolveid)
+- [`load`](https://cn.rollupjs.org/plugin-development/#load)
+- [`transform`](https://cn.rollupjs.org/plugin-development/#transform)
+
+它们还有一个扩展的 `options` 参数,包含其他特定于 Vite 的属性。你可以在 [SSR 文档](/guide/ssr#ssr-specific-plugin-logic) 中查阅更多内容。
+
+一些 `resolveId` 调用的 `importer` 值可能是根目录下的通用 `index.html` 的绝对路径,这是由于 Vite 非打包的开发服务器模式无法始终推断出实际的导入者。对于在 Vite 的解析管道中处理的导入,可以在导入分析阶段跟踪导入者,提供正确的 `importer` 值。
以下钩子在服务器关闭时被调用:
-- [`buildEnd`](https://rollupjs.org/guide/en/#buildend)
-- [`closeBundle`](https://rollupjs.org/guide/en/#closebundle)
+- [`buildEnd`](https://cn.rollupjs.org/plugin-development/#buildend)
+- [`closeBundle`](https://cn.rollupjs.org/plugin-development/#closebundle)
-请注意 [`moduleParsed`](https://rollupjs.org/guide/en/#moduleparsed) 钩子在开发中是 **不会** 被调用的,因为 Vite 为了性能会避免完整的 AST 解析。
+请注意 [`moduleParsed`](https://cn.rollupjs.org/plugin-development/#moduleparsed) 钩子在开发中是 **不会** 被调用的,因为 Vite 为了性能会避免完整的 AST 解析。
-[Output Generation Hooks](https://rollupjs.org/guide/en/#output-generation-hooks)(除了 `closeBundle`) 在开发中是 **不会** 被调用的。你可以认为 Vite 的开发服务器只调用了 `rollup.rollup()` 而没有调用 `bundle.generate()`。
+[Output Generation Hooks](https://cn.rollupjs.org/plugin-development/#output-generation-hooks)(除了 `closeBundle`) 在开发中是 **不会** 被调用的。你可以认为 Vite 的开发服务器只调用了 `rollup.rollup()` 而没有调用 `bundle.generate()`。
## Vite 独有钩子 {#vite-specific-hooks}
@@ -175,7 +177,7 @@ Vite 插件也可以提供钩子来服务于特定的 Vite 目标。这些钩子
### `config` {#config}
- **类型:** `(config: UserConfig, env: { mode: string, command: string }) => UserConfig | null | void`
-- **种类:** `async`, `sequential`
+- **种类:** `async`,`sequential`
在解析 Vite 配置前调用。钩子接收原始用户配置(命令行选项指定的会与配置文件合并)和一个描述配置环境的变量,包含正在使用的 `mode` 和 `command`。它可以返回一个将被深度合并到现有配置中的部分配置对象,或者直接改变配置(如果默认的合并不能达到预期的结果)。
@@ -188,10 +190,10 @@ Vite 插件也可以提供钩子来服务于特定的 Vite 目标。这些钩子
config: () => ({
resolve: {
alias: {
- foo: 'bar'
- }
- }
- })
+ foo: 'bar',
+ },
+ },
+ }),
})
// 直接改变配置(应仅在合并不起作用时使用)
@@ -201,7 +203,7 @@ Vite 插件也可以提供钩子来服务于特定的 Vite 目标。这些钩子
if (command === 'build') {
config.root = 'foo'
}
- }
+ },
})
```
@@ -212,7 +214,7 @@ Vite 插件也可以提供钩子来服务于特定的 Vite 目标。这些钩子
### `configResolved` {#configresolved}
- **类型:** `(config: ResolvedConfig) => void | Promise`
-- **种类:** `async`, `parallel`
+- **种类:** `async`,`parallel`
在解析 Vite 配置后调用。使用这个钩子读取和存储最终解析的配置。当插件需要根据运行的命令做一些不同的事情时,它也很有用。
@@ -237,7 +239,7 @@ Vite 插件也可以提供钩子来服务于特定的 Vite 目标。这些钩子
} else {
// build: 由 Rollup 调用的插件
}
- }
+ },
}
}
```
@@ -247,7 +249,7 @@ Vite 插件也可以提供钩子来服务于特定的 Vite 目标。这些钩子
### `configureServer` {#configureserver}
- **类型:** `(server: ViteDevServer) => (() => void) | void | Promise<(() => void) | void>`
-- **种类:** `async`, `sequential`
+- **种类:** `async`,`sequential`
- **此外请看** [ViteDevServer](./api-javascript#vitedevserver)
是用于配置开发服务器的钩子。最常见的用例是在内部 [connect](https://github.com/senchalabs/connect) 应用程序中添加自定义中间件:
@@ -259,7 +261,7 @@ Vite 插件也可以提供钩子来服务于特定的 Vite 目标。这些钩子
server.middlewares.use((req, res, next) => {
// 自定义请求处理...
})
- }
+ },
})
```
@@ -278,7 +280,7 @@ Vite 插件也可以提供钩子来服务于特定的 Vite 目标。这些钩子
// 自定义请求处理...
})
}
- }
+ },
})
```
@@ -298,7 +300,7 @@ Vite 插件也可以提供钩子来服务于特定的 Vite 目标。这些钩子
if (server) {
// 使用 server...
}
- }
+ },
}
}
```
@@ -307,10 +309,11 @@ Vite 插件也可以提供钩子来服务于特定的 Vite 目标。这些钩子
### `configurePreviewServer` {#configurepreviewserver}
-- **类型:** `(server: { middlewares: Connect.Server, httpServer: http.Server }) => (() => void) | void | Promise<(() => void) | void>`
-- **种类:** `async`, `sequential`
+- **类型:** `(server: PreviewServer) => (() => void) | void | Promise<(() => void) | void>`
+- **种类:** `async`,`sequential`
+- **参见:** [PreviewServerForHook](./api-javascript#previewserverforhook)
- 与 [`configureServer`](/guide/api-plugin.html#configureserver) 相同但是作为预览服务器。。它提供了一个 [connect](https://github.com/senchalabs/connect) 服务器实例及其底层的 [http server](https://nodejs.org/api/http.html)。与 `configureServer` 类似,`configurePreviewServer` 这个钩子也是在其他中间件安装前被调用的。如果你想要在其他中间件 **之后** 安装一个插件,你可以从 `configurePreviewServer` 返回一个函数,它将会在内部中间件被安装之后再调用:
+ 与 [`configureServer`](/guide/api-plugin.html#configureserver) 相同,但用于预览服务器。`configurePreviewServer` 这个钩子与 `configureServer` 类似,也是在其他中间件安装前被调用。如果你想要在其他中间件 **之后** 安装一个插件,你可以从 `configurePreviewServer` 返回一个函数,它将会在内部中间件被安装之后再调用:
```js
const myPlugin = () => ({
@@ -322,14 +325,14 @@ Vite 插件也可以提供钩子来服务于特定的 Vite 目标。这些钩子
// 自定义处理请求 ...
})
}
- }
+ },
})
```
### `transformIndexHtml` {#transformindexhtml}
-- **类型:** `IndexHtmlTransformHook | { enforce?: 'pre' | 'post', transform: IndexHtmlTransformHook }`
-- **种类:** `async`, `sequential`
+- **类型:** `IndexHtmlTransformHook | { order?: 'pre' | 'post', handler: IndexHtmlTransformHook }`
+- **种类:** `async`,`sequential`
转换 `index.html` 的专用钩子。钩子接收当前的 HTML 字符串和转换上下文。上下文在开发期间暴露[`ViteDevServer`](./api-javascript#vitedevserver)实例,在构建期间暴露 Rollup 输出的包。
@@ -339,6 +342,8 @@ Vite 插件也可以提供钩子来服务于特定的 Vite 目标。这些钩子
- 注入到现有 HTML 中的标签描述符对象数组(`{ tag, attrs, children }`)。每个标签也可以指定它应该被注入到哪里(默认是在 `` 之前)
- 一个包含 `{ html, tags }` 的对象
+ 默认情况下 `order` 是 `undefined`,这个钩子会在 HTML 被转换后应用。为了注入一个应该通过 Vite 插件管道的脚本, `order: 'pre'` 指将在处理 HTML 之前应用。 `order: 'post'` 是在所有未定义的 `order` 的钩子函数被应用后才应用。
+
**基础示例:**
```js
@@ -348,9 +353,9 @@ Vite 插件也可以提供钩子来服务于特定的 Vite 目标。这些钩子
transformIndexHtml(html) {
return html.replace(
/(.*?)<\/title>/,
- `Title replaced! `
+ `Title replaced! `,
)
- }
+ },
}
}
```
@@ -366,7 +371,7 @@ Vite 插件也可以提供钩子来服务于特定的 Vite 目标。这些钩子
server?: ViteDevServer
bundle?: import('rollup').OutputBundle
chunk?: import('rollup').OutputChunk
- }
+ },
) =>
| IndexHtmlTransformResult
| void
@@ -391,9 +396,14 @@ Vite 插件也可以提供钩子来服务于特定的 Vite 目标。这些钩子
}
```
+ ::: warning 注意
+ 如果你正在使用一个对入口文件有特殊处理方式的框架(比如 [SvelteKit](https://github.com/sveltejs/kit/discussions/8269#discussioncomment-4509145)),那么这个钩子就不会被触发。
+ :::
+
### `handleHotUpdate` {#handlehotupdate}
- **类型:** `(ctx: HmrContext) => Array | void | Promise | void>`
+- **参见:** [HMR API](./api-hmr)
执行自定义 HMR 更新处理。钩子接收一个带有以下签名的上下文对象:
@@ -415,7 +425,26 @@ Vite 插件也可以提供钩子来服务于特定的 Vite 目标。这些钩子
- 过滤和缩小受影响的模块列表,使 HMR 更准确。
- - 返回一个空数组,并通过向客户端发送自定义事件来执行完整的自定义 HMR 处理:
+ - 返回一个空数组并进行全面刷新:
+
+ ```js
+ handleHotUpdate({ server, modules, timestamp }) {
+ // 手动使模块失效
+ const invalidatedModules = new Set()
+ for (const mod of modules) {
+ server.moduleGraph.invalidateModule(
+ mod,
+ invalidatedModules,
+ timestamp,
+ true
+ )
+ }
+ server.ws.send({ type: 'full-reload' })
+ return []
+ }
+ ```
+
+ - 返回一个空数组,并通过向客户端发送自定义事件,来进行完全自定义的 HMR处理:
```js
handleHotUpdate({ server }) {
@@ -450,6 +479,8 @@ Vite 插件也可以提供钩子来服务于特定的 Vite 目标。这些钩子
- 带有 `enforce: 'post'` 的用户插件
- Vite 后置构建插件(最小化,manifest,报告)
+请注意,这与钩子的排序是分开的,钩子的顺序仍然会受到它们的 `order` 属性的影响,这一点 [和 Rollup 钩子的表现一样](https://cn.rollupjs.org/plugin-development/#build-hooks)。
+
## 情景应用 {#conditional-application}
默认情况下插件在开发(serve)和构建(build)模式中都会调用。如果插件只需要在预览或构建期间有条件地应用,请使用 `apply` 属性指明它们仅在 `'build'` 或 `'serve'` 模式时调用:
@@ -478,15 +509,14 @@ apply(config, { command }) {
一般来说,只要 Rollup 插件符合以下标准,它就应该像 Vite 插件一样工作:
-- 没有使用 [`moduleParsed`](https://rollupjs.org/guide/en/#moduleparsed) 钩子。
+- 没有使用 [`moduleParsed`](https://cn.rollupjs.org/plugin-development/#moduleparsed) 钩子。
- 它在打包钩子和输出钩子之间没有很强的耦合。
如果一个 Rollup 插件只在构建阶段有意义,则在 `build.rollupOptions.plugins` 下指定即可。它的工作原理与 Vite 插件的 `enforce: 'post'` 和 `apply: 'build'` 相同。
你也可以用 Vite 独有的属性来扩展现有的 Rollup 插件:
-```js
-// vite.config.js
+```js [vite.config.js]
import example from 'rollup-plugin-example'
import { defineConfig } from 'vite'
@@ -495,14 +525,12 @@ export default defineConfig({
{
...example(),
enforce: 'post',
- apply: 'build'
- }
- ]
+ apply: 'build',
+ },
+ ],
})
```
-查看 [Vite Rollup 插件](https://vite-rollup-plugins.patak.dev) 获取兼容的官方 Rollup 插件列表及其使用指南。
-
## 路径规范化 {#path-normalization}
Vite 对路径进行了规范化处理,在解析路径时使用 POSIX 分隔符( / ),同时保留了 Windows 中的卷名。而另一方面,Rollup 在默认情况下保持解析的路径不变,因此解析的路径在 Windows 中会使用 win32 分隔符( \\ )。然而,Rollup 插件会使用 `@rollup/pluginutils` 内部的 [`normalizePath` 工具函数](https://github.com/rollup/plugins/tree/master/packages/pluginutils#normalizepath),它在执行比较之前将分隔符转换为 POSIX。所以意味着当这些插件在 Vite 中使用时,`include` 和 `exclude` 两个配置模式,以及与已解析路径比较相似的路径会正常工作。
@@ -526,19 +554,20 @@ Vite 暴露了 [`@rollup/pluginutils` 的 `createFilter`](https://github.com/rol
### 服务端到客户端 {#server-to-client}
-在插件一侧,我们可以使用 `server.ws.send` 去给所有客户端广播事件:
+在插件一侧,我们可以使用 `server.ws.send` 来向客户端广播事件:
-```js
-// vite.config.js
+```js [vite.config.js]
export default defineConfig({
plugins: [
{
// ...
configureServer(server) {
- server.ws.send('my:greetings', { msg: 'hello' })
- }
- }
- ]
+ server.ws.on('connection', () => {
+ server.ws.send('my:greetings', { msg: 'hello' })
+ })
+ },
+ },
+ ],
})
```
@@ -548,8 +577,10 @@ export default defineConfig({
在客户端侧,使用 [`hot.on`](/guide/api-hmr.html#hot-on-event-cb) 去监听事件:
-```ts
-// client side
+```ts twoslash
+import 'vite/client'
+// ---cut---
+// 客户端
if (import.meta.hot) {
import.meta.hot.on('my:greetings', (data) => {
console.log(data.msg) // hello
@@ -562,7 +593,7 @@ if (import.meta.hot) {
为了从客户端向服务端发送事件,我们可以使用 [`hot.send`](/guide/api-hmr.html#hot-send-event-payload):
```ts
-// client side
+// 客户端
if (import.meta.hot) {
import.meta.hot.send('my:from-client', { msg: 'Hey!' })
}
@@ -570,8 +601,7 @@ if (import.meta.hot) {
然后使用 `server.ws.on` 并在服务端监听这些事件:
-```js
-// vite.config.js
+```js [vite.config.js]
export default defineConfig({
plugins: [
{
@@ -579,27 +609,50 @@ export default defineConfig({
configureServer(server) {
server.ws.on('my:from-client', (data, client) => {
console.log('Message from client:', data.msg) // Hey!
- // reply only to the client (if needed)
+ // 只回复客户端(如果需要的话)
client.send('my:ack', { msg: 'Hi! I got your message!' })
})
- }
- }
- ]
+ },
+ },
+ ],
})
```
### 自定义事件的 TypeScript 类型定义指南 {#typeScript-for-custom-events}
-可以通过扩展 `CustomEventMap` 这个 interface 来为自定义事件标注类型:
+Vite 会在内部从 `CustomEventMap` 这个接口推断出 payload 的类型,可以通过扩展这个接口来为自定义事件进行类型定义:
-```ts
-// events.d.ts
-import 'vite/types/customEvent'
+:::tip 提示
+在指定 TypeScript 声明文件时,确保包含 `.d.ts` 扩展名。否则,TypeScript 可能不会知道试图扩展的是哪个文件。
+:::
-declare module 'vite/types/customEvent' {
+```ts [events.d.ts]
+import 'vite/types/customEvent.d.ts'
+
+declare module 'vite/types/customEvent.d.ts' {
interface CustomEventMap {
'custom:foo': { msg: string }
// 'event-key': payload
}
}
```
+
+这个接口扩展被 `InferCustomEventPayload` 所使用,用来推断事件 `T` 的 payload 类型。要了解更多关于这个接口如何被使用的信息,请参考 [HMR API 文档](./api-hmr#hmr-api)。
+
+```ts twoslash
+import 'vite/client'
+import type { InferCustomEventPayload } from 'vite/types/customEvent.d.ts'
+declare module 'vite/types/customEvent.d.ts' {
+ interface CustomEventMap {
+ 'custom:foo': { msg: string }
+ }
+}
+// ---cut---
+type CustomFooPayload = InferCustomEventPayload<'custom:foo'>
+import.meta.hot?.on('custom:foo', (payload) => {
+ // payload 的类型为 { msg: string }
+})
+import.meta.hot?.on('unknown:event', (payload) => {
+ // payload 的类型为 any
+})
+```
diff --git a/guide/api-vite-runtime.md b/guide/api-vite-runtime.md
new file mode 100644
index 00000000..39845ff3
--- /dev/null
+++ b/guide/api-vite-runtime.md
@@ -0,0 +1,236 @@
+# Vite Runtime API {#vite-runtime-api}
+
+:::warning 底层 API
+这个 API 在 Vite 5.1 中作为一个实验性特性引入。它被添加以 [收集反馈](https://github.com/vitejs/vite/discussions/15774)。在Vite 5.2 中,它可能会有破坏性的变化,所以在使用它时,请确保将 Vite 版本固定在 `~5.1.0`。这是一个面向库和框架作者的底层 API。如果你的目标是开发应用,请确保首先查看 [Vite SSR 精选板块](https://github.com/vitejs/awesome-vite#ssr) 的高级 SSR 插件和工具。
+
+目前,这种 API 正在以 [环境 API](https://github.com/vitejs/vite/discussions/16358) 的形式进行修正,并在 `^6.0.0-alpha.0` 版本中发布。
+:::
+
+"Vite 运行时" 是一个工具,它允许首先用 Vite 插件处理任何代码后运行。它与 `server.ssrLoadModule` 不同,因为运行时实现是从服务器解耦的。这允许库和框架作者实现他们自己的服务器和运行时之间的通信层。
+
+这个特性的一个目标是提供一个可定制的API来处理和运行代码。Vite 提供了足够的工具来开箱即用 Vite 运行时,但如果用户的需求与 Vite 的内置实现不一致,他们可以在其基础上进行构建。
+
+除非另有说明,所有API都可以从 `vite/runtime` 导入。
+
+## `ViteRuntime`
+
+**类型签名:**
+
+```ts
+export class ViteRuntime {
+ constructor(
+ public options: ViteRuntimeOptions,
+ public runner: ViteModuleRunner,
+ private debug?: ViteRuntimeDebugger,
+ ) {}
+ /**
+ * 要执行的 URL。可以是文件路径、服务器路径,或者是相对于根目录的 id。
+ */
+ public async executeUrl(url: string): Promise
+ /**
+ * 执行的入口文件 URL。可以是文件路径、服务器路径,或者是相对于根目录的 id。
+ * 如果是由 HMR 触发的全面重载,那么这就是将要被重载的模块。
+ * 如果这个方法被多次调用,所有的入口文件都将逐一被重新加载。
+ */
+ public async executeEntrypoint(url: string): Promise
+ /**
+ * 清除所有缓存,包括 HMR 监听器。
+ */
+ public clearCache(): void
+ /**
+ * 清除所有缓存,移除所有 HMR 监听器,并重置 sourcemap 支持。
+ * 此方法不会停止 HMR 连接。
+ */
+ public async destroy(): Promise
+ /**
+ * 如果通过调用 `destroy()` 方法销毁了运行时,则返回 `true`。
+ */
+ public isDestroyed(): boolean
+}
+```
+
+::: tip 进阶用法
+如果你是从 `server.ssrLoadModule` 迁移过来,并且想要支持模块热替换(HMR),你可以考虑用 [`createViteRuntime`](#createviteruntime) 替代。
+:::
+
+当你初始化 `ViteRuntime` 类时,需要 `root` 和 `fetchModule` 这两个选项。Vite 在 [`server`](/guide/api-javascript) 实例中公开了 `ssrFetchModule`,以便更方便地与 Vite SSR 集成。Vite 主入口也导出了 `fetchModule` - 它不会假设代码的运行方式,这与期望代码通过 `new Function` 运行的 `ssrFetchModule` 是不同的,这一点可以从这些函数返回的 sourcemap 中看出。
+
+`ViteRuntime` 中的 Runner 负责执行代码。Vite 开箱即用地提供了 `ESModulesRunner`,它使用 `new AsyncFunction` 来运行代码。如果你的 JavaScript 运行环境不支持不安全的执行,你可以提供你自己的实现。
+
+运行时公开的两个主要方法是 `executeUrl` 和 `executeEntrypoint`。它们之间唯一的区别是,如果模块热替换(HMR)触发了 `full-reload` 事件,那么 `executeEntrypoint` 执行的所有模块都将重新执行。但请注意,当这种情况发生时,Vite 运行时不会更新 `exports` 对象(它会被覆盖),如果你需要最新的 `exports` 对象,你需要重新运行 `executeUrl` 或从 `moduleCache` 再次获取模块。
+
+**使用示例:**
+
+```js
+import { ViteRuntime, ESModulesRunner } from 'vite/runtime'
+import { root, fetchModule } from './rpc-implementation.js'
+
+const runtime = new ViteRuntime(
+ {
+ root,
+ fetchModule,
+ // 你也可以提供 hmr.connection 以支持 HMR。
+ },
+ new ESModulesRunner(),
+)
+
+await runtime.executeEntrypoint('/src/entry-point.js')
+```
+
+## `ViteRuntimeOptions`
+
+```ts
+export interface ViteRuntimeOptions {
+ /**
+ * 项目根目录
+ */
+ root: string
+ /**
+ * 获取模块信息的方法
+ * 对于 SSR,Vite 提供了你可以使用的 `server.ssrFetchModule` 函数。
+ * 对于其他运行时用例,Vite 也从其主入口点提供了 `fetchModule`。
+ */
+ fetchModule: FetchFunction
+ /**
+ * 配置 sourcemap 的解析方式。如果 `process.setSourceMapsEnabled` 可用,优先选择 `node`。
+ * 否则,默认使用 `prepareStackTrace`,这会覆盖 `Error.prepareStackTrace` 方法。
+ * 你可以提供一个对象来配置如何解析那些没有被 Vite 处理过的文件的内容和源代码映射。
+ */
+ sourcemapInterceptor?:
+ | false
+ | 'node'
+ | 'prepareStackTrace'
+ | InterceptorOptions
+ /**
+ * 禁用 HMR 或配置 HMR 选项。
+ */
+ hmr?:
+ | false
+ | {
+ /**
+ * 配置 HMR 如何在客户端和服务器之间通信。
+ */
+ connection: HMRRuntimeConnection
+ /**
+ * 配置 HMR 日志。
+ */
+ logger?: false | HMRLogger
+ }
+ /**
+ * 自定义模块缓存。如果未提供,它将为每个 Vite 运行环境实例创建一个独立的模块缓存。
+ */
+ moduleCache?: ModuleCacheMap
+}
+```
+
+## `ViteModuleRunner`
+
+**类型签名:**
+
+```ts
+export interface ViteModuleRunner {
+ /**
+ * 运行被 Vite 转换过的代码。
+ * @param context Function context
+ * @param code Transformed code
+ * @param id ID that was used to fetch the module
+ */
+ runViteModule(
+ context: ViteRuntimeModuleContext,
+ code: string,
+ id: string,
+ ): Promise
+ /**
+ * 运行已外部化的模块。
+ * @param file File URL to the external module
+ */
+ runExternalModule(file: string): Promise
+}
+```
+
+Vite 默认导出了实现了这个接口的 `ESModulesRunner`。它使用 `new AsyncFunction` 来执行代码,所以如果代码中有内联的源代码映射(sourcemap),它应该包含 [2行的偏移](https://tc39.es/ecma262/#sec-createdynamicfunction) 以适应新添加的行。这是由 `server.ssrFetchModule` 自动完成的。如果你的 runner 实现没有这个限制,你应该直接使用 `fetchModule`(从 `vite` 导出)。
+
+## HMRRuntimeConnection
+
+**类型签名:**
+
+```ts
+export interface HMRRuntimeConnection {
+ /**
+ * 在向客户端发送消息之前进行检查
+ */
+ isReady(): boolean
+ /**
+ * 向客户端发送消息
+ */
+ send(message: string): void
+ /**
+ * 配置当此连接触发更新时如何处理 HMR。
+ * 此方法期望连接将开始监听 HMR 更新,并在接收到时调用此回调。
+ */
+ onUpdate(callback: (payload: HMRPayload) => void): void
+}
+```
+
+这个接口定义了如何建立模块热替换(HMR)的通信。Vite 从主入口处导出 `ServerHMRConnector`,以在 Vite SSR 期间支持 HMR。当自定义事件被触发时(例如,`import.meta.hot.send("my-event")`),通常会调用 `isReady` 和 `send` 方法。
+
+只有在新的运行环境启动时,才会调用 `onUpdate`。它传递下来一个在连接触发 HMR 事件时应该调用的方法。实现方式取决于连接的类型(例如,它可以是 `WebSocket`/`EventEmitter`/`MessageChannel`),但通常看起来像这样:
+
+```js
+function onUpdate(callback) {
+ this.connection.on('hmr', (event) => callback(event.data))
+}
+```
+
+回调会被放入队列中,它会等待当前的更新完成后才处理下一个更新。与浏览器的实现不同,Vite 运行环境中的 HMR 更新会等到所有的监听器(例如,`vite:beforeUpdate`/`vite:beforeFullReload`)都完成后才更新模块。
+
+## `createViteRuntime`
+
+**类型签名:**
+
+```ts
+async function createViteRuntime(
+ server: ViteDevServer,
+ options?: MainThreadRuntimeOptions,
+): Promise
+```
+
+**使用示例:**
+
+```js
+import { createServer } from 'vite'
+
+const __dirname = fileURLToPath(new URL('.', import.meta.url))
+
+;(async () => {
+ const server = await createServer({
+ root: __dirname,
+ })
+ await server.listen()
+
+ const runtime = await createViteRuntime(server)
+ await runtime.executeEntrypoint('/src/entry-point.js')
+})()
+```
+
+这个方法可以作为 `server.ssrLoadModule` 的简单替代。不同于 `ssrLoadModule`,`createViteRuntime` 默认就支持 HMR。你可以传递 [`options`](#mainthreadruntimeoptions) 来定制 SSR 运行环境的行为,以满足你的需求。
+
+## `MainThreadRuntimeOptions`
+
+```ts
+export interface MainThreadRuntimeOptions
+ extends Omit {
+ /**
+ * 禁用 HMR 或配置 HMR 日志。
+ */
+ hmr?:
+ | false
+ | {
+ logger?: false | HMRLogger
+ }
+ /**
+ * 提供自定义模块运行器。这决定了代码的执行方式。
+ */
+ runner?: ViteModuleRunner
+}
+```
diff --git a/guide/assets.md b/guide/assets.md
index 25b04a97..f7528fc4 100644
--- a/guide/assets.md
+++ b/guide/assets.md
@@ -7,12 +7,14 @@
服务时引入一个静态资源会返回解析后的公共路径:
-```js
+```js twoslash
+import 'vite/client'
+// ---cut---
import imgUrl from './img.png'
document.getElementById('hero-img').src = imgUrl
```
-例如,`imgUrl` 在开发时会是 `/img.png`,在生产构建后会是 `/assets/img.2d8efhg.png`。
+例如,`imgUrl` 在开发时会是 `/src/img.png`,在生产构建后会是 `/assets/img.2d8efhg.png`。
行为类似于 Webpack 的 `file-loader`。区别在于导入既可以使用绝对公共路径(基于开发期间的项目根路径),也可以使用相对路径。
@@ -28,20 +30,49 @@ document.getElementById('hero-img').src = imgUrl
- Git LFS 占位符会自动排除在内联之外,因为它们不包含它们所表示的文件的内容。要获得内联,请确保在构建之前通过 Git LFS 下载文件内容。
+- 默认情况下,TypeScript 不会将静态资源导入视为有效的模块。要解决这个问题,需要添加 [`vite/client`](./features#client-types)。
+
+::: tip 通过 `url()` 内联 SVG
+当在 JS 中手动构造 `url()` 并传入一个 SVG 的 URL 时,应该用双引号将变量包裹起来。
+
+```js twoslash
+import 'vite/client'
+// ---cut---
+import imgUrl from './img.svg'
+document.getElementById('hero-img').style.background = `url("${imgUrl}")`
+```
+
+:::
+
### 显式 URL 引入 {#explicit-url-imports}
-未被包含在内部列表或 `assetsInclude` 中的资源,可以使用 `?url` 后缀显式导入为一个 URL。这十分有用,例如,要导入 [Houdini Paint Worklets](https://houdini.how/usage) 时:
+未被包含在内部列表或 `assetsInclude` 中的资源,可以使用 `?url` 后缀显式导入为一个 URL。这十分有用,例如,要导入 [Houdini Paint Worklets](https://developer.mozilla.org/en-US/docs/Web/API/CSS/paintWorklet_static) 时:
-```js
+```js twoslash
+import 'vite/client'
+// ---cut---
import workletURL from 'extra-scalloped-border/worklet.js?url'
CSS.paintWorklet.addModule(workletURL)
```
+### 显式内联处理 {#explicit-inline-handling}
+
+可以分别使用`?inline`或`?no-inline`后缀,明确导入带内联或不带内联的静态资源。
+
+```js twoslash
+import 'vite/client'
+// ---cut---
+import imgUrl1 from './img.svg?no-inline'
+import imgUrl2 from './img.png?inline'
+```
+
### 将资源引入为字符串 {#importing-asset-as-string}
资源可以使用 `?raw` 后缀声明作为字符串引入。
-```js
+```js twoslash
+import 'vite/client'
+// ---cut---
import shaderString from './shader.glsl?raw'
```
@@ -49,19 +80,25 @@ import shaderString from './shader.glsl?raw'
脚本可以通过 `?worker` 或 `?sharedworker` 后缀导入为 web worker。
-```js
+```js twoslash
+import 'vite/client'
+// ---cut---
// 在生产构建中将会分离出 chunk
import Worker from './shader.js?worker'
const worker = new Worker()
```
-```js
+```js twoslash
+import 'vite/client'
+// ---cut---
// sharedworker
import SharedWorker from './shader.js?sharedworker'
const sharedWorker = new SharedWorker()
```
-```js
+```js twoslash
+import 'vite/client'
+// ---cut---
// 内联为 base64 字符串
import InlineWorker from './shader.js?worker&inline'
```
@@ -80,10 +117,7 @@ import InlineWorker from './shader.js?worker&inline'
目录默认是 `/public`,但可以通过 [`publicDir` 选项](/config/shared-options.md#publicdir) 来配置。
-请注意:
-
-- 引入 `public` 中的资源永远应该使用根绝对路径 —— 举个例子,`public/icon.png` 应该在源码中被引用为 `/icon.png`。
-- `public` 中的资源不应该被 JavaScript 文件引用。
+请注意,应该始终使用根绝对路径来引入 `public` 中的资源 —— 举个例子,`public/icon.png` 应该在源码中被引用为 `/icon.png`。
## new URL(url, import.meta.url)
@@ -101,6 +135,7 @@ document.getElementById('hero-img').src = imgUrl
```js
function getImageUrl(name) {
+ // 请注意,这不包括子目录中的文件
return new URL(`./dir/${name}.png`, import.meta.url).href
}
```
@@ -112,6 +147,25 @@ function getImageUrl(name) {
const imgUrl = new URL(imagePath, import.meta.url).href
```
+::: details 工作原理
+
+Vite 会将 `getImageUrl` 函数改造为:
+
+```js
+import __img0png from './dir/img0.png'
+import __img1png from './dir/img1.png'
+
+function getImageUrl(name) {
+ const modules = {
+ './dir/img0.png': __img0png,
+ './dir/img1.png': __img1png,
+ }
+ return new URL(modules[`./dir/${name}.png`], import.meta.url).href
+}
+```
+
+:::
+
::: warning 注意:无法在 SSR 中使用
如果你正在以服务端渲染模式使用 Vite 则此模式不支持,因为 `import.meta.url` 在浏览器和 Node.js 中有不同的语义。服务端的产物也无法预先确定客户端主机 URL。
:::
diff --git a/guide/backend-integration.md b/guide/backend-integration.md
index 43b87665..790dff4e 100644
--- a/guide/backend-integration.md
+++ b/guide/backend-integration.md
@@ -8,11 +8,18 @@
1. 在你的 Vite 配置中配置入口文件和启用创建 `manifest`:
- ```js
- // vite.config.js
+ ```js twoslash [vite.config.js]
+ import { defineConfig } from 'vite'
+ // ---cut---
export default defineConfig({
+ server: {
+ cors: {
+ // 通过浏览器访问的源
+ origin: 'http://my-backend.example.com',
+ },
+ },
build: {
- // 在 outDir 中生成 manifest.json
+ // 在 outDir 中生成 .vite/manifest.json
manifest: true,
rollupOptions: {
// 覆盖默认的 .html 入口
@@ -44,7 +51,7 @@
这对于图片等资源的正确加载是必需的。
- 如果你正使用 `@vitejs/plugin-react` 配合 React,你还需要在上述脚本前添加下面这个,因为插件不能修改你正在服务的 HTML:
+ 如果你正使用 `@vitejs/plugin-react` 配合 React,你还需要在上述脚本前添加下面这个,因为插件不能修改你正在服务的 HTML(请将 `http://localhost:5173` 替换为 Vite 正在运行的本地 URL):
```html
```
-3. 在生产环境中:在运行 `vite build` 之后,一个 `manifest.json` 文件将与静态资源文件一同生成。一个示例清单文件会像下面这样:
+3. 在生产环境中:在运行 `vite build` 之后,一个 `.vite/manifest.json` 文件将与静态资源文件一同生成。一个示例清单文件会像下面这样:
- ```json
+ ```json [.vite/manifest.json]
{
- "main.js": {
- "file": "assets/main.4889e940.js",
- "src": "main.js",
+ "_shared-B7PI925R.js": {
+ "file": "assets/shared-B7PI925R.js",
+ "name": "shared",
+ "css": ["assets/shared-ChJ_j-JJ.css"]
+ },
+ "_shared-ChJ_j-JJ.css": {
+ "file": "assets/shared-ChJ_j-JJ.css",
+ "src": "_shared-ChJ_j-JJ.css"
+ },
+ "baz.js": {
+ "file": "assets/baz-B2H3sXNv.js",
+ "name": "baz",
+ "src": "baz.js",
+ "isDynamicEntry": true
+ },
+ "views/bar.js": {
+ "file": "assets/bar-gkvgaI9m.js",
+ "name": "bar",
+ "src": "views/bar.js",
"isEntry": true,
- "dynamicImports": ["views/foo.js"],
- "css": ["assets/main.b82dbe22.css"],
- "assets": ["assets/asset.0ab0f9cd.png"]
+ "imports": ["_shared-B7PI925R.js"],
+ "dynamicImports": ["baz.js"]
},
"views/foo.js": {
- "file": "assets/foo.869aea0d.js",
+ "file": "assets/foo-BRBmoGS9.js",
+ "name": "foo",
"src": "views/foo.js",
- "isDynamicEntry": true,
- "imports": ["_shared.83069a53.js"]
- },
- "_shared.83069a53.js": {
- "file": "assets/shared.83069a53.js"
+ "isEntry": true,
+ "imports": ["_shared-B7PI925R.js"],
+ "css": ["assets/foo-5UjPuW-k.css"]
}
}
```
@@ -83,12 +104,92 @@
- 清单是一个 `Record` 结构的对象。
- 对于 入口 或动态入口 chunk,键是相对于项目根目录的资源路径。
- 对于非入口 chunk,键是生成文件的名称并加上前缀 `_`。
- - Chunk 将信息包含在其静态和动态导入上(两者都是映射到清单中相应 chunk 的键),以及任何与之相关的 CSS 和资源文件。
+ - 当 [`build.cssCodeSplit`](/config/build-options.md#build-csscodesplit) 为 `false` 时生成的 CSS 文件,键为 `style.css`。
+ - Chunk 将信息包含在其静态和动态导入上(两者都是映射到清单中相应 chunk 的键),以及任何与之相关的 CSS 和资源文件。
+
+4. 你可以利用这个文件来渲染带有哈希文件名的链接或预加载指令。
+
+ 这是一个用来渲染正确链接的 HTML 模板示例。这里的语法仅用于解释,
+ 你需要用你的服务器模板语言来替换。`importedChunks` 函数只是
+ 用来说明,并不是 Vite 提供的。
+
+ ```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ```
+
+ 具体来说,一个生成 HTML 的后端在给定 manifest 文件和一个入口文件的情况下,
+ 应该包含以下标签:
+
+ - 对于入口文件 chunk 的 `css` 列表中的每个文件,都应包含一个 ` ` 标签。
+ - 递归追踪入口文件的 `imports` 列表中的所有 chunk,并为每个导入的 chunk 的每个 CSS 文件
+ 包含一个 ` ` 标签。
+ - 对于入口文件 chunk 的 `file` 键的标签(对于 JavaScript 是
+ `
+
+
+ ```
+
+ 而对于入口文件 `views/bar.js`,应该包含以下标签:
```html
-
-
-
+
+
+
+
```
+
+ ::: details `importedChunks` 的伪代码实现
+ `importedChunks` 在 TypeScript 中的一个伪实现示例
+ (这需要根据您的编程语言和模板语言进行调整):
+
+ ```ts
+ import type { Manifest, ManifestChunk } from 'vite'
+
+ export default function importedChunks(
+ manifest: Manifest,
+ name: string,
+ ): ManifestChunk[] {
+ const seen = new Set()
+
+ function getImportedChunks(chunk: ManifestChunk): ManifestChunk[] {
+ const chunks: ManifestChunk[] = []
+ for (const file of chunk.imports ?? []) {
+ const importee = manifest[file]
+ if (seen.has(file)) {
+ continue
+ }
+ seen.add(file)
+
+ chunks.push(...getImportedChunks(importee))
+ chunks.push(importee)
+ }
+
+ return chunks
+ }
+
+ return getImportedChunks(manifest[name])
+ }
+ ```
+
+ :::
diff --git a/guide/build.md b/guide/build.md
index 82bb5044..f821222c 100644
--- a/guide/build.md
+++ b/guide/build.md
@@ -4,16 +4,25 @@
## 浏览器兼容性 {#browser-compatibility}
-用于生产环境的构建包会假设目标浏览器支持现代 JavaScript 语法。默认情况下,Vite 的目标是能够 [支持原生 ESM script 标签](https://caniuse.com/es6-module)、[支持原生 ESM 动态导入](https://caniuse.com/es6-module-dynamic-import) 和 [`import.meta`](https://caniuse.com/mdn-javascript_operators_import_meta) 的浏览器:
+默认情况下,生产包假定使用包含在 [Baseline](https://web-platform-dx.github.io/web-features/) 广泛可用目标中的现代浏览器。默认的浏览器支持范围是:
-- Chrome >=87
-- Firefox >=78
-- Safari >=13
-- Edge >=88
+
-你也可以通过 [`build.target` 配置项](/config/build-options.md#build-target) 指定构建目标,最低支持 `es2015`。
+- Chrome >=107
+- Edge >=107
+- Firefox >=104
+- Safari >=16
-请注意,默认情况下 Vite 只处理语法转译,且 **默认不包含任何 polyfill**。你可以前往 [Polyfill.io](https://polyfill.io/v3/) 查看,这是一个基于用户浏览器 User-Agent 字符串自动生成 polyfill 包的服务。
+你也可以通过 [`build.target` 配置项](/config/build-options.md#build-target) 指定构建目标,最低支持 `es2015`。如果设置较低的目标值,Vite 仍然需要这些最低的浏览器支持范围,因为它依赖于[原生的 ESM 动态导入](https://caniuse.com/es6-module-dynamic-import)和 [`import.meta`](https://caniuse.com/mdn-javascript_operators_import_meta):
+
+
+
+- Chrome >=64
+- Firefox >=67
+- Safari >=11.1
+- Edge >=79
+
+请注意,默认情况下 Vite 只处理语法转译,且 **不包含任何 polyfill**。你可以访问 https://cdnjs.cloudflare.com/polyfill/ ,这个网站可以根据用户的浏览器 UserAgent 字符串自动生成 polyfill 包。
传统浏览器可以通过插件 [@vitejs/plugin-legacy](https://github.com/vitejs/vite/tree/main/packages/plugin-legacy) 来支持,它将自动生成传统版本的 chunk 及与其相对应 ES 语言特性方面的 polyfill。兼容版的 chunk 只会在不支持原生 ESM 的浏览器中进行按需加载。
@@ -29,18 +38,27 @@
若想要进一步控制基础路径,请查看 [高级 base 选项](#advanced-base-options).
+### 相对基础路径 {#relative-base}
+
+如果无法提前确定基础路径,可以使用 `"base": "./"` 或 `"base": ""` 设置相对基础路径。这将使所有生成的 URL 相对于每个文件。
+
+:::warning 使用相对基础路径时对旧浏览器的支持
+
+使用相对基础路径需要 `import.meta` 的支持。如果你需要支持 [不支持 `import.meta` 的浏览器](https://caniuse.com/mdn-javascript_operators_import_meta),可以使用 [`legacy` 插件](https://github.com/vitejs/vite/tree/main/packages/plugin-legacy)。
+
+:::
+
## 自定义构建 {#customizing-the-build}
-构建过程可以通过多种 [构建配置选项](/config/#build-options) 来自定义构建。具体来说,你可以通过 `build.rollupOptions` 直接调整底层的 [Rollup 选项](https://rollupjs.org/guide/en/#big-list-of-options):
+构建过程可以通过多种 [构建配置选项](/config/#build-options) 来自定义构建。具体来说,你可以通过 `build.rollupOptions` 直接调整底层的 [Rollup 选项](https://cn.rollupjs.org/configuration-options/):
-```js
-// vite.config.js
+```js [vite.config.js]
export default defineConfig({
build: {
rollupOptions: {
- // https://rollupjs.org/guide/en/#big-list-of-options
- }
- }
+ // https://cn.rollupjs.org/configuration-options/
+ },
+ },
})
```
@@ -48,30 +66,31 @@ export default defineConfig({
## 产物分块策略 {#chunking-strategy}
-你可以配置在使用 `build.rollupOptions.output.manualChunks` 时各个 chunk 是如何分割的(查看 [Rollup 相应文档](https://rollupjs.org/guide/en/#outputmanualchunks))。到 Vite 2.8 时,默认的策略是将 chunk 分割为 `index` 和 `vendor`。这对一些 SPA 来说是好的策略,但是要对每一种用例目标都提供一种通用解决方案是非常困难的。从 Vite 2.9 起,`manualChunks` 默认情况下不再被更改。你可以通过在配置文件中添加 `splitVendorChunkPlugin` 来继续使用 “分割 Vendor Chunk” 策略:
+你可以通过配置 `build.rollupOptions.output.manualChunks` 来自定义 chunk 分割策略(查看 [Rollup 相应文档](https://cn.rollupjs.org/configuration-options/#output-manualchunks))。如果你使用的是一个框架,那么请参考他们的文档来了解如何配置分割 chunk。
-```js
-// vite.config.js
-import { splitVendorChunkPlugin } from 'vite'
-export default defineConfig({
- plugins: [splitVendorChunkPlugin()]
+## 处理加载报错 {#load-error-handling}
+
+当 Vite 加载动态导入失败时,会触发 `vite:preloadError` 事件。`event.payload` 包含原始的导入错误信息。如果调用 `event.preventDefault()`,则不会抛出错误。
+
+```js twoslash
+window.addEventListener('vite:preloadError', (event) => {
+ window.location.reload() // 例如,刷新页面
})
```
-也可以用一个工厂函数 `splitVendorChunk({ cache: SplitVendorChunkCache })` 来提供该策略,在需要与自定义逻辑组合的情况下,`cache.reset()` 需要在 `buildStart` 阶段被调用,以便构建的 watch 模式在这种情况下正常工作。
+当重新部署时,托管服务可能会删除之前部署的资源。因此,之前访问过您站点的用户可能会遇到导入错误。这种错误发生的原因是用户设备上运行的资源过时,并尝试导入相应的旧代码块,而这些代码块已经被删除。这个事件对于解决这种情况会很有帮助。
-## 文件变化时重新构建 {#rebuild-on-files-changs}
+## 文件变化时重新构建 {#rebuild-on-files-changes}
-你可以使用 `vite build --watch` 来启用 rollup 的监听器。或者,你可以直接通过 `build.watch` 调整底层的 [`WatcherOptions`](https://rollupjs.org/guide/en/#watch-options) 选项:
+你可以使用 `vite build --watch` 来启用 rollup 的监听器。或者,你可以直接通过 `build.watch` 调整底层的 [`WatcherOptions`](https://cn.rollupjs.org/configuration-options/#watch) 选项:
-```js
-// vite.config.js
+```js [vite.config.js]
export default defineConfig({
build: {
watch: {
- // https://rollupjs.org/guide/en/#watch-options
- }
- }
+ // https://cn.rollupjs.org/configuration-options/#watch
+ },
+ },
})
```
@@ -95,79 +114,129 @@ export default defineConfig({
在构建过程中,你只需指定多个 `.html` 文件作为入口点即可:
-```js
-// vite.config.js
-import { resolve } from 'path'
+```js twoslash [vite.config.js]
+import { dirname, resolve } from 'node:path'
+import { fileURLToPath } from 'node:url'
import { defineConfig } from 'vite'
+const __dirname = dirname(fileURLToPath(import.meta.url))
+
export default defineConfig({
build: {
rollupOptions: {
input: {
main: resolve(__dirname, 'index.html'),
- nested: resolve(__dirname, 'nested/index.html')
- }
- }
- }
+ nested: resolve(__dirname, 'nested/index.html'),
+ },
+ },
+ },
})
```
如果你指定了另一个根目录,请记住,在解析输入路径时,`__dirname` 的值将仍然是 vite.config.js 文件所在的目录。因此,你需要把对应入口文件的 `root` 的路径添加到 `resolve` 的参数中。
+请注意,在 HTML 文件中,Vite 忽略了 `rollupOptions.input` 对象中给定的入口名称,而是在生成 dist 文件夹中的 HTML 资源文件时,使用了文件已解析的路径 ID。这确保了与开发服务器的工作方式保持一致的结构。
+
## 库模式 {#library-mode}
当你开发面向浏览器的库时,你可能会将大部分时间花在该库的测试/演示页面上。在 Vite 中你可以使用 `index.html` 获得如丝般顺滑的开发体验。
当这个库要进行发布构建时,请使用 [`build.lib` 配置项](/config/build-options.md#build-lib),以确保将那些你不想打包进库的依赖进行外部化处理,例如 `vue` 或 `react`:
-```js
-// vite.config.js
-import { resolve } from 'path'
+::: code-group
+
+```js twoslash [vite.config.js (单入口)]
+import { dirname, resolve } from 'node:path'
+import { fileURLToPath } from 'node:url'
import { defineConfig } from 'vite'
+const __dirname = dirname(fileURLToPath(import.meta.url))
+
export default defineConfig({
build: {
lib: {
entry: resolve(__dirname, 'lib/main.js'),
name: 'MyLib',
- // the proper extensions will be added
- fileName: 'my-lib'
+ // 将添加适当的扩展名后缀
+ fileName: 'my-lib',
},
rollupOptions: {
- // 确保外部化处理那些你不想打包进库的依赖
+ // 确保外部化处理那些
+ // 你不想打包进库的依赖
external: ['vue'],
output: {
- // 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
+ // 在 UMD 构建模式下为这些外部化的依赖
+ // 提供一个全局变量
globals: {
- vue: 'Vue'
- }
- }
- }
- }
+ vue: 'Vue',
+ },
+ },
+ },
+ },
})
```
-入口文件将包含可以由你的包的用户导入的导出:
+```js twoslash [vite.config.js (多入口)]
+import { dirname, resolve } from 'node:path'
+import { fileURLToPath } from 'node:url'
+import { defineConfig } from 'vite'
+
+const __dirname = dirname(fileURLToPath(import.meta.url))
+
+export default defineConfig({
+ build: {
+ lib: {
+ entry: {
+ 'my-lib': resolve(__dirname, 'lib/main.js'),
+ secondary: resolve(__dirname, 'lib/secondary.js'),
+ },
+ name: 'MyLib',
+ },
+ rollupOptions: {
+ // 确保外部化处理那些
+ // 你不想打包进库的依赖
+ external: ['vue'],
+ output: {
+ // 在 UMD 构建模式下为这些外部化的依赖
+ // 提供一个全局变量
+ globals: {
+ vue: 'Vue',
+ },
+ },
+ },
+ },
+})
+```
+
+:::
+
+入口文件将包含可以被您的包的用户导入的导出内容:
-```js
-// lib/main.js
+```js [lib/main.js]
import Foo from './Foo.vue'
import Bar from './Bar.vue'
export { Foo, Bar }
```
-使用如上配置运行 `vite build` 时,将会使用一套面向库的 Rollup 预设,并且将为该库提供两种构建格式:`es` 和 `umd` (可在 `build.lib` 中配置):
+使用如上配置运行 `vite build` 时,将会使用一套面向库的 Rollup 预设,并且将为该库提供两种构建格式:
+
+- `es` 和 `umd` (单入口)
+- `es` 和 `cjs` (多入口)
+
+格式可通过 [`build.lib.format`](/config/build-options.md#build-lib)选项配置。
```
$ vite build
building for production...
-dist/my-lib.js 0.08 KiB / gzip: 0.07 KiB
-dist/my-lib.umd.cjs 0.30 KiB / gzip: 0.16 KiB
+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` 中使用如下格式:
+推荐在库的 `package.json` 中使用如下格式:
-```json
+::: code-group
+
+```json [package.json (单入口)]
{
"name": "my-lib",
"type": "module",
@@ -183,18 +252,67 @@ dist/my-lib.umd.cjs 0.30 KiB / gzip: 0.16 KiB
}
```
-::: tip 注意
-如果 `package.json` 不包含 `"type": "module"`,Vite 会生成不同的文件后缀名以兼容 Node.js。`.js` 会变为 `.mjs` 而 `.cjs` 会变为 `.js`.
+```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-support}
+
+如果您的库导入了 CSS,除了内置的 JS 文件外,它还将作为一个 CSS 文件打包在一起,例如 `dist/my-lib.css`。文件名默认为 `build.lib.fileName`,但也可以使用 [`build.lib.cssFileName`](/config/build-options.md#build-lib)进行更改。
+
+您可以在 `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"' }` 例如静态替换它们。
+在库模式中,所有 [`import.meta.env.*`](./env-and-mode.md) 的使用都会在构建生产版本时被静态替换。但是,`process.env.*` 的使用不会,这样你的库的使用者就可以动态地改变它。如果这是不可取的,你可以使用 `define: { 'process.env.NODE_ENV': '"production"' }` 来静态替换它们,或者使用 [`esm-env`](https://github.com/benmccann/esm-env) 来更好地兼容打包工具和运行时。
+:::
+
+::: warning 进阶用法
+库模式包括了一种简单而又有见地的配置,适用于面向浏览器和 JS 框架的库。如果你正在构建非面向浏览器的库,或需要高级构建流程,可以直接使用 [Rollup](https://cn.rollupjs.org) 或 [esbuild](https://esbuild.github.io)。
:::
## 进阶基础路径选项 {#advanced-base-options}
::: warning
-该功能是实验性的,这个 API 可能在未来后续版本中发生变更而不遵循语义化版本号。请在使用它时注意维护 Vite 的版本。
+该功能是实验性的,可以在这里 [提供反馈](https://github.com/vitejs/vite/discussions/13834)。
:::
对更高级的使用场景,被部署的资源和公共文件可能想要分为不同的路径,例如使用不同缓存策略的场景。
@@ -206,32 +324,47 @@ dist/my-lib.umd.cjs 0.30 KiB / gzip: 0.16 KiB
单个静态的 [基础路径](#public-base-path) 在这种场景中就不够用了。Vite 在构建时为更高级的基础路径选项提供了实验性支持,可以使用 `experimental.renderBuiltUrl`。
-```ts
+```ts twoslash
+import type { UserConfig } from 'vite'
+// prettier-ignore
+const config: UserConfig = {
+// ---cut-before---
experimental: {
- renderBuiltUrl(filename: string, { hostType }: { hostType: 'js' | 'css' | 'html' }) {
+ renderBuiltUrl(filename, { hostType }) {
if (hostType === 'js') {
return { runtime: `window.__toCdnUrl(${JSON.stringify(filename)})` }
} else {
return { relative: true }
}
- }
+ },
+},
+// ---cut-after---
}
```
如果 hash 后的资源和公共文件没有被部署在一起,可以根据该函数的第二个参数 `context` 上的字段 `type` 分别定义各个资源组的选项:
-```ts
+```ts twoslash
+import type { UserConfig } from 'vite'
+import path from 'node:path'
+// prettier-ignore
+const config: UserConfig = {
+// ---cut-before---
experimental: {
- renderBuiltUrl(filename: string, { hostId, hostType, type }: { hostId: string, hostType: 'js' | 'css' | 'html', type: 'public' | 'asset' }) {
+ 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 {
+ } 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` 的对象,就需要在必要的地方自行处理编码,因为运行时的代码将会按照原样呈现。
diff --git a/guide/cli.md b/guide/cli.md
new file mode 100644
index 00000000..2ee61ad7
--- /dev/null
+++ b/guide/cli.md
@@ -0,0 +1,132 @@
+# 命令行接口 {#command-line-interface}
+
+## 开发服务器 {#dev-server}
+
+### `vite` {#vite}
+
+在当前目录下启动 Vite 开发服务器。`vite dev` 和 `vite serve` 是 `vite` 的别名。
+
+#### 使用 {#usage}
+
+```bash
+vite [root]
+```
+
+#### 选项 {#options}
+
+| 选项 | |
+| ------------------------- | --------------------------------------------------------------------------------------------- |
+| `--host [host]` | 指定主机名称 (`string`) |
+| `--port ` | 指定端口 (`number`) |
+| `--open [path]` | 启动时打开浏览器 (`boolean \| string`) |
+| `--cors` | 启用 CORS (`boolean`) |
+| `--strictPort` | 如果指定的端口已在使用中,则退出 (`boolean`) |
+| `--force` | 强制优化器忽略缓存并重新构建 (`boolean`) |
+| `-c, --config ` | 使用指定的配置文件 (`string`) |
+| `--base ` | 公共基础路径(默认为:`/`)(`string`) |
+| `-l, --logLevel ` | info \| warn \| error \| silent (`string`) |
+| `--clearScreen` | 允许或禁用打印日志时清除屏幕 (`boolean`) |
+| `--configLoader ` | 使用 `bundle` 来采用 esbuild 打包配置,或是 `runner`(实验性)来在运行时处理,默认是 `bundle` |
+| `--profile` | 启动内置的 Node.js 调试器(查看 [性能瓶颈](/guide/troubleshooting#performance-bottlenecks)) |
+| `-d, --debug [feat]` | 显示调试日志 (`string \| boolean`) |
+| `-f, --filter ` | 过滤调试日志 (`string`) |
+| `-m, --mode ` | 设置环境模式 (`string`) |
+| `-h, --help` | 显示可用的 CLI 选项 |
+| `-v, --version` | 显示版本号 |
+
+## 构建 {#build}
+
+### `vite build` {#vite-build}
+
+构建生产版本。
+
+#### 使用 {#usage-1}
+
+```bash
+vite build [root]
+```
+
+#### 选项 {#options-1}
+
+| 选项 | |
+| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
+| `--target ` | 编译目标(默认为:`"modules"`)(`string`) |
+| `--outDir ` | 输出目录(默认为:`dist`)(`string`) |
+| `--assetsDir ` | 在输出目录下放置资源的目录(默认为:`"assets"`)(`string`) |
+| `--assetsInlineLimit ` | 静态资源内联为 base64 编码的阈值,以字节为单位(默认为:`4096`)(`number`) |
+| `--ssr [entry]` | 为服务端渲染配置指定入口文件 (`string`) |
+| `--sourcemap [output]` | 构建后输出 source map 文件(默认为:`false`)(`boolean \| "inline" \| "hidden"`) |
+| `--minify [minifier]` | 允许或禁用最小化混淆,或指定使用哪种混淆器(默认为:`"esbuild"`)(`boolean \| "terser" \| "esbuild"`) |
+| `--manifest [name]` | 构建后生成 manifest.json 文件 (`boolean \| string`) |
+| `--ssrManifest [name]` | 构建后生成 SSR manifest.json 文件 (`boolean \| string`) |
+| `--emptyOutDir` | 若输出目录在根目录外,强制清空输出目录 (`boolean`) |
+| `-w, --watch` | 在磁盘中模块发生变化时,重新构建 (`boolean`) |
+| `-c, --config ` | 使用指定的配置文件 (`string`) |
+| `--base ` | 公共基础路径(默认为:`/`)(`string`) |
+| `-l, --logLevel ` | Info \| warn \| error \| silent (`string`) |
+| `--clearScreen` | 允许或禁用打印日志时清除屏幕 (`boolean`) |
+| `--configLoader ` | 使用 `bundle` 来采用 esbuild 打包配置,或是 `runner`(实验性)来在运行时处理,或者使用原生运行时加载 `native`(实验性),默认是 `bundle` |
+| `--profile` | 启动内置的 Node.js 调试器(查看 [性能瓶颈](/guide/troubleshooting#performance-bottlenecks)) |
+| `-d, --debug [feat]` | 显示调试日志 (`string \| boolean`) |
+| `-f, --filter ` | 过滤调试日志 (`string`) |
+| `-m, --mode ` | 设置环境模式 (`string`) |
+| `-h, --help` | 显示可用的 CLI 选项 |
+| `--app` | 构建所有环境,这与 `builder: {}` 是一样的(`boolean`,实验性) |
+
+## 其他 {#others}
+
+### `vite optimize` {#vite-optimize}
+
+预构建依赖。
+
+**Deprecated**: 预构建过程自动运行,不需要调用。
+
+#### 使用 {#usage-2}
+
+```bash
+vite optimize [root]
+```
+
+#### 选项 {#options-2}
+
+| 选项 | |
+| ------------------------- | --------------------------------------------------------------------------------------------- |
+| `--force` | 强制优化器忽略缓存并重新构建 (`boolean`) |
+| `-c, --config ` | 使用指定的配置文件 (`string`) |
+| `--base ` | 公共基础路径(默认为:`/`)(`string`) |
+| `-l, --logLevel ` | Info \| warn \| error \| silent (`string`) |
+| `--clearScreen` | 允许或禁用打印日志时清除屏幕 (`boolean`) |
+| `--configLoader ` | 使用 `bundle` 来采用 esbuild 打包配置,或是 `runner`(实验性)来在运行时处理,默认是 `bundle` |
+| `-d, --debug [feat]` | 显示调试日志 (`string \| boolean`) |
+| `-f, --filter ` | 过滤调试日志 (`string`) |
+| `-m, --mode ` | 设置环境模式 (`string`) |
+| `-h, --help` | 显示可用的 CLI 选项 |
+
+### `vite preview` {#vite-preview}
+
+本地预览构建产物。不要将其用作生产服务器,因为它不是为此而设计的。
+
+#### 使用 {#usage-3}
+
+```bash
+vite preview [root]
+```
+
+#### 选项 {#options-3}
+
+| 选项 | |
+| ------------------------- | --------------------------------------------------------------------------------------------- |
+| `--host [host]` | 指定主机名称 (`string`) |
+| `--port ` | 指定端口 (`number`) |
+| `--strictPort` | 如果指定的端口已在使用中,则退出 (`boolean`) |
+| `--open [path]` | 启动时打开浏览器 (`boolean \| string`) |
+| `--outDir ` | 输出目录(默认为:`dist`)(`string`) |
+| `-c, --config ` | 使用指定的配置文件 (`string`) |
+| `--base ` | 公共基础路径(默认为:`/`)(`string`) |
+| `-l, --logLevel ` | Info \| warn \| error \| silent (`string`) |
+| `--clearScreen` | 允许或禁用打印日志时清除屏幕 (`boolean`) |
+| `--configLoader ` | 使用 `bundle` 来采用 esbuild 打包配置,或是 `runner`(实验性)来在运行时处理,默认是 `bundle` |
+| `-d, --debug [feat]` | 显示调试日志 (`string \| boolean`) |
+| `-f, --filter ` | 过滤调试日志 (`string`) |
+| `-m, --mode ` | 设置环境模式 (`string`) |
+| `-h, --help` | 显示可用的 CLI 选项 |
diff --git a/guide/comparisons.md b/guide/comparisons.md
index 861918b4..dd0c0f37 100644
--- a/guide/comparisons.md
+++ b/guide/comparisons.md
@@ -2,11 +2,11 @@
## WMR {#wmr}
-Preact 团队的 [WMR](https://github.com/preactjs/wmr) 提供了类似的特性集,而 Vite 2.0 对 Rollup 插件接口的支持正是受到了它的启发。
+Preact 团队的 [WMR](https://github.com/preactjs/wmr) 旨在提供类似的功能集,Vite 的通用 Rollup 插件 API(用于开发和构建)就是受此启发而设计的。
-WMR 主要是为了 [Preact](https://preactjs.com/) 项目而设计,并为其提供了集成度更高的功能,比如预渲染。就使用范围而言,它更加贴合于 Preact 框架,与 Preact 本身一样强调紧凑的大小。如果你正在使用 Preact,那么 WMR 可能会提供更好的体验。
+目前,WMR 已经停止维护。Preact 团队现在建议搭配使用 Vite 和 [@preactjs/preset-vite](https://github.com/preactjs/preset-vite)。
-## @web/dev-server {#webdev-server}
+## @web/dev-server {#web-dev-server}
[@web/dev-server](https://modern-web.dev/docs/dev-server/overview/)(曾经是 `es-dev-server`)是一个伟大的项目,基于 koa 的 Vite 1.0 开发服务器就是受到了它的启发。
@@ -16,6 +16,6 @@ WMR 主要是为了 [Preact](https://preactjs.com/) 项目而设计,并为其
## Snowpack {#snowpack}
-[Snowpack](https://www.snowpack.dev/) 也是一个与 Vite 十分类似的非构建式原生 ESM 开发服务器。该项目已经不维护了。团队目前正在开发 [Astro](https://astro.build/),一个由 Vite 驱动的静态站点构建工具。Astro 团队目前是我们生态中非常活跃的成员,它们帮助 Vite 进益良多。
+[Snowpack](https://www.snowpack.dev/) 也是一个与 Vite 十分类似的非构建式原生 ESM 开发服务器。该项目已经不维护了。团队目前正在开发 [Astro](https://astro.build/),一个由 Vite 驱动的静态站点构建工具。Astro 团队目前是我们生态中非常活跃的成员,他们帮助 Vite 进益良多。
-除了不同的实现细节外,这两个项目在技术上比传统工具有很多共同优势。Vite 的依赖预构建也受到了 Snowpack v1(现在是 [`esinstall`](https://github.com/snowpackjs/snowpack/tree/main/esinstall))的启发。若想了解 Vite 同这两个项目之间的一些主要区别,可以查看 [the v2 Comparisons Guide](https://v2.vitejs.dev/guide/comparisons)。
+除了不同的实现细节外,这两个项目在技术上比传统工具有很多共同优势。Vite 的依赖预构建也受到了 Snowpack v1(现在是 [`esinstall`](https://github.com/snowpackjs/snowpack/tree/main/esinstall))的启发。若想了解 Vite 同这两个项目之间的一些主要区别,可以查看 [Vite v2 比较指南](https://v2.vite.dev/guide/comparisons)。
diff --git a/guide/dep-pre-bundling.md b/guide/dep-pre-bundling.md
index e3014685..d697b056 100644
--- a/guide/dep-pre-bundling.md
+++ b/guide/dep-pre-bundling.md
@@ -1,42 +1,35 @@
# 依赖预构建 {#dependency-pre-bundling}
-当你首次启动 `vite` 时,你可能会注意到打印出了以下信息:
-
-```
-Pre-bundling dependencies: (正在预构建依赖:)
- react
- react-dom
-(this will be run only when your dependencies or config have changed)(这将只会在你的依赖或配置发生变化时执行)
-```
+当你首次启动 `vite` 时,Vite 在本地加载你的站点之前预构建了项目依赖。默认情况下,它是自动且透明地完成的。
## 原因 {#the-why}
-这就是 Vite 执行的所谓的“依赖预构建”。这个过程有两个目的:
+这就是 Vite 执行时所做的“依赖预构建”。这个过程有两个目的:
-1. **CommonJS 和 UMD 兼容性:** 开发阶段中,Vite 的开发服务器将所有代码视为原生 ES 模块。因此,Vite 必须先将作为 CommonJS 或 UMD 发布的依赖项转换为 ESM。
+1. **CommonJS 和 UMD 兼容性:** 在开发阶段中,Vite 的开发服务器将所有代码视为原生 ES 模块。因此,Vite 必须先将以 CommonJS 或 UMD 形式提供的依赖项转换为 ES 模块。
- 当转换 CommonJS 依赖时,Vite 会执行智能导入分析,这样即使导出是动态分配的(如 React),按名导入也会符合预期效果:
+ 在转换 CommonJS 依赖项时,Vite 会进行智能导入分析,这样即使模块的导出是动态分配的(例如 React),具名导入(named imports)也能正常工作:
```js
// 符合预期
import React, { useState } from 'react'
```
-2. **性能:** Vite 将有许多内部模块的 ESM 依赖关系转换为单个模块,以提高后续页面加载性能。
+2. **性能:** 为了提高后续页面的加载性能,Vite 将那些具有许多内部模块的 ESM 依赖项转换为单个模块。
- 一些包将它们的 ES 模块构建作为许多单独的文件相互导入。例如,[`lodash-es` 有超过 600 个内置模块](https://unpkg.com/browse/lodash-es/)!当我们执行 `import { debounce } from 'lodash-es'` 时,浏览器同时发出 600 多个 HTTP 请求!尽管服务器在处理这些请求时没有问题,但大量的请求会在浏览器端造成网络拥塞,导致页面的加载速度相当慢。
+ 有些包将它们的 ES 模块构建为许多单独的文件,彼此导入。例如,[`lodash-es` 有超过 600 个内置模块](https://unpkg.com/browse/lodash-es/)!当我们执行 `import { debounce } from 'lodash-es'` 时,浏览器同时发出 600 多个 HTTP 请求!即使服务器能够轻松处理它们,但大量请求会导致浏览器端的网络拥塞,使页面加载变得明显缓慢。
- 通过预构建 `lodash-es` 成为一个模块,我们就只需要一个 HTTP 请求了!
+ 通过将 `lodash-es` 预构建成单个模块,现在我们只需要一个HTTP请求!
::: tip 注意
-依赖预构建仅会在开发模式下应用,并会使用 `esbuild` 将依赖转为 ESM 模块。在生产构建中则会使用 `@rollup/plugin-commonjs`。
+依赖预构建仅适用于开发模式,并使用 `esbuild` 将依赖项转换为 ES 模块。在生产构建中,将使用 `@rollup/plugin-commonjs`。
:::
## 自动依赖搜寻 {#automatic-dependency-discovery}
-如果没有找到相应的缓存,Vite 将抓取你的源码,并自动寻找引入的依赖项(即 "bare import",表示期望从 `node_modules` 解析),并将这些依赖项作为预构建包的入口点。预构建通过 `esbuild` 执行,所以它通常非常快。
+如果没有找到现有的缓存,Vite 会扫描您的源代码,并自动寻找引入的依赖项(即 "bare import",表示期望从 `node_modules` 中解析),并将这些依赖项作为预构建的入口点。预打包使用 `esbuild` 执行,因此通常速度非常快。
-在服务器已经启动之后,如果遇到一个新的依赖关系导入,而这个依赖关系还没有在缓存中,Vite 将重新运行依赖构建进程并重新加载页面。
+在服务器已经启动后,如果遇到尚未在缓存中的新依赖项导入,则 Vite 将重新运行依赖项构建过程,并在需要时重新加载页面。
## Monorepo 和链接依赖 {#monorepos-and-linked-dependencies}
@@ -44,51 +37,52 @@ Pre-bundling dependencies: (正在预构建依赖:)
然而,这需要被链接的依赖被导出为 ESM 格式。如果不是,那么你可以在配置里将此依赖添加到 [`optimizeDeps.include`](/config/dep-optimization-options.md#optimizedeps-include) 和 [`build.commonjsOptions.include`](/config/build-options.md#build-commonjsoptions) 这两项中。
-```js
+```js twoslash [vite.config.js]
+import { defineConfig } from 'vite'
+// ---cut---
export default defineConfig({
optimizeDeps: {
- include: ['linked-dep']
+ include: ['linked-dep'],
},
build: {
commonjsOptions: {
- include: [/linked-dep/, /node_modules/]
- }
- }
+ include: [/linked-dep/, /node_modules/],
+ },
+ },
})
```
-当这个被链接的依赖发生变更后,在重启开发服务器时在命令中带上 `--force` 选项让所有更改生效。
-
-::: warning 重复删除
-由于对链接依赖的解析方式不同,传递性的依赖项可能会不正确地进行重复数据删除,而造成运行时的问题。如果你偶然发现了这个问题,请使用 `npm pack` 来修复它。
-:::
+当对链接的依赖进行更改时,请使用 `--force` 命令行选项重新启动开发服务器,以使更改生效。
## 自定义行为 {#customizing-the-behavior}
-默认的依赖项发现为启发式可能并不总是可取的。在你想要显式地从列表中包含/排除依赖项的情况下, 请使用 [`optimizeDeps` 配置项](/config/dep-optimization-options.md)。
+有时候默认的依赖启发式算法(discovery heuristics)可能并不总是理想的。如果您想要明确地包含或排除依赖项,可以使用 [`optimizeDeps` 配置项](/config/dep-optimization-options.md) 来进行设置。
-当你遇到不能直接在源码中发现的 import 时,`optimizeDeps.include` 或 `optimizeDeps.exclude` 就是典型的用例。例如,import 可能是插件转换的结果。这意味着 Vite 无法在初始扫描时发现 import —— 它只能在浏览器请求文件时转换后才能发现。这将导致服务器在启动后立即重新打包。
+`optimizeDeps.include` 或 `optimizeDeps.exclude` 的一个典型使用场景,是当 Vite 在源码中无法直接发现 import 的时候。例如,import 可能是插件转换的结果。这意味着 Vite 无法在初始扫描时发现 import —— 只能在文件被浏览器请求并转换后才能发现。这将导致服务器在启动后立即重新打包。
`include` 和 `exclude` 都可以用来处理这个问题。如果依赖项很大(包含很多内部模块)或者是 CommonJS,那么你应该包含它;如果依赖项很小,并且已经是有效的 ESM,则可以排除它,让浏览器直接加载它。
+你可以通过 [`optimizeDeps.esbuildOptions` 选项](/config/dep-optimization-options.md#optimizedeps-esbuildoptions) 进一步自定义 esbuild。例如,添加一个 esbuild 插件来处理依赖项中的特殊文件,或者更改 [build `target`](https://esbuild.github.io/api/#target)。
+
## 缓存 {#caching}
### 文件系统缓存 {#file-system-cache}
-Vite 会将预构建的依赖缓存到 `node_modules/.vite`。它根据几个源来决定是否需要重新运行预构建步骤:
+Vite 将预构建的依赖项缓存到 `node_modules/.vite` 中。它会基于以下几个来源来决定是否需要重新运行预构建步骤:
-- `package.json` 中的 `dependencies` 列表
-- 包管理器的 lockfile,例如 `package-lock.json`, `yarn.lock`,或者 `pnpm-lock.yaml`
-- 可能在 `vite.config.js` 相关字段中配置过的
+- 包管理器的锁文件内容,例如 `package-lock.json`,`yarn.lock`,`pnpm-lock.yaml`,或者 `bun.lockb`;
+- 补丁文件夹的修改时间;
+- `vite.config.js` 中的相关字段;
+- `NODE_ENV` 的值。
只有在上述其中一项发生更改时,才需要重新运行预构建。
-如果出于某些原因,你想要强制 Vite 重新构建依赖,你可以用 `--force` 命令行选项启动开发服务器,或者手动删除 `node_modules/.vite` 目录。
+如果出于某些原因你想要强制 Vite 重新构建依赖项,你可以在启动开发服务器时指定 `--force` 选项,或手动删除 `node_modules/.vite` 缓存目录。
### 浏览器缓存 {#browser-cache}
-解析后的依赖请求会以 HTTP 头 `max-age=31536000,immutable` 强缓存,以提高在开发时的页面重载性能。一旦被缓存,这些请求将永远不会再到达开发服务器。如果安装了不同的版本(这反映在包管理器的 lockfile 中),则附加的版本 query 会自动使它们失效。如果你想通过本地编辑来调试依赖项,你可以:
+已预构建的依赖请求使用 HTTP 头 `max-age=31536000, immutable` 进行强缓存,以提高开发期间页面重新加载的性能。一旦被缓存,这些请求将永远不会再次访问开发服务器。如果安装了不同版本的依赖项(这反映在包管理器的 lockfile 中),则会通过附加版本查询自动失效。如果你想通过本地编辑来调试依赖项,您可以:
-1. 通过浏览器调试工具的 Network 选项卡暂时禁用缓存;
-2. 重启 Vite dev server,并添加 `--force` 命令以重新构建依赖;
+1. 通过浏览器开发工具的 Network 选项卡暂时禁用缓存。
+2. 重启 Vite 开发服务器指定 `--force` 选项,来重新构建依赖项。
3. 重新载入页面。
diff --git a/guide/env-and-mode.md b/guide/env-and-mode.md
index 3f80148f..6d895726 100644
--- a/guide/env-and-mode.md
+++ b/guide/env-and-mode.md
@@ -1,30 +1,46 @@
# 环境变量和模式 {#env-variables-and-modes}
-## 环境变量 {#env-variables}
+Vite 在特殊的 `import.meta.env` 对象下暴露了一些常量。这些常量在开发阶段被定义为全局变量,并在构建阶段被静态替换,以使树摇(tree-shaking)更有效。
+
+## 内置常量 {#built-in-constants}
-Vite 在一个特殊的 **`import.meta.env`** 对象上暴露环境变量。这里有一些在所有情况下都可以使用的内建变量:
+一些内置常量在所有情况下都可用:
- **`import.meta.env.MODE`**: {string} 应用运行的[模式](#modes)。
- **`import.meta.env.BASE_URL`**: {string} 部署应用时的基本 URL。他由[`base` 配置项](/config/shared-options.md#base)决定。
-- **`import.meta.env.PROD`**: {boolean} 应用是否运行在生产环境。
+- **`import.meta.env.PROD`**: {boolean} 应用是否运行在生产环境(使用 `NODE_ENV='production'` 运行开发服务器或构建应用时使用 `NODE_ENV='production'` )。
- **`import.meta.env.DEV`**: {boolean} 应用是否运行在开发环境 (永远与 `import.meta.env.PROD`相反)。
- **`import.meta.env.SSR`**: {boolean} 应用是否运行在 [server](./ssr.md#conditional-logic) 上。
-### 生产环境替换 {#production-replacement}
+## 环境变量 {#env-variables}
-在生产环境中,这些环境变量会在构建时被**静态替换**,因此,在引用它们时请使用完全静态的字符串。动态的 key 将无法生效。例如,动态 key 取值 `import.meta.env[key]` 是无效的。
+Vite 自动将环境变量暴露在 `import.meta.env` 对象下,作为字符串。
-它还将替换出现在 JavaScript 和 Vue 模板中的字符串。这本应是非常少见的,但也可能是不小心为之的。在这种情况下你可能会看到类似 `Missing Semicolon` 或 `Unexpected token` 等错误,例如当 `"process.env``.NODE_ENV"` 被替换为 `""development": "`。有一些方法可以避免这个问题:
+为了防止意外地将一些环境变量泄漏到客户端,只有以 `VITE_` 为前缀的变量才会暴露给经过 vite 处理的代码。例如下面这些环境变量:
-- 对于 JavaScript 字符串,你可以使用 unicode 零宽度空格来分割这个字符串,例如: `'import.meta\u200b.env.MODE'`。
+```[.env]
+VITE_SOME_KEY=123
+DB_PASSWORD=foobar
+```
-- 对于 Vue 模板或其他编译到 JavaScript 字符串的 HTML,你可以使用 [`` 标签](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/wbr),例如:`import.meta.env.MODE`。
+只有 `VITE_SOME_KEY` 会被暴露为 `import.meta.env.VITE_SOME_KEY` 提供给客户端源码,而 `DB_PASSWORD` 则不会。
+
+```js
+console.log(import.meta.env.VITE_SOME_KEY) // "123"
+console.log(import.meta.env.DB_PASSWORD) // undefined
+```
+
+如果你想要自定义环境变量的前缀,请参阅 [envPrefix](/config/shared-options.html#envprefix) 选项。
+
+:::tip 环境变量解析
+如上所示,`VITE_SOME_KEY` 是一个数字,但在解析时会返回一个字符串。布尔类型的环境变量也会发生同样的情况。在代码中使用时,请确保转换为所需的类型。
+:::
-## `.env` 文件 {#env-files}
+### `.env` 文件 {#env-files}
Vite 使用 [dotenv](https://github.com/motdotla/dotenv) 从你的 [环境目录](/config/shared-options.md#envdir) 中的下列文件加载额外的环境变量:
@@ -37,49 +53,67 @@ Vite 使用 [dotenv](https://github.com/motdotla/dotenv) 从你的 [环境目录
:::tip 环境加载优先级
-一份用于指定模式的文件(例如 `.env.production`)会比通用形式的优先级更高(例如 `.env`)。
+一份用于指定模式的文件(例如 `.env.production`)会比通用文件的优先级更高(例如 `.env`)。
+
+Vite 总是会加载 `.env` 和 `.env.local` 文件,除此之外还会加载模式特定的 `.env.[mode]` 文件。在模式特定文件中声明的变量优先级高于通用文件中的变量,但仅在 `.env` 或 `.env.local` 中定义的变量仍然可以在环境中使用。
另外,Vite 执行时已经存在的环境变量有最高的优先级,不会被 `.env` 类文件覆盖。例如当运行 `VITE_SOME_KEY=123 vite build` 的时候。
`.env` 类文件会在 Vite 启动一开始时被加载,而改动会在重启服务器后生效。
+
:::
-加载的环境变量也会通过 `import.meta.env` 以字符串形式暴露给客户端源码。
+此外,Vite 使用 [dotenv-expand](https://github.com/motdotla/dotenv-expand) 来扩展在 env 文件中编写的变量。想要了解更多相关语法,请查看 [它们的文档](https://github.com/motdotla/dotenv-expand#what-rules-does-the-expansion-engine-follow)。
-为了防止意外地将一些环境变量泄漏到客户端,只有以 `VITE_` 为前缀的变量才会暴露给经过 vite 处理的代码。例如下面这些环境变量:
+请注意,如果想要在环境变量中使用 `$` 符号,则必须使用 `\` 对其进行转义。
-```
-VITE_SOME_KEY=123
-DB_PASSWORD=foobar
+```[.env]
+KEY=123
+NEW_KEY1=test$foo # test
+NEW_KEY2=test\$foo # test$foo
+NEW_KEY3=test$KEY # test123
```
-只有 `VITE_SOME_KEY` 会被暴露为 `import.meta.env.VITE_SOME_KEY` 提供给客户端源码,而 `DB_PASSWORD` 则不会。
+:::warning 安全注意事项
-```js
-console.log(import.meta.env.VITE_SOME_KEY) // 123
-console.log(import.meta.env.DB_PASSWORD) // undefined
-```
+- `.env.*.local` 文件应是本地的,可以包含敏感变量。你应该将 `*.local` 添加到你的 `.gitignore` 中,以避免它们被 git 检入。
-如果你想自定义 env 变量的前缀,请参阅 [envPrefix](/config/shared-options.html#envprefix)。
+- 由于任何暴露给 Vite 源码的变量最终都将出现在客户端包中,`VITE_*` 变量应该不包含任何敏感信息。
- :::warning 安全注意事项
+:::
-如果你想要自定义 env 变量的前缀,请参阅 [envPrefix](/config/shared-options.html#envprefix) 选项。
+::: details 反向扩展变量
-- `.env.*.local` 文件应是本地的,可以包含敏感变量。你应该将 `.local` 添加到你的 `.gitignore` 中,以避免它们被 git 检入。
+Vite 支持以相反的顺序扩展变量。
+例如,下面的 `.env` 将被评估为 `VITE_FOO=foobar`, `VITE_BAR=bar`。
-- 由于任何暴露给 Vite 源码的变量最终都将出现在客户端包中,`VITE_*` 变量应该不包含任何敏感信息。
- :::
+```[.env]
+VITE_FOO=foo${VITE_BAR}
+VITE_BAR=bar
+```
+
+这在 shell 脚本和其他工具(如 `docker-compose`)中不起作用。
+不过,Vite 支持这种行为,因为 `dotenv-expand` 已经支持这种行为很长时间了,JavaScript 生态系统中的其他工具也使用支持这种行为的旧版本。
-### TypeScript 的智能提示 {#intellisense}
+为避免出现互操作问题,建议避免依赖这种行为。今后,Vite 可能会对这种行为发出警告。
+
+:::
+
+## TypeScript 的智能提示 {#intellisense}
默认情况下,Vite 在 [`vite/client.d.ts`](https://github.com/vitejs/vite/blob/main/packages/vite/client.d.ts) 中为 `import.meta.env` 提供了类型定义。随着在 `.env[mode]` 文件中自定义了越来越多的环境变量,你可能想要在代码中获取这些以 `VITE_` 为前缀的用户自定义环境变量的 TypeScript 智能提示。
-要想做到这一点,你可以在 `src` 目录下创建一个 `env.d.ts` 文件,接着按下面这样增加 `ImportMetaEnv` 的定义:
+要想做到这一点,你可以在 `src` 目录下创建一个 `vite-env.d.ts` 文件,接着按下面这样增加 `ImportMetaEnv` 的定义:
-```typescript
+```typescript [vite-env.d.ts]
///
+interface ViteTypeOptions {
+ // 添加这行代码,你就可以将 ImportMetaEnv 的类型设为严格模式,
+ // 这样就不允许有未知的键值了。
+ // strictImportMetaEnv: unknown
+}
+
interface ImportMetaEnv {
readonly VITE_APP_TITLE: string
// 更多环境变量...
@@ -90,41 +124,91 @@ interface ImportMeta {
}
```
-如果你的代码依赖于浏览器环境的类型,比如 [DOM](https://github.com/microsoft/TypeScript/blob/main/lib/lib.dom.d.ts) 和 [WebWorker](https://github.com/microsoft/TypeScript/blob/main/lib/lib.webworker.d.ts),你可以在 `tsconfig.json` 中修改 [lib](https://www.typescriptlang.org/tsconfig#lib) 字段来获取类型支持。
+如果你的代码依赖于浏览器环境的类型,比如 [DOM](https://github.com/microsoft/TypeScript/blob/main/src/lib/dom.generated.d.ts) 和 [WebWorker](https://github.com/microsoft/TypeScript/blob/main/src/lib/webworker.generated.d.ts),你可以在 `tsconfig.json` 中修改 [lib](https://www.typescriptlang.org/tsconfig#lib) 字段来获取类型支持。
-```json
+```json [tsconfig.json]
{
"lib": ["WebWorker"]
}
```
+:::warning 导入语句会破坏类型增强
+
+如果 `ImportMetaEnv` 增强不起作用,请确保在 `vite-env.d.ts` 中没有任何 `import` 语句。更多信息请参阅 [TypeScript 文档](https://www.typescriptlang.org/docs/handbook/2/modules.html#how-javascript-modules-are-defined)。
+
+:::
+
+## HTML 环境变量替换 {#html-constant-replacement}
+
+Vite 还支持在 HTML 文件中替换环境变量。`import.meta.env` 中的任何属性都可以通过特殊的 `%CONST_NAME%` 语法在 HTML 文件中使用:
+
+```html
+Vite is running in %MODE%
+Using data from %VITE_API_URL%
+```
+
+如果环境变量在 `import.meta.env` 中不存在,比如不存在的 `%NON_EXISTENT%`,则会将被忽略而不被替换,这与 JS 中的 `import.meta.env.NON_EXISTENT` 不同,JS 中会被替换为 `undefined`。
+
+正因为 Vite 被许多框架使用,它在复杂的替换(如条件替换)上故意不持任何意见。Vite 可以使用 [现有的用户插件](https://github.com/vitejs/awesome-vite#transformers) 或者一个实现了 [`transformIndexHtml` 钩子](./api-plugin#transformindexhtml) 的自定义插件来扩展。
+
## 模式 {#modes}
默认情况下,开发服务器 (`dev` 命令) 运行在 `development` (开发) 模式,而 `build` 命令则运行在 `production` (生产) 模式。
这意味着当执行 `vite build` 时,它会自动加载 `.env.production` 中可能存在的环境变量:
-```
-# .env.production
+```[.env.production]
VITE_APP_TITLE=My App
```
在你的应用中,你可以使用 `import.meta.env.VITE_APP_TITLE` 渲染标题。
-然而,重要的是要理解 **模式** 是一个更广泛的概念,而不仅仅是开发和生产。一个典型的例子是,你可能希望有一个 “staging” (预发布|预上线) 模式,它应该具有类似于生产的行为,但环境变量与生产环境略有不同。
-
-你可以通过传递 `--mode` 选项标志来覆盖命令使用的默认模式。例如,如果你想为我们假设的 staging 模式构建应用:
+在某些情况下,若想在 `vite build` 时运行不同的模式来渲染不同的标题,你可以通过传递 `--mode` 选项标志来覆盖命令使用的默认模式。例如,如果你想在 staging (预发布)模式下构建应用:
```bash
vite build --mode staging
```
-为了使应用实现预期行为,我们还需要一个 `.env.staging` 文件:
+还需要新建一个 `.env.staging` 文件:
-```
-# .env.staging
-NODE_ENV=production
+```[.env.staging]
VITE_APP_TITLE=My App (staging)
```
-现在,你的 staging 应用应该具有类似于生产的行为,但显示的标题与生产环境不同。
+由于 `vite build` 默认运行生产模式构建,你也可以通过使用不同的模式和对应的 `.env` 文件配置来改变它,用以运行开发模式的构建:
+
+```[.env.testing]
+NODE_ENV=development
+```
+
+### NODE_ENV 和 模式 {#node-env-and-modes}
+
+需要注意的是,`NODE_ENV`(`process.env.NODE_ENV`)和模式是两个不同的概念。以下是不同命令如何影响 `NODE_ENV` 和模式:
+
+| Command | NODE_ENV | Mode |
+| ---------------------------------------------------- | --------------- | --------------- |
+| `vite build` | `"production"` | `"production"` |
+| `vite build --mode development` | `"production"` | `"development"` |
+| `NODE_ENV=development vite build` | `"development"` | `"production"` |
+| `NODE_ENV=development vite build --mode development` | `"development"` | `"development"` |
+
+`NODE_ENV` 和模式的不同值也会反映在相应的 `import.meta.env` 属性上:
+
+| Command | `import.meta.env.PROD` | `import.meta.env.DEV` |
+| ---------------------- | ---------------------- | --------------------- |
+| `NODE_ENV=production` | `true` | `false` |
+| `NODE_ENV=development` | `false` | `true` |
+| `NODE_ENV=other` | `false` | `true` |
+
+| Command | `import.meta.env.MODE` |
+| -------------------- | ---------------------- |
+| `--mode production` | `"production"` |
+| `--mode development` | `"development"` |
+| `--mode staging` | `"staging"` |
+
+:::tip `.env` 文件中的 `NODE_ENV`
+
+`NODE_ENV=...` 可以在命令中设置,也可以在 `.env` 文件中设置。如果在 `.env.[mode]` 文件中指定了 `NODE_ENV`,则可以使用模式来控制其值。不过,`NODE_ENV` 和模式仍然是两个不同的概念。
+
+命令中使用 `NODE_ENV=...` 的主要好处是,它允许 Vite 提前检测到该值。这也使你能够在 Vite 配置中读取 `process.env.NODE_ENV`,因为 Vite 只有在解析配置之后才能加载环境变量文件。
+:::
diff --git a/guide/features.md b/guide/features.md
index 030340ae..c3cd4945 100644
--- a/guide/features.md
+++ b/guide/features.md
@@ -2,7 +2,7 @@
对非常基础的使用来说,使用 Vite 开发和使用一个静态文件服务器并没有太大区别。然而,Vite 还通过原生 ESM 导入提供了许多主要用于打包场景的增强功能。
-## NPM 依赖解析和预构建 {#npm-dependency-resolving-and-pre-bundling}
+## npm 依赖解析和预构建 {#npm-dependency-resolving-and-pre-bundling}
原生 ES 导入不支持下面这样的裸模块导入:
@@ -22,7 +22,7 @@ Vite 通过 HTTP 头来缓存请求得到的依赖,所以如果你想要编辑
## 模块热替换 {#hot-module-replacement}
-Vite 提供了一套原生 ESM 的 [HMR API](./api-hmr)。 具有 HMR 功能的框架可以利用该 API 提供即时、准确的更新,而无需重新加载页面或清除应用程序状态。Vite 内置了 HMR 到 [Vue 单文件组件(SFC)](https://github.com/vitejs/vite/tree/main/packages/plugin-vue) 和 [React Fast Refresh](https://github.com/vitejs/vite/tree/main/packages/plugin-react) 中。也通过 [@prefresh/vite](https://github.com/JoviDeCroock/prefresh/tree/main/packages/vite) 对 Preact 实现了官方集成。
+Vite 提供了一套原生 ESM 的 [HMR API](./api-hmr)。 具有 HMR 功能的框架可以利用该 API 提供即时、准确的更新,而无需重新加载页面或清除应用程序状态。Vite 内置了 HMR 到 [Vue 单文件组件(SFC)](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue) 和 [React Fast Refresh](https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react) 中。也通过 [@prefresh/vite](https://github.com/JoviDeCroock/prefresh/tree/main/packages/vite) 对 Preact 实现了官方集成。
注意,你不需要手动设置这些 —— 当你通过 [`create-vite`](./) 创建应用程序时,所选模板已经为你预先配置了这些。
@@ -30,7 +30,17 @@ Vite 提供了一套原生 ESM 的 [HMR API](./api-hmr)。 具有 HMR 功能的
Vite 天然支持引入 `.ts` 文件。
-Vite 仅执行 `.ts` 文件的转译工作,并 **不** 执行任何类型检查。并假设类型检查已经被你的 IDE 或构建过程接管了(你可以在构建脚本中运行 `tsc --noEmit` 或者安装 `vue-tsc` 然后运行 `vue-tsc --noEmit` 来对你的 `*.vue` 文件做类型检查)。
+### 仅执行转译 {#transpile-only}
+
+请注意,Vite 仅执行 `.ts` 文件的转译工作,**并不执行** 任何类型检查。并假定类型检查已经被你的 IDE 或构建过程处理了。
+
+Vite 之所以不把类型检查作为转换过程的一部分,是因为这两项工作在本质上是不同的。转译可以在每个文件的基础上进行,与 Vite 的按需编译模式完全吻合。相比之下,类型检查需要了解整个模块图。把类型检查塞进 Vite 的转换管道,将不可避免地损害 Vite 的速度优势。
+
+Vite 的工作是尽可能快地将源模块转化为可以在浏览器中运行的形式。为此,我们建议将静态分析检查与 Vite 的转换管道分开。这一原则也适用于其他静态分析检查,例如 ESLint。
+
+- 在构建生产版本时,你可以在 Vite 的构建命令之外运行 `tsc --noEmit`。
+
+- 在开发时,如果你需要更多的 IDE 提示,我们建议在一个单独的进程中运行 `tsc --noEmit --watch`,或者如果你喜欢在浏览器中直接看到上报的类型错误,可以使用 [vite-plugin-checker](https://github.com/fi3ework/vite-plugin-checker)。
Vite 使用 [esbuild](https://github.com/evanw/esbuild) 将 TypeScript 转译到 JavaScript,约是 `tsc` 速度的 20~30 倍,同时 HMR 更新反映到浏览器的时间小于 50ms。
@@ -47,36 +57,59 @@ export type { T }
#### `isolatedModules`
+- [TypeScript 文档](https://www.typescriptlang.org/tsconfig#isolatedModules)
+
应该设置为 `true`。
这是因为 `esbuild` 只执行没有类型信息的转译,它并不支持某些特性,如 `const enum` 和隐式类型导入。
你必须在 `tsconfig.json` 中的 `compilerOptions` 下设置 `"isolatedModules": true`。如此做,TS 会警告你不要使用隔离(isolated)转译的功能。
-然而,一些库(如:[`vue`](https://github.com/vuejs/core/issues/1228))不能很好地与 `"isolatedModules": true` 共同工作。你可以在上游仓库修复好之前暂时使用 `"skipLibCheck": true` 来缓解这个错误。
+如果一个依赖项和 `"isolatedModules": true` 不兼容的话,你可以在上游仓库修复好之前暂时使用 `"skipLibCheck": true` 来缓解这个错误。
#### `useDefineForClassFields`
-从 Vite v2.5.0 开始,如果 TypeScript 的 target 是 `ESNext`,此选项默认值则为 `true`。这与 [`tsc` v4.3.2 及以后版本的行为](https://github.com/microsoft/TypeScript/pull/42663) 一致。这也是标准的 ECMAScript 的运行时行为。
+- [TypeScript 文档](https://www.typescriptlang.org/tsconfig#useDefineForClassFields)
+
+如果 TypeScript 的 target 是 `ES2022` 或更高版本,包括 `ESNext`,那么默认值将为 `true`。这与 [TypeScript 4.3.2 及以后版本的行为](https://github.com/microsoft/TypeScript/pull/42663) 保持一致。
+若设了其他 TypeScript target,则本项会默认为 `false`.
-但对于那些习惯其他编程语言或旧版本 TypeScript 的开发者来说,这可能是违反直觉的。
-你可以参阅 [TypeScript 3.7 发布日志](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#the-usedefineforclassfields-flag-and-the-declare-property-modifier) 中了解更多关于如何兼容的信息。
+`true` 是标准的 ECMAScript 运行时行为。
如果你正在使用一个严重依赖 class fields 的库,请注意该库对此选项的预期设置。
+虽然大多数库期望 `"useDefineForClassFields": true`,但如果你的库不支持它,你可以明确地将 `useDefineForClassFields` 设置为 `false`。
+
+#### `target` {#target}
+
+- [TypeScript 文档](https://www.typescriptlang.org/tsconfig#target)
-大多数库都希望 `"useDefineForClassFields": true`,如 [MobX](https://mobx.js.org/installation.html#use-spec-compliant-transpilation-for-class-properties),[Vue Class Components 8.x](https://github.com/vuejs/vue-class-component/issues/465) 等。
+Vite 忽略 `tsconfig.json` 中的 `target` 值,遵循与 `esbuild` 相同的行为。
-但是有几个库还没有兼容这个新的默认值,其中包括 [`lit-element`](https://github.com/lit/lit-element/issues/1030)。如果遇到这种情况,请将 `useDefineForClassFields` 设置为 `false`。
+要在开发中指定目标,可使用 [`esbuild.target`](/config/shared-options.html#esbuild) 选项,默认值为 `esnext`,以实现最小的转译。在构建中,[`build.target`](/config/build-options.html#build-target) 选项优先于 `esbuild.target`,如有需要也可以进行设置。
+
+::: warning `useDefineForClassFields`
+
+如果 `target` 不是 `ESNext` 或 `ES2022` 或更新版本,或者没有 `tsconfig.json` 文件,`useDefineForClassFields` 将默认为 `false`,这可能会导致默认的 `esbuild.target` 值为 `esnext` 的问题。它可能会转译为 [static initialization blocks](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Static_initialization_blocks#browser_compatibility),这在你的浏览器中可能不被支持。
+
+因此,建议将 `target` 设置为 `ESNext` 或 `ES2022` 或更新版本,或者在配置 `tsconfig.json` 时将 `useDefineForClassFields` 显式设置为 `true`。
+:::
#### 影响构建结果的其他编译器选项 {#other-compiler-options-affecting-the-build-result}
- [`extends`](https://www.typescriptlang.org/tsconfig#extends)
- [`importsNotUsedAsValues`](https://www.typescriptlang.org/tsconfig#importsNotUsedAsValues)
- [`preserveValueImports`](https://www.typescriptlang.org/tsconfig#preserveValueImports)
+- [`verbatimModuleSyntax`](https://www.typescriptlang.org/tsconfig#verbatimModuleSyntax)
+- [`jsx`](https://www.typescriptlang.org/tsconfig#jsx)
- [`jsxFactory`](https://www.typescriptlang.org/tsconfig#jsxFactory)
- [`jsxFragmentFactory`](https://www.typescriptlang.org/tsconfig#jsxFragmentFactory)
+- [`jsxImportSource`](https://www.typescriptlang.org/tsconfig#jsxImportSource)
+- [`experimentalDecorators`](https://www.typescriptlang.org/tsconfig#experimentalDecorators)
+- [`alwaysStrict`](https://www.typescriptlang.org/tsconfig#alwaysStrict)
-如果你的代码库很难迁移到 `"isolatedModules": true`,或许你可以尝试通过第三方插件来解决,比如 [rollup-plugin-friendly-type-imports](https://www.npmjs.com/package/rollup-plugin-friendly-type-imports)。但是,这种方式不被 Vite 官方支持。
+::: tip `skipLibCheck`
+Vite 启动模板默认情况下会设置 `"skipLibCheck": "true"`,以避免对依赖项进行类型检查,因为它们可能只支持特定版本和配置的 TypeScript。你可以在 [vuejs/vue-cli#5688](https://github.com/vuejs/vue-cli/pull/5688) 了解更多信息。
+:::
### 客户端类型 {#client-types}
@@ -86,62 +119,119 @@ Vite 默认的类型定义是写给它的 Node.js API 的。要将其补充到
///
```
-同时,你也可以将 `vite/client` 添加到 `tsconfig` 中的 `compilerOptions.types` 下:
+::: details 使用 `compilerOptions.types`
-```json
+或者,你也可以将 `vite/client` 添加到 `tsconfig.json` 中的 `compilerOptions.types` 下:
+
+```json [tsconfig.json]
{
"compilerOptions": {
- "types": ["vite/client"]
+ "types": ["vite/client", "some-other-global-lib"]
}
}
```
-这将会提供以下类型定义补充:
+需要注意的是,如果指定了 [`compilerOptions.types`](https://www.typescriptlang.org/tsconfig#types),则只有这些包会被包含在全局作用域内(而不是所有的“@types”包)。
+
+:::
+
+`vite/client` 会提供以下类型定义补充:
- 资源导入 (例如:导入一个 `.svg` 文件)
-- `import.meta.env` 上 Vite 注入的环境变量的类型定义
+- `import.meta.env` 上 Vite 注入的 [常量](./env-and-mode#env-variables) 的类型定义
- `import.meta.hot` 上的 [HMR API](./api-hmr) 类型定义
::: tip
-要覆盖默认的类型定义,请在三斜线注释前添加定义。例如,要为 React 组件中的 `*.svg` 文件定义类型:
+要覆盖默认的类型定义,请添加一个包含你所定义类型的文件,请在三斜线注释 reference `vite/client` 前添加定义。
-```ts
-declare module '*.svg' {
- const content: React.FC>
- export default content
-}
+例如,要为 React 组件中的 `*.svg` 文件定义类型:
-///
-```
+- `vite-env-override.d.ts` (the file that contains your typings):
+ ```ts
+ declare module '*.svg' {
+ const content: React.FC>
+ export default content
+ }
+ ```
+- The file containing the reference to `vite/client` (normally `vite-env.d.ts`):
+ ```ts
+ ///
+ ///
+ ```
:::
-## Vue {#vue}
+## HTML {#html}
-Vite 为 Vue 提供第一优先级支持:
+HTML 文件位于 Vite 项目的[最前端和中心](/guide/#index-html-and-project-root),作为应用程序的入口点,可轻松构建单页和[多页应用程序](/guide/build.html#multi-page-app)。
-- Vue 3 单文件组件支持:[@vitejs/plugin-vue](https://github.com/vitejs/vite/tree/main/packages/plugin-vue)
-- Vue 3 JSX 支持:[@vitejs/plugin-vue-jsx](https://github.com/vitejs/vite/tree/main/packages/plugin-vue-jsx)
-- Vue 2.7 支持:[vitejs/vite-plugin-vue2](https://github.com/vitejs/vite-plugin-vue2)
-- Vue <2.7 的支持:[underfin/vite-plugin-vue2](https://github.com/underfin/vite-plugin-vue2)
+项目根目录中的任何 HTML 文件都可以通过各自的目录路径直接访问:
+
+- `/index.html` -> `http://localhost:5173/`
+- `/about.html` -> `http://localhost:5173/about.html`
+- `/blog/index.html` -> `http://localhost:5173/blog/index.html`
+
+由 HTML 元素引用的资源,例如 `
+
+