Vitest ESM/CJS 混在で `Cannot use import statement outside a module` が出る技術対処集
Vitest でテストを実行している最中に Cannot use import statement outside a module というエラーに遭遇したことはありませんか?
このエラーは、ESM(ECMAScript Modules)と CJS(CommonJS)が混在する環境でよく発生し、多くの開発者を悩ませる問題です。
本記事では、Vitest プロジェクトで ESM/CJS 混在時に発生する Cannot use import statement outside a module エラーの原因を体系的に整理し、具体的な対処方法を段階的に解説します。
エラーコードや設定例も豊富に記載しているため、検索してすぐに解決策にたどり着けるように構成しました。
背景
モジュールシステムの歴史的経緯
JavaScript のモジュールシステムは、歴史的に CJS(CommonJS)と ESM(ECMAScript Modules)という 2 つの方式が存在してきました。
以下の図は、モジュールシステムの進化を示しています。
mermaidflowchart LR
  cjs["CJS<br/>(Node.js 初期)"] -->|標準化| esm["ESM<br/>(ES2015~)"]
  esm -->|現在| mixed["ESM/CJS<br/>混在環境"]
  mixed -->|課題| error["モジュール解決<br/>エラー"]
Node.js は当初 CJS を採用していましたが、ES2015(ES6)以降、JavaScript 標準として ESM が導入されました。 現在の開発環境では、両方式が混在するケースが増えており、これがエラーの主な原因となっています。
Vitest とモジュールシステム
Vitest は Vite ベースのテストフレームワークで、標準で ESM をサポートしています。 しかし、既存のプロジェクトや npm パッケージには CJS で書かれたものも多く、これらを統合する際に問題が発生しやすくなります。
以下の表は、モジュールシステムの特徴を比較したものです。
| # | 項目 | CJS | ESM | 
|---|---|---|---|
| 1 | 構文 | require() / module.exports | import / export | 
| 2 | 読み込み | 同期 | 非同期 | 
| 3 | トップレベル await | 不可 | 可能 | 
| 4 | Node.js サポート | v0.x~ | v12.x~(v13.2~ で安定) | 
| 5 | ブラウザサポート | 不可(バンドル必須) | 可能 | 
| 6 | ファイル拡張子 | .js / .cjs | .js / .mjs | 
Vitest は ESM をネイティブにサポートしているため、ESM で書かれたコードは基本的にそのまま動作します。 一方で、CJS モジュールや古い設定ファイルを含むプロジェクトでは、適切な設定が必要になってくるのです。
課題
エラーの発生パターン
Cannot use import statement outside a module エラーは、主に以下の 3 つのパターンで発生します。
mermaidflowchart TD
  start["Vitest 実行"] --> check["モジュール解決"]
  check -->|パターン 1| p1["package.json に<br/>type: module がない"]
  check -->|パターン 2| p2["依存パッケージが<br/>CJS のみ"]
  check -->|パターン 3| p3["Vitest 設定で<br/>変換対象外"]
  p1 --> error["SyntaxError:<br/>Cannot use import<br/>statement outside<br/>a module"]
  p2 --> error
  p3 --> error
図で理解できる要点:
- エラーは主に 3 つの原因パターンに分類できる
 - いずれも「モジュール解決」の段階で発生する
 - 適切な設定でそれぞれ個別に対処可能
 
