Viteは高速ビルドツールですが、様々なプラグインが開発されており、その中にはVueを静的なHTMLへ出力してくれる(つまり、SSGしてくれる)ものがあったので、試してみました。
プラグインは、 vite-ssg を使います。
ドキュメント記載の通り、インストールして、セットアップします。
注意すべき点としては、createAppではなく、ViteSSGを使うこと。
// src/main.ts
import { ViteSSG } from 'vite-ssg'
import App from './App.vue'
+ // `export const createApp` is required instead of the original `createApp(App).mount('#app')`
+ export const createApp = ViteSSG(
+ // the root component
+ App,
+ // vue-router options
+ { routes },
+ // function to have custom setups
+ ({ app, router, routes, isClient, initialState }) => {
+ // install plugins etc.
+ }
+ )
また、 vue-ssg のドキュメントで、 vue-router をインストールしていることから、ルーティングはvue-routerを使います。
createRouter() して、ルーティング情報を書いても良いのですが、ここでも vite-plugin-pagesというプラグインを使うと便利でした。
これをインストールことで、 src/pages 配下にvueファイルを配置すれば、よしなにルーティングしてくれます。
vite.config.ts に Pages() を追加します。
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import Pages from 'vite-plugin-pages'
export default defineConfig({
plugins: [
vue(),
+ Pages(),
]
})
TypeScriptの場合はtypesも追加しておきましょう。
// tsconfig.json
{
"compilerOptions": {
+ "types": [
+ "vite/client",
+ "vite-plugin-pages/client",
+ ]
}
あとは、 src/main.tsに virtual:generated-pagesを使ってよしなにルーティング情報からHTMLを生成してくれます。
// src/main.ts
import { ViteSSG } from 'vite-ssg'
import generatedRoutes from 'virtual:generated-pages'
import App from './App.vue'
+ const routes = generatedRoutes
export const createApp = ViteSSG(
// the root component
App,
// vue-router options
{ routes },
// function to have custom setups
({ app, router, routes, isClient, initialState }) => {
// install plugins etc.
}
)
vite-ssg build
これで問題ないと思いきや・・・
生成したHTMLは、vue-router を使ってルーティングするため、SSGで静的HTMLを生成しても、直接参照することができません。
たとえば、 localhost:8100から router-link を使って、localhost:8100/aboutやlocalhost:8100/about/への遷移は可能ですが、localhost:8100/aboutやlocalhost:8100/about/を直接参照しようとすると「404 not found」が返ってきます。
SSGすると、つくられるのはabout.htmlなので、localhost:8100/aboutだと「404 not found」が発生してしまうのは当然です。
では、どうすれば良いのか?![]()
apatchやnginx等だと、configファイルなどにURLのパスに対して.html拡張子付きのファイルを参照するように設定を書くことで回避できます。
しかし、AWS S3などの単純なストレージに対してはそうはいきません。
方法はいくつかありますが、SSGの出力を見直すのが良さそうです。
localhost:8100/about/は、localhost:8100/about/index.htmlのことなので、このようにHTMLを出力するように vite-ssg 側を書き換えます。
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import Pages from 'vite-plugin-pages'
export default defineConfig({
plugins: [
vue(),
Pages({
+ extendRoute: (route, parent) => {
+ if (!process.env['VITE_SSG']) return route
+
+ if (route.component.match(/\/index\.(vue|js)$/) && route.path !== '/') {
+ return {
+ ...route,
+ path: `${route.path}/index`
+ }
+ }
+ return route
+ }
+ }),
]
})
今回は、vite-plugin-pagesのextendRouteに書き換え処理を書きましたが、vite-ssgのssgOptionsでも同様のことができたので、どちらでも良いと思います。(違いなどがあれば教えてください。)
これで about.html ではなく、 about/index.html が出力されたことがわかります。
AWS S3だと、localhost:8100/aboutもlocalhost:8100/about/へリダイレクトしてくれるので、これで無事解決です。
さいごに
Vue3でSSGを考えた時、Nuxt3が一番最初に思いつきますが、Nuxt3は現在SSGに未対応なようです。
なので、今現在、Vue3でSSGするならvite-ssgを使うしかないのですが、思いのほか色々なところで躓いたので、それを記録として残しました。vite-ssg で躓いている方々への参考になれば幸いです。



