引言
「在应用里写组件」和「做一套可发布的组件库」是两回事:库要被 npm 安装、按需引入、类型提示、样式可控、版本演进。Vite 的**库模式(lib mode)**正是为此设计。本文讲用 Vite 开发组件库的完整流程:先讲为什么独立构建组件库(复用/一致性/独立版本)、库模式构建配置(build.lib/formats/external/多入口)、组件与样式方案(CSS 方案选择/主题变量/样式隔离)、类型声明与 dts(构建生成 .d.ts)、按需加载与 sideEffects(子路径导出与摇树)、发布 npm 流程(打包/版本/发布/发布验证)、版本管理与变更日志(语义化版本/CHANGELOG)、与 Monorepo 的整合(多包管理)、最后是组件库的调试与文档(Storybook/文档站/测试)。目标:你能从零搭建一套可发布、可按需、可维护的组件库。
前置:/vite-monorepo-architecture/(Monorepo 架构)、/vite-build-optimization/(构建优化)、/vite-plugin-development/(插件开发)。
目录
- 1. 为什么独立构建组件库
- 2. 库模式构建配置
- 3. 组件与样式方案
- 4. 类型声明与 dts
- 5. 按需加载与 sideEffects
- 6. 发布 npm 流程
- 7. 版本管理与变更日志
- 8. 与 Monorepo 的整合
- 9. 组件库的调试与文档
- 10. 速查表与一句话记忆
- 延伸阅读
1. 为什么独立构建组件库
组件库 vs 应用内组件:
应用内组件:只服务当前应用,可快速修改
组件库:独立包,被多个应用/团队消费
→ 组件库 = 「组件资产化」:可复用、可共享、可演进
组件库的价值:
1. 复用:一套组件多应用用(不重复写)
2. 一致性:统一设计/交互(品牌一致)
3. 独立版本:库版本与消费应用解耦
4. 专注维护:组件迭代不影响业务代码
→ 价值 = 复用 + 一致性 + 版本独立 + 专注
什么时候需要组件库:
- 多应用共享 UI(多个产品线)
- 设计系统落地(Design System)
- 团队规模大(UI 标准化需求)
- 对外发布(开源/商业组件)
→ 信号 = 多应用 × 标准化 × 独立团队
组件库的边界:
- 领域无关:通用组件(Button/Modal)vs 业务组件(订单卡)
- 通用组件进库、业务组件留应用
- 库不过度抽象(少而精,避免玩具化)
- 库依赖最小化(peerDependencies 外置)
→ 边界 = 通用性 × 依赖最小 × 精而不滥
组件库的挑战:
- 构建:库产物(ESM/CJS/dts)而非应用 bundle
- 按需:消费者只用部分(子路径/摇树)
- 样式:主题可控 + 隔离(不污染)
- 版本:破坏性变更管理(semver)
→ 挑战 = 产物/按需/样式/版本四关
心智:组件库 = 组件资产化(独立包被多应用消费),价值:复用、一致性、独立版本、专注维护;信号 = 多应用 × 标准化 × 独立团队;边界 = 通用组件进库、业务组件留应用、依赖最小化、精而不滥;四大挑战:库产物(ESM/CJS/dts)、按需(子路径/摇树)、样式(主题+隔离)、版本(semver)。
2. 库模式构建配置
lib 模式基础配置:
// vite.config.ts
import { defineConfig } from 'vite'
import { resolve } from 'path'
export default defineConfig({
build: {
lib: {
entry: resolve(__dirname, 'src/index.ts'), // 入口
formats: ['es', 'cjs'], // 输出格式
fileName: (format) => `index.${format}.js`
},
rollupOptions: {
// 外置 peer 依赖(不打进产物)
external: ['react', 'react-dom'],
}
}
})
formats 的选择:
- es:ESM(现代,可摇树)→ 主推
- cjs:CommonJS(旧工具兼容)→ 兼容
- umd:全局变量(CDN/script 引入)
- iife:立即执行(无导出,单一脚本)
- 实践:es + cjs(双产物),必要才 umd
→ 产物 = es 主推 + cjs 兼容 + 可选 umd
external:外置依赖:
- peer 依赖外置:react/react-dom 不打进库
(避免双份 React、库体积大)
- 配置 external + package.json peerDependencies
- 非 peer 的辅助依赖:可内置或也外置(权衡)
- 外置的好处:库小、无重复、宿主决定版本
→ external = peer 依赖外置,库瘦身不冲突
多入口库(子路径):
// 多入口:每个组件独立产物(子路径按需)
build: {
lib: {
entry: {
index: 'src/index.ts',
button: 'src/components/Button/index.ts',
modal: 'src/components/Modal/index.ts'
},
formats: ['es']
}
}
// 产物:index.es.js + button.es.js + modal.es.js
库模式 vs 应用构建:
- 应用:入口 HTML、优化产物、压缩、资源内联
- 库:入口源码、多格式、外置依赖、保留导出
- 库不要:HTML 输出、完整代码分割(保持可摇)
- 库要:dts(见下节)、sourcemap、资源外置
→ 库构建 = 面向「被消费」而非「被打开」
库构建的陷阱:
- 忘记 external(React 打进库 → 双份)
- 只出 cjs(现代工具不认/不可摇)
- 样式没处理(CSS 分离或注入)
- 资源路径错误(图片等 asset 相对路径)
→ 陷阱 = external/formats/样式/资源四查
心智:库模式基础 = build.lib(entry/formats/fileName)+ external(peer 依赖外置防双份 React)+ rollupOptions;formats 选 es(主推可摇)+ cjs(兼容)+ 必要 umd;多入口 = 每组件独立产物(button.es.js 等)支持子路径按需;库构建面向「被消费」:多格式 + 外置 + 保留导出 + 不 HTML 输出;陷阱四查:external、formats、样式处理、资源相对路径。
3. 组件与样式方案
样式方案的选型:
方案 1:CSS Modules
- 局部作用域(隔离)+ 编译期
- 适合:工具组件库(内部样式隔离)
方案 2:CSS-in-JS(styled-components/emotion)
- 运行时生成 + 主题支持
- 适合:主题化要求高的库
方案 3:原子 CSS(Tailwind/Unocss)
- 类名组合(体积小/一致)
- 适合:设计 token 系统化
方案 4:原生 CSS + 变量(CSS Variables)
- 主题通过 CSS 变量切换
- 轻量、无运行时
→ 选型 = 主题需求 × 隔离 × 运行时成本
主题化:CSS 变量方案:
/* 组件样式用 CSS 变量(主题可覆盖) */
.button {
background: var(--ui-color-primary, #4096ff);
border-radius: var(--ui-radius-md, 8px);
}
/* 主题切换:覆盖变量 */
.dark-theme {
--ui-color-primary: #1668dc;
}
样式隔离的考量:
- CSS Modules:编译期隔离(类名加 hash)
- CSS-in-JS:运行时隔离(作用域 + 命名)
- 原生 CSS:需命名前缀(ui-button- 防冲突)
- 全局 reset:避免全量覆盖宿主样式
→ 隔离 = 类名作用域 + 命名规范
样式构建(库模式):
- CSS 独立文件(样式分离,便于按需引 CSS)
- 或 CSS-in-JS 内联(运行时,无独立 CSS)
- CSS Modules:构建后类名映射(isolated)
- 主题 CSS:独立 theme.css(消费者按需引入)
→ 构建 = 样式产出方式决定消费方式
样式的按需与摇树:
// 库声明「CSS 文件有副作用」(不可摇)
{
"sideEffects": ["./dist/**/*.css"]
}
// → CSS 不被当无副作用删除(见摇树篇)
样式方案的实践建议:
- 工具库起步:CSS Modules + CSS 变量(简单可控)
- 主题复杂:CSS-in-JS(动态主题)
- 设计 token:变量集中管理(颜色/间距/字体)
- 样式规范:命名前缀 + 变量 + 无全局污染
→ 实践 = 简单起步 + token 集中 + 隔离规范
心智:样式方案选型:CSS Modules(编译期隔离,工具库推荐)、CSS-in-JS(运行时+主题,主题化库)、原子 CSS(token 系统化)、原生 CSS+变量(轻量主题切换);主题用 CSS 变量(var(–ui-color-primary) 可覆盖);隔离 = 类名作用域 + 命名前缀(ui-button-)+ 避免全局 reset;构建:CSS 独立文件便于按需、CSS 声明 sideEffects 数组防被摇树误删;实践:工具库起步 CSS Modules+变量、token 集中管理、无全局污染。
4. 类型声明与 dts
为什么库需要 dts:
- TypeScript 消费者需要类型提示
- 无 dts:消费端只能 any(失去类型安全)
- dts = 库的「类型契约」(props/返回值)
- 缺失 dts = 库体验大打折扣
→ dts = 库对 TS 消费者的「接口文档」
生成 dts 的方式:
1. Vite 插件:vite-plugin-dts
- 基于 TypeScript 编译器生成 .d.ts
- 构建时自动输出类型声明
2. tsc 单独跑:tsc --emitDeclarationOnly
- 简单但需配置输出
→ 推荐 vite-plugin-dts(构建集成)
vite-plugin-dts 配置:
// vite.config.ts
import dts from 'vite-plugin-dts'
export default defineConfig({
plugins: [
dts({
insertTypesEntry: true, // 生成主入口 types
outDir: 'dist/types', // 输出目录
rollupTypes: true // 聚合类型(合并声明)
})
]
})
dts 的输出结构:
dist/
index.d.ts (入口类型)
button.d.ts (子路径类型)
...
types/ (聚合后的类型)
→ 输出 = 入口 + 子路径各自的 dts
dts 的入口声明:
{
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.es.js",
"require": "./dist/index.cjs.js"
},
"./button": {
"types": "./dist/button.d.ts",
"import": "./dist/button.es.js"
}
}
}
// 每个入口配 types(TS 解析用)
dts 的注意:
- 类型要「公开可消费」(不泄露内部类型)
- 泛型/重载:声明准确(消费端体验)
- 副作用导入类型(import type)不进产物
- 版本间类型变化:破坏性变更要 semver(见第 7 节)
→ 注意 = 类型契约稳定性
验证 dts:
- 消费端:写最小 TS 文件使用库(有类型提示)
- tsc 检查:无错误(类型正确性)
- 发布前:跑 tsc --noEmit 在消费样例
- 类型测试:expectType 断言关键类型
→ 验证 = 消费样例 + tsc + 类型断言
心智:dts = 库对 TS 消费者的类型契约(props/返回值),缺失则消费端 any;生成用 vite-plugin-dts(insertTypesEntry/rollupTypes 聚合);输出 = 入口 index.d.ts + 子路径各 dts;package.json exports 每个入口配 types 字段;注意:类型公开可消费、不泄露内部、semver 管理类型变更;验证 = 消费样例 tsc + expectType 断言。
5. 按需加载与 sideEffects
按需加载的两种方式:
1. 摇树(自动):ESM + sideEffects + 具名导入
import { Button } from 'ui-lib'
→ 打包器只留 Button(见摇树篇)
2. 子路径(路径级):按路径引入
import Button from 'ui-lib/button'
→ 精确到组件,连摇树都不用(更直接)
→ 两种按需 = 自动(摇树)+ 显式(子路径)
库的可摇配置:
{
"sideEffects": ["./dist/**/*.css"],
"exports": {
".": {
"import": "./dist/index.es.js",
"types": "./dist/index.d.ts"
},
"./button": {
"import": "./dist/button.es.js",
"types": "./dist/button.d.ts"
}
}
}
// 纯 JS 无副作用:sideEffects 只列 CSS
// 子路径:每个组件独立入口
CSS 的按需:
- 样式分离:index.css 全量 / button.css 按组件
- 摇树不能删 CSS(有副作用 → 声明保留)
- 子路径 + CSS:import 'ui-lib/button/style.css'
- 或:CSS-in-JS(样式随 JS 按需,无独立 CSS)
→ CSS 按需 = 分文件 + 显式引入 或 CSS-in-JS
自动按需的插件方案:
- 传统 UI 库(Element/antd):babel-plugin-import
→ 转换具名导入为子路径(自动按需)
- 现代库:Vite 原生支持 ESM 摇树(无需插件)
- 若库为 CJS:才需按需插件(转子路径)
→ 自动按需 = ESM 摇树原生 / 旧 CJS 用插件
验证按需效果:
- 只 import Button → 构建看体积(应不含 Modal)
- 子路径 import → 体积最小(精确)
- CSS 是否保留(sideEffects 生效)
- 摇树 + 子路径都验证
→ 验证 = 单组件体积 + 子路径 + CSS 保留
按需的常见坑:
- 只出 CJS:摇树失效(需子路径/插件)
- 无 exports:无法子路径导入
- sideEffects 缺失:CSS 被误删(样式丢)
- 入口 bundle 而非分模块:子路径用不了
→ 坑 = 产物格式 + exports + sideEffects + 分模块
心智:按需两种:摇树(ESM+sideEffects+具名导入自动)与子路径(‘ui-lib/button’ 路径级精确);库配置:sideEffects 只列 CSS(纯 JS 无副作用)+ exports 子路径入口;CSS 按需 = 分文件显式引入(button/style.css)或 CSS-in-JS 随 JS;传统 CJS 库用 babel-plugin-import 转子路径,现代 ESM 原生摇树无需;验证 = 单组件体积 + 子路径 + CSS 保留;坑四查:CJS 格式/exports 缺失/sideEffects 误删/非分模块入口。
6. 发布 npm 流程
发布前的准备:
1. 构建:vite build(es + cjs + dts)
2. 校验产物:dist 完整(入口/子路径/dts/样式)
3. 检查 package.json:name/version/exports/main/types
4. 本地验证:消费样例安装测试
5. 测试:单元测试通过(Vitest)
→ 发布前 = 构建 + 校验 + 本地消费 + 测试
package.json 的发布字段:
{
"name": "ui-lib",
"version": "1.0.0",
"main": "./dist/index.cjs.js",
"module": "./dist/index.es.js",
"types": "./dist/index.d.ts",
"exports": {
".": { "types": "./dist/index.d.ts", "import": "./dist/index.es.js", "require": "./dist/index.cjs.js" },
"./button": { "types": "./dist/button.d.ts", "import": "./dist/button.es.js" }
},
"files": ["dist"],
"sideEffects": ["./dist/**/*.css"],
"peerDependencies": { "react": ">=18" }
}
files 字段:
- files: ["dist"]:发布只包含 dist(不泄漏源码)
- 不发布:src/测试/文档(保持包干净)
- .npmignore 或 files 白名单
- 检查:npm pack 预览包内容
→ files = 白名单控制发布内容
发布命令:
# 构建 + 发布
npm run build
npm publish
# 预览包内容(发布前检查)
npm pack --dry-run
# 测试版(非正式)
npm publish --tag beta
# 私服发布
npm publish --registry https://npm.internal.example.com
发布的验证:
- 发布后:npm install 新版本(消费样例)
- 检查:import 正常、类型提示、按需生效
- 回滚:版本不可删除 → 发布 bugfix(如 1.0.1)
- 文档更新:CHANGELOG/README(见下节)
→ 验证 = 新装消费 + 功能/类型/按需三查
发布的陷阱:
- 忘记构建就发布(旧产物)
- files 没配(把源码/测试发布出去)
- exports 路径错(消费者 import 404)
- 版本没提交(发布的是 git 状态)
- 未设置 peerDependencies(缺 React 报错)
→ 陷阱 = 构建/内容/路径/版本/peer 五查
心智:发布流程 = 构建(es+cjs+dts)→ 校验产物 → 检查 package.json(exports/main/types/files/sideEffects/peerDependencies)→ 本地消费验证 → npm pack 预览 → npm publish(–tag beta 测版/私服);files:[“dist”] 白名单不泄漏源码;验证 = 新装消费(import/类型/按需三查);回滚用 bugfix 版本;陷阱五查:没构建、files 不配、exports 路径错、版本未提交、peerDependencies 缺失。
7. 版本管理与变更日志
语义化版本(SemVer):
MAJOR.MINOR.PATCH
MAJOR:破坏性变更(不兼容)
MINOR:向后兼容的新功能
PATCH:向后兼容的 bugfix
规则:
破坏性变更 → 升 MAJOR
新功能兼容 → 升 MINOR
修复 → 升 PATCH
→ SemVer = 版本号即「兼容性承诺」
破坏性变更的判定:
- API 删除/改名/改签名 → 破坏性(MAJOR)
- 默认行为变化 → 破坏性
- 新增 props/导出 → 兼容(MINOR)
- 类型变化(收窄/改类型)→ 可能是破坏性
- CSS 结构变化 → 可能是破坏性(覆盖样式者)
→ 判定 = 消费者是否「需要改动」才能用
变更日志(CHANGELOG):
# CHANGELOG
## v2.0.0 (2026-09-30)
### BREAKING
- 移除 `Button.size="xs"`,改用 `size="small"`
### 新增
- 新增 `Modal.footer` 自定义底部
### 修复
- 修复 `Button` 在 Safari 的点击事件
## v1.5.0 (2026-08-01)
...
生成变更日志:
- Conventional Commits:提交信息规范(feat/fix/breaking)
- 工具:standard-version / changesets(自动生成)
- Changesets:Monorepo 常用(多包变更管理)
- 手动维护:发布前整理(小团队够用)
→ 变更日志 = 提交规范 + 自动生成工具
版本发布的节奏:
- 功能分支 → 合并 → 构建测试 → 发布
- 破坏性变更:先 deprecate 通知,再 MAJOR 发布
- 版本策略:滚动发布 vs 批次发布
- 标签:git tag v2.0.0(与版本对应)
→ 节奏 = 持续交付 + semver 规则 + 标签
版本的管理工具:
- changesets:多包 + 自动版本/日志(Monorepo)
- release-it:自动化发布流程(版本/标签/发布)
- standard-version:conventional 自动版本
- 手动:改 version + CHANGELOG + git tag
→ 工具 = 按规模选(多包 changesets、单包 release-it)
心智:SemVer = 版本号即兼容性承诺(MAJOR 破坏性/MINOR 兼容新功能/PATCH bugfix);破坏性判定 = 消费者是否需要改动才能用(API 删除/改名/默认行为/类型收窄/CSS 结构);CHANGELOG 用 Conventional Commits + changesets/standard-version 自动生成(BREAKING/新增/修复 结构);节奏 = 持续交付 + semver + git tag;工具:changesets(多包)/release-it(单包自动化)/standard-version(conventional)。
8. 与 Monorepo 的整合
Monorepo + 组件库:
结构:
monorepo/
packages/
ui-lib/ ← 组件库(独立包)
ui-icons/ ← 图标包
app-admin/ ← 消费应用
app-web/ ← 消费应用
→ 组件库与消费应用同仓 = 联动开发
Monorepo 的价值:
1. 联动开发:改库立刻在应用看到(workspace 链接)
2. 统一依赖:共同依赖版本一致
3. 原子提交:库 + 应用改动同 commit
4. 共享工具:lint/tsconfig/test 统一
→ 价值 = 联动 + 一致 + 原子 + 共享
workspace 配置:
// package.json(根)
{
"workspaces": ["packages/*"]
}
// 或 pnpm-workspace.yaml
packages:
- "packages/*"
workspace 的本地消费:
- npm/pnpm/yarn workspaces:包互相链接(无需 publish)
- app 里 import 'ui-lib' → 直接指向 packages/ui-lib/src
(dev 源码 or 构建产物,取决于配置)
- 改动库源码 → 应用 HMR 生效(无需重发布)
→ workspace = 本地「发布前」的联动开发
开发 vs 消费的切换:
- 开发模式:应用直接引用库源码(HMR 联动)
- 发布模式:库构建后消费(验证产物)
- 工具:tsup/vite dev + workspace 源码引用
- 注意:构建产物模式(防 dev 引源码差异)
→ 切换 = dev 引源码 / 发布引产物,防差异
Monorepo 的构建策略:
- 按依赖顺序构建:先库后应用(拓扑)
- 增量构建:只构建变更的包
- 工具:turborepo/nx(任务编排)
- CI:全量 vs 变更包测试
→ 构建 = 拓扑顺序 + 增量 + 编排工具
Monorepo 的陷阱:
- 版本耦合:多包一起发(需 changesets)
- 依赖提升问题(hoisting 冲突)
- 构建顺序错误(应用先于库构建)
- 源码/产物混用(dev 引 src、发布引 dist 不一致)
→ 陷阱 = 版本/依赖/顺序/模式四查
心智:Monorepo + 组件库 = 库与消费应用同仓联动开发(packages/ui-lib + app-admin);价值:改库立刻应用可见、统一依赖、原子提交、共享工具;workspaces(package.json 或 pnpm-workspace.yaml)本地链接无需 publish;切换 dev 引源码(HMR 联动)/发布引产物(验证),防源码产物混用;构建按拓扑顺序 + turborepo/nx 编排 + 增量;陷阱:版本耦合(changesets)、hoisting、构建顺序、src/dist 混用。
9. 组件库的调试与文档
调试环境(Storybook):
- Storybook:组件开发环境(独立渲染每个组件)
- 看:状态/主题/交互(各 props 组合)
- 交互测试:Storybook play 功能
- Vite 集成:storybook-vite 支持 Vite 构建
→ Storybook = 组件库的「可视化开发台」
组件文档(文档站):
- 文档内容:用法/API 表格(props/events/slots)/示例/FAQ
- 自动生成:Storybook docs / 注释抽取
- MDX:文档 + 组件混排(示例可运行)
- 站点:Storybook / VitePress / Docusaurus
→ 文档 = 用法 + API + 示例 + 可运行
组件测试:
- 单元:组件渲染/交互(Vitest + React Testing Library)
- 快照:结构变化检测
- 视觉回归:截图对比(chromatic/playwright)
- 无障碍:a11y 检查
→ 测试 = 单元 + 快照 + 视觉 + a11y
组件的开发工作流:
1. Storybook 开发(看组件状态)
2. 单元测试(功能正确)
3. 文档更新(API/示例)
4. 视觉回归(防样式破坏)
5. 构建 + 验证(消费样例)
→ 流程 = 开发 → 测试 → 文档 → 回归 → 构建
开发体验的完善:
- 示例应用:playground(真实使用场景)
- lint + 类型检查(质量门禁)
- 组件命名/API 规范(一致性)
- 无障碍规范(键盘/ARIA)
→ 体验 = 示例 + 门禁 + 规范 + a11y
心智:组件库开发环境 = Storybook(可视化开发台,各 props 状态 + 交互测试,storybook-vite 集成)+ 文档站(用法/API 表格/MDX 可运行示例,Storybook/VitePress)+ 测试(Vitest 单元 + React Testing Library + 快照 + 视觉回归 chromatic + a11y 检查);工作流 = Storybook 开发 → 单元测试 → 文档 → 视觉回归 → 构建验证;完善 = playground 示例 + lint/类型门禁 + 命名 API 规范 + 无障碍规范。
10. 速查表与一句话记忆
全篇速查:
| 主题 | 结论 |
|---|---|
| 为什么建库 | 复用/一致性/独立版本/专注 |
| lib 模式 | entry/formats(es+cjs)/external |
| 样式 | CSS Modules/CSS-in-JS/变量主题 |
| dts | vite-plugin-dts + exports types |
| 按需 | ESM 摇树 + 子路径导出 |
| 发布 | 构建→校验→pack→publish |
| 版本 | SemVer + Conventional 日志 |
| Monorepo | workspaces 联动开发 |
| 调试 | Storybook + 测试 + 文档 |
一句话记忆:用 Vite 开发组件库 = 把组件「资产化」为可复用、可独立版本、可多应用消费的包,核心四关:产物(lib 模式 build.lib + formats es/cjs + external 外置 peer 依赖防双份 React)、按需(ESM 摇树 + sideEffects 只列 CSS + exports 子路径 ‘ui-lib/button’ 路径级按需)、样式(CSS Modules 编译期隔离 / CSS-in-JS 运行时主题 / CSS 变量主题切换,命名前缀防全局污染,CSS 声明 sideEffects 防误删)、版本(SemVer 兼容性承诺 + Conventional Commits + changesets 自动日志,破坏性变更判定 = 消费者是否需改动才能用);类型契约用 vite-plugin-dts 生成(exports 每入口配 types);发布流程 = 构建 → 校验产物 → files:[“dist”] 白名单 → npm pack 预览 → publish(陷阱五查:没构建/files 不配/exports 路径错/版本未提交/peer 缺失);Monorepo 用 workspaces 本地联动开发(dev 引源码 HMR、发布引产物验证,防 src/dist 混用)+ changesets 管版本 + turborepo 按拓扑构建;调试 = Storybook 可视化开发台 + Vitest/RTL 单元 + 视觉回归 + 文档站(MDX 可运行示例);组件库原则:通用组件进库、业务组件留应用、依赖最小化、精而不滥。
延伸阅读
- /vite-monorepo-architecture/ — Monorepo 架构与实践
- /vite-build-optimization/ — 构建配置与产物优化
- /vite-tree-shaking-deep-dive/ — Tree-shaking 与按需加载
- /vite-vitest-testing/ — Vitest 测试
- 前端工程专题 — 前端工程化与组件生态
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。