FontAwesome v7 + ES Modules 互換性問題の解決
Claude 4 Sonnet.icon
問題の概要
FontAwesome v7 に更新すると、Vitest/CI環境で以下のエラーが発生:
code:_
TypeError: Module ".../@fortawesome/fontawesome-svg-core/package.json" needs an import attribute of "type: json"
根本原因
ESMは JavaScript の標準的なモジュールシステムで、従来の CommonJS より厳格なルールを持つ。 code:javascript
// 昔の書き方(CommonJS)
const config = require('./config.json'); // 何でも読める
// ES Modules(Node.js v17.5以降)
import config from './config.json' with { type: 'json' }; // JSON には型指定が必要
FontAwesome v7 での問題
1. v6時代: CommonJS ベースで問題なし
2. v7移行: ES Modules 対応したが...
3. 内部JSON読み込み: package.json を読む処理で型指定が不完全
4. Node.js厳格化: JSON import に with { type: 'json' } が必要
5. FontAwesome未対応: ライブラリ側でまだ修正されていない
問題の発生パターン
code:javascript
// FontAwesome 内部で(おそらく)このようなコードが存在
import packageInfo from './package.json'; // ❌ エラー!
// 本来必要な書き方
import packageInfo from './package.json' with { type: 'json' }; // ✅
解決策:noExternal 設定
修正内容
code:typescript
// vitest.config.ts
export default defineConfig({
ssr: {
// TODO: Remove when FontAwesome v7 fixes JSON import assertions
noExternal: [
'@fortawesome/fontawesome-svg-core',
'@fortawesome/free-solid-svg-icons',
'@fortawesome/react-fontawesome'
],
},
// ...
})
なぜこれで解決するか
通常の処理フロー(external)
code:_
1. あなたのコード: import { FontAwesome } from '@fortawesome/react-fontawesome'
2. Node.js: 「外部パッケージを読み込もう」
3. FontAwesome内部: import pkg from './package.json' // ❌ ここでエラー!
4. Node.js: 「JSONには with { type: 'json' } が必要だ!」→ 停止
noExternal 設定後の処理フロー
code:_
ビルド時:
1. Vite が FontAwesome のソースコードを読み取り
2. Vite が import の問題を解決(Vite独自の仕組みで)
3. 解決済みのコードを一つのバンドルファイルに出力
実行時:
1. Node.js は完成済みのバンドルファイルのみを実行
2. もう JSON import の問題のあるコードは存在しない
鍵となるポイント: Node.js がチェックする時点では、Vite によって問題が解決済みのコードのみが存在する。
技術負債の観点
短期的影響
✅ 問題の即座の解決
✅ 一般的な回避策(多くのViteプロジェクトで使用)
❌ バンドルサイズの微増
長期的考慮事項
FontAwesome 側での修正が期待される
修正後は設定を削除可能
コメントで将来対応を明記することを推奨
なぜ全て noExternal にしないか
table:_
方式 バンドルサイズ ビルド速度 キャッシュ効率
External(通常) 小(100KB) 高速(5秒) 高効率
noExternal(全込み) 大(2MB) 低速(30秒) 低効率
最適解: 問題のあるライブラリのみピンポイントで noExternal 設定
結論
この修正は FontAwesome v7 の ES Modules 互換性問題に対する 必要最小限の一時的措置 です。ライブラリ側での修正を待ちながら、現在のプロジェクトを動作させるための適切な対応と言えます。