按环境切换构建配置与暗黑模式修复
概述
打包优化真正落地时,最先值得修的往往不是构建配置,而是生产环境下才暴露的样式硬编码问题。本节先修复暗黑模式下的背景硬编码,再把 vite.config.ts 改为函数式配置以拿到 mode,按开发/生产切换 ElementPlusResolver、按环境变量开关 visualizer,并用 cross-env 保证跨平台可用,最终把构建配置拆成“开发体验 / 生产构建 / 临时分析”三层管理。
学习目标
- 能识别并修复生产环境才暴露的样式硬编码(如写死的
bg-white),改用主题 CSS 变量。 - 掌握
vite.config.ts函数式配置写法,从参数读取mode做环境分支。 - 理解
ElementPlusResolver只适合开发环境,生产 external 后应关闭它。 - 区分
mode与进程环境变量:临时分析开关更适合走ANALYZE=true。 - 会用
cross-env统一跨平台环境变量写法,建立配置分层意识。
一、生产环境才暴露的样式硬编码
这一节第一件事不是改 Vite 配置,而是修了一个典型生产问题:暗黑模式下中间内容区域没有跟着变暗。最后定位到组件里把背景写死成了 bg-white。
这类问题在开发时容易被忽略,因为局部看没问题,但一旦主题切换、生产构建、全局样式叠加,硬编码颜色就会把主题链路截断。修复方式是走 CSS 变量,而不是直接写死颜色。
<template>
<main class="bg-[var(--el-bg-color)]">
<router-view />
</main>
</template>构建优化不只研究 bundle,也包括把生产环境里暴露出来的样式细节修干净。
二、vite.config.ts 改为函数式配置拿 mode
想要知道当前是不是生产模式,最直接的方法是把 vite.config.ts 改成函数形式,从参数读取 mode。可先在终端打印验证:pnpm build-only 打印出 production,pnpm dev 打印出 development。
import { defineConfig } from "vite"
export default defineConfig(({ mode }) => {
const isProd = mode === "production"
return {
// ...
}
})有了 mode,后面所有“开发环境需要、生产环境不需要”的配置才能自然分支出去,这是 Vite 配置进入工程化条件控制的标准入口。
三、ElementPlusResolver 只在开发环境启用
一个核心问题是:明明已经做了 CDN external,element-plus 为什么还影响产物体积?结论是生产环境不需要再开 ElementPlusResolver,因为它会自动解析组件并继续把相关依赖拉回构建链,与“已 external 到 CDN”的目标冲突。
所以策略是:开发环境保留 resolver 提升体验,生产环境关闭 resolver 避免 bundle 被重新拉大。
Components({
resolvers: isProd ? [] : [ElementPlusResolver()],
})external 不是一处配置就能结束,它还要和解析器配置联动。
四、mode 控模式,env 控附加行为
课程区分了两类配置条件:
- 开发 / 生产固有差异(如 resolver 是否启用),适合用
mode判断; - 某次构建临时想不想分析 bundle(如
visualizer是否自动弹页),不适合写进mode,更适合走环境变量ANALYZE=true。
const isAnalyze = process.env.ANALYZE === "true"这形成了清晰的配置分层:mode 控模式,env 控附加行为。并不是所有条件都该绑到 mode 上,临时开关型行为更适合走环境变量。
五、cross-env 统一跨平台环境变量
直接在 package.json 里写 ANALYZE=true pnpm build-only,在 macOS / Linux 和 Windows 上写法不完全一样,跨平台可能出问题。标准解法是用 cross-env 统一环境变量写法。
{
"scripts": {
"analyze": "cross-env ANALYZE=true pnpm build-only"
}
}只要脚本涉及环境变量,跨平台团队就值得优先考虑 cross-env,它解决的是真实的协作问题。
六、构建配置按目的拆层
把 visualizer 从“默认总是打开”改成“只在分析脚本打开”后,项目有了两条明确构建路径:日常 build-only 安静出产物,分析 analyze 才弹 treemap。
这一节的本质不是多学几个插件,而是学会把构建配置按“目的”拆层:开发体验型(ElementPlusResolver)、生产构建型(CDN external、resolver 关闭)、临时分析型(visualizer、ANALYZE=true)。配置文件越复杂,越需要按目标分层,才不会互相打架。
const isProd = mode === "production"
const isAnalyze = process.env.ANALYZE === "true"七、把三层配置合流:函数式 vite.config.ts 全貌
前面每节都在单独讲一个开关,落到真实项目里要把它们收进同一个函数式配置。关键是插件数组里用逻辑表达式做条件项,再用 .filter(Boolean) 把假值项剔掉,避免 plugins 里混入 false 导致构建报错。
import { defineConfig } from "vite"
import { visualizer } from "rollup-plugin-visualizer"
import Components from "unplugin-vue-components/vite"
import { ElementPlusResolver } from "unplugin-vue-components/resolvers"
export default defineConfig(({ mode }) => {
const isProd = mode === "production"
const isAnalyze = process.env.ANALYZE === "true"
return {
plugins: [
Components({
resolvers: isProd ? [] : [ElementPlusResolver()],
}),
isAnalyze && visualizer({ open: true }),
].filter(Boolean),
}
})使用 cross-env 前记得先装到开发依赖:pnpm add -D cross-env。装好之后,analyze 脚本才能在 Windows 上与 macOS / Linux 行为一致。配置越往后越复杂,越要靠这种“按目的分层 + 条件裁剪”的方式保持可读,而不是把所有逻辑平铺在一个大对象里。
常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 暗黑模式下局部内容还是白的 | 背景色写死成了 bg-white | 改成主题变量,如 bg-[var(--el-bg-color)] |
生产 external 了 element-plus 但包里还有它 | 生产构建里 ElementPlusResolver 还在自动引入组件 | 根据 mode 在生产环境关闭 resolver |
| 想分析体积但不想每次 build 都弹图 | visualizer 一直 open: true | 用 process.env.ANALYZE 单独控制分析模式 |
| Windows 上分析脚本跑不起来 | 环境变量写法与类 Unix 不同 | 使用 cross-env 统一脚本行为 |
为什么不直接把所有开关写进 .env | 像 ANALYZE 是一次性分析开关,不一定常驻 | 短期开关用脚本环境变量更直接 |
| 分析页开了但别的功能又坏了 | 改了太多配置没分层验证 | 先确认普通构建链路可用,再单独验证分析模式 |