You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

纯ESM模式TS Node项目运行报MODULE_NOT_FOUND路径别名错误

纯ESM模式下TypeScript+Node.js路径别名失效修复方案

问题根因

报错核心是三类配置完全不适配原生ESM模块规范:

  • 现有依赖里的esm、module-alias、tsconfig-paths全部是基于CommonJS的模块劫持逻辑实现的,ESM模式下Node.js没有提供动态修改模块解析路径的CommonJS风格钩子,这三个包的别名解析逻辑完全不生效。
  • ts-node配置里的require字段仅在CommonJS模式下生效,ESM启动流程不存在require预加载阶段,写在该字段下的注册脚本根本不会执行。
  • 现有_moduleAliases配置全部指向编译后的build目录,开发环境直接跑ts源码时根本不存在该目录,就算别名逻辑生效也找不到对应文件。

分步修复操作

  • 清理无效依赖和冗余配置
    执行命令卸载不兼容的包:
    npm uninstall esm module-alias tsconfig-paths
    
    打开package.json,删除esm配置段、_moduleAliases配置段,删除start脚本里的-r esm -r module-alias/register参数;在package.json顶层添加"type": "module",这是Node.js识别项目为ESM模式的强制要求,也是top-level await能正常运行的前提。
    打开tsconfig.json,删除ts-node配置下的require数组。
  • 替换别名实现方案
    纯ESM模式下不需要第三方路径别名包,直接用Node.js原生支持的imports字段实现别名,兼容性最好。
    在package.json里添加imports配置,注意ESM别名强制要求以#开头:
    {
      "imports": {
        "#config/*": "./config/*",
        "#repos/*": "./src/repos/*",
        "#models/*": "./src/models/*",
        "#shared/*": "./src/shared/*",
        "#server": "./src/server.ts",
        "#services/*": "./src/services/*",
        "#routes/*": "./src/routes/*",
        "#graphql/*": "./src/graphql/*"
      }
    }
    
    同步修改tsconfig.json的编译配置,把模块相关配置改成NodeNext适配ESM规范,同时把paths配置和package.json的imports字段对齐:
    {
      "compilerOptions": {
        "target": "ES2022",
        "module": "NodeNext",
        "moduleResolution": "NodeNext",
        "strict": false,
        "baseUrl": "./",
        "allowSyntheticDefaultImports": true,
        "experimentalDecorators": true,
        "emitDecoratorMetadata": true,
        "paths": {
          "#config/*":   ["./config/*"],
          "#repos/*":    ["./src/repos/*"],
          "#models/*":   ["./src/models/*"],
          "#shared/*":   ["./src/shared/*"],
          "#server":     ["./src/server.ts"],
          "#services/*": ["./src/services/*"],
          "#routes/*":   ["./src/routes/*"],
          "#graphql/*":  ["./src/graphql/*"]
        },
        "useUnknownInCatchVariables": false
      },
      "include": ["src/**/*.ts", "spec/**/*.ts"],
      "exclude": ["src/public/", "node_modules"],
      "ts-node": {
        "esm": true,
        "experimentalSpecifierResolution": "node"
      }
    }
    
    全局替换项目源码里的import路径,把原来@开头的别名全部替换成#开头,比如import api from '@routes/api'改成import api from '#routes/api.js'。注意ESM模式下必须写全文件后缀,TS源码里导入本地文件统一写.js后缀,ts-node和TS编译器都能正常识别,编译后后缀也会自动对应。
  • 调整启动命令
    修改package.json里的nodemonConfig配置,把exec字段改成ESM模式的标准启动方式:
    {
      "nodemonConfig": {
        "watch": ["src"],
        "ext": "ts, html",
        "ignore": ["src/public"],
        "exec": "node --loader ts-node/esm ./src/index.ts"
      }
    }
    
    生产环境编译后,把package.json里imports字段的源码路径全部替换成build目录下的产物路径,比如./src/routes/*改成./build/routes/*,启动命令直接用node ./build/index.js --env=production即可,不需要加任何额外的预加载参数。

注意:如果用的是Node.js 18以下版本,需要升级到Node.js 18.13+,低版本对ESM的imports字段和ts-node ESM loader的兼容性存在已知问题。

内容的提问来源于stack exchange,提问作者Mustafak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 10:30:39