エラーコードの詳細
エラーコード: SyntaxError
javascriptSyntaxError: Cannot use import statement outside a module
このエラーメッセージは、Node.js が ESM の import 構文を CJS コンテキストで解釈しようとした際に発生します。
発生条件
以下の条件が重なると、このエラーが発生しやすくなります。
| # | 条件 | 説明 | 
|---|---|---|
| 1 | package.json に type: "module" がない | Node.js は CJS として解釈 | 
| 2 | .js ファイルで import を使用 | ESM 構文が使えない | 
| 3 | node_modules 内のパッケージが CJS | Vitest の変換対象外 | 
| 4 | Vitest 設定で transformMode が不適切 | 変換処理がスキップされる | 
これらの条件を理解することで、エラーの原因を素早く特定できます。
典型的なエラーシナリオ
シナリオ 1: package.json の設定不足
プロジェクトルートの package.json に type: "module" の記載がない場合、Node.js はすべての .js ファイルを CJS として扱います。
json{
  "name": "my-vitest-project",
  "version": "1.0.0",
  "scripts": {
    "test": "vitest"
  }
}
上記のように type フィールドがない場合、テストファイルで import を使用するとエラーが発生します。
シナリオ 2: 依存パッケージの CJS 形式
npm パッケージの中には、CJS 形式のみで配布されているものがあります。
これらのパッケージを import で読み込もうとすると、Vitest の変換処理が適用されずエラーになる場合があります。
javascript// テストファイル
import { someFunction } from 'old-cjs-package'; // エラー発生
シナリオ 3: Vitest 設定の不備
Vitest の設定ファイル(vitest.config.ts など)で、適切な変換オプションが指定されていない場合もエラーが発生します。
typescript// vitest.config.ts(問題のある例)
import { defineConfig } from 'vitest/config';
export default defineConfig({
  test: {
    // deps の設定が不足
  },
});
これらのシナリオを押さえておくことで、エラーの原因を効率的に絞り込むことができるでしょう。
解決策
対処フローチャート
エラーに遭遇したときは、以下のフローに従って段階的に対処していきましょう。
mermaidflowchart TD
  error["エラー発生"] --> step1{"package.json<br/>に type: module<br/>があるか?"}
  step1 -->|なし| fix1["type: module<br/>を追加"]
  step1 -->|あり| step2{"依存パッケージが<br/>CJS か?"}
  step2 -->|はい| fix2["deps.inline<br/>で変換対象に追加"]
  step2 -->|いいえ| step3{"Vitest 設定<br/>は正しいか?"}
  step3 -->|不適切| fix3["transformMode<br/>を設定"]
  step3 -->|適切| fix4["ファイル拡張子<br/>を確認"]
  fix1 --> resolved["解決"]
  fix2 --> resolved
  fix3 --> resolved
  fix4 --> resolved
図で理解できる要点:
- まず 
package.jsonの基本設定を確認 - 次に依存パッケージの形式をチェック
 - 最後に Vitest の詳細設定を見直す
 
解決方法 1: package.json の設定
type フィールドの追加
最も基本的な対処法は、package.json に type: "module" を追加することです。
json{
  "name": "my-vitest-project",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "test": "vitest"
  }
}
追加した設定の意味:
"type": "module"により、.jsファイルが ESM として解釈されます- これで 
import/export構文が使用可能になります 
注意点
type: "module" を追加すると、プロジェクト全体が ESM モードになります。
既存の CJS ファイルがある場合は、以下のいずれかの対応が必要です。
| # | 対応方法 | 説明 | 
|---|---|---|
| 1 | .cjs 拡張子に変更 | CJS ファイルを明示的に識別 | 
| 2 | ESM に書き換え | require → import に変換 | 
| 3 | 動的 import を使用 | await import() で読み込み | 
解決方法 2: Vitest の deps.inline 設定
CJS パッケージの変換設定
依存パッケージが CJS 形式の場合、Vitest の deps.inline オプションを使って変換対象に含めます。
typescript// vitest.config.ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
  test: {
    // 依存パッケージの変換設定
    deps: {
      inline: [
        // 特定のパッケージを指定
        'old-cjs-package',
      ],
    },
  },
});
設定の意味:
deps.inlineに指定したパッケージは、Vitest が ESM に変換して読み込みます- CJS 形式のパッケージでも 
importで使用可能になります 
正規表現による一括指定
複数のパッケージをまとめて指定したい場合は、正規表現を使用できます。
typescript// vitest.config.ts(正規表現を使用)
import { defineConfig } from 'vitest/config';
export default defineConfig({
  test: {
    deps: {
      inline: [
        // @legacy スコープのすべてのパッケージ
        /^@legacy\/.*/,
        // 特定のプレフィックスを持つパッケージ
        /^old-/,
      ],
    },
  },
});
活用ポイント:
- スコープ付きパッケージ(
@org/package)を一括指定できます - 命名規則が統一されている場合に便利です
 
