Open4

【npm / Vite】Error: Cannot find module @rollup/rollup-linux-arm64-gnu エラーについて📝

ピン留めされたアイテム
まさぴょん🐱まさぴょん🐱

原因と解決策📝

該当のDockerfile

FROM node:22-bookworm-slim

RUN npm install -g pnpm

# コンテナ内の作業ディレクトリを/app/frontendに設定
WORKDIR /app/frontend

# 依存関係をコピーしてインストール
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile

# docker-compose.yml でボリュームマッピングしているので、ソースコードのCopyはしない。

# フロントエンドのポートを設定
EXPOSE 3222

# 開発サーバー: 0.0.0.0ホストで公開することで、コンテナ外からもアクセスできるようにする。
CMD ["pnpm", "run", "dev", "--", "--host", "0.0.0.0"]

原因

  1. Rollup v4 から「ネイティブ実行ファイル」を同梱した構成に変わり、
    実行時に OS/CPU ごとに用意されたパッケージ
    @rollup/rollup-<platform>-<arch>-<libc>require() します。
  2. コンテナは Apple Silicon(arm64) 上で動く Debian Linux なので
    Rollup は @rollup/rollup-linux-arm64-gnu を読みに行きます。
  3. ところが Node v22 用にビルドされた arm64 向けバイナリはまだ公開されておらず、
    pnpm install 時に optionalDependencies のインストールが失敗 →
    モジュールが置かれない → 実行時に “Cannot find module …” で落ちます。

解決策(どれか 1 つで OK)

A. LTS 版 Node に戻す(最も簡単・推奨)

# frontend/Dockerfile
- FROM node:22-bookworm-slim
+ FROM node:20-bookworm-slim   # あるいは 18

20LTS ならバイナリが配布されているので自動で解決します。

B. ネイティブではなく WASM 版 Rollup を強制使用する
package.json に override/resolution を追加して再インストールします。

• pnpm の場合

{
  "pnpm": {
    "overrides": {
      "rollup": "npm:@rollup/wasm-node"
    }
  }
}

• npm の場合

{
  "overrides": {
    "rollup": "npm:@rollup/wasm-node"
  }
}

• Yarn の場合

{
  "resolutions": {
    "rollup": "npm:@rollup/wasm-node@*"
  }
}

その後 pnpm install --frozen-lockfile(または npm/yarn)をやり直します。
※ WASM 版はビルド速度が若干遅くなります。

C. 該当バイナリが公開されるまで待つ
将来 Rollup 側で Node 22 用の arm64 バイナリが公開されれば何もしなくても動きます。

まとめ

今回のエラーは「Node 22 + arm64 用 Rollup ネイティブバイナリがまだ無い」ことが原因です。
LTS 版 Node に戻すか、@rollup/wasm-node を使うことで解消できます。

まさぴょん🐱まさぴょん🐱

@rollup/rollup-linux-x64-gnuと、@rollup/rollup-linux-arm64-gnuの違いは?

概要

@rollup/rollup-linux-x64-gnu@rollup/rollup-linux-arm64-gnuRollup 4 系が内部で使う Rust/N-API ネイティブバイナリ を、
それぞれ x86-64 (AMD/Intel) 向けARM64 (AArch64) 向け にビルドして単体パッケージ化したものです。
どちらも GNU libc(glibc)環境の Linux で動く点は同じですが、CPU の命令セットが違うため互換性はありません。
したがって 実行するコンテナ/サーバの CPU アーキテクチャに合わせて npm か pnpm が自動的に片方だけを optionalDependencies として解凍して使います。


パッケージごとの概要

パッケージ名 内包バイナリ (canonical triplet) 対応 CPU 典型的な動作環境
@rollup/rollup-linux-x64-gnu x86_64-unknown-linux-gnu x86-64/AMD64 Intel/AMD サーバ、GitHub Actions (ubuntu-latest) 等
@rollup/rollup-linux-arm64-gnu aarch64-unknown-linux-gnu ARM64 Raspberry Pi 5、AWS Graviton、Apple Silicon Linux VM など

引用: readme に “This is the x86_64-unknown-linux-gnu binary” / “This is the aarch64-unknown-linux-gnu binary” と明記 (npm, npm)


なぜ 2 種類あるのか

CPU アーキテクチャのちがい

  • x86-64 (AMD64) - CISC 系。Intel/AMD PC や多くのクラウド VM で標準 (Stack Overflow)
  • ARM64 (AArch64) - RISC 系。省電力で、スマホ・Apple M シリーズ・Graviton などサーバでも普及 (Medium)

GCC などツールチェインが出力するターゲット三つ組 “x86_64-unknown-linux-gnu / aarch64-unknown-linux-gnu” は、
「CPU – ベンダ – OS/ABI」を表します (Unix & Linux Stack Exchange, GCC)。

Rollup 4 のネイティブバイナリ

Rollup 4 では plug-in ローダや minify の一部を Rust で実装し、N-API 共有ライブラリ (.node) を各プラットフォームごとに事前ビルドして NPM 配布しています。
npm/pnpm はインストール時に optionalDependencies から自環境に合うものだけ解凍し、残りは無視します。
この仕組みが壊れると “Cannot find module @rollup/rollup-linux-x64-gnu” エラーになります (GitHub, GitHub, Stack Overflow, Stack Overflow)。


どちらを使えば良いか

利用シーン 推奨パッケージ
AMD/Intel 系 Linux (Ubuntu, Debian, CentOS, Alpine-glibc 等) @rollup/rollup-linux-x64-gnu
ARM64 系 Linux (Amazon Graviton, Raspberry Pi OS 64-bit, Ubuntu arm64 など) @rollup/rollup-linux-arm64-gnu

