import.meta 不能直接挂载环境变量,但可通过构建工具注入或运行时全局上下文实现租户感知,并结合动态导入加载租户专属模块。

在多租户场景中,import.meta 本身不能直接“挂载”环境变量,但它可作为运行时元信息的入口,配合构建工具(如 Vite、Rollup)或自定义注入机制,将租户上下文透传至模块内部,从而实现逻辑分发。关键不在于 import.meta 的能力,而在于如何让它承载租户标识,并让模块据此做条件判断。
利用构建时注入 + import.meta.env 实现租户感知
Vite 等现代构建工具会将 import.meta.env 编译为静态替换对象。你可在启动时通过环境变量(如 VITE_TENANT_ID=acme)注入租户标识:
- 在
.env.acme中写入VITE_TENANT_ID=acme,启动时执行vite --mode acme - 模块中直接读取:
if (import.meta.env.VITE_TENANT_ID === 'acme') { /* 加载 acme 专属组件 */ } - 注意:该方式适用于构建时确定租户的场景(如独立部署),不适用于单实例服务多租户动态切换
运行时动态挂载租户上下文到 import.meta
import.meta 是只读对象,无法直接赋值,但可通过全局代理或模块级初始化“模拟挂载”:
- 在应用入口(如
main.ts)中设置全局租户上下文:window.__TENANT__ = { id: 'acme', features: ['sso', 'branding'] }; - 在需要分发的模块中,通过
import.meta.env.SSR === false && window.__TENANT__读取(浏览器端);服务端需配合框架上下文(如 Express req 或 Nuxt useRequestEvent)传递 - 更稳妥做法是封装一个
useTenant()组合式函数,内部统一桥接window.__TENANT__或 SSR 上下文,避免模块直接耦合import.meta
结合动态导入实现租户专属模块加载
逻辑分发的本质是按租户加载不同实现,而非仅 if-else 分支:
- 约定模块路径结构:
src/tenants/${tenantId}/features/payment.ts - 使用动态
import()按需加载:const paymentModule = await import(`../tenants/${tenantId}/features/payment.ts`); - 为避免构建时报错(路径不可静态分析),可用
require.context(Webpack)或 Vite 的import.meta.glob预注册租户模块集合 - 示例:
const tenants = import.meta.glob('../tenants/*/features/payment.ts', { eager: true }); const mod = tenants[`../tenants/acme/features/payment.ts`];
避免常见陷阱
多租户逻辑分发容易误入歧途:
-
不要在模块顶层直接依赖 import.meta.env —— 它在 SSR 中为 undefined,应包裹在
if (import.meta.env.SSR) { ... } else { ... }或使用onMounted/useEffect延迟读取 - 租户 ID 不应硬编码在 import.meta 中 —— 它必须来自可信来源(登录态、子域名、请求头),否则存在越权风险
- 逻辑分发 ≠ 样式隔离 —— 租户主题、文案等建议用 CSS 变量 + JSON 配置驱动,与 JS 分发解耦

