すべての依存パッケージを変換する場合
すべての node_modules 内のパッケージを変換対象にする場合は、true を指定します。
typescript// vitest.config.ts(全パッケージ変換)
import { defineConfig } from 'vitest/config';
export default defineConfig({
  test: {
    deps: {
      inline: true, // すべてのパッケージを変換
    },
  },
});
注意点:
- すべてのパッケージを変換するため、テスト実行時間が長くなる可能性があります
 - まずは特定のパッケージを指定し、必要に応じて範囲を広げることをおすすめします
 
解決方法 3: transformMode の設定
Web モードと SSR モードの違い
Vitest には、変換方式として「Web モード」と「SSR モード」の 2 つがあります。
| # | モード | 対象 | 特徴 | 
|---|---|---|---|
| 1 | Web | ブラウザ環境 | DOM API が使える、動的 import を使用 | 
| 2 | SSR | Node.js 環境 | Node.js API が使える、同期的な require を使用 | 
デフォルトでは、Vitest は適切なモードを自動選択しますが、明示的に指定することで問題を解決できる場合があります。
SSR モードの明示的指定
typescript// vitest.config.ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
  test: {
    // 環境の明示的指定
    environment: 'node',
    // deps 設定
    deps: {
      inline: ['problematic-package'],
    },
  },
});
設定の意味:
environment: 'node'により、Node.js 環境でのテスト実行を明示します- SSR モードの変換処理が適用されます
 
transformMode の詳細設定
より細かく制御したい場合は、transformMode を直接指定できます。
typescript// vitest.config.ts(詳細設定)
import { defineConfig } from 'vitest/config';
export default defineConfig({
  test: {
    deps: {
      inline: [/^@myorg\/.*/],
    },
    // 変換モードの詳細指定
    server: {
      deps: {
        inline: [/^@myorg\/.*/],
      },
    },
  },
});
解決方法 4: ファイル拡張子による制御
.mjs と .cjs の使い分け
ファイル拡張子を使って、明示的にモジュール形式を指定する方法もあります。
javascript// utils.mjs(ESM として確実に扱われる)
export function add(a, b) {
  return a + b;
}
javascript// legacy.cjs(CJS として確実に扱われる)
module.exports = {
  multiply: (a, b) => a * b,
};
使い分けの指針:
.mjs: ESM 構文を使いたいファイル.cjs: CJS 構文を使いたいファイル.js:package.jsonのtypeフィールドに従う
混在プロジェクトでの実践例
ESM と CJS が混在する場合の実践的なディレクトリ構成例です。
bashproject/
├── package.json          # "type": "module" を指定
├── src/
│   ├── modern.js        # ESM(import/export)
│   └── legacy.cjs       # CJS(require/module.exports)
└── test/
    ├── modern.test.js   # ESM テスト
    └── legacy.test.cjs  # CJS テスト(必要に応じて)
ポイント:
- プロジェクト全体は ESM をベースにする
 - 一部の古いコードのみ 
.cjs拡張子を使う - 段階的に ESM へ移行できます
 
