DEBUG.WIKI
晚安云;香港 CN2 ¥15/月
PanstarCloud:部署应用,接入 AI,云服务器与 AI 网关
野草云;香港 200Mbps 峰值;不限月流量 · BGP VPS;查看套餐 →

Node 能解析 ## 别名,Vite 却报 Missing "#" specifier

包内 imports 的名称含第二个井号时,Vite 可能把后半段当成 URL fragment。统一改为单井号命名时要同时调整映射与导入。

Node 直接执行可以解析包内 ##/ 别名,Vite 的 ssrLoadModule 或 SSR 构建却报 Missing "#" specifier。若 package.json 使用了第二个 #,先检查它是不是被 Vite 拆成 URL fragment,而不是立即补装一个叫 # 的包。

已核对的 Vite 8.3.4 正式子路径解析会先去掉第一个 #,再把剩下字符串按文件名和后缀拆开。名称若以 ##/ 开头,第二个 # 在这个阶段被当作 fragment 起点,实际拿去查 imports 的键只剩第一个 #。

包内名称与页面锚点经过了不同规则

Node 的包内 imports 必须以 # 开头;合法的第二个井号不自动表示浏览器页面锚点。下面是用于说明映射的示例:

{
  "type": "module",
  "imports": {
    "##/*": "./src/*"
  }
}

源码里的 import '##/foo.js' 原本要定位 src/foo.js。确认最近的 package.json、映射目标及文件真实存在,且 Node 与 Vite 比较的是同一份检出、相同条件和相同模块入口。不同条件导出、错误工作目录也可能让两边得到不同结果。

把包内别名统一成单井号名称

需要兼容当前 Vite 路径时,可以采用没有第二个井号的包内命名,例如把上述映射改为:

{
  "type": "module",
  "imports": {
    "#app/*": "./src/*"
  }
}

并同步修改对应导入:

import '#app/foo.js';

这是同一个目标文件的新名称,#app 仅作示例,应先确认项目没有占用这个别名。保存原清单和代码,在可审查的改动中更新全部包内引用、测试入口以及生成代码的模板。不要只改 package.json 而保留旧 import,也不要批量替换页面 URL 的 hash、CSS 选择器或字符串数据。

如果 alias 是一个包对外约定的部分,先检查所有包内消费者和构建入口;不便统一改名时,可以仅对受影响的本地调用改用准确相对导入,但仍需覆盖其实际调用范围。给 Vite 新增一个同名 resolve.alias 会引入第二套映射规则,不宜在没有核对 Node 与测试运行器的情况下叠加。

重新启动开发服务,以原 SSR 入口验证,再检查生产 SSR 构建。除了“不报错”,还要确认被导入模块的导出与副作用来自预期文件,正常单井号别名仍可解析。

已核对的 8.3.4 仍有上述拆分顺序,不能把关闭的问题或未发布代码当作现有修复。后续正式版本修复后,是否恢复旧命名应按项目维护成本决定;回退要同时恢复清单与全部引用,避免两种名称只有一半被支持。