できない.dev

esbuild で「You installed esbuild for another platform」が出て起動できない

You installed esbuild for another platform は、別 OS で入れた node_modules を持ち込むと出る。
動かす側で node_modules を消して npm ci し直せば直る。

公開: 更新:

要約

esbuild を CLI で実行しても、JavaScript API から呼んでも、次のエラーで止まる。

Error:
You installed esbuild for another platform than the one you're currently using.
This won't work because esbuild is written with native code and needs to
install a platform-specific binary executable.
 
Specifically the "@esbuild/win32-x64" package is present but this platform
needs the "@esbuild/linux-x64" package instead. People often get into this
situation by installing esbuild on Windows or macOS and copying "node_modules"
into a Docker image that runs Linux, or by copying "node_modules" between
Windows and WSL environments.

esbuild の本体は Go で書かれたネイティブバイナリで、npm からは OS と CPU ごとのパッケージ(@esbuild/linux-x64・@esbuild/win32-x64 など)として入る。
インストールした環境の分だけが node_modules に入るので、別の OS へ node_modules を持ち込むと、その OS 用のバイナリが無くて起動できない。
Windows 11 で npm install esbuild(0.28.2)した node_modules を、Linux の node:22-bookworm-slim コンテナにマウントして実行すると、上の表示になった。

解決策

1. node_modules をイメージに入れず、中で npm ci する

.dockerignore に node_modules を書き、依存はイメージの中で入れ直す。

node_modules
FROM node:22-bookworm-slim
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .

Windows で作った package-lock.json のままでも、Linux の npm ci は @esbuild/linux-x64 を入れた。
ロックファイルには各プラットフォーム用のパッケージが並んでいて、npm ci は実行している環境に合うものを選ぶ。.dockerignore を置かずに COPY . . だけにした Dockerfile は、RUN npx esbuild の段階で同じエラーになった。

2. bind mount では node_modules を分ける

Compose でソースを bind mount するときは、node_modules に名前付きボリュームを重ね、コンテナ側の依存をホストと分ける。

services:
  app:
    build: .
    volumes:
      - ./:/app
      - node_modules:/app/node_modules
volumes:
  node_modules:

マウントの重なり方は docker compose のボリュームマウントで node_modules が消えるで詳しく扱っている。

3. 動かす側で入れ直す

WSL など、実行する環境で node_modules を消して入れ直す。
コンテナの中で次を実行すると @esbuild/linux-x64 に入れ替わり、esbuild が起動した。

rm -rf node_modules
npm ci

esbuild のドキュメント(新しいタブで開く)も、npm と pnpm では node_modules をコピーせず、コピー先で npm ci か npm install を実行する方法を挙げている。
Yarn なら .yarnrc.yml の supportedArchitectures に両方の環境を書き、複数の OS 用のバイナリを同時に入れておく方法もある。

よくある原因

  1. COPY . . で node_modules ごとコピーしている: .dockerignore が無いと、ホストの node_modules がビルドコンテキストに含まれ、イメージに入る。
  2. bind mount でホストの node_modules が見えている: docker run -v "$PWD:/app" や Compose の ./:/app では、コンテナの /app/node_modules はホスト側のディレクトリそのものになる。
  3. Windows と WSL で使い回している: Windows 側で入れたプロジェクトを WSL から開いて実行すると、Linux 用のバイナリが無い。

この手順で直った?