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

使用基础导入时TypeScript提示「无法找到模块」的原因排查

问题

搭建基于TypeScript的Apollo GraphQL项目时,编译正常但运行时出现导入错误:

Cannot find module '/Users/czbaker/Projects/express-apollo-ts/dist/gql/resolvers' imported from /Users/czbaker/Projects/express-apollo-ts/dist/main.js

项目相关文件如下:

src/main.ts

import express, { Express, Request, Response } from 'express';
import { ApolloServer } from '@apollo/server';
import { expressMiddleware } from '@apollo/server/express4';
import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer';
import http, { Server } from 'http';
import path from 'path';
import dotenv from 'dotenv';

// GQL
import { resolvers } from './gql/resolvers';
import { typeDefs } from './gql/typeDefs';

// 注意:此处代码缺少app和httpServer的定义,需补充
// const app: Express = express();
// const httpServer: Server = http.createServer(app);

// Load config
const envpath: string = path.resolve(process.cwd(), '.env');
dotenv.config({
    path: envpath,
    debug: true
});

// Create Apollo Server
const server = new ApolloServer({ 
    resolvers, 
    typeDefs,
    plugins: [ApolloServerPluginDrainHttpServer({ httpServer })]
});
await server.start();

// Use Middleware
app.use(expressMiddleware(server));

// Launch Server
await new Promise<void>((resolve) => httpServer.listen({ port: process.env.SERVER_PORT }, resolve));
console.log(`Server available at http://localhost:${process.env.SERVER_PORT}/`);

src/gql/resolvers.ts

export const resolvers: any = {
    Query: {
        hello: () => "World!"
    }
}

src/gql/typeDefs.ts

export const typeDefs = `#graphql
    type Query {
        hello: String;
    }
`

tsconfig.json

{
    "compilerOptions": {
      "rootDirs": ["src"],
      "outDir": "dist",
      "lib": ["es2020"],
      "target": "es2020",
      "module": "ES6",
      "moduleResolution": "node",
      "esModuleInterop": true,
      "types": ["node"],
    },
    "include": [
      "src/**/*"
    ],
    "exclude": [
      "node_modules"
    ]
  }

package.json

{
  "name": "express-apollo-ts",
  "version": "1.0.0",
  "description": "Apollo GraphQL server via Express/TypeScript/Mongoose w/ Subscription support",
  "main": "main.ts",
  "repository": "https://github.com/czbak3r/express-apollo-ts",
  "author": "Charles Baker",
  "license": "MIT",
  "type": "module",
  "devDependencies": {
    "@types/express": "^4.17.14",
    "@types/node": "^18.11.9",
    "nodemon": "^2.0.20",
    "typescript": "^4.9.3"
  },
  "dependencies": {
    "@apollo/server": "^4.2.1",
    "dotenv": "^16.0.3",
    "express": "^4.18.2",
    "graphql": "^16.6.0",
    "mongoose": "^6.7.3"
  },
  "scripts": {
    "dev": "concurrently \"tsc --watch\" \"nodemon -q dist/main.js\"",
    "build": "tsc",
    "start": "nodemon ./dist/main.js"
  }
}

编译后dist目录结构:

dist/
├── main.js
└── gql/
    ├── resolvers.js
    └── typeDefs.js

已尝试tsc监听模式和ts-node,结果一致,怀疑和ESM相关,但对ESM不熟悉。


解决方案

核心原因

项目在package.json中设置了"type": "module",Node.js会以**ESM(ECMAScript模块)**模式运行代码。ESM有严格要求:所有相对导入必须包含完整文件扩展名(如.js)。但当前TypeScript编译配置下,编译后的导入语句不会自动添加.js后缀,导致Node.js无法找到对应模块。

具体修复步骤

  1. 修改tsconfig.json配置
    将module和moduleResolution调整为适配ESM的模式,让TypeScript自动在编译后的代码中添加正确扩展名:

    {
        "compilerOptions": {
          "rootDirs": ["src"],
          "outDir": "dist",
          "lib": ["es2020"],
          "target": "es2020",
          "module": "NodeNext", // 替换原ES6
          "moduleResolution": "NodeNext", // 替换原node
          "esModuleInterop": true,
          "types": ["node"],
          "resolveJsonModule": true // 可选,若需导入json文件
        },
        "include": ["src/**/*"],
        "exclude": ["node_modules"]
      }
    
  2. 补充main.ts中缺失的变量定义
    代码中未定义app和httpServer,会导致运行时额外报错,需补充:

    const app: Express = express();
    const httpServer: Server = http.createServer(app);
    
  3. (可选)优化TypeScript导入写法
    使用NodeNext模块模式时,TypeScript允许在源码中用.ts后缀导入文件,编译时会自动替换为.js:

    // 原导入
    import { resolvers } from './gql/resolvers';
    // 可改为(NodeNext模式下两种写法都支持)
    import { resolvers } from './gql/resolvers.ts';
    

验证修复

重新执行npm run build,查看dist/main.js中的导入语句,会自动变为:

import { resolvers } from './gql/resolvers.js';
import { typeDefs } from './gql/typeDefs.js';

此时运行npm run start,导入错误即可解决。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 02:25:29