解決方法 5: TypeScript プロジェクトの場合
tsconfig.json の module 設定
TypeScript プロジェクトでは、tsconfig.json の設定も重要になります。
json{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "bundler",
    "target": "ESNext",
    "lib": ["ESNext"],
    "types": ["vitest/globals"]
  }
}
各オプションの意味:
"module": "ESNext": ESM 形式で出力"moduleResolution": "bundler": バンドラー向けのモジュール解決"target": "ESNext": 最新の JavaScript 構文を使用"types": ["vitest/globals"]: Vitest のグローバル型定義を読み込み
Vitest での TypeScript 設定
typescript// vitest.config.ts
import { defineConfig } from 'vitest/config';
import tsconfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
  plugins: [
    // tsconfig の paths を解決
    tsconfigPaths(),
  ],
  test: {
    globals: true,
    environment: 'node',
    deps: {
      inline: [
        // TypeScript パッケージの変換
        /^@ts-namespace\/.*/,
      ],
    },
  },
});
設定のポイント:
tsconfigPaths()プラグインで、TypeScript のパスエイリアスが使えますglobals: trueで、describeやitをインポート不要にできます
必要なパッケージのインストールは以下の通りです。
bashyarn add -D vite-tsconfig-paths
インストールコマンドの意味:
vite-tsconfig-paths: Vite で TypeScript の paths 設定を使用可能にするプラグイン-D: 開発依存関係としてインストール
具体例
ケーススタディ 1: レガシー React プロジェクトの移行
初期状態(エラー発生)
レガシーな React プロジェクトで Vitest を導入しようとした際のエラーです。
javascript// src/utils/format.js
export function formatDate(date) {
  return date.toISOString().split('T')[0];
}
javascript// test/utils/format.test.js
import { describe, it, expect } from 'vitest';
import { formatDate } from '../../src/utils/format';
describe('formatDate', () => {
  it('should format date correctly', () => {
    const date = new Date('2025-01-15');
    expect(formatDate(date)).toBe('2025-01-15');
  });
});
エラーメッセージ:
javascriptError: Cannot use import statement outside a module
  at Object.compileFunction (node:vm:360:18)
  at wrapSafe (node:internal/modules/cjs/loader:1055:15)
解決手順
ステップ 1: package.json の修正
json{
  "name": "legacy-react-app",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "test": "vitest",
    "test:ui": "vitest --ui"
  },
  "devDependencies": {
    "vitest": "^1.0.0"
  }
}
変更内容:
"type": "module"を追加し、ESM モードを有効化しました
ステップ 2: Vitest 設定ファイルの作成
typescript// vitest.config.ts
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';
export default defineConfig({
  plugins: [react()],
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: './test/setup.ts',
    deps: {
      inline: [
        // React 関連の古いパッケージを変換
        'react-test-renderer',
      ],
    },
  },
});
設定の意味:
@vitejs/plugin-react: React の JSX を変換しますenvironment: 'jsdom': ブラウザ環境をエミュレートしますdeps.inline: CJS 形式の React 関連パッケージを変換対象にします
ステップ 3: 必要なパッケージのインストール
bashyarn add -D vitest @vitejs/plugin-react jsdom @vitest/ui
インストールパッケージの説明:
vitest: テストフレームワーク本体@vitejs/plugin-react: React のサポートjsdom: DOM 環境のシミュレーション@vitest/ui: テスト結果の UI ツール
実行結果
bashyarn test
scss✓ test/utils/format.test.js (1)
  ✓ formatDate (1)
    ✓ should format date correctly
Test Files  1 passed (1)
     Tests  1 passed (1)
  Start at  10:23:45
  Duration  342ms
成功のポイント:
package.jsonで ESM モードを明示- Vitest 設定で React 環境を適切に構築
 - CJS パッケージを変換対象に追加
 
ケーススタディ 2: Axios を使った API クライアントのテスト
初期状態(エラー発生)
Axios を使用した API クライアントで、テスト実行時にエラーが発生しました。
typescript// src/api/client.ts
import axios from 'axios';
export async function fetchUser(id: number) {
  const response = await axios.get(`/api/users/${id}`);
  return response.data;
}
typescript// test/api/client.test.ts
import { describe, it, expect, vi } from 'vitest';
import axios from 'axios';
import { fetchUser } from '../../src/api/client';
vi.mock('axios');
describe('fetchUser', () => {
  it('should fetch user data', async () => {
    const mockData = { id: 1, name: 'Test User' };
    vi.mocked(axios.get).mockResolvedValue({
      data: mockData,
    });
    const result = await fetchUser(1);
    expect(result).toEqual(mockData);
  });
});
エラーメッセージ:
javascriptError: Cannot use import statement outside a module
  at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1350:14)
