1. 結論(この記事で得られること)
Nuxt3への移行中、「なんでbuildだけ落ちるの?」って経験、ありませんか?私も3年前、初めてNuxt3に触れたとき同じ壁にぶつかりました。
この記事で得られる具体的な成果:
- Vue2依存ライブラリが原因のbuildエラーを30分以内に特定・解決できる
- 「transpile」、「alias」、「vite.optimizeDeps」の使い分けが実務レベルで判断できる
- AIを使った切り分けフローで、属人化しない調査プロセスが作れる
- 本番デプロイ前のテスト戦略まで実装できる
結論から言うと、「エラーログを読む → 依存関係を可視化 → 段階的にtranspile → 最終手段はalias」 この順序を守れば、ほぼ確実に解決できます。
2. 前提(環境・読者層)
想定読者
- Nuxt3移行プロジェクトにアサインされたエンジニア
- Vue2ライブラリを使い続けたいが、buildエラーで詰まっている方
- 「動くけど本番ビルドで落ちる」謎現象に悩んでいる方
前提環境
{
"nuxt": "^3.10.0",
"vue": "^3.4.0",
"node": ">=18.0.0"
}
よくある症状
[vite] Internal server error: Failed to parse source
[nuxt] [request error] export 'default' (imported as 'LibraryName') was not found
ERROR [nuxt] [request error] Cannot use import statement outside a module
dev環境では動くのに、「npm run build」や「npm run generate」だけ落ちる——これ、Vue2系ライブラリのCommonJS/ESM混在が原因です。
3. Before:よくあるつまずきポイント
3-1. 「devは動くのにbuildだけ落ちる」の正体
昔の私がハマったのがこれでした。開発中は問題なく動くのに、本番ビルドで急に:
✖ [ERROR] Could not resolve "vue-awesome-swiper"
原因は明白でした:
- Viteの開発サーバー:緩めのモジュール解決(CommonJSも動的に変換)
- 本番ビルド(Rollup):厳密なESM前提(Vue3互換性チェックが入る)
3-2. よくある誤った対処
❌ やりがちな失敗例
// nuxt.config.ts
export default defineNuxtConfig({
// 全部transpileすればいいでしょ?(←重い&副作用あり)
build: {
transpile: [/.*/]
}
})
これやると、全nodeモジュールがbabel変換対象になってビルド時間が10倍になります。私は初回これで30分待ちました…。
3-3. エラーメッセージの読み間違い
[vite] Named export 'VueAwesomeSwiper' not found.
このエラー、実は「VueAwesomeSwiper」自体の問題じゃなくて、その奥にある「swiper」(Vue2版)が問題だったりします。
4. After:基本的な解決パターン
4-1. まずは依存関係の可視化
# package.jsonから実際の依存を確認
npm ls vue-awesome-swiper
npm ls swiper
# node_modules内の実体を確認
cat node_modules/vue-awesome-swiper/package.json | grep '"main"\|"module"\|"exports"'
判断基準:
- 「"main": "dist/index.cjs"」 → CommonJS(transpile必要)
- 「"module": "dist/index.mjs"」 → ESM対応(基本OK)
- 「peerDependencies」に「vue: ^2.x」 → Vue2専用(要注意)
4-2. 段階的transpile戦略
// nuxt.config.ts
export default defineNuxtConfig({
build: {
transpile: [
// Step1: エラーが出たライブラリだけ
'vue-awesome-swiper',
// Step2: その依存も追加(ログを見て判断)
'swiper/vue',
// Step3: 正規表現で関連パッケージをまとめて
/^@company\/legacy-.*/
]
}
})
4-3. vite.optimizeDepsとの使い分け
export default defineNuxtConfig({
vite: {
optimizeDeps: {
// SSR時はスキップしたいライブラリ(DOMアクセスするやつ)
exclude: ['vue-awesome-swiper'],
// 事前バンドルで高速化したいもの
include: ['lodash-es', 'dayjs']
}
},
build: {
// buildエラーが出たら、こっちにも追加
transpile: ['vue-awesome-swiper']
}
})
実務での使い分けルール:
- 「optimizeDeps.exclude」:SSR非対応ライブラリ(window使うやつ)
- 「transpile」:Vue2/CommonJSなライブラリ
- 両方必要な場合もある(後述の詳細実装で解説)
4-4. 緊急時のalias回避策
export default defineNuxtConfig({
alias: {
// Vue2版を無理やりVue3互換版に差し替え
'vue-awesome-swiper': 'swiper/vue',
// CommonJS版を避けてESM版を直接指定
'old-library': 'old-library/dist/index.mjs'
}
})
ただし、これは最終手段です。型定義がズレたり、APIが違ったりするので、本来は依存ライブラリ自体をVue3対応版に更新すべき。