Node.jsでTypeScriptファイルの拡張子「.ts」が認識されない問題
Herokuなどの環境でTypeScriptアプリケーションを実行する際に、Unknown file extension ".ts"
というエラーが発生することがあります。この問題は、Node.jsのESモジュール(ESM)とCommonJSの設定が適切に構成されていない場合に起こります。
問題の原因
このエラーの主な原因は以下の組み合わせです:
package.json
で"type": "module"
が設定されているtsconfig.json
でESモジュール関連の設定がされている- ts-nodeがESモジュールモードで実行されていない
{
"type": "module", // ← これが原因の一つ
"scripts": {
"start": "ts-node src/App.ts" // ← ESM対応が必要
}
}
解決方法
方法1: CommonJSを使用する(推奨)
最もシンプルな解決策は、CommonJSモードを使用することです。
- package.jsonから
"type": "module"
を削除 - tsconfig.jsonをCommonJS用に設定
{
"compilerOptions": {
"target": "ES6",
"module": "CommonJS", // ← CommonJSを使用
"moduleResolution": "node",
"esModuleInterop": true,
"outDir": "dist"
}
}
TIP
CommonJSモードでは、従来のrequire
構文とimport
構文の両方が使用できます。esModuleInterop: true
によって互換性が確保されます。
方法2: ESモジュールを維持する場合
ESモジュールを使用する必要がある場合は、以下の設定が必要です。
{
"type": "module",
"scripts": {
"start": "ts-node --esm src/App.ts" // ← --esmフラグを追加
}
}
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "node"
},
"ts-node": {
"esm": true // ← ts-nodeにESMを有効化
}
}
実行時には以下のいずれかの方法を使用します:
# 方法1: --esmフラグを使用
ts-node --esm src/App.ts
# 方法2: Node.jsのloaderを使用
node --loader ts-node/esm src/App.ts
方法3: モダンな代替ツールを使用する
最近ではts-node
の代わりにより優れたツールが利用できます。
tsxの使用(2024年現在、推奨)
npm install -D tsx
{
"scripts": {
"dev": "tsx watch src/App.ts",
"start": "tsx src/App.ts"
}
}
vite-nodeの使用
npm install -D vite-node
{
"scripts": {
"dev": "vite-node --watch src/App.ts"
}
}
INFO
tsxとvite-nodeは、ESモジュールをネイティブにサポートし、設定が少なくて済むという利点があります。
Herokuへのデプロイ設定
Herokuでは、ビルドプロセスを適切に設定する必要があります。
{
"scripts": {
"build": "tsc",
"start": "node dist/App.js"
},
"engines": {
"node": ">=18.0.0"
}
}
WARNING
本番環境では、TypeScriptをJavaScriptにコンパイルしてから実行することを推奨します。これにより、パフォーマンスが向上し、実行時コンパイルのオーバーヘッドを避けられます。
よくある問題と解決策
Node.jsのバージョン問題
特定のNode.jsバージョン(特にv18)ではESモジュール関連の問題が発生することがあります。
# Node.jsのバージョンを確認
node --version
# 必要に応じてバージョン変更(nvmを使用)
nvm install 20
nvm use 20
拡張子の明示的な指定
ESモジュールでは、インポート時に拡張子を明示する必要がある場合があります。
// 従来
import { MyModule } from './my-module'
// ESMでは拡張子が必要な場合がある
import { MyModule } from './my-module.js'
まとめ
シナリオ | 推�解決策 |
---|---|
新しいプロジェクト | tsxまたはvite-nodeを使用 |
既存プロジェクト(CommonJS) | module: "CommonJS" 設定 |
既存プロジェクト(ESM維持) | ts-node --esm と設定 |
本番環境 | TypeScriptを事前コンパイル |
TypeScriptとNode.jsのモジュールシステムは歴史的に複雑な経緯がありますが、適切な設定とモダンなツールを使用することで、これらの問題は解決できます。
最新の情報については、TypeStrong/ts-nodeのGitHubリポジトリを確認することをお勧めします。