Vite+ 会成为我的新前端默认工具链吗 vite plus frontend toolchain Vite VitePlus Oxc Vitest Frontend 前端
3720 字
19 分钟
Vite+ 会成为我的新前端默认工具链吗

TL;DR

如果今天让我新开一个前端项目,我大概率会优先考虑这套组合:

  • Vite 8 作为 dev/build 的基础
  • Vite+ 作为统一入口,接管 create、dev、build、test、lint、format、run
  • Oxlint + Oxfmt 替代大部分 ESLint / Prettier 的日常反馈链路
  • Vitest 4 做单测、组件测试和 Browser Mode
  • Playwright 负责真正的端到端和移动端模拟
  • monorepo 场景下,用 Vite+ 的 task runner 和缓存先顶上,而不是一上来就引入很重的工程编排

我现在越来越不想在新项目里重新拼一遍工具链了。

不是说 ESLint、Prettier、pnpm workspace、Turborepo、Vitest、Playwright 这些东西不好。它们都很好,也都很成熟。但问题是,每次新项目都要重新想一遍:

  • lint 怎么配
  • format 怎么配
  • test 怎么拆
  • monorepo 脚本怎么跑
  • CI 缓存怎么写
  • 单仓库升级到 monorepo 要不要重构命令
  • Node 版本和包管理器怎么约束

这些事情单独看都不大,但加起来就是一种很稳定的消耗。

所以 Vite+ 让我感兴趣的地方,不是它又多了一个 CLI,而是它想把这些原本分散的前端基础设施,收束到一个入口里。

说白了,我想要的不是“更酷的脚手架”,而是一个新项目可以直接沿用的默认工作流。


1. 为什么是现在:Vite 8 之后,前端工具链的底座变了#

Vite 8 最大的变化,是把底层 bundler 收束到了 Rolldown

以前 Vite 的经典结构是:

  • 开发时主要依赖 esbuild 的速度
  • 生产构建走 Rollup 的生态和稳定性

这个设计很务实,也撑起了 Vite 很长时间。但它也带来一个长期存在的问题:开发和生产不是同一个 bundler,很多行为要靠适配和对齐。

到了 Vite 8,Rolldown 成为统一的 Rust bundler。官方说构建相对 Rollup 有 10-30x 的提升,同时继续维持 Rollup 插件兼容。这件事的意义不只是“构建更快”,而是 Vite、Rolldown、Oxc 这几层开始真正靠近了。

我觉得这里有一个很关键的趋势:

前端工具链正在从“很多 JS 工具拼起来”,慢慢变成“一组底层能力协同工作”。

过去我们习惯了这种组合:

  • Babel / SWC 负责转换
  • ESLint 负责检查
  • Prettier 负责格式化
  • Rollup / webpack / esbuild 负责打包
  • Vitest / Jest 负责测试
  • 任务编排再交给 npm scripts、Turborepo 或 Nx

它当然能跑,但每一层之间都有边界成本。配置重复、解析重复、文件扫描重复、缓存策略也重复。

Vite 8 + Vite+ 的方向,是把这些东西尽量统一到一套更贴近底层的链路里。

这也是我觉得它值得单独写一篇的原因。


2. Vite+ 到底解决什么问题#

Vite+ 不是简单的 create-vite 加强版。

VoidZero 对它的定位是 unified toolchain,也就是一个统一的 Web 开发入口。它把这些工具组合到一起:

  • Vite
  • Vitest
  • Oxlint
  • Oxfmt
  • Rolldown
  • tsdown
  • Vite Task

对应到命令上,大概是:

Terminal window
vp create # 创建项目 / monorepo
vp install # 自动使用正确包管理器安装依赖
vp dev # 启动开发服务
vp check # lint + format check + type check
vp test # 运行 Vitest
vp build # 生产构建
vp run # 跑脚本和任务,支持 monorepo 依赖顺序与缓存
vp pack # 打包库或独立应用
vp env # 管理 Node 环境

我比较喜欢的是它的目标很直接:

把“项目该怎么跑”这件事从 package.json 脚本里抽出来,变成更稳定的工程约定。

很多前端项目刚开始都很简单:

{
"scripts": {
"dev": "vite",
"build": "vite build",
"test": "vitest",
"lint": "eslint .",
"format": "prettier --write ."
}
}

但项目长大后,脚本会慢慢变成这样:

