「Vike」って知っていますか?
Vikeは、ViteをベースにSSRやSSGなどのレンダリング方法を選べるようにするフレームワークです。Reactだけに限らず使えますが、Reactを使う場合は公式の vike-react を組み合わせます。
もともとはViteのプラグイン vite-plugin-ssr として知られていたものが、現在のVikeにつながっています。「Vikeの意味」や「ViteとVikeの違い」を調べている場合は、Viteがビルドツール、Vikeがその上でルーティングやSSR・SSGを扱うためのフレームワーク、と考えると分かりやすいです。
Viteが開発・ビルドの土台で、VikeがルーティングやSSR・SSGを担当します。Reactで使うときは、vike-react を組み合わせてページの描画を構成します。
Vite × ReactでSSGを使いたいと思って探していたところ見つけたのですが、動的ルートのSSGで少しだけハマったので、現行仕様を確認しながらまとめ直しました。
公式ドキュメントは以下です。
VikeでSSGするための基本設定
SSGは、ビルド時にHTMLを生成しておく方式です。Vikeでは、現在は vite.config.js のプラグインにSSG用のオプションを渡すのではなく、ページ側の + ファイルで設定します。
まず、vite.config.js のVikeプラグインは次のように読み込みます。
import vike from 'vike/plugin'
export default {
plugins: [vike()]
}SSGの設定は、ページディレクトリの +config.js に書きます。
export default {
prerender: true
}そのうえで vike build を実行すると、対象ページのHTMLがビルド時に生成されます。生成先は通常 dist/client/ です。
古い記事やサンプルで見かける vite.config.js 側のSSG設定ではなく、現行の公式案内では +config.js などの + ファイルにVikeの設定を置く 形が基本です。
参考
Vike公式:Pre-rendering
Vike公式:Vite plugin
Vike公式:設定ファイルの移行
ReactアプリでVikeを使う
既存のVikeアプリにReactを追加する場合は、公式の vike-react をインストールします。
npm install vike-reactそして pages/+config.js でReactの設定を拡張します。
import vikeReact from 'vike-react/config'
export default {
prerender: true,
extends: [vikeReact]
}ページのコンポーネントは、例えば次のように +Page.jsx に作成します。
export default function Page() {
return <h1>Vike + React</h1>
}動的ルートをSSGさせる
ただ、これだけでは /category/@slug のような動的ルートの全ページを自動で生成できません。
動的ルートをSSGするには、ビルドプロセスの中でVike側に生成対象のURL一覧を渡します。
そのために onBeforePrerenderStart() というフックを使います。名前の通り、プリレンダリングの前に実行されるフックです。
このフックが実行されるのは、基本的に vike build でプリレンダリングするときです。開発中の vike dev では実行されないので、動的ページのURL一覧を確認するときはビルド時のログを確認します。
export default '/movie/@movieId'export { onBeforePrerenderStart }
async function onBeforePrerenderStart() {
const movies = await Movie.findAll()
const moviePageURLs = movies.map(movie => '/movie/' + movie.id)
return moviePageURLs
}生成したいパスを配列に詰めて返しているだけですね。
実際のコードに当てはめてみた
今回作成していたサイトには /category/@slug という動的ルートがありました。例えば、カテゴリ一覧からURLを作るなら次のようになります。
export default '/category/@slug'export { onBeforePrerenderStart }
import { categories } from '../../../constants'
async function onBeforePrerenderStart() {
const categoryPageURLs = categories.map(
category => '/category/' + category.slug
)
// 同じURLを複数回返さない
return [...new Set(categoryPageURLs)]
}エラーが発生する
ここで少しハマりました。ドキュメントの通りにファイルを作成したのですが、次のようなエラーが出ました。
Error: [vike][Wrong Usage] URL /category/work provided twice by the onBeforePrerenderStart() hook (/pages/category/+onBeforePrerenderStart.ts). Make sure to provide the URL only once instead.同じURLが複数出ているので、1回だけ返してほしいという意味です。カテゴリの元データに同じslugが含まれていたり、複数の処理で同じURLを追加していたりすると発生します。
まずは onBeforePrerenderStart() が返す配列を確認して、重複を取り除きます。上の例では Set を使っています。
また、次の点も確認します。
- +route.js で定義しているパスと、返しているURLの形が一致しているか
- 同じ動的ルートを別の場所でも定義していないか
- categories の中に同じ slug が入っていないか
解決方法
今回の構成では、次のように index ディレクトリの中へファイルを移動することで解決しました。
/category/+route.js
/category/+onBeforePrerenderStart.js
↓
/category/index/+route.js
/category/index/+onBeforePrerenderStart.jsこのように index というディレクトリを作ってその中に入れる方法です。
これはすべての重複URLエラーに効く万能な解決方法ではありません。まず返却URLの重複とルート定義を確認し、それでもルートの解釈が意図と違う場合にディレクトリ構成を見直す、という順番がよさそうです。
Vikeの公式リポジトリには、動的ルートを含むサンプルもあります。実際のプロジェクトの構成と見比べると、+route.js や +onBeforePrerenderStart.js の配置を考えるときの参考になります。
ビルド前後に確認すること
動的ルートを追加したら、次の順番で確認します。
- onBeforePrerenderStart() が返すURLをログに出す
- 同じURLがないことを確認する
- vike build を実行する
- dist/client/ に期待するHTMLが生成されているか確認する
- 本番相当の環境で、一覧ページと動的ページのリンクを確認する
SSGはビルド時にHTMLを生成するため、データを追加しただけでは公開済みのHTMLは変わりません。カテゴリなどのデータを更新した場合は、改めてビルドとデプロイが必要です。
最後に
今回はVikeとは何か、ReactアプリでSSGする基本設定、動的ルートを事前生成する方法をまとめました。
以前の記事では vite.config.js にSSGの設定を書いていましたが、現在は pages/+config.js に prerender: true を設定する形が基本です。Vikeや関連パッケージを更新するときは、プロジェクトのバージョンと公式ドキュメントを合わせて確認するのが安全です。
今回も動的ルートで少しハマりました。SSGさせる方法というより、どちらかというとエラー解決記事になっていますね。
VikeはSSRとSSGを同じプロジェクトで扱えるところが便利なので、次はデータ取得やSSRとの使い分けも試してみたいです。
スポンサーリンク
