mjsファイルとは？ 🧐

:::note info | message
`.mjs` ファイルは、JavaScriptの**ECMAScript Modules (ES Modules)** 形式であることを明示するためのファイル拡張子です。ES Modulesは、現代のJavaScriptで推奨されるモジュールシステムであり、`import` と `export` 文を使用してモジュールを管理します。📦
:::

### `.mjs` ファイルが登場した背景 📜

歴史的に、Node.jsなどのJavaScript実行環境では **CommonJS** という異なるモジュールシステムが広く使われてきました。CommonJSでは `require()` と `module.exports` を使用します。

しかし、ウェブブラウザや新しいJavaScriptの仕様では、**ES Modules** が標準となりました。ここで問題が発生しました。

  * **`.js` ファイルの曖昧さ**: ある `.js` ファイルがCommonJS形式なのか、ES Modules形式なのかを、ファイルの内容を解析せずに判断するのは難しいです。
  * **Node.jsの互換性問題**: Node.jsはCommonJSが主流だったため、ES Modulesの導入には互換性の課題がありました。

この問題を解決するために、Node.jsコミュニティを中心に **`.mjs`** 拡張子（"Module JavaScript" の略と言われることが多い）が導入されました。これにより、ファイル拡張子を見ただけで、それがES Modules形式のファイルであることが明確にわかるようになりました。

-----

### `.mjs` ファイルと `.js` ファイルの主な違い ✨

| 特徴               | `.mjs` ファイル                                                                             | `.js` ファイル（デフォルト）                                                                                                                                                                                                                                                                                                                                           |
| :----------------- | :------------------------------------------------------------------------------------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **モジュール形式** | **ECMAScript Modules (ES Modules)** として扱われることが保証されます。`import` / `export` 構文が機能します。 | Node.js環境では、デフォルトで **CommonJS** として扱われます（ただし、`package.json` に `"type": "module"` が設定されているディレクトリ内ではES Modulesとして扱われることもあります）。\<br\>ブラウザ環境では、HTMLの `<script type="module">` で読み込まれた場合はES Modules、それ以外は従来のスクリプトとして扱われます。 |
| **厳格モード** | デフォルトで**厳格モード (strict mode)** で実行されます。                                   | デフォルトでは厳格モードではありません（ただし、CommonJSモジュールは暗黙的に厳格モードになることがあります）。                                                                                                                                                                                                                                                                  |
| **`this` の挙動** | 最上位スコープの `this` は `undefined` です。                                               | 最上位スコープの `this` は `module.exports` を指します。                                                                                                                                                                                                                                                                                                              |
| **解決ルール** | 異なる解決ルールが適用される場合があります（例: `.js`, `.json`, `.node` の順で解決するなど）。 | 異なる解決ルールが適用される場合があります（例: `.js`, `.json`, `.node` の順で解決するなど）。                                                                                                                                                                                                                                                                         |

-----

### `.mjs` ファイルの活用シナリオ 🚀

1.  **Node.js 環境でのES Modulesの使用**:
    Node.jsの古いバージョンや、`package.json` の `"type": "commonjs"` が設定されているプロジェクトで、ES Modulesを明示的に使用したい場合に `.mjs` 拡張子を利用します。

    ```javascript
    // my-module.mjs (ES Modules)
    export function greet(name) {
      return `Hello, ${name}!`;
    }

    // app.js (CommonJS環境から.mjsを読み込む場合)
    // Node.js v13.2.0 以降では、動的 import() で .mjs を読み込めます
    async function run() {
      const { greet } = await import('./my-module.mjs');
      console.log(greet('World')); // Hello, World!
    }
    run();
    ```

2.  **ブラウザ環境での明確化**:
    ブラウザで直接ES Modulesを読み込む場合、HTMLの `<script type="module" src="app.mjs"></script>` とすることで、そのファイルがES Modulesであることをより明確に示せます（ただし、`.js` 拡張子でも `type="module"` があればES Modulesとして扱われます）。

3.  **モジュールバンドラーとの連携**:
    WebpackやRollupなどのモジュールバンドラーは、`.mjs` 拡張子をES Modulesとして正しく認識し、処理してくれます。これにより、様々なモジュール形式が混在するプロジェクトでも、バンドラーが適切に処理できるようになります。

-----

### `.mjs` ファイルのサンプルコードと使用した場合・使用しなかった場合の比較 📊

ここでは、Node.js環境におけるES Modulesの扱いを比較してみましょう。

#### 📌 サンプルコード (`.mjs` ファイルを使用した場合)

**`message.mjs`:**

```javascript
// これはES Modules形式
export const hello = "Hello from .mjs!";
export function sayGoodbye() {
  return "Goodbye from .mjs!";
}
```

**`app.js`:**

```javascript
// CommonJS環境のファイル
// .mjs ファイルは、Node.jsの動的 import() を使って読み込む
async function run() {
  try {
    const { hello, sayGoodbye } = await import('./message.mjs');
    console.log(hello);         // 出力: Hello from .mjs!
    console.log(sayGoodbye());  // 出力: Goodbye from .mjs!
  } catch (error) {
    console.error("Error importing .mjs:", error);
  }
}

run();

// CommonJS形式で何かをエクスポートする例 (app.js自体はCommonJS)
module.exports = {
  appName: "My Hybrid App"
};
```

**実行コマンド:**
`node app.js`

この場合、`app.js` はCommonJSモジュールとして実行されつつ、`import()` を使って `.mjs` ファイルをES Modulesとして非同期に読み込み、そのエクスポートされた値を利用できます。

-----

#### 📌 `.mjs` ファイルを使用しなかった場合の比較（`.js` ファイルと `type: "module"`）

Node.jsでES Modulesを`.js` ファイルで扱いたい場合、最も一般的な方法は、プロジェクトの `package.json` に `"type": "module"` を追加することです。これにより、そのディレクトリ内（およびサブディレクトリ）のすべての `.js` ファイルがデフォルトでES Modulesとして扱われるようになります。

**`package.json`:**

```json
{
  "name": "my-es-module-app",
  "version": "1.0.0",
  "type": "module", // ✨ これが重要 ✨
  "main": "app.js",
  "scripts": {
    "start": "node app.js"
  }
}
```

**`message.js`:**

```javascript
// package.jsonで "type": "module" が設定されているので、これはES Modules形式
export const hello = "Hello from .js (ESM)!";
export function sayGoodbye() {
  return "Goodbye from .js (ESM)!";
}
```

**`app.js`:**

```javascript
// package.jsonで "type": "module" が設定されているので、これもES Modules形式
import { hello, sayGoodbye } from './message.js'; // ✨ .js 拡張子が必要になることが多い ✨

console.log(hello);         // 出力: Hello from .js (ESM)!
console.log(sayGoodbye());  // 出力: Goodbye from .js (ESM)!

// ES Modules形式で何かをエクスポートする例
export const appVersion = "1.0";
```

**実行コマンド:**
`node app.js`

この設定では、すべての `.js` ファイルがES Modulesとして扱われるため、CommonJSの `require()` や `module.exports` を使用するとエラーになります。プロジェクト全体をES Modulesに移行する場合に適しています。

-----

:::note alert | message alert
`.mjs` 拡張子は、CommonJSが主流の環境でES Modulesを**部分的に導入したい**場合や、ファイル形式を**明確に識別したい**場合に特に有効です。一方、プロジェクト全体をES Modulesに移行する場合は、`package.json` に `"type": "module"` を設定し、すべての `.js` ファイルをES Modulesとして扱うのが一般的になっています。どちらの方法を選ぶかは、プロジェクトの要件や環境によって異なります。 🚨
:::