{
"scripts": {
"dev": "xxx",
"dev:web": "xxx",
"dev:admin": "xxx",
"build": "xxx",
"build:web": "xxx",
"build:admin": "xxx",
"lint": "xxx",
"lint:fix": "xxx",
"format": "xxx",
"format:check": "xxx",
"typecheck": "xxx",
"test": "xxx",
"test:unit": "xxx",
"test:browser": "xxx",
"test:e2e": "xxx"
}
}

然后每个项目都不一样。

新同事进来第一件事不是写业务,而是先问:这个仓库到底该跑哪个命令?CI 和本地是不是同一套?monorepo 里改了一个 package,要不要全量 build?

Vite+ 想统一的就是这些日常动作。

这件事并不性感,但很有价值。


3. Oxlint + Oxfmt:先把反馈速度提上来#

我一直觉得 lint 和 format 的价值不在“显得工程规范”,而在反馈速度。

如果一个工具慢到大家不愿意本地跑,那它在团队里就会慢慢变成 CI 惩罚器。代码写完了,push 上去,CI 红了,然后再回来改。这个流程非常消耗人。

Oxlint 的定位很明确:不用配置也能抓很多错误和无用代码,并且速度比 ESLint 快很多。Oxc 文档里提到,Oxlint 大概是 ESLint 的 50-100 倍速度,并且会随着 CPU 核心数扩展。

Oxfmt 则是 Prettier-compatible formatter。它支持 JS、JSX、TS、TSX、JSON、YAML、HTML、Vue、CSS、Markdown、MDX 等常见格式。官方说 Oxfmt 大概比 Prettier 快 30 倍,并且 JavaScript / TypeScript 已经通过 Prettier 的 conformance tests。

当然,这里我不会直接说“可以无脑替代 ESLint 和 Prettier”。

更稳的策略应该是分阶段:

小到中型新项目#

可以直接尝试:

Terminal window
vp check

把 lint、format check、type check 都收进一个命令里。

如果不用 Vite+,也可以单独这样配:

{
"scripts": {
"lint": "oxlint",
"format": "oxfmt",
"format:check": "oxfmt --check"
}
}

已有大型项目#

不要一把梭。

我会先这样做:

  1. 保留现有 ESLint
  2. 先在本地和 CI 前置跑 Oxlint
  3. eslint-plugin-oxlint 关闭 Oxlint 已经覆盖的 ESLint 规则
  4. 对必须依赖生态插件的规则,继续交给 ESLint
  5. 等差异足够小,再考虑进一步迁移

这和 Oxc 官方建议也比较接近:大型项目可以先让 Oxlint 在 ESLint 前面跑,拿到更快的反馈回路。

我的判断是:

Oxlint 更适合做第一层快速反馈,ESLint 暂时还适合兜底复杂生态规则。

比如某些框架插件、公司内部规则、非常细的可访问性策略,短期内不一定都能丢给 Oxlint。

但新项目就不一样了。新项目没有历史包袱,我更愿意直接让 Oxlint/Oxfmt 成为默认项。


4. 单代码仓库:先简单,但不要把未来堵死#

如果只是一个普通前端应用,我现在会尽量保持结构简单:

my-app/
src/
tests/
vite.config.ts
vitest.config.ts
package.json

默认命令大概是:

Terminal window
vp dev
vp check
vp test
vp build

这里关键不是命令少,而是命令语义稳定。

我希望以后不管项目变成什么样,大家都知道:

  • 开发就是 vp dev
  • 提交前就是 vp check
  • 测试就是 vp test
  • 构建就是 vp build

这比在 package.json 里写十几个类似命令更容易维护。

我会把配置控制在很少的范围内:

vite.config.ts
import { defineConfig } from 'vite'
export default defineConfig({
// 先保持少配置
})

新项目最怕一开始就工程化过度。

有些东西可以晚点再引入:

  • 多应用
  • 多 package
  • 复杂缓存
  • 代码生成
  • e2e 矩阵
  • 内部组件库

但有些约定最好一开始就定好:

  • Node 版本
  • 包管理器
  • lint / format / typecheck 入口
  • test 文件命名
  • CI 必跑命令

这就是 Vite+ 这种统一入口的价值:它不会强迫你一开始就做成 monorepo,但它给后面扩展留下了路径。


5. monorepo:不要为了 monorepo 而 monorepo#