解決手順
ステップ 1: Vitest 設定の追加
typescript// vitest.config.ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
  test: {
    globals: true,
    environment: 'node',
    deps: {
      inline: [
        // Axios を変換対象に追加
        'axios',
        // Axios が内部で使用するパッケージも追加
        'follow-redirects',
      ],
    },
  },
});
設定のポイント:
- Axios 本体だけでなく、依存パッケージも 
inlineに追加しています - これにより、すべての関連モジュールが適切に変換されます
 
ステップ 2: package.json の確認
json{
  "name": "api-client-app",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "test": "vitest"
  }
}
確認ポイント:
"type": "module"が設定されていることを確認します
実行結果
bashyarn test
scss✓ test/api/client.test.ts (1)
  ✓ fetchUser (1)
    ✓ should fetch user data
Test Files  1 passed (1)
     Tests  1 passed (1)
  Start at  10:25:32
  Duration  198ms
成功のポイント:
- Axios とその依存パッケージを 
deps.inlineに追加 - モック機能が正常に動作
 
ケーススタディ 3: Lodash などの CJS ユーティリティライブラリ
初期状態(エラー発生)
Lodash を使用したユーティリティ関数のテストでエラーが発生しました。
typescript// src/utils/array.ts
import _ from 'lodash';
export function uniqueValues<T>(arr: T[]): T[] {
  return _.uniq(arr);
}
export function groupByKey<T>(
  arr: T[],
  key: keyof T
): Record<string, T[]> {
  return _.groupBy(arr, key as string);
}
typescript// test/utils/array.test.ts
import { describe, it, expect } from 'vitest';
import {
  uniqueValues,
  groupByKey,
} from '../../src/utils/array';
describe('array utils', () => {
  describe('uniqueValues', () => {
    it('should return unique values', () => {
      const input = [1, 2, 2, 3, 3, 3];
      expect(uniqueValues(input)).toEqual([1, 2, 3]);
    });
  });
  describe('groupByKey', () => {
    it('should group items by key', () => {
      const input = [
        { category: 'A', value: 1 },
        { category: 'B', value: 2 },
        { category: 'A', value: 3 },
      ];
      const result = groupByKey(input, 'category');
      expect(result.A).toHaveLength(2);
      expect(result.B).toHaveLength(1);
    });
  });
});
エラーメッセージ:
javascriptError: Cannot use import statement outside a module
  /__w/project/node_modules/lodash/lodash.js:1
解決手順
方法 A: lodash-es を使用(推奨)
Lodash には ESM 版の lodash-es があるため、こちらを使用するのが最もシンプルです。
bashyarn remove lodash
yarn add lodash-es
yarn add -D @types/lodash-es
インストールの意味:
lodash-es: Lodash の ESM バージョン@types/lodash-es: TypeScript の型定義
typescript// src/utils/array.ts(修正後)
import { uniq, groupBy } from 'lodash-es';
export function uniqueValues<T>(arr: T[]): T[] {
  return uniq(arr);
}
export function groupByKey<T>(
  arr: T[],
  key: keyof T
): Record<string, T[]> {
  return groupBy(arr, key as string);
}
変更のポイント:
- デフォルトインポートから名前付きインポートに変更しました
 lodash-esは完全に ESM 対応しているため、追加設定不要です
方法 B: deps.inline で変換(既存コードを変更したくない場合)
既存のコードを変更せずに対応する場合は、Vitest 設定で変換します。
typescript// vitest.config.ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
  test: {
    globals: true,
    environment: 'node',
    deps: {
      inline: [
        // Lodash を変換対象に追加
        'lodash',
      ],
    },
  },
});
注意点:
- この方法では、Lodash 全体を変換するため、初回実行が遅くなる可能性があります
 - 可能であれば、方法 A の 