通常は手動で意識する必要はありません。
ただし Docker マルチプラットフォーム buildCI/CD で lockfile を持ち回す 場合、npm i --ignore-scripts && npm rebuild もしくは
pnpm install --shamefully-hoist で各環境ごとに再解決させるとエラーを回避できます (GitHub, GitHub)。


MUSL 版との違いに注意

Rollup には *-musl 版も存在します。これは Alpine Linux のように musl libc を使うディストリ向けで、glibc 前提の *-gnu バイナリとは ABI が互換しません。
Alpine で glibc を入れていない場合は @rollup/rollup-linux-x64-musl / -arm64-musl を選択してください (Stack Overflow)。


まとめ

  • 違いは CPU 命令セットのみ。両者とも glibc ベースの Linux 用ネイティブバイナリ。
  • npm/pnpm が自動で選択するので、通常は lockfile を正しく運用していれば意識不要。
  • “Cannot find module …-gnu” エラーはローカルと CI のアーキテクチャ不一致や lockfile 共有が原因。npm ci か環境別 lockfile を推奨。

これで用途に応じてどちらを選べばよいか判断できるはずです。

まさぴょん🐱まさぴょん🐱

pnpmで、optionalDependenciesとして両方追加すべきか?

最初に結論だけ — pnpm ならふつうは両方を optionalDependencies に手動追加する必要はありません
ただし ①“別アーキテクチャの node_modules をコピー/ボリューム共有する”
②“CI で 1 つの lockfile を x64 と arm64 の両方で再利用する” といった特殊なワークフローでは、ワークアラウンドとして

"optionalDependencies": {
  "@rollup/rollup-linux-x64-gnu": "^4.40.0",
  "@rollup/rollup-linux-arm64-gnu": "^4.40.0"
}

のように 両方書く方法も有効です。その場合は容量増とアップデート手間を覚悟してください。代わりに pnpm 9 以降の supportedArchitectures 機能を使うと自動で必要なバイナリだけ拾わせることができます(推奨)。以下で詳しく説明します。


1. エラーの原因

  • Rollup v4 以降は Rust 製ネイティブバイナリ(.node)をアーキテクチャ別 npm パッケージに切り出しています(GitHub)。

  • @rollup/rollup-linux-*Rollup 本体の optionalDependencies として宣言されており、npm / pnpm はインストール時に自分の CPU & OS に合うものだけを解凍する設計です(UNPKG)。

  • ところが lockfile 付きで別アーキテクチャに移動したり、Docker でホスト側 node_modules をマウントしたりすると、実行時に存在しないバイナリを探しに行って

    Error: Cannot find module @rollup/rollup-linux-arm64-gnu.
    npm has a bug related to optional dependencies …
    

    が発生します(GitHub)。

  • 上流 npm の既知バグ (#4828) で optionalDependencies が lockfile に固定されてしまうことも根本要因の一つです(GitHub)。


2. pnpm でのベストプラクティス

2-1. supportedArchitectures で解決(推奨)

pnpm v8+ には 複数アーキテクチャ向けに optionalDeps を追加インストールさせる公式設定があります(pnpm.io, pnpm.io)。

# pnpm-workspace.yaml 例
supportedArchitectures:
  os: [current, linux]   # 今動いている OS と Linux を対象に
  cpu: [x64, arm64]      # x64 も arm64 も入れる

これで lockfile はそのままに、必要なバイナリ両方をキャッシュできるため、
CI や Docker マルチプラットフォーム build での「無いモジュール」エラーを防げます。

2-2. optionalDependencies に手動で書く方法(暫定ワークアラウンド)

Netlify/GitHub Actions などでは

"optionalDependencies": {
  "@rollup/rollup-linux-x64-gnu": "4.9.5"   // あるいは arm64 版も
}

を追記している事例が多数報告されています(GitHub, Netlify Support Forums)。
pnpm でも動きますが

  • どのバージョンを pin するかを手動管理する必要がある
  • 使わないバイナリも常にダウンロードされてパッケージサイズが増える

といったデメリットがあります。

2-3. そもそも node_modules をコピーしない

Docker で多いのは ホスト側の node_modules をそのままマウントしているケースです(GitHub)。

  • .dockerignorenode_modules を除外する
  • イメージ内で pnpm install --frozen-lockfile を実行する
  • または名前付き volume を使い、ホストと分離する(Stack Overflow)

――といった対策でエラー自体が発生しなくなることが多いです。


3. マルチアーキテクチャ CI の具体例

# GitHub Actions
- name: Install deps (x64 runner)
  run: pnpm install --frozen-lockfile
- name: Build

# arm64 self-hosted runner でも同じ lockfile を使う場合
# supportedArchitectures を設定しておけば追加インストールなしで動く

Netlify/Vercel の Linux build だけ失敗する場合は
pnpm -r rebuildpnpm install --unsafe-perm を追加するだけで解決した報告もあります(Netlify Support Forums)。


4. まとめ

シナリオ 推奨対応
単一アーキテクチャ開発 > 単一アーキテクチャ本番 lockfile を維持し、環境ごとに pnpm install するだけで OK
x64↔arm64 を行き来する開発・CI supportedArchitectures を設定して pnpm に両方のバイナリを落とさせる
短期的な回避策が必要 optionalDependencies に必要な @rollup/rollup-linux-* を明示追加(サイズ増に注意)
Docker でホストの node_modules を共有 共有をやめ、コンテナ内で pnpm install/名前付き volume に切り替え

結論: ― pnpm を使っていて multi-arch が要件なら supportedArchitectures を推奨。どうしても lockfile をいじれない等の事情がある場合に限り、x64 と arm64 の両バイナリを optionalDependencies に手動で追加してください。