我对 monorepo 的态度一直比较保守。

不是不能用,而是要先问:你真的需要吗?

这些情况我觉得可以上:

  • 一个产品里有多个前端应用,比如 web、admin、docs
  • 有共享组件库、工具库、类型包
  • 多个 package 需要一起改、一起测、一起发
  • 团队已经被跨仓库同步折磨过了

如果只是一个应用,硬拆成 monorepo,通常只是把简单问题复杂化。

一个比较舒服的结构可能是这样:

repo/
apps/
web/
admin/
packages/
ui/
config/
shared/
vite.config.ts
package.json

Vite+ 里比较值得关注的是 vp run 和 Vite Task。

它不像普通 pnpm run 只是把命令跑起来,而是会考虑:

  • workspace 感知
  • 任务依赖顺序
  • 自动缓存
  • 哪些输入文件会影响任务结果
  • 哪些环境变量会影响缓存

比如在 monorepo 里,根配置可以打开缓存:

vite.config.ts
import { defineConfig } from 'vite'
export default defineConfig({
run: {
cache: true,
},
})

然后日常就可以:

Terminal window
vp run build
vp run test
vp run lint

当然,缓存不是魔法。

我会特别注意这几件事:

  • 生成物不要被算进输入里,比如 dist/
  • 临时文件不要干扰缓存,比如 .vite-temp/
  • 任务依赖要写清楚,尤其是 packages/uiapps/web 使用时
  • 影响构建的环境变量要纳入缓存 key
  • CI 和本地的缓存策略不要完全割裂

我比较喜欢的实践是:

monorepo 先用 Vite+ 的任务能力跑起来,只有当它不够用时,再考虑引入更重的 Nx / Turborepo。

这不是说 Nx 或 Turborepo 不好,而是新项目不一定需要一开始就背这么多概念。


6. Vitest:从单测到 Browser Mode#

Vitest 现在已经不只是“Vite 生态里的 Jest 替代品”了。

对我来说,它比较适合承担三层测试:

  1. Node 环境单测:工具函数、数据转换、业务逻辑
  2. jsdom / happy-dom 组件测试:轻量 DOM 行为
  3. Browser Mode:需要真实浏览器能力的组件或交互测试

Vitest 的 projects 配置很适合把这些拆开。以前叫 workspace,现在官方更推荐 projects。

比如可以这样:

vitest.config.ts
import { defineConfig } from 'vitest/config'
import { playwright } from '@vitest/browser-playwright'
export default defineConfig({
test: {
projects: [
{
test: {
name: 'unit',
environment: 'node',
include: ['tests/unit/**/*.test.ts', 'src/**/*.unit.test.ts'],
},
},
{
test: {
name: 'browser',
include: ['tests/browser/**/*.test.ts', 'src/**/*.browser.test.ts'],
browser: {
enabled: true,
provider: playwright(),
instances: [{ browser: 'chromium' }],
},
},
},
],
},
})

这样做的好处是边界很清楚:

  • 纯逻辑不要进浏览器,快一点
  • 需要真实 DOM / layout / browser API 的测试再进 Browser Mode
  • 不同测试环境不要互相污染

我现在不太喜欢所有测试都塞进一个环境里。

因为最后一定会变成这种局面:有的测试明明只需要 Node,却被迫跑在更重的环境里;有的测试明明依赖真实浏览器,却在模拟环境里靠 mock 撑着。

拆开之后,心智负担反而更低。


7. 移动端:不要只改 viewport#

如果项目要认真考虑移动端,我不会只写几个响应式断点就结束。

移动端至少要看这些东西:

  • 视口尺寸
  • touch 行为
  • user agent
  • safe area
  • 横竖屏
  • 输入法弹起
  • 滚动容器
  • hover 不存在时的交互
  • 弱网络和慢设备下的体验

Vitest Browser Mode 可以覆盖一部分真实浏览器里的组件行为,但真正的移动端端到端,我还是会交给 Playwright。

Playwright 的 device emulation 可以模拟很多设备参数,比如 userAgent、screenSize、viewport、hasTouch、isMobile、locale、timezone 等。

例如:

playwright.config.ts
import { defineConfig, devices } from '@playwright/test'
export default defineConfig({
projects: [
{
name: 'Desktop Chrome',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'Mobile Safari',
use: { ...devices['iPhone 15'] },
},
{
name: 'Pixel',
use: { ...devices['Pixel 7'] },
},
],
})

