emahiro/b.log

Drastically Repeat Yourself !!!!

Nuxt2 ⇒ Nuxt3 に上げた話

Overview

タイトルの通りですが、Nuxt2 で書かれていた自分のポートフォリオサイト (emahiro.dev) を Nuxt3 に移行したのでその移行手順とハマったポイントについて記載します。

なおこのブログを書いている現在では Nuxt3 系はまだベータのままです。 (一応 RC にはなってるので現時点から大幅な破壊的変更が入ることは少ないと思われます)

また前提として自分は Nuxt2 系の最初のテンプレートの状態を少し変更したくらいのページ、つまり Plain な Nuxt のアプリケーションをアップデートしてるに過ぎず、実際には使っている依存の関係で一筋縄ではないかないケースがあるかと思います。

このエントリではあくまで Nuxt2 → Nuxt3 に Plain な状態でも上げるだけでいくつかつまづいたのでそのハマったポイントと解決策を備忘録として記載します。

準備

Nuxt2 系の最新まで上げる

まず最初に Nuxt2 系で書かれていたポートフォリオサイトを Nuxt2 の最新まで上げることにしました。

各種依存ライブラリを最新に上げる

Nuxt2 にあげたら次に npm audit fix して必要な各種依存のバージョンを上げます。

$ npm audit fix

まず Nuxt を最新にして依存周りも全部調整してビルドが通る状態にしてから Nuxt3 への移行を開始します。

Migration to Nuxt3

Nuxt2 → Nuxt3 への移行は 公式のマイグレーション手引き に従って作業を進めます。

Nuxt Bridge

まずは nuxt-bridge に移行します。これは Nuxt2 → 3 への架け橋的なポジションで公式のページには何がサポートされていて、何がサポートされてないのかのマトリクスがあります。

この Bridge の立ち位置はよくわからないんですが Nuxt2 系のエコシステムから Nuxt3 にすぐには移行できない理由があるケースにおいて、Nuxt2 系のコードをある程度残しつつ Nuxt3 の恩恵を受けるためのものなのかなと思いました。

そもそも SSG だったり、これは欲しいやろな〜と言った機能群については現時点ではまだ Nuxt3 においてサポートされてませんが、やはり Vue3 に対応した部分は使いたいと思われるのでそのために使われるものなのかなと考えています。

ただし、今後 Nuxt3 が正式リリースされた後にあった、どこまでこの Bridge がサポートされるのかわからなかったので、私は基本的には Bridge に上げた後、すぐに Nuxt3 の最新版にポートフォリオサイト全体を移行しました。

やり方はほとんど公式に書いてある通りなので詳細は割愛し、進める過程ではまったところをまとめます。

Named export 'isWindows' not found が発生する

https://github.com/nuxt/framework/issues/1697 に issue が上がっていたのでこちらを参考にしました。

これを解決するために set-env を追加します。

npm add -D set-env

ref: https://www.npmjs.com/package/std-env

これを install する際に core-js がないとエラーが発生したので、依存に追加します。

npm insatll --save core-js

core-js をインストール後にビルドができるようになっていればマイグレーション完了です。

Nitro サーバーが起動しない

Nuxt-Bridge の段階では SSG を使うことができ、ポートフォリオサイト自体も元々 SSG を使っていたので SSG を ON にしておきます。

import { defineNuxtConfig } from 'nuxt'
export default defineNuxtConfig({
  nitro: false,
  ssr: false,
    target: 'static',
})

ref: https://github.com/nuxt/bridge/issues/27

SSG を On にした状態でビルドが成功したら Nuxt-Bridge への移行が完了です。

Nuxt3

Nuxt3 の移行にするために Nuxt-Bridge を外して Nuxt3 に移行ます。

※ 既に 202207 時点で Nuxt3 は RC4 まで来ています。

手順としては https://www.npmjs.com/package/nuxt3 に書いてある通りに install し、nuxt-bridge を package.json から削除します。

Nitro を動かすには SSG モードを OFF にする

Nuxt3 はこのエントリを書いてる時点では SSG を正式にサポートしてません。そのため Nuxt3 でアプリケーションを起動するには SSG モードをオフにして SSR を強制的に使用するほかありません。

import { defineNuxtConfig } from 'nuxt'
export default defineNuxtConfig({
  nitro: true,
  ssr: true,
    // target: 'static',
})

SSR を強制されると言うことは、Nuxt3 で動いているアプリケーションを動かすためには、Node のランタイムがセットで必要になります。

