1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CommonJS と ES Moduleの違いを整理しました

1
Posted at

CommonJS と ES Module は、どちらも ファイルを分割して、他のファイルから使えるようにする仕組みです。

Node.js 公式ドキュメントでも、Node.js には CommonJS modulesECMAScript modules の2つのモジュールシステムがあると説明されています。(Node.js)


ざっくり違い

比較 CommonJS ES Module
主な構文 require, module.exports import, export
略称 CJS ESM
生まれ Node.js 独自系 JavaScript 標準
読み込み 基本的に同期的 静的解析しやすい
ブラウザ対応 そのままでは不可 標準対応
現代の推奨 既存Node.jsで多い 新規開発ではおすすめ
TypeScriptとの相性 使える 現代構成では使いやすい

TypeScript 公式ドキュメントでも、現在重要なモジュールシステムとして ECMAScript modules / ESMCommonJS / CJS が説明されています。(TypeScript)


CommonJS の書き方

CommonJS は、昔から Node.js でよく使われてきた形式です。

export 側

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

module.exports = {
  add,
};

import 側

// app.js
const { add } = require("./math");

console.log(add(1, 2));

CommonJS では、読み込むときに require() を使います。

const { add } = require("./math");

外に公開するときは module.exports を使います。

module.exports = {
  add,
};

ES Module の書き方

ES Module は、JavaScript 標準のモジュール形式です。

export 側

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

import 側

// app.js
import { add } from "./math.js";

console.log(add(1, 2));

ES Module では、読み込むときに import を使います。

import { add } from "./math.js";

外に公開するときは export を使います。

export function add(a, b) {
  return a + b;
}

一番大きな違い

一番大きな違いは、CommonJS は Node.js 独自寄り、ES Module は JavaScript 標準という点です。

CommonJS
  Node.js で昔から使われてきた方式

ES Module
  JavaScript 標準の方式
  ブラウザでも Node.js でも使える

そのため、現代のフロントエンドや新規 TypeScript プロジェクトでは、基本的に ES Module がよく使われます。


default export の違い

ES Module では、default export がよく使われます。

// logger.js
export default function logger(message) {
  console.log(message);
}
// app.js
import logger from "./logger.js";

logger("hello");

CommonJS では近い形として、こう書けます。

// logger.js
module.exports = function logger(message) {
  console.log(message);
};
// app.js
const logger = require("./logger");

logger("hello");

ただし、CommonJS と ES Module を混ぜると、この default の扱いで混乱しやすいです。


named export の違い

ES Module の named export はこうです。

// user.js
export const name = "Taro";

export function getName() {
  return name;
}
// app.js
import { name, getName } from "./user.js";

CommonJS ではこうです。

// user.js
const name = "Taro";

function getName() {
  return name;
}

module.exports = {
  name,
  getName,
};
// app.js
const { name, getName } = require("./user");

見た目は似ていますが、内部の仕組みは別物です。


Node.js で ES Module を使う条件

Node.js で .js を ES Module として扱うには、よくある方法は package.json にこれを書くことです。

{
  "type": "module"
}

この場合、.js ファイルで import / export が使えます。

import { add } from "./math.js";

逆に "type": "module" がない通常の Node.js プロジェクトでは、.js は CommonJS として扱われることが多いです。

const { add } = require("./math");

Node.js 公式ドキュメントでも、ES Module は .mjs、または package.json"type": "module" などによって有効化されると説明されています。(Node.js)


拡張子の注意

ES Module では、Node.js で相対 import するときに拡張子を書くのが基本です。

import { add } from "./math.js";

CommonJS では省略されることが多いです。

const { add } = require("./math");

TypeScript で Node.js 向け ESM を書く場合も、ソースは .ts でも import は .js にすることがあります。

// src/index.ts
import { add } from "./math.js";

なぜなら、実行時には dist/math.js を読むからです。


TypeScript ではどうなる?

TypeScript では、書いたコードをどの形式に変換するかを tsconfig.json で決めます。

CommonJS に出力する例です。

{
  "compilerOptions": {
    "module": "CommonJS"
  }
}

ES Module に近い Node.js 向け構成です。

{
  "compilerOptions": {
    "module": "NodeNext",
    "moduleResolution": "NodeNext"
  }
}

新規の Node.js + TypeScript なら、ES Module 構成では NodeNext を使うことが多いです。


実務での使い分け

新規開発なら ES Module 寄り

import express from "express";

export function createApp() {
  const app = express();
  return app;
}

React、Next.js、Vite、Vue、Nuxt、モダンな Node.js + TypeScript では、ES Module が自然です。


既存の Node.js プロジェクトなら CommonJS も多い

const express = require("express");

module.exports = function createApp() {
  const app = express();
  return app;
};

古い Express アプリ、古い npm パッケージ、既存の Node.js バッチなどでは CommonJS がまだ多いです。


よくあるエラー

Cannot use import statement outside a module

これは、Node.js がそのファイルを CommonJS として扱っているのに、import を書いたときによく出ます。

import express from "express";

対策例です。

{
  "type": "module"
}

または .mjs を使います。

app.mjs

ERR_REQUIRE_ESM

これは、CommonJS の require() で ES Module 専用パッケージを読み込もうとしたときによく出ます。

const somePackage = require("some-esm-only-package");

対策は、呼び出し側も ES Module に寄せることです。

import somePackage from "some-esm-only-package";

まとめ

実務的には、こう覚えるとよいです。

CommonJS
  require / module.exports
  Node.js で昔から使われてきた
  既存プロジェクトで多い

ES Module
  import / export
  JavaScript 標準
  ブラウザ・Node.js・TypeScriptで使いやすい
  新規開発ではこちらがおすすめ

新しく Node.js + TypeScript backend を作るなら、基本は ES Module でよいです。

{
  "type": "module"
}
{
  "compilerOptions": {
    "module": "NodeNext",
    "moduleResolution": "NodeNext"
  }
}

既存の CommonJS プロジェクトでは、無理に全部変えるより、依存パッケージやビルド環境を確認しながら段階的に ES Module に寄せるのが安全です。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?