Posts [Express] ERR_REQUIRE_ESM 오류 해결하기
Post
Cancel

[Express] ERR_REQUIRE_ESM 오류 해결하기

개발 환경

  • Express: 4.21.0
  • TypeScript: 4.9.5
  • ts-node: 10.9.2

문제 상황

GitHub Repository 에 이슈를 생성하기 위해 octokit 라이브러리를 사용하고 있었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { Octokit } from "octokit";

import env from "@modules/env";

const octokit = new Octokit({
  auth: env.githubConfig.auth,
});

const OWNER = env.githubConfig.owner;
const REPO = env.githubConfig.repo;
const github = async () => {
  try {
    const response = await octokit.request(
      `POST /repos/${OWNER}/${REPO}/issues`,
      {
        owner: "OWNER",
        repo: "REPO",
        title: "title",
        body: "body",
        headers: {
          "X-GitHub-Api-Version": "2022-11-28",
        },
      }
    );
  } catch (error) {
    console.error(error);
  }
};

이슈 생성자를 내 계정이 아닌 GitHub App(bot) 으로 변경하기 위해 @octokit/auth-app@octokit/rest 으로 라이브러리로 변경하면서 아래와 같이 코드를 변경했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { Octokit } from "@octokit/rest";
import { createAppAuth } from "@octokit/auth-app";

import env from "@modules/env";

const octokit = new Octokit({
  authStrategy: createAppAuth,
  auth: {
    appId: env.githubConfig.appId,
    privateKey: env.githubConfig.privateKey,
    installationId: env.githubConfig.installationId,
  },
});

const github = async () => {
  const { owner, repo } = env.githubConfig;

  try {
    const response = await octokit.issues.create({
      owner,
      repo,
      title: "title",
      body: "body",
    });
  } catch (error) {
    console.error(error);
  }
};

라이브러리를 변경하고 나서 서버를 실행하니 아래와 같은 오류가 발생했다.

1
Error [ERR_REQUIRE_ESM]: require() of ES Module ...

원인 파악

ERR_REQUIRE_ESM 오류는 commonJS 환경에서 require() 함수로 ESM(ECMAScript Modules) 을 불러올 때 때 발생한다.

commonJS 와 ESM 의 차이를 간단하게 살펴보면 아래와 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 1. commonJS

// math.js
function add(a, b) {
  return a + b;
}

module.exports = { add };

// main.js
const math = require("./math"); // CommonJS 방식으로 모듈을 불러옴
console.log(math.add(2, 3)); // 출력: 5

// 2. ESM

// math.mjs
export function add(a, b) {
  return a + b;
}

// main.mjs
import { add } from "./math.mjs"; // ESM 방식으로 모듈을 불러옴
console.log(add(2, 3)); // 출력: 5

프로젝트의 tsconfig.json 에는 아래와 같이 설정되어있었다.

1
2
3
4
5
6
{
  "compilerOptions": {
    "module": "commonjs",
  },
  // ... 이하 생략
}

해결 방법

ts-node 대신 tsx 사용하기

TypeScript 를 컴파일 하기 위해 사용했던 ts-node 대신 tsx 로 변경했다.

1
2
3
4
# package.json

"deploy": "pm2 start --interpreter tsx build/app.js",
"start": "nodemon --exec tsx ./src/app.ts"

tsconfig.jsoncompilerOptions.module 값을 module 로 변경해보기도 했지만, 여러 설정을 한 번에 바꾸다보니 문제 해결이 쉽게 되지 않았다.

소스 코드를 내가 작성한 게 아니라 다른 분께서 작성한 걸 넘겨 받아서 유지보수만 하고 있었던 상황이었기에 최대한 코드를 수정하지 않고 싶었다.

ts-node 대신 tsx 를 사용하면 깔끔하게 문제가 해결된다는 글을 읽고 적용해보았고, 다행히 문제가 금방 해결되었다.

@PrimaryColumn 데이터 타입 추가

tsx 로 변경하고 나서 다른 오류가 발생했다.

ColumnTypeUndefinedError: Column type for EvaluationQuestionMapEntity#e_key is not defined and cannot be guessed. Make sure you have turned on an “emitDecoratorMetadata”: true option in tsconfig.json. Also make sure you have imported “reflect-metadata” on top of the main entry file in your application (before any entity imported).If you are using JavaScript instead of TypeScript you must explicitly provide a column type.

TypeORM 을 사용하고 있었는데, 엔티티와 관련해서 오류가 발생하고 있었다.

1
2
3
4
5
@Entity("events")
export class Events {
  @PrimaryColumn()
  id: number;
}

문제는 @PrimaryColumn 어노테이션에 데이터 타입을 명시하지 않아서 발생하는 문제였다.

어노테이션의 매개변수로 데이터 타입을 입력하면 문제가 해결된다.

1
2
3
4
5
@Entity("events")
export class Events {
  @PrimaryColumn("int")
  id: number;
}

참고자료

This post is licensed under CC BY 4.0 by the author.