{T}

按环境切换构建配置与暗黑模式修复

概述

打包优化真正落地时,最先值得修的往往不是构建配置,而是生产环境下才暴露的样式硬编码问题。本节先修复暗黑模式下的背景硬编码,再把 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 变量,而不是直接写死颜色。

Vue SFC
<template>
  <main class="bg-[var(--el-bg-color)]">
    <router-view />
  </main>
</template>

构建优化不只研究 bundle,也包括把生产环境里暴露出来的样式细节修干净。

二、vite.config.ts 改为函数式配置拿 mode

想要知道当前是不是生产模式,最直接的方法是把 vite.config.ts 改成函数形式,从参数读取 mode。可先在终端打印验证:pnpm build-only 打印出 productionpnpm dev 打印出 development

ts
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 被重新拉大。

ts
Components({
  resolvers: isProd ? [] : [ElementPlusResolver()],
})

external 不是一处配置就能结束,它还要和解析器配置联动。

四、mode 控模式,env 控附加行为

课程区分了两类配置条件:

  • 开发 / 生产固有差异(如 resolver 是否启用),适合用 mode 判断;
  • 某次构建临时想不想分析 bundle(如 visualizer 是否自动弹页),不适合写进 mode,更适合走环境变量 ANALYZE=true
ts
const isAnalyze = process.env.ANALYZE === "true"

这形成了清晰的配置分层:mode 控模式,env 控附加行为。并不是所有条件都该绑到 mode 上,临时开关型行为更适合走环境变量。

五、cross-env 统一跨平台环境变量

直接在 package.json 里写 ANALYZE=true pnpm build-only,在 macOS / Linux 和 Windows 上写法不完全一样,跨平台可能出问题。标准解法是用 cross-env 统一环境变量写法。

json
{
  "scripts": {
    "analyze": "cross-env ANALYZE=true pnpm build-only"
  }
}

只要脚本涉及环境变量,跨平台团队就值得优先考虑 cross-env,它解决的是真实的协作问题。

六、构建配置按目的拆层

visualizer 从“默认总是打开”改成“只在分析脚本打开”后,项目有了两条明确构建路径:日常 build-only 安静出产物,分析 analyze 才弹 treemap。

这一节的本质不是多学几个插件,而是学会把构建配置按“目的”拆层:开发体验型(ElementPlusResolver)、生产构建型(CDN external、resolver 关闭)、临时分析型(visualizerANALYZE=true)。配置文件越复杂,越需要按目标分层,才不会互相打架。

ts
const isProd = mode === "production"
const isAnalyze = process.env.ANALYZE === "true"

七、把三层配置合流:函数式 vite.config.ts 全貌

前面每节都在单独讲一个开关,落到真实项目里要把它们收进同一个函数式配置。关键是插件数组里用逻辑表达式做条件项,再用 .filter(Boolean) 把假值项剔掉,避免 plugins 里混入 false 导致构建报错。

ts
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: trueprocess.env.ANALYZE 单独控制分析模式
Windows 上分析脚本跑不起来环境变量写法与类 Unix 不同使用 cross-env 统一脚本行为
为什么不直接把所有开关写进 .envANALYZE 是一次性分析开关,不一定常驻短期开关用脚本环境变量更直接
分析页开了但别的功能又坏了改了太多配置没分层验证先确认普通构建链路可用,再单独验证分析模式

延伸阅读