写过八年 Vite 配置,今天才发现「环境」这件事根本就没被认真管过——Vite 7 把这件事彻底变了

写过八年 Vite 配置,今天才发现「环境」这件事根本就没被认真管过——Vite 7 把这件事彻底变了

配 Vite 配了八年,你大概经历过这几个阶段:第一个阶段是 SPA 阶段,所有东西都往 client 环境塞,没感觉有什么不对;第二个阶段是接 SSR,发现 server.ssrLoadModule 和普通构建是两套逻辑,但勉强能跑;第三个阶段是接边缘计算(Cloudflare Workers、Vercel Edge),发现浏览器跑一套、Node 跑一套、Edge 又是一套,三套构建、三套配置、三个坑。

这个阶段一过,你就开始在 vite.config.ts 里堆 if/else,在插件里打环境判断补丁,整个人变成了 Vite 配置工程师。

2026 年,Vite 7 正式把这件事收口了——Environment API 从实验阶段毕业,成为一等公民

以前的问题在哪

Vite 5 及之前,构建目标只有一个隐式的「客户端环境」,SSR 靠顶层的 ssr 配置项打补丁。看起来能用,但问题藏在细节里:

模块图是共享的。 server.moduleGraph 同时服务 client 和 ssr,但两个环境的依赖解析逻辑完全不同——client 用浏览器条件(browserdevelopment),SSR 用 Node 条件(noderequire)。混在一起,模块解析结果就会出错。

插件不知道自己在哪个环境跑。 同一个插件的 transform 钩子,对 client 代码和 SSR 代码可能需要不同的处理逻辑,但插件拿不到这个上下文,只能靠读文件路径猜,或者靠 import.meta.env.SSR 这个 hack 判断。

每个新运行时都要新插件。 接 Cloudflare Workers 要装 @cloudflare/vite-plugin,接 Vitest 要装对应插件,它们各自造了一套环境抽象,互不兼容。

Vite 7 Environment API 是什么

一句话:每个运行时环境有自己独立的模块图、插件管道和构建配置,配置层统一表达,运行时按需实例化。

// vite.config.ts — Vite 7 标准写法
import { defineConfig } from vite
import react from @vitejs/plugin-react

export default defineConfig({
  plugins: [react()],
  environments: {
    // 浏览器端
    client: {
      build: { outDir: dist/client }
    },
    // Node.js SSR
    ssr: {
      dev: { optimizeDeps: { include: [react-dom/server] } },
      build: { outDir: dist/server, target: node20 }
    },
    // RSC / 服务端组件
    rsc: {
      build: { outDir: dist/rsc, noExternal: true }
    },
    // 边缘运行时
    edge: {
      resolve: { noExternal: true, conditions: [edge, worker] },
      build: { outDir: dist/edge }
    }
  }
})

这四个环境,在同一个 Vite dev server 里同时启动,client 环境用浏览器通过 HTTP 请求模块,ssr 环境用 Node.js Module Runner 直接调用模块,edge 环境连接到 workerd 运行时。每个环境有自己独立的 EnvironmentModuleGraph,解析条件完全隔离。

插件终于知道自己在哪个环境了

这是最被低估的变化。以前写插件,判断运行环境只能靠:

// 以前的土办法
if (id.includes(node_modules) || import.meta.env.SSR) { ... }

现在,插件钩子里直接拿到 this.environment

const myPlugin = (): Plugin => ({
  name: my-plugin,
  transform(code, id) {
    // Vite 7 直接告诉你当前在哪个环境
    if (this.environment.name === client) {
      // 处理浏览器端代码
    } else if (this.environment.name === ssr) {
      // 处理 SSR 代码
    } else if (this.environment.name === edge) {
      // 处理 Edge 代码
    }
  }
})

插件作者不再需要为每个运行时写独立插件,一个插件可以按环境分支处理。@cloudflare/vite-plugin 就是基于这个 API 重构的——同一个插件,同时负责本地 workerd 开发环境和线上 Edge 构建。

buildApp 钩子:多环境构建编排

生产构建也有变化。以前 SSR 构建靠 vite build --ssr,和 client 构建完全独立,没有协调机制。

Vite 7 引入了 builder.buildApp 钩子,框架可以精细控制构建顺序和并行策略:

export default defineConfig({
  builder: {
    async buildApp(builder) {
      const environments = Object.values(builder.environments)
      await Promise.all(
        environments.map(env => builder.build(env))
      )
    }
  }
})

这让框架作者可以针对不同场景优化:SSR + RSC 场景可以并行构建两个服务端环境,减少总构建时间。

向下兼容,老配置还能用

这是关键设计原则:Vite 7 没有破坏任何现有配置

如果你写的是纯 SPA/MPA,vite.config.ts 看起来和 Vite 5 一模一样,Vite 内部自动把所有顶级配置映射到 environments.client,不需要改任何代码:

// Vite 5 项目直接升级 Vite 7,什么都不用改
export default defineConfig({
  build: { outDir: dist },
  optimizeDeps: { include: [react] }
})

老配置自动获得 Vite 7 的构建性能提升(Rolldown 替代 esbuild+Rollup),但环境模型不变。

为什么这对中国前端团队特别重要

国内团队有两个典型场景特别受益:

第一,多部署目标项目。 现在很多项目同时要跑在:浏览器端(Vite 默认)、Node 服务端(Express/Fastify)、阿里云 FC 或腾讯云 SCF 边缘函数。以前每套目标都单独配 Vite 实例,或者靠 define 全局变量 hack 解决。Environment API 让这些在同一个配置文件里表达,运维文档和维护成本都降下来。

第二,微前端 + 模块联邦。 Module Federation 2.0 依赖宿主应用和远程应用各自的构建配置一致。Environment API 让每个环境的构建参数显式表达,不同团队负责不同环境时,配置接口清晰,减少对接摩擦。

下一步怎么落地

如果你现在想迁移,分两步走:

第一步:确认当前 Vite 版本。 Node.js 20.19+ 或 22.12+ 是 Vite 7 的硬要求,老版本先升 Node。

第二步:把 SSR 配置迁移到 environments。 找到现有的 ssr: { ... } 配置,翻译成 environments.ssr: { ... }。Vite 7 会给一个废弃警告,告诉你把 ssr 迁移到 environments。这个翻译是 1:1 的,不涉及业务逻辑变化。

// 旧写法(Vite 5)
export default defineConfig({
  ssr: {
    target: node,
    noExternal: [react-dom]
  }
})

// 新写法(Vite 7)
export default defineConfig({
  environments: {
    ssr: {
      build: { target: node20 },
      resolve: { noExternal: [react-dom] }
    }
  }
})

第三步:如果接了 Cloudflare Workers 或 TanStack Start,不需要额外配置。 这些插件内部已经基于 Environment API 写了环境工厂函数,升级 Vite 7 之后插件自动获得完整类型提示和 IDE 支持。


Vite 7 的 Environment API 不是一个花哨的新功能,它是 Vite 历史上第一次把「运行时多样性」这件事在构建层正式承认。以前我们用 Vite 假装只有一个世界,然后靠补丁假装另一个世界也存在。2026 年,不需要假装了——你需要几个环境,Vite 7 就给你几个,每个都是一等公民

评论区

0 条评论

登录后可评论。

阿柯·前端架构 15 阅读