← ブログ一覧
サブ記事

Cloudflare WorkersではNode.jsが使えない——fs.readFileで即死した話

AstroサイトをCloudflare Pagesにデプロイしたら node:fs が動かなかった。原因と?rawを使った解決法を解説


登場人物

  • リナ社長 … 高校生なのに会社経営するやり手ギャル。テックにも強くてAI活用が得意。
  • タクヤ … 入社3年目の男性社員。真面目で少しだけコードが書ける。

今回は、Cloudflare Workersでfs.readFileが即死した事件から実行環境の前提を学ぶ回。


タクヤ「社長、Claudeにコード作ってもらったのに、デプロイしたら即エラーって何ですか」

リナ社長「あーそれ、Cloudflare Workersの罠にハマったやつじゃん。てか同じとこで詰まった人めちゃくちゃ多いと思う」

タクヤ「どういうことですか……?」


何が起きたのか

ミニロト解析ページでは、当選番号のCSVデータを読み込む必要があった。

最初にClaudeが生成したコードはこんな感じ:

import fs from 'node:fs';
import path from 'node:path';

const csv = fs.readFileSync(
  path.resolve('src/data/miniloto.csv'),
  'utf-8'
);

ローカルでは問題なく動いた。でもCloudflare Pagesにデプロイした瞬間、こうなった。

Error: No such module "node:fs"

タクヤ「え、fsって普通のNode.jsの機能ですよね?なんで動かないんですか」

リナ社長「そこ!Cloudflare Workersって実はNode.jsじゃないんだよね」


なぜ node:fs が動かないのか

Cloudflare Pagesの裏側で動いているのは Cloudflare Workers というランタイム。これはNode.jsではなく、V8エンジン直接で動くサンドボックス環境。

環境ランタイムnode:fs
ローカル (npm run dev)Node.js✅ 使える
Cloudflare PagesCloudflare Workers (V8)❌ 使えない

タクヤ「ローカルで動くのに本番で動かないのは最悪ですね……」

リナ社長「まじでね。でも解決策はシンプルだよ」


解決策:?raw インポートで直接読む

AstroにはViteの ?raw インポートという機能があって、ファイルの中身を文字列としてそのまま読み込める。これはビルド時に解決されるのでWorkersのランタイムに依存しない。

// ❌ Before(node:fsを使う方法)
import fs from 'node:fs';
const csv = fs.readFileSync('src/data/miniloto.csv', 'utf-8');

// ✅ After(?rawインポートを使う方法)
import rawCsv from '../data/miniloto.csv?raw';
const csv = rawCsv;

タクヤ?raw ってなんですか、初めて見ました」

リナ社長「Viteの機能でね、ファイルをそのまま文字列で取り込める。Astroの裏側はViteだから使えるんだよ」

タクヤ「ビルド時に解決されるってことは、Workersのランタイムに関係なくなるってことか」

リナ社長「そーそー。理解が早くなってきたじゃん」


fs以外にも:エッジランタイムで詰まりやすいNode API

タクヤnode:fs 以外にも、使えないやつってあるんですか?」

リナ社長「あるある。Cloudflare Workersに限らず、Vercel EdgeとかDeno Deployみたいな”エッジランタイム”は共通でNodeのネイティブAPIが制限されてるんだよね」

エッジランタイムは、各リクエストを軽量なV8アイソレートで動かすために、OSのファイルシステムやプロセスへの直接アクセスを持ちません。そのため、Node.js前提のコードは次のようなAPIで引っかかりがちです。

よく詰まるAPI代替
node:fs(ファイル読み込み)ビルド時の ?raw インポート、または R2 / KV などのストレージ
node:pathURL ベースの処理、文字列操作で代替
node:crypto の一部標準の Web Crypto API(crypto.subtle
process.env への依存プラットフォームのバインディング(env)経由で受け取る

タクヤ「Web標準のAPIに寄せておけば、どのエッジでも動きやすいってことですね」

リナ社長「そういうこと。Cloudflareには nodejs_compat フラグで一部のNode APIを使えるようにする逃げ道もあるけど、全部が埋まるわけじゃない。最初からWeb標準で書くのが一番ラクだよ」

ポイントは「ローカルのNode.jsで動く=本番でも動く」ではないこと。wrangler dev のように本番に近いランタイムでローカル確認すると、デプロイ前にこの手の差異に気づけます。


ポイントまとめ

リナ社長「今回の学びをまとめるとこれ」

  • Cloudflare Workers は Node.js ではないnode:fsnode:path は使えない
  • ローカルで動いてもデプロイで死ぬことがある → 環境の違いを最初から意識する
  • 静的ファイルは ?raw で読む → ビルド時に解決されるのでランタイムに影響しない

タクヤ「最初からこれ知ってたら詰まらなかったんですね」

リナ社長「そういうこと。だからClaudeに指示するときも”Cloudflare Workersで動かすこと・node:fsは使わないこと”って最初に伝えるのがコツ。制約を先に教えると正しいコードを出してくれる」


ミニロト解析ページ作成の全体まとめ記事に戻る

コメント