但这里也要清醒一点:模拟不等于真机。

它可以很好地发现:

  • 响应式布局错位
  • touch 点击区域太小
  • 移动端菜单打不开
  • Safari/WebKit 下的兼容问题
  • 表单在小屏幕上不可用

但它不一定能完全覆盖:

  • 真机性能
  • 某些 WebView 行为
  • 软键盘遮挡
  • 系统级手势冲突
  • 真实网络和机型差异

所以我的默认策略会是:

  • 日常 CI:Playwright 移动端模拟
  • 关键版本:至少拿一台 iPhone 和一台 Android 真机过主流程
  • PWA / H5 活动页:额外关注 WebView 和分享入口

移动端最怕的是桌面看起来没问题,真到手机上一堆细节炸掉。


8. 我会怎么给新项目定默认脚本#

如果用 Vite+,我会尽量减少自定义脚本,让团队形成固定动作。

{
"scripts": {
"dev": "vp dev",
"check": "vp check",
"test": "vp test",
"build": "vp build"
}
}

如果是 monorepo:

{
"scripts": {
"dev": "vp dev",
"check": "vp check",
"test": "vp run test",
"build": "vp run build"
}
}

CI 里大概保持这样:

Terminal window
vp install
vp check
vp test
vp build

如果有 e2e:

Terminal window
pnpm playwright install --with-deps
pnpm playwright test

当然,这里要看 Vite+ 后续和 Playwright 的集成情况。如果后面它能把 e2e 也更自然地收进 vp test,那会更舒服。


9. 风险:Vite+ 还在 Alpha,不要把它当成完全成熟的基建#

这篇虽然是在推荐 Vite+,但我不想把它写成无脑吹。

Vite+ 现在还处在 Alpha 阶段,这意味着:

  • API 和配置可能变化
  • 某些边界场景还没被大量生产项目验证
  • monorepo 缓存可能会遇到细节问题
  • 生态插件不一定全部适配到最佳状态
  • 团队成员需要接受新的命令入口

所以我的建议会分场景:

场景我的建议
个人项目 / 新项目可以直接试 Vite+
小团队新项目可以试,但保留回退方案
中大型已有项目先迁 Oxlint/Oxfmt 或 Vite 8,不急着全量 Vite+
严肃生产 monorepo先开分支验证缓存、CI、构建差异
强依赖复杂 ESLint 插件暂时保留 ESLint 兜底

我的态度是:

新项目可以激进一点,老项目要保守一点。

工具链迁移最怕的是为了速度,把确定性弄丢了。


10. 我现在的默认选择#

如果是我来做一个新的前端项目,我大概会这样选:

普通 Web App#

  • Vite 8
  • Vite+
  • Oxlint + Oxfmt
  • Vitest unit tests
  • Playwright e2e

组件库 / 工具库#

  • Vite+ / tsdown
  • Vitest
  • Oxlint + Oxfmt
  • examples 用 Vite 跑起来
  • 发布前跑 vp pack

中后台 monorepo#

  • apps/web
  • apps/admin
  • packages/ui
  • packages/shared
  • Vite+ task cache
  • Vitest projects
  • Playwright 跑核心流程

移动端优先 H5#

  • Vite+
  • Vitest Browser Mode
  • Playwright mobile projects
  • 真机主流程检查
  • 对 safe area、touch、输入法、滚动做额外 checklist

最后#

我觉得 Vite+ 最有价值的地方,不是让某一个命令快一点。

真正重要的是,它试图把前端项目里那些每天都会发生、但每个仓库都写得不一样的事情统一起来:开发、构建、测试、检查、格式化、任务运行、monorepo 缓存、运行时管理。

这听起来没有那么酷,但对长期维护很重要。

前端工具链这些年一直在变快。以前我们关心的是“这个工具比那个工具快多少”,现在我更关心的是另一件事:

一个项目从第一天到变复杂之后,工具链还能不能保持同一套心智模型。

如果 Vite+ 后面稳定下来,它很可能会成为我新前端项目的默认入口。

至少现在,我愿意把它放进首选列表里。


参考资料:

Vite+ 会成为我的新前端默认工具链吗
https://bangwu.me/posts/vite-plus-frontend-toolchain/
作者
棒无
发布于
2026-04-27
许可协议
CC BY-NC-SA 4.0