これにより後述しますが、Firebase を動かす際に Firebase Functions をこの Node のランタイムで使用することになりますので、Firebase Functions で独自の実装だったり、API などを書いてるケースでは Functions を SSR ランタイムで占有されることになってしまいます。

Cannot start nuxt: Cannot find module '@nuxt/vite-builder' が出る

npm add -D @nuxt/vite-builder で vite-builder を追加する。

FontAwesome が動かない

※ 現時点での話になります。

元々ポートフォリオサイトでは FontAwesome を使用してましたが、この FontAwesome が原因で TypeError: Invalid value used as weak map key 発生しました。

調べると RC の状態でも FontAwesome を使うことができるやり方は見つかりましたが、結果として現時点では FontAwesome を使うことを諦めました。

https://zenn.dev/itsuo/articles/24e4f16eb0a190 あたりが参考になりましたが今無理して導入しなくてもいいかなと。

ちなみに公式でも Nuxt3 対応は進んでいるっぽいです → https://www.npmjs.com/package/@fortawesome/vue-fontawesome

FontAwesome を一時的に諦めたら Nuxt3 RC でもビルドが通るようにはなりました。

Nuxt3 のビルド方式に Firebase の設定を合わせる

Nuxt3 からはビルドの成果物置き場が変わります。

Nuxt2 ではビルドの成果物が dist というディレクトリになりましたが、Nuxt3 系では .output と言うディレクトリが成果物の置き場になります。

Firebase を使っている場合は、Hosting 対象を以下のように変更します。

"hosting": {
-    "public": "dist",
+    "public": ".output/public"
}

また SSR モードを ON にしている場合、Functions の src も .outout に出力される、SSR 用のディレクトリに変更します。

"functions": {
+    "runtime": "nodejs16"
+    "souce": ".output/server"
}

Firebase の対応

一部を上記の Bridge, Nuxt3RC 対応でも触れてはいますが、現状 Firebase に対応させようとすると現時点ではちょっとめんどくさいことが多いです。

特に現時点では SSG が Nuxt3 で対応していないために、Fuctions を SSR のランタイムとして動作せる必要があったりとちょっとばかり制限があるように感じます。(そんなことない、というマサカリは飛んできそうですがw)

本音を言えば簡易的なポートフォリオサイトなのであれば、HTML をそのまま出力してしまって Hosting にポン置きしたいなと考えています。

Firebase 本体にも issue としてはいくつか上がっておりこれから改善されることを期待して待っていたいと思います。

公式のビルドコマンドでは Firebase Deploy が通らない

これが一番困りました。現状 Firebase10.9 以上?だと nuxi build (*1) のみで生成した SSR のランタイムは動かないです(デプロイ時に転けます)

*1.nuxi は Nuxt3 用のコマンド

issue としては以下が上がっていました。

これの具体的なワークアラウンドとしては Nuxt3 の SSR で利用されている Nitro サーバー向けにビルドをする、というものがあります。

issue には具体的に以下のようなビルドコマンドが記載されていましたのでこれをそのまま叩くと手元から Firebase Deploy が通るようになります。

NITRO_PRESET=firebase nuxi build

ただしこれだけだと Functions のデプロイはまだうまくいきませんでした。

Functions のビルド結果が入っている .output/server 内部の package.json をベースに node_modules をインストールしておくことが必要でした。

このため、package.json には firebase 向けに以下のように Firebase 向けの script を用意しました。

"scripts": {
+    "fb:build": "NITRO_PRESET=firebase nuxi build",
+    "fb:start": "NITRO_PRESET=firebase nuxi build && firebase emulators:start",
+    "fb:clean": "cd .output/server && rm -rf node_modules && npm i && cd ../../"
}

Actions の設定は以下のようにしました。

steps:
   - name: Checkout Repo
     uses: actions/checkout@master
 
   - name: Setup Node
     uses: actions/setup-node@v3
     with:
       node-version: ${{ matrix.node }}
 
   - name: Install Dependencies
     run: npm install
 
   - name: Build for firebase
     run: NITRO_PRESET=firebase npm run build
 
   - name: Clean for firebase
     run: |
       cd .output/server
       rm -rf node_modules
       npm i
       cd ../../
 
   - name: Deploy to Firebase
     uses: w9jds/firebase-action@master
     with:
       args: deploy
     env:
       FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}

See Also

zenn.dev