11
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Viteを使ってSSGを試した話

Last updated at Posted at 2022-03-08

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.tsPages() を追加します。

// 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.tsvirtual: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

package_json_—workspace__ワークスペース.png

これで問題ないと思いきや・・・

生成したHTMLは、vue-router を使ってルーティングするため、SSGで静的HTMLを生成しても、直接参照することができません。
たとえば、 localhost:8100から router-link を使って、localhost:8100/aboutlocalhost:8100/about/への遷移は可能ですが、localhost:8100/aboutlocalhost:8100/about/を直接参照しようとすると「404 not found」が返ってきます。

vite-ssg-local.gif

SSGすると、つくられるのはabout.htmlなので、localhost:8100/aboutだと「404 not found」が発生してしまうのは当然です。

では、どうすれば良いのか?:thinking:

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-pagesextendRouteに書き換え処理を書きましたが、vite-ssgssgOptionsでも同様のことができたので、どちらでも良いと思います。(違いなどがあれば教えてください。)

vite_config_ts_—workspace__ワークスペース.png

これで about.html ではなく、 about/index.html が出力されたことがわかります。
AWS S3だと、localhost:8100/aboutlocalhost:8100/about/へリダイレクトしてくれるので、これで無事解決です。

さいごに

Vue3でSSGを考えた時、Nuxt3が一番最初に思いつきますが、Nuxt3は現在SSGに未対応なようです。

Nuxt_3_-_Introduction.png

なので、今現在、Vue3でSSGするならvite-ssgを使うしかないのですが、思いのほか色々なところで躓いたので、それを記録として残しました。vite-ssg で躓いている方々への参考になれば幸いです。

11
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?