🧀

Next.jsでのES6とCommonJSの互換性問題

に公開

Next.jsで開発を進める際に、ES6モジュールとCommonJSモジュールの互換性問題に直面することがあります。この問題が発生すると、コードが正しく動作せず、エラーが発生することがあります。この記事では、その原因と解決方法を分かりやすく解説します。

原因

JavaScriptには主に2つのモジュールシステムがあります。

  1. ES6モジュール
    importexportを使用
  2. CommonJSモジュール
    requiremodule.exportsを使用

想像してください。あなたの家には2台のテレビがあります。1台は新しいスマートテレビ(ES6モジュール)で、もう1台は古いテレビ(CommonJSモジュール)です。スマートテレビは専用のリモコン(import/export)で操作しますが、古いテレビは汎用リモコン(require/module.exports)で操作します。

もし、スマートテレビの専用リモコンを古いテレビで使おうとすると、テレビが反応しないので「このリモコンは使えません」と言われます。同様に、ES6モジュールをCommonJSモジュールとしてインポートしようとすると、エラーが発生します。

問題の例

例えば、CommonJSモジュールをES6モジュールとしてインポートしようとすると、以下のようなエラーが発生します。

import someCommonJsModule from 'some-common-js-module';

// エラー:
// SyntaxError: The requested module 'some-common-js-module' does not provide an export named 'default'

これは、専用リモコン(import)を古いテレビ(CommonJSモジュール)で使おうとしたときに起きる問題と同じです。

解決方法

この互換性問題を解決するための3つの方法を紹介します。

1. esModuleInteropを有効にする

専用リモコンを汎用リモコンとして使えるようにする方法です。tsconfig.jsonファイルでesModuleInteropを有効にすることで、CommonJSモジュールをES6モジュールのようにインポートできます。

tsconfig.json
{
  "compilerOptions": {
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true
  }
}

これにより、次のようにインポートすることができます。

import someCommonJsModule from 'some-common-js-module';

2. requireを使用する

汎用リモコンをそのまま使う方法です。TypeScriptファイル内で直接requireを使用してCommonJSモジュールをインポートします。

const someCommonJsModule = require('some-common-js-module');

3. next.config.jsでトランスパイルを設定する

古いテレビをスマートテレビのリモコンでも操作できるようにする方法です。Next.jsの設定ファイルnext.config.jsで特定のパッケージをトランスパイルするように設定します。
(私はこの方法で解決しました。)

  1. next-transpile-modulesパッケージをインストール
npm install next-transpile-modules
  1. next.config.jsを以下のように設定
next.config.js
const withTM = require('next-transpile-modules')(['some-common-js-module']);

module.exports = withTM({
  // 他のNext.jsの設定
});

まとめ

Next.jsでES6モジュールとCommonJSモジュールの互換性問題を解決するには、以下の3つの方法があります。

  1. tsconfig.jsonesModuleInteropを有効にする
  2. TypeScriptファイル内でrequireを使用する
  3. next.config.jsでトランスパイルを設定する

誤った情報があれば、コメントでご指摘いただけるとありがたいです。

Discussion