はじめに
本記事は個人開発でGo言語を使用してAPI開発をした際のコミットした内容に基づいて生成AIから文章を生成した内容を一部書き加えたものになります
Node 20 環境で tsx を使った開発起動がいくつかの権限・互換性エラーで落ちたので、発生順に原因と解消手順をまとめます。
同様の環境でハマった方の助けになれば。
環境
- node: v20.12.2(途中 v20.0.0 でも再現)
- tsx: ^4.19.1
- OS: Linux x64
症状(発生順)
-
tsx: Permission denied sh: 1: tsx: Permission denied
→node_modules/.bin/tsx
が 0 バイト or 実行不可 -
NODE_OPTIONS
のフラグが拒否
node: --optimize-for-size is not allowed in NODE_OPTIONS
-
--loader
非推奨によるエラー
Error: tsx must be loaded with --import instead of --loader The --loader flag was deprecated in Node v20.6.0 and v18.19.0
-
esbuild 実行権限エラー
TransformError: spawn .../@esbuild/linux-x64/bin/esbuild EACCES
原因
- node_modules/.bin/tsx のスタブ破損/実行権限なし
- Node 20 の NODE_OPTIONS は許可フラグのホワイトリスト制で、
--optimize-for-size
は対象外 - Node 20.6+ では --loader が非推奨になり、--import への移行が推奨
-
@esbuild/*/bin/esbuild
に実行権限がなくspawn ... EACCES
最終的な解決
- tsx を直叩きせず、Node の
--import
で tsx を読み込む -
NODE_OPTIONS
から非許可フラグ(例: --optimize-for-size)を除去 -
@esbuild/*/bin/esbuild
に**実行権限(+x)**を付与
(もしくはnpm rebuild esbuild
/ クリーン再構築)
{
"scripts": {
"dev": "NODE_OPTIONS=\"--max-old-space-size=8192\" node --no-warnings --import=tsx server/index.ts",
"dev:light": "NODE_OPTIONS=\"--max-old-space-size=4096\" node --no-warnings --import=tsx server/index.ts",
"start": "NODE_ENV=production node dist/index.js"
}
}
esbuild バイナリに実行権限を付与
node_modules
配下の esbuild ネイティブ実行ファイルに +x
を付ける:
# プロジェクト直下で実行
find node_modules -type f -path "*/@esbuild/*/bin/esbuild" -exec chmod +x {} +
(権限破損が疑われる場合は以下も有効)
rm -rf node_modules package-lock.json
npm ci
# もしくは
npm rebuild esbuild
手順
-
tsx 直実行をやめる
- 変更前:
tsx index.ts
- 変更後:
NODE_OPTIONS="--max-old-space-size=8192" node --no-warnings --import=tsx server/index.ts
-
--loader tsx
→--import=tsx
に置換(Node 20 互換)
エラー文のとおり--import
を使用。 -
esbuild の権限エラー(EACCES)を解消
find ... -exec chmod +x
で@esbuild/*/bin/esbuild
を実行可能に。
検証
# dev 起動
npm run dev
# 本番ビルドの JS を直実行
npm run start
# tsx を明示的に参照して実行(パス直指定の確認用)
node --no-warnings --import=./node_modules/tsx/dist/esm/index.mjs server/index.ts
トラブルシューティング用コマンド
# Node バージョン/ビルド情報
node -v
node -p "process.versions"
# tsx スタブの状態(サイズ/権限)
ls -l node_modules/.bin/tsx
# esbuild ネイティブ実行ファイルの権限
ls -l node_modules/tsx/node_modules/@esbuild/linux-x64/bin/esbuild || true
# 依存の解決元確認
npm ls tsx @esbuild/linux-x64
予防策・知見
- 依存破損時はクリーン再構築が最速
rm -rf node_modules package-lock.json
npm ci
- Node 20 以降は
--loader
ではなく--import
を使う(将来の削除に備えて移行)
まとめ
- Node 20 での tsx 利用は 起動方法(
--import
) とNODE_OPTIONS
の制限 を押さえるのがコツ - 上記の変更と権限付与で npm run dev は安定して起動できるようになりました