【Nuxt3 × SPA】既存のプロジェクトをNuxt3へアップデートする
Nuxt3へのアップデートをハンズオン形式で説明しています。破壊的変更がこんもりとあるNuxt3ですが、ちょうど最小構成のプロジェクトがあるので対応してみました。
前提
- node v18.0.0
- ※ 前回の動作環境を引き継いで進めていきます。
あまり影響無さそうな細かいことは割愛しているので、必要あれば変更箇所をご覧ください。
構成を変えていく
詳細に説明するとクソ長くなりそうなので、前回からの変更分だけを抜粋して説明していきます。
公式のコマンド
Nuxt3へのアップデート
$ npx nuxi upgrade
Need to install the following packages:
nuxi@3.5.1
Ok to proceed? (y) y
いろいろ削除
package.jsonがごっそりと変わるので、既存のパッケージを削除していきます。
$ rm -rf node_modules
$ rm -rf yarn.lock
ついでにYarnのキャッシュを抹消しておく
$ yarn cache clean --force
旧バージョンに依存したファイルやディレクトリを削除
$ rm -rf types/
$ rm -rf store/
$ rm -rf layouts/error.vue
$ rm -rf plugins/firebase.ts
$ rm jsconfig.json
$ rm nuxt.config.js
書き換える
Nuxt3は破壊的アップデートが多いため、書き換えなければBuildも通らない…のようなやばい対応箇所が多いです。
小規模プロジェクトでも、作り直した方が早いんじゃないかというくらいに結構カロリーを使います。
- package.json
- firebase.json
- tsconfig.json
- pages/index.vue
package.json
dependenciesとdevDependenciesの不用なモジュールを入れ替える
{
"name": "firebase-study",
"version": "1.0.0",
"private": true,
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare"
},
// ここから
"dependencies": {
"firebase": "^9.22.1",
"nuxt": "^3.5.1",
"vuetify": "^3.3.1"
},
"devDependencies": {
"@mdi/font": "^7.2.96",
"firebase-tools": "^12.2.1",
"sass": "^1.62.1"
}
}
firebase.json
Nuxt3へのアップデートにより、Nitro Engine
という新しいサーバーエンジンが搭載されるようになりました。
Nitro(ナイトロ)の旨みは他記事でもさんざん説明されているようですが、簡潔にどんなものか。
- 軽量
- ServiceWorkerでの動作
- サーバーレス環境での動作
- ホットリロードの高速化
開発環境が快適になるのはとっても嬉しい。
{
"hosting": {
"public": ".output/public",
"ignore": [
"firebase.json",
"**/.*"
]
}
}
tsconfig.json
今回から、Nuxt3側で生成してくれているみたいなので、そちらを参照していきます。
とってもすっきりしました。嬉しい。
※ パフォーマンス上の理由から、nuxi build
時に、型をチェックしていないようです
{
"extends": "./.nuxt/tsconfig.json"
}
pages/index.vue
こちらが変更点です。
setup構文については公式が一番わかりやすいです。
変数 colorSwitch
のみ動的な変更があるので ref
にしています。
ref
やreactive
など、動的変更があるもの、無いもので分けることにもパフォーマンスへの影響があるようです。
コード量が減る代わりに、意識することは増えそう。
<template>
<div>
<v-container>
<v-card :style="colorSwitch === 'cool' ? coolColor : cuteColor" class="color-pallet">
<v-card-text v-html="richText"/>
<v-card-actions>
<v-btn color="#08ffc8" @click="colorSwitch='cool'">クール系</v-btn>
<v-btn color="#ffb6b9" @click="colorSwitch='cute'">かわいい系</v-btn>
</v-card-actions>
</v-card>
</v-container>
</div>
</template>
<script setup lang="ts">
type ColorType = {
"--color-h1": string
"--color-h2": string
"--color-h3": string
"--color-back": string
}
const coolColor: ColorType = {
"--color-h1": '#08ffc8',
"--color-h2": '#fff7f7',
"--color-h3": '#dadada',
"--color-back": '#204969'
}
const cuteColor: ColorType = {
"--color-h1": '#ffb6b9',
"--color-h2": '#fae3d9',
"--color-h3": '#bbded6',
"--color-back": '#8ac6d1'
}
const colorSwitch = ref<'cool' | 'cute'>('cool')
const richText: string = `<h1>h1タグだよ</h1><p>こんにちは、h1タグです。</p><h2>h2タグだよ</h2><p>こんにちは、h2タグです。</p><h3>h3タグだよ</h3><p>こんにちは、h3タグです。</p>`
</script>
<style lang="sass">
.color-pallet
h1
background: var(--color-h1)
h2
background: var(--color-h2)
h3
background: var(--color-h3)
p
color: var(--color-back)
</style>
いろいろ追加する
nuxt3に対応したファイルを追加していきます。
pluginsディレクトリ内のファイル名にサフィックスをつけることで、クライアントサイドもしくはサーバーサイドどちらでロードするかを指定できます。
いままで process.browser
などで分けていましたが、若干きもかったので嬉しい。
$ touch app.vue
$ touch nuxt.config.ts
$ touch plugins/firebase.client.ts
$ touch plugins/vuetify.ts
app.vue
layouts
内の各コンポーネントを適用させるため、app.vueで記述していきます。
<template>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>
nuxt.config.ts
がっつり書き変わってますが、記述量はだいぶ減りました。
環境変数の呼び出し方は以下のとおりです。
const { apiKey, authDomain } = useRuntimeConfig().public
// もしくは
useRuntimeConfig().public.apiKey
変更後↓
export default defineNuxtConfig({
ssr: false,
build: {
transpile: ["vuetify"]
},
runtimeConfig: {
public: {
apiKey: process.env.FB_API_KEY,
authDomain: process.env.FB_PROJECT_ID + '.firebaseapp.com',
projectId: process.env.FB_PROJECT_ID,
storageBucket: process.env.FB_PROJECT_ID + '.appspot.com',
messagingSenderId: process.env.FB_MESSAGING_SENDER_ID,
appId: process.env.FB_APP_ID,
}
},
app: {
head: {
titleTemplate: '%s - firebase-study',
title: 'firebase-study',
htmlAttrs: {
lang: 'en'
},
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ name: 'description', content: '' },
{ name: 'format-detection', content: 'telephone=no' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
}
}
})
firebase.client.ts
今回はSPAなので関係ありませんが、SSRもしくはSSGにてFirebase Authentication
を利用すると、ちょっとめんどくさいので注意が必要です。
import { FirebaseApp, getApp, getApps, initializeApp } from 'firebase/app'
export default defineNuxtPlugin(() => {
const config = useRuntimeConfig().public;
const firebaseConfig = {
apiKey: config.apiKey,
authDomain: config.authDomain,
databaseURL: config.databaseURL,
projectId: config.projectId,
storageBucket: config.storageBucket,
messagingSenderId: config.messagingSenderId,
appId: config.appId,
measurementId: config.measurementId
};
const firebaseApp: FirebaseApp = !getApps().length ? initializeApp(firebaseConfig) : getApp();
return {
provide: {
firebase: firebaseApp,
}
}
});
vuetify.ts
コンポーネントのデフォルト設定などもここでできるようですが、今回は割愛します。
※ 今後書いていくつもり
import { createVuetify, IconOptions } from "vuetify";
import * as directives from "vuetify/directives";
import { aliases, mdi } from 'vuetify/iconsets/mdi'
import * as components from 'vuetify/components'
export default defineNuxtPlugin((nuxtApp) => {
const icons: IconOptions = {
defaultSet: 'mdi',
aliases,
sets: {
mdi
}
}
const vuetify = createVuetify({
icons: icons,
components,
directives
});
nuxtApp.vueApp.use(vuetify);
});
静的ファイルの設置
nuxt3へのアップデートにより、今までのstaticディレクトリを認識しなくなりました。
かわりに静的ファイルはpublicディレクトリへ移行することになります。
EOL
私の契約している会社でも慌ただしくNuxt3移行を行なっております。
加えてEOLがありました。
2023年5月22日 時点の発表によると、EOLは2023年中のようです。
この規模のアップデートを大規模プロジェクトで行うのは、ちょっと震えますね。
死人が出そうです。
Nuxt 2 will reach End of Life (EOL) on December 31st, 2023 at the same time as Vue 2 does. All supported versions should run on all currently supported Node.js releases.
共有
【今回の作業ブランチ】
https://github.com/yutahhh/firebase-study/tree/feature/%235
【Hosting】
https://fir-study-42747.web.app/
実際、middlewareやcomposablesなど、説明しきれていない箇所はまだあるので、追々別記事にてアウトプットしていこうかと思います。
お疲れ様でした。