lodash-esへの移行をおすすめします 
実行結果
bashyarn test
scss✓ test/utils/array.test.ts (2)
  ✓ array utils (2)
    ✓ uniqueValues (1)
      ✓ should return unique values
    ✓ groupByKey (1)
      ✓ should group items by key
Test Files  1 passed (1)
     Tests  2 passed (2)
  Start at  10:28:15
  Duration  285ms
成功のポイント:
- ESM 版のライブラリを使用することで、追加設定なしで動作しました
 - 既存の CJS ライブラリを使い続ける場合は、
deps.inlineで対応可能です 
ケーススタディ 4: モノレポ環境での対処
初期状態(エラー発生)
Yarn Workspaces を使用したモノレポ環境で、パッケージ間の参照でエラーが発生しました。
cssmonorepo/
├── package.json
├── packages/
│   ├── shared/
│   │   ├── package.json
│   │   └── src/
│   │       └── utils.ts
│   └── app/
│       ├── package.json
│       ├── src/
│       │   └── main.ts
│       └── test/
│           └── main.test.ts
typescript// packages/shared/src/utils.ts
export function capitalize(str: string): string {
  return str.charAt(0).toUpperCase() + str.slice(1);
}
typescript// packages/app/src/main.ts
import { capitalize } from '@monorepo/shared';
export function greet(name: string): string {
  return `Hello, ${capitalize(name)}!`;
}
typescript// packages/app/test/main.test.ts
import { describe, it, expect } from 'vitest';
import { greet } from '../src/main';
describe('greet', () => {
  it('should greet with capitalized name', () => {
    expect(greet('john')).toBe('Hello, John!');
  });
});
エラーメッセージ:
swiftError: Cannot use import statement outside a module
  at packages/app/node_modules/@monorepo/shared/src/utils.ts:1
解決手順
ステップ 1: ルートの package.json 設定
json{
  "name": "monorepo",
  "private": true,
  "type": "module",
  "workspaces": ["packages/*"],
  "devDependencies": {
    "vitest": "^1.0.0"
  }
}
設定のポイント:
- ルートレベルで 
"type": "module"を設定します - すべてのワークスペースに適用されます
 
ステップ 2: 各パッケージの package.json 設定
json// packages/shared/package.json
{
  "name": "@monorepo/shared",
  "version": "1.0.0",
  "type": "module",
  "main": "./src/utils.ts",
  "exports": {
    ".": "./src/utils.ts"
  }
}
json// packages/app/package.json
{
  "name": "@monorepo/app",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "test": "vitest"
  },
  "dependencies": {
    "@monorepo/shared": "workspace:*"
  }
}
設定のポイント:
- 各パッケージでも 
"type": "module"を明示します exportsフィールドでエントリーポイントを明確にしますworkspace:*でワークスペース内の依存関係を指定します
ステップ 3: Vitest 設定ファイルの作成
typescript// packages/app/vitest.config.ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
  test: {
    globals: true,
    environment: 'node',
    deps: {
      inline: [
        // ワークスペース内のパッケージを変換対象に追加
        '@monorepo/shared',
      ],
    },
  },
  resolve: {
    alias: {
      // ワークスペース内のパッケージの解決
      '@monorepo/shared': '../shared/src/utils.ts',
    },
  },
});
設定の意味:
deps.inlineでワークスペース内のパッケージを変換対象にしますresolve.aliasでパスエイリアスを設定し、確実に解決できるようにします
実行結果
bashcd packages/app
yarn test
scss✓ test/main.test.ts (1)
  ✓ greet (1)
    ✓ should greet with capitalized name
Test Files  1 passed (1)
     Tests  1 passed (1)
  Start at  10:32:47
  Duration  156ms
成功のポイント:
- モノレポ全体で ESM モードを統一しました
 - ワークスペース内のパッケージを 
