基于环境变量在Vite中动态导入LESS主题的实现问题
基于环境变量在Vite中动态导入LESS主题的实现问题
我之前维护多主题Vite项目时也碰到过一模一样的需求,折腾了几次总算摸透了可行的解决办法,给你分享三个不同场景下的方案,按需选就行:
方案一:条件判断静态导入(适合项目数量少的场景)
这是最省心的办法,因为Vite构建时会静态分析所有可能的导入路径,直接按环境变量做分支判断就行:
// 在项目入口文件(比如main.js/ts)里添加 const currentSite = import.meta.env.VITE_APP_SITE_NAME; // 匹配对应环境的主题文件 if (currentSite === 'project1') { import('./styles/themes/project1.less'); } else if (currentSite === 'project2') { import('./styles/themes/project2.less'); } else if (currentSite === 'project3') { import('./styles/themes/project3.less'); } else { // 兜底加载默认主题,避免无匹配时样式错乱 import('./styles/themes/default.less'); }
这个方案优势就是简单直接,Vite会把所有主题文件都打包,但运行时只会加载对应环境的那一个。如果你的项目数量不多,这个绝对是首选。
方案二:glob批量导入(适合项目较多的场景)
要是维护的项目多,写一堆if-else太麻烦,可以用Vite自带的import.meta.glob批量导入所有主题文件,再按环境变量匹配:
// 同样在main.js/ts中 const currentSite = import.meta.env.VITE_APP_SITE_NAME; // 匹配themes目录下所有.less文件,返回的对象键是文件路径、值为导入函数 const allThemes = import.meta.glob('./styles/themes/*.less'); // 拼接当前站点对应的主题路径 const targetThemePath = `./styles/themes/${currentSite}.less`; // 检查对应主题是否存在,存在则加载,否则用默认 if (allThemes[targetThemePath]) { allThemes[targetThemePath](); } else { allThemes['./styles/themes/default.less'](); }
这里要注意glob的匹配规则,必须和你实际的主题文件目录完全对应。Vite会在构建时预解析所有匹配到的主题文件,运行时再动态加载对应项,既不用写一堆判断,也能保证打包灵活性。
方案三:Vite配置全局注入(适合全局主题变量场景)
如果你的主题变量是全项目通用的(所有组件都会用到),可以直接在Vite配置里根据环境变量注入主题文件,连入口文件的导入都省了:
// vite.config.js/ts import { defineConfig, loadEnv } from 'vite'; import path from 'path'; import fs from 'fs'; export default defineConfig(({ mode }) => { // 加载当前环境的变量 const env = loadEnv(mode, process.cwd()); const currentSite = env.VITE_APP_SITE_NAME; // 用绝对路径拼接主题文件,避免路径歧义 let themePath = path.resolve(__dirname, `src/styles/themes/${currentSite}.less`); // 检查文件是否存在,不存在则 fallback 到默认主题 if (!fs.existsSync(themePath)) { themePath = path.resolve(__dirname, 'src/styles/themes/default.less'); } return { css: { preprocessorOptions: { less: { // 把主题文件全局注入到所有LESS文件中 additionalData: `@import "${themePath}";`, javascriptEnabled: true, // 如果主题里用到了JS表达式就开这个 }, }, }, }; });
这个方案的好处是主题变量全局可用,任何组件的LESS代码里都能直接用,不用每次手动导入。不过要注意,这是构建时静态注入的,所以环境变量必须在构建前就配置好。
几个容易踩的坑:
- 环境变量必须以
VITE_开头,Vite默认只暴露这类变量给客户端,不然拿不到VITE_APP_SITE_NAME。 - 动态导入别用完全动态的路径(比如
import(./${currentSite}.less)),Vite静态分析识别不了,会打包报错,要么用条件判断,要么用glob。 - 用TypeScript的话,
import.meta.glob可能有类型提示问题,简单场景加个// @ts-ignore忽略就行,复杂场景可以自己写类型声明。
你可以先试试第一个方案,最容易上手,项目多的话再换第二个或第三个。要是还有问题,看看Vite控制台的报错,大概率是路径写错或者环境变量没配置对。
备注:内容来源于stack exchange,提问作者Lee Ren Jie
相关产品推荐
相关产品推荐

