DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
晚安云;香港 CN2 ¥15/月
雨云;给项目一台云服务器

Vite 在 Windows 把同一文件打包两次,单例状态不共享

Vite 8.2.1 的 development 模式构建中,tsconfig paths 直达文件与目录转导可产生斜杠不同的模块 ID。显式绝对路径别名可绕开该分流,仍需核对真实产物。

单例明明已经注册了数据,另一处导入却读到空集合;生成文件里同一段模块代码还出现两次。如果只在 Windows、Vite 的 development 模式构建中发生,检查模块 ID 是否同时含有正斜杠和反斜杠。

这一具体情况出现在 Vite 8.2.1、Windows 11,通过 build API 设置 mode: 'development',使用 tsconfig paths 而没有显式别名。同一环境的 production 构建没有表现出同样问题,不能扩大为所有 Windows 构建都会重复。

两条导入路径变成两个身份

比如配置将 @/* 指向 src,同一份文件既经目录入口转导,也被直接导入:

import { ErrorCode } from '@/enums';
import { ErrorCode as DirectErrorCode } from '@/enums/config.enums';

若两条路径最终分别留下 C:/project/src/enums/config.enums.ts 和 C:\project\src\enums\config.enums.ts,打包器可能按不同字符串建立两个模块。常量对象看起来值相同,但模块级注册表、缓存或实例就不再共享。

先从实际产物的模块信息及业务初始化位置核对,不只统计相同文本。某些代码本来就可能有意重复生成;需要确认两份 ID 指向同一物理文件,并且不同调用方确实连到了不同状态。初始化时序、循环依赖和真正装了两份包,也要分别排除。

用绝对路径别名统一这一前缀

应用确实将 @ 约定为当前配置旁的 src 时,可以在已有配置中合并 resolve.alias:

import { fileURLToPath, URL } from 'node:url';
import { defineConfig } from 'vite';

export default defineConfig({
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url)),
    },
  },
});

别名值需要是绝对文件系统路径;不要直接填字符串 './src',期待它自动按配置文件所在目录解析。monorepo、配置文件在其他目录或 @ 已有不同用途时,应按实际根目录调整,不覆盖已有规则。

这只让相应导入先走统一的别名路径,TypeScript 检查和其他工具仍可能需要原来的 paths 配置。两边的指向要一致,不能修好 Vite 后让编辑器解析到另一份源码。

验收的是同一份状态

保留原 development 构建入口和两种导入形式,检查同一文件只形成一个模块身份,并验证从一路写入的状态能由另一路读到。再单独检查原 production 构建,避免别名改变包入口或条件解析。

选择后续 Vite 版本时,继续保留这组双路径验证,不用版本号大小代替产物确认。也不要给单例加一个全局变量来掩盖双实例,那可能把原本隔离的窗口、进程或请求状态混在一起。