deps.inlineに追加することで、変換処理が適用されました resolve.aliasにより、パス解決が確実になりました
まとめ
Cannot use import statement outside a module エラーは、ESM と CJS の混在環境で頻繁に遭遇する問題ですが、適切な対処法を知っていればスムーズに解決できます。
本記事で紹介した対処法を、段階的に適用していくことをおすすめします。
対処法の優先順位
エラーに遭遇したら、以下の順番で対処していきましょう。
| # | 対処法 | 優先度 | 効果 | 
|---|---|---|---|
| 1 | package.json に type: "module" を追加 | ★★★ | プロジェクト全体を ESM 化 | 
| 2 | Vitest の deps.inline で変換対象を指定 | ★★★ | 特定パッケージの変換 | 
| 3 | ESM 版ライブラリへの移行(例: lodash-es) | ★★☆ | 根本的な解決 | 
| 4 | ファイル拡張子(.mjs / .cjs)の使い分け | ★☆☆ | 部分的な制御 | 
| 5 | transformMode の詳細設定 | ★☆☆ | 高度なカスタマイズ | 
重要なポイント
本記事で解説した内容を振り返ると、以下の点が特に重要です。
- 
package.json の設定が基本
type: "module"を追加することで、多くのケースが解決します- プロジェクト全体の方針を明確にすることが大切です
 
 - 
deps.inline の活用
- CJS パッケージを ESM として変換できる強力な機能です
 - 特定のパッケージから段階的に対応できます
 
 - 
エラーメッセージの読み解き
- エラーが発生しているファイルパスから、原因を特定できます
 node_modules内のエラーは、deps.inlineで対処します
 - 
段階的な移行が可能
- すべてを一度に変更する必要はありません
 - ファイル拡張子を使い分けることで、ESM と CJS を共存させられます
 
 
トラブルシューティングのチェックリスト
エラーが解決しない場合は、以下を順番に確認してみてください。
-  
package.jsonに"type": "module"が記載されているか? - Vitest の設定ファイルが正しく読み込まれているか?
 -  問題のあるパッケージが 
deps.inlineに含まれているか? -  ファイル拡張子(
.js/.mjs/.cjs)は適切か? -  TypeScript を使用している場合、
tsconfig.jsonのmodule設定は適切か? - モノレポの場合、ワークスペース内のパッケージも変換対象になっているか?
 
これらをチェックすることで、ほとんどのケースで問題を解決できるはずです。 それでも解決しない場合は、Vitest の公式ドキュメントやコミュニティに相談してみましょう。
ESM への移行は、現代の JavaScript 開発において避けて通れない道です。 本記事が、その移行をスムーズに進める助けになれば幸いです。
関連リンク
articleVitest ESM/CJS 混在で `Cannot use import statement outside a module` が出る技術対処集
articleVitest モジュールモック技術の基礎と応用:`vi.mock` / `vi.spyOn` を極める
articleVitest フレーク検知技術の運用:`--retry` / シード固定 / ランダム順序で堅牢化
articleVitest テストアーキテクチャ技術:Unit / Integration / Contract の三層設計ガイド
articleVitest `vi` API 技術チートシート:`mock` / `fn` / `spyOn` / `advanceTimersByTime` 一覧
articleVitest × jsdom / happy-dom 技術セットアップ:最小構成と落とし穴
articleWebSocket が「200 OK で Upgrade されない」原因と対処:プロキシ・ヘッダー・TLS の落とし穴
articleWebRTC 本番運用の SLO 設計:接続成功率・初画出し時間・通話継続率の基準値
articleAstro のレンダリング戦略を一望:MPA× 部分ハイドレーションの強みを図解解説
articleWebLLM が読み込めない時の原因と解決策:CORS・MIME・パス問題を総点検
articleVitest ESM/CJS 混在で `Cannot use import statement outside a module` が出る技術対処集
articleテスト環境比較:Vitest vs Jest vs Playwright CT ― Vite プロジェクトの最適解
blogiPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
blogGoogleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
blog【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
blogGoogleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
blogPixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
blogフロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
review今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
reviewついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
review愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
review週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
review新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
review科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来