VuePress から Nuxt3 に移行しました
移行のモチベーション
- なんとなく React が分かってきて仕事で使いたいと思った
- 一方 Vue は趣味で使い続けたい
- Nuxt3 使ってみたい
- VuePress だとデザインとかマークアップの修正が行いづらい
みたいな考えがあったのですがそこまで作りたいものも今のところないのでとりあえず放置気味になっていたこのサイトを改修しようと思いました。
一応 VuePress のままでも問題はなかったが、デザインも直したい箇所がたくさんあったので Nuxt3 への移行を決めました。
移行作業
移行作業では下記を目標として作業しました。
- ダークモードとテーマ切替えの実装
- デザインをシンプルにまとめる
インストール・環境設定
基本的にはNuxt3のサイトに書いてあるとおり進めていった。
Beta だった時期に試した時はnuxi
が呼び出せなかったりバグがあったがそういったバグとかも治っていてnpx nuxi init nuxt-app
すんなりインストールできた。
結構普段はcreate-**-app
とか使わずにマニュアルで環境を作ってしまうことが多いけどコマンド一つで環境が整うのめっちゃ楽でいいですね。
Nuxt は環境をセットアップしたあとにインストールコマンドが必要なのでnpm i
しておく。
Nuxt CLI v3.0.0-rc.4
> Local: http://localhost:3000/
> Network: http://192.168.10.18:3000/
爆速で localhost が立ち上がってびっくりするけどリンクを開くとロード画面が開いて若干待たされる。
それでも開発環境の立ち上がりは十分早いのでストレスは無い。
※画像はv3.0.0-rc.4
時点でのロード画面v3.0.0-rc.5
だとまた違うロード画面になっていた。
こういう細かいところもちゃんと作り込んでいるので Vue 関連のプロジェクトは好きだなと思う。
Vue3 の壁
とりあえずで進めたはいいが前に Vue を書いたのが 2.x の頃なので書き方を忘れていたり新しい API が分からなかったりで結構苦労した。
Composition API っていうの使っておけばいいんでしょ?というレベル感でとりあえず進めていく。
レイアウトの作成
とりあえずレイアウトから作っていこうと思ってレイアウトの編集から始めた。
基本的にはlayout > default.vue
に基本レイアウトを作成して、それ以外のレイアウトが必要な場合はlayout
ディレクトリで別の名前を作っていく感じらしい。
今回のリニューアルの際にダークモードも自分で実装しようと思ったのでレイアウト側でそれを定義する。
基本的なやり方は前に記事にしたものを見返しながら設定していった。
- CSS 側で配色を定義
- それを変更するためのロジックを用意
- 別途 meta を変更するためのロジックを用意
という感じなのでそれを進めていく。
記事を書いている時点でのレイアウトファイル(最新版)
一応それっぽくダークモードとの切り替えができているが端末のテーマがダークモードだった場合にライトモードからダークモードへの切り替わりでちらつきが発生してしまうので後々直しておこうと思う。
※後にNuxt ColorMode
というパッケージを入れて修正しています。
以前のサイトからコンポーネントを移植
以前のサイトもそこまでコンテンツは無いので移植するコンポーネントも多くないのでサクッと終わった。
Zenn の記事データを取ってくるコンポーネントとJSON ファイルを元に制作物一覧を生成するコンポーネントぐらいなのでそこまでトラブルも起きずに Vue2 から 3 への変更ができた。
Zenn の記事データを取ってくるコンポーネントについて以前はaxios
を使っていたが別にfetch
でいいじゃんということでそこだけは書き換えをおこなったけどほとんど昔のコードとロジックは同じ。
記事データの移行
記事データを移行するにあたって VuePress のように自動でパースはしてくれなさそうなので、Markdown パーサを入れようと思っていたが
どうやらNuxt Contentというものがあるのを発見した。Nuxt のcontent
ディレクトリについての説明はこっち
サクッと読んだ感じcontent
ディレクトリに.md
ファイルを入れてうまいことやると記事(マークアップ)を生成してくれそうなのでこれを使うことにする。
パッケージのインストール
別途@nuxt/content
のパッケージが必要そうなのでインストールする必要がある。
npm install --save-dev @nuxt/content
でインストールしてnuxt.config.ts
に下記の項目を追加する。
import { defineNuxtConfig } from 'nuxt'// https://v3.nuxtjs.org/api/configuration/nuxt.configexport default defineNuxtConfig({ modules: [ '@nuxt/content' ], content: { // https://content.nuxtjs.org/api/configuration/ }, app: { head: { meta: [ { name: 'color-scheme', content: 'light dark' }, ], link: [ { rel: 'stylesheet', href: '/assets/css/main.css' }, ], } }})
とりあえず構成としてはこのようにしたいので設定をしていく。
pages
┗ post
┣ index.vue // ブログ一覧
┗ [...slug].vue // 個別記事
/content/
ディレクトリもこんな感じでパスをあわせておくと良さそう。
Content
┗ post
┗ // ...各記事データ
記事のコンテンツは[...slug].vue
というファイルを作ればルーティングしてくれるらしい。
内部は下記のように<ContentDoc></ContentDoc>
というコンポーネントを入れればマークアップを展開してくれる。
<template> <div> <ContentDoc></ContentDoc> </div></template>
特にどのコンテンツをインポートするとか、API への接続とかの処理を記載しなくてもディレクトリを合わせて[...slug].vue
を作るだけで記事を表示してくれるのでサクッとドキュメントページを作りたい人にも良さそう。
記事ページのカスタマイズ
デフォルトの見た目でもまあいいが一部見た目を変更したりしたいのでちょっと手を加えていく。
最初は記事ページ用の css を用意してそれを記事ページだけで読み込ませようかと思ったけど、一応ちゃんとしたやり方があったのでそっちでやっていく。
公式ドキュメントだと、/components/content/
ディレクトリにcomponent sourcesを見ながら同じ名前のコンポーネントを作成すればいけそうなので試してみる。
- Checkout the original component sources.
- Use the exact same props.
- Name it the same in your components/content/ directory.
- Make it yours 🚀.
- 変更したいコンポーネント(タグ)を決める
Prose**.vue
ファイルをcomponent/content/
に作成- component sourcesと同じ
prpos
を利用してファイルを作成する
といった感じで進めれば編集可能。
ハイライトの追加
ハイライトの導入はnuxt.config.ts > content > highlight
からテーマを追加することで有効化できる。
しかし、下記のようなエラーが出てしまったので一旦ハイライトの指定を別のものに変えて対応した。
[nuxt] [request error] No grammar provided for <source.diff>
at Registry.e._collectDependenciesForDep (/G:/dev-local/d6/node_modules/shiki-es/dist/shiki.mjs:12:24999)
at Registry.<anonymous> (/G:/dev-local/d6/node_modules/shiki-es/dist/shiki.mjs:12:25495)
at /G:/dev-local/d6/node_modules/shiki-es/dist/shiki.mjs:12:23016
at Object.next (/G:/dev-local/d6/node_modules/shiki-es/dist/shiki.mjs:12:23125)
at s (/G:/dev-local/d6/node_modules/shiki-es/dist/shiki.mjs:12:21828)
Shiki のLanguageを見てみるとdiff
には対応しているようなのできちんと対応すれば表示されそう。
ダークモード時に自動でテーマを変えてほしいなー、と思っていながらドキュメントを見ると複数のハイライトテーマに対応しているようなので設定してみた。
しかしうまく設定できず、型定義を見ると公式ドキュメントのような設定はできないっぽいので一旦はコードブロック内部の背景色を固定して対応した。
highlight: false | { /** * Default theme that will be used for highlighting code blocks. */ theme?: Theme; /** * Preloaded languages that will be available for highlighting code blocks. */ preload?: Lang[];};
※Theme
型はテーマ名として指定できる文字列の union 型
ダークモードの追加
最初はダークモードの実装を自分で行っていたが、Nuxt ColorMode
というモジュールがあるのでそちらを利用する。
基本的な使い方としてはNuxt Content
と同じようにモジュールをインストールして、nuxt.config.ts
にモジュールを追加する。
export default defineNuxtConfig({ modules: [ '@nuxt/content', '@nuxtjs/color-mode', ], colorMode: { dataValue: 'theme', }, // ...});
colorMode
の中に項目を追加することで設定を変更可能。
このモジュールはサイトのカラーモードの状態管理(設定状況をキャッシュしてくれるっぽい?)のみを行うので切り替えるテーマは自分で作成する必要がある。
モジュールはテーマに応じてhtml
要素のクラス名と data 属性の値を変更してくれるのでそれに応じて CSS 変数を差し替える方法で対応するのが一番楽だと思う。
:root { --c-static-dark: #333; --c-static-darker: #222; --c-static-darkest: #111; --c-static-light: #ddd; --c-static-lighter: #eee; --c-static-lightest: #fff; --c-static-base-dark: #1f214e; --c-static-base-light: #c6c8ec; --c-static-secondary: #70909e; --c-static-important: #db3131;}html:not([class*="dark-mode"]) { color-scheme: light; --c-dark: var(--c-static-dark); --c-darker: var(--c-static-darker); --c-darkest: var(--c-static-darkest); --c-light: var(--c-static-light); --c-lighter: var(--c-static-lighter); --c-lightest: var(--c-static-lightest); --c-base-dark: var(--c-static-base-dark); --c-base-light: var(--c-static-base-light); --c-secondary: var(--c-static-secondary); --c-important: var(--c-static-important);}html.dark-mode { color-scheme: dark; --c-dark: var(--c-static-light); --c-darker: var(--c-static-lighter); --c-darkest: var(--c-static-lightest); --c-light: var(--c-static-dark); --c-lighter: var(--c-static-darker); --c-lightest: var(--c-static-darkest); --c-base-dark: var(--c-static-base-light); --c-base-light: var(--c-static-base-dark); --c-secondary: var(--c-static-secondary); --c-important: var(--c-static-important);}
ちなみにこのサイトの設定は上記のような感じ(最新版)
ダークモード・ライトモードで色が変わるように設定しているが、静的な値も欲しい場合もあるので:root
で一旦静的な値を定義しておいてそれをそれぞれ代入していく感じで書いています。
多分このやり方がダークモードに対応しているデザインシステムとかでも一般的だと思う(※要検証)
機能としてはそこまで大きなモジュールではないがきちんとprefers-color-mode の仕様を考慮していたり※、設定値の記憶など細かい箇所もきちんと作られているのでこのモジュールで機能が不足することはなさそう。
また、ページ個別でカラーモードを強制できる機能もあるので段階的にダークモードの導入をしていく方法なども用意されている。
※prefers-color-mode
には'light'
と'dark'
以外の値も入ってくる可能性があるので想定していない値が入ってきた場合のフォールバック値が必要
コンポーネント側は下記のようにuseColorMode
からインスタンスを作成して<ColorModeInstance>.preference
の値を変更することでカラーモードの変更が可能。
現在の値は<ColorModeInstance>.value
で参照できる。
<script lang="ts" setup>import { useColorMode } from '#imports';const colorMode = useColorMode();const toggleDarkMode = () => { colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark'; console.log(`current theme ${colorMode.value}`);}</script>
Netlify でのデプロイ
VuePress 時代から Netlify を使っていたのでそのまま Netlify にデプロイすることにした。
Nuxt3 のドキュメントにもNetlify に関しての記述があります。
ここにも書いてある通り Netlify へのデプロイではほとんど設定する項目はありません。
既にアカウントを作成している人は Add new site からリポジトリを連携して、ビルドコマンドとパブリッシュディレクトリを追加するだけで自動的にサイトが公開されます。
特にビルド設定を変更していない場合は、build settings の項目内の Build command にnpm run build
を入れ Publish directory をdist
に設定するだけで公開される。
本当にやることが無いのでデプロイについて書くことはそこまでないです。
Nitro のドキュメントにはZero-Config Providersとしてazure
やvercel
も記載されている。
Node.js ServerのページにPM2
での使い方も記載されているのでセルフホストするときなどはこっちを見ればよさそう。
最後に
というわけで VuePress から Nuxt3 への移行は完了しました。
Netlify がデフォルトで Nuxt のデプロイに対応していたり、Nuxt Content が用意されていたりしてかなりスムーズに移行ができました。
VuePress と違いレイアウトを作成する必要がありますが、リポジトリの作成からデプロイまでそこまで時間がかからないので拡張性を考えると Nuxt+Nuxt Content でのドキュメント管理の可能性を感じました。
まとめ
- Nuxt Content が優秀
- Nuxt3 + Netlify の組み合わせは楽
今後やりたいこと
- 各ページへ ogp の設定
- 記事ページに URL を入れたら ogp を展開してくれるようにしたい