emahiro/b.log

Drastically Repeat Yourself !!!!

Nuxt3 で SSG ができるようになっていた

Overview

※ 筆者がたまたま Nuxt3 を弄っていて気づいた話なので最新の動向は GitHub の Discussion を追ってください。

github.com

Nuxt3 に移行を始めた当初は Nuxt3 が RC になったばかりで、Static Site Generator (SSG) が実装されていませんでしたが、先日 RC5 で試してみたら nuxt.config.js の defineNuxtConfigssr:false かつ target:static の状態でビルドができるようになっていましたので、自分のポートフォリオサイトでは SSR をやめて SSG に移行しました。

Context

あらためて調べてみると公式でも公開されてましたね(まだフルで実装はされていないっぽいです)

v3.nuxtjs.org

そもそも、元々自分が Hosting してるポートフォリオサイトは Firebase 上に構築しているのですが、Nuxt3 に移行したタイミングでは SSR モードでしかビルド & ホスティングができず、CloudFunctions のサービスを SSR 用のサーバーとして使う必要があり、Functions に実装していた固有の実装を諦めた、という背景がありました。

大したページでもなく、そもそも SSR が必要とされるユースケースはなかったので、いい機会だったので元々採用していた SSG モードにして、SSR モードのためだけに占有されていた Functions のリソース開放も兼ねて、ポートフォリオサイトのビルドを作り直しました。

SSG やってみた

公式で記載されている通り、SSG を利用するには defineNuxtConfig 内の ssr property を false に変更します。
※ nitro を使った prerender の実装についてはべっっと調べてみる予定です。

ssr: false にした状態で改めて nuxi build を実行すると以下のように .output 配下に html ファイルが作られるようになります(SSR モードの時はこれが作られませんでした)

Nuxt CLI v3.0.0-rc.5                                                                                                                                        02:20:51

 WARN  [kit] [compat] Using extendBuild in Nuxt 3 has no effect. Instead call extendWebpackConfig and extendViteConfig.                                     02:20:53

ℹ Vite client warmed up in 353ms                                                                                                                            02:20:53

 WARN                                                                                                                                                       02:20:54
(!) Some chunks are larger than 500 KiB after minification. Consider:
- Using dynamic import() to code-split the application
- Use build.rollupOptions.output.manualChunks to improve chunking: https://rollupjs.org/guide/en/#outputmanualchunks
- Adjust chunk size limit for this warning via build.chunkSizeWarningLimit.

ℹ Client built in 1325ms                                                                                                                                    02:20:54
ℹ Building server...                                                                                                                                        02:20:54
✔ Server built in 5ms                                                                                                                                       02:20:54
✔ Generated public .output/public                                                                                                                     nitro 02:20:55
ℹ Initializing prerenderer                                                                                                                            nitro 02:20:55

 WARN                                                                                                                                                       02:20:55
(!) Some chunks are larger than 500 KiB after minification. Consider:
- Using dynamic import() to code-split the application
- Use build.rollupOptions.output.manualChunks to improve chunking: https://rollupjs.org/guide/en/#outputmanualchunks
- Adjust chunk size limit for this warning via build.chunkSizeWarningLimit.

ℹ Prerendering 3 routes                                                                                                                               nitro 02:20:56
  ├─ / (2ms)                                                                                                                                          nitro 02:20:56
  ├─ /200 (1ms)                                                                                                                                       nitro 02:20:56
  ├─ /404 (0ms)                                                                                                                                       nitro 02:20:56
start Building server...                                                                                                                              nitro 02:20:56
start Writing server bundle...                                                                                                                        nitro 02:20:57
✔ Server built                                                                                                                                        nitro 02:20:57
  ├─ .output/server/package.json (307 B) (182 B gzip)
  ├─ .output/server/index.mjs (458 B) (257 B gzip)
  ├─ .output/server/chunks/nitro/node-server.mjs.map (57.5 kB) (4.4 kB gzip)
  ├─ .output/server/chunks/nitro/node-server.mjs (17.1 kB) (5.37 kB gzip)
  ├─ .output/server/chunks/handlers/renderer.mjs.map (15.6 kB) (2.74 kB gzip)
  ├─ .output/server/chunks/handlers/renderer.mjs (11.8 kB) (3.83 kB gzip)
  ├─ .output/server/chunks/app/client.manifest.mjs.map (825 B) (335 B gzip)
  └─ .output/server/chunks/app/client.manifest.mjs (833 B) (319 B gzip)

prerender 用の2つの html ファイルと server 用の成果物が生成されます。

SSR モードの時の成果物は以下で、HTML が生成されないので SSR と SSG では成果物が異なることがわかります。

Firebase を使っている場合、Hosting 先は .output/public 配下なので変わりませんが、SSG モードにすると index.html がそのままホスティングされます。
また Functions に SSR 用のサーバーを立ててそれ経由でしかホスティングされたサイトにアクセスできませんでしたが、HTML ファイルをポン置きするだけでホスティングできるようになったので Functions の役割は元に戻せます。

というわけで Hosting するものを html に変えて再度デプロイをしてみたところ普通 https://emahiro.dev/ にアクセスすることができました。(もうこれでいいじゃん)

Functions も役目を終えたので元に戻すために改めて firebase init functions を実行して Functions のファイルを生成しました。

あと変更してみて気づいたことですが、SSG にしてみて感じたのは表示速度が速くなっていました。
おそらく SSR モードの時は Functions を起動するまでの cold start 問題にぶち当たっていたと思われます。

余談

Functions deploy がこける問題

lint と build が predeploy で強制的にかかってしまう

firebase init functions を実行すると、firebase.json の設定も変更され predeploy で lint と build が実行されてしまいます。

// firebase.json

"functions": {
    "predeploy": [
      "npm --prefix \"$RESOURCE_DIR\" run lint" // default
      "npm --prefix \"$RESOURCE_DIR\" run build" //default
    ],
    "source": "functions"
}

local では source に指定した path を指定して lint & build をしてくれるのですが、lint は成果物となる js にもかかってしまうこと、そして actions では working directory の path の package.json が使われてしまっており、source フィールドの指定が効いてないなかったことが起因して、command not found が発生して actions から deploy ができなくなっていた問題がありました。

行った対応は以下3つです。

  1. .eslintignore にコンパイルされた js が入る lib directory を記載して lint 対象から外す。
  2. predeploy の設定を ignore。
  3. actions で functions directory に入った状態で lint & build をするように変更。