ちょっとしたWebアプリのモックアップを作る案件があったため、せっかくなので色々と最新のバージョンを盛り込んで構築したメモ。
-
Nuxt 3 (執筆時点で3.0.0-rc.12)
- Vue 3やviteを使ってみたかった
-
Vuetify 3 (執筆時点で3.0.0-beta.14)
- とりあえず新しそうだったため
-
Mock Service Worker (msw)
- 通信部分は本物っぽく作り、モックアップではダミーサーバー、後々本物のAPIサーバーに置き換えたい。少し調べた所、mswが良さそうだったので採用。
プロジェクト生成
最近のフレームワークは一発で空プロジェクトを作れるので楽。Nuxt3はnuxiコマンドを使う。
$ npx nuxi init my-app-name
生成したmy-app-nameディレクトリをVSCodeで開いて開発を行う。
開いたら、ひとまずyarn installを実行する。
$ yarn install
なお、VSCodeでフロントエンド(Vue)開発をする際にはこのあたりの拡張機能をインストールしておけば良いはず。
- Volar
- ESLint
- Prettier
- EditorConfig
テスト起動
以下で開発サーバーを起動。
$ yarn dev
ブラウザーで http://localhost:3000/ を開く。
警告の修正
アプリのエントリポイントであるapp.vue
を開くと、Volarの警告が表示された。
将来のバージョンでは表示されないかもしれないが、ここではひとまず言われた通りに@types/node
のバージョンを固定しておく。
$ yarn add -D @types/node@18.8.0
上記を実行後、VSCodeを再起動すると警告は表示されなくなった。
Vuetify 3の追加
NuxtにVuetifyを追加する場合、yarnでパッケージを追加した後、NuxtにVuetifyを初期化させるフックとしてplugins/
にファイルを追加する。
Nuxt3でもこの部分は変わっていないようだが、plugins/
以下のファイルが自動認識されるためnuxt.config.ts
への追記が不要になっている。
参考にさせて頂いた記事:
https://zenn.dev/one_dock/articles/ab6d178741956d
パッケージの追加
$ yarn add vuetify@next mdi
$ yarn add -D sass
plugins/vuetify.ts
import { createVuetify } from "vuetify"
import * as components from "vuetify/components"
import * as directives from "vuetify/directives"
export default defineNuxtPlugin((nuxtApp) => {
const vuetify = createVuetify({
components,
directives,
})
nuxtApp.vueApp.use(vuetify)
})
なお、このタイミングで、セミコロンなしのコーディングスタイルが好みだったのでPrettierの設定ファイルを作成した。
.prettierrc
{
"semi": false
}
また、組み込みのCSSとトランスパイル処理を認識させるために以下の設定を追加する。
nuxt.config.ts
export default defineNuxtConfig({
css: ["vuetify/lib/styles/main.sass", "mdi/css/materialdesignicons.min.css"],
build: {
transpile: ["vuetify"],
},
})
以上でVuetifyの設定は完了なので、試しにapp.vue
を書き換えてボタンでも置いてみる。
app.vue
<template>
<div>Hello, Vuetify</div>
<v-btn color="blue-grey" prepend-icon="mdi-magnify">SEARCH</v-btn>
</template>
mswの設定
Nuxt3で通信を行う際はuseFetchを使うのが一番簡単そうに見えた。
ボタンをクリックした際に通信を行う処理を書いてみる。
app.vue
<template>
<div>Hello, Vuetify</div>
<div>data: {{ jsonData }}</div>
<v-btn color="blue-grey" prepend-icon="mdi-magnify" @click="onClick"
>SEARCH</v-btn
>
</template>
<script setup lang="ts">
const jsonData = useState("jsonData", () => ({}))
const onClick = async () => {
const { data } = await useFetch("/api/search")
jsonData.value = data.value
}
</script>
この状態でボタンをクリックすると、/api/search
はSPAのパスとしてルーティングされてしまうため、jsonDataにHTML文字列が格納されて表示される。
mswの設定を行い、/api/search
が適当なJSONを返すようにする。
msw関連のファイルはmocks/
に配置することとする(任意)。
参考にさせて頂いた記事:
https://tech.smartshopping.co.jp/nuxt_with_mock_service_worker
ライブラリのインストール
$ yarn add -D msw
mocks/api/search.ts
APIが返す(ダミーの)レスポンスをコードとして書く。
import { ResponseResolver, MockedRequest, restContext } from "msw"
const get: ResponseResolver<MockedRequest, typeof restContext> = (
_req,
res,
ctx
) => {
return res(
ctx.status(200),
ctx.json([
// ここがダミーのJSONデータ
{
message: "Hello",
},
])
)
}
export default { get }
mocks/handlers.ts
mocks/api/
以下のファイルをURLと関連付ける。
import { rest } from "msw"
import search from "@/mocks/api/search"
export const handlers = [rest.get("/api/search", search.get)]
mocks/browser.ts
ブラウザーで起動するService Workerを定義する。
(SSRを使う場合はNode.js側のService Workerも定義するらしいが、割愛。)
import { setupWorker } from "msw"
import { handlers } from "./handlers"
export const worker = setupWorker(...handlers)
plugins/msw.ts
mswの初期化フック。前述の通り、このファイルを作成するだけでNuxtから認識される。
import { worker } from "@/mocks/browser"
export default () => {
worker.start()
}
public/mockServiceWorker.js
mswのサービスワーカーがGET /mockServiceWorker.js
して使うライブラリ。
以下のコマンドで作成する。
$ mkdir public
$ npx msw init public/ --save=false
nuxt.config.ts
今回はモックアップとしてビルド成果物をHTTPサーバーに配置する想定なので、SSRを無効化する。
// https://v3.nuxtjs.org/api/configuration/nuxt.config
export default defineNuxtConfig({
css: ["vuetify/lib/styles/main.sass", "mdi/css/materialdesignicons.min.css"],
build: {
transpile: ["vuetify"],
},
ssr: false, // 追加
})
以上でmswが有効化され、画面のボタンクリック時に実際のHTTPリクエストの代わりにソースコードで定義されたダミーデータが取得されたような動作となる。
また、この状態でyarn generate
で生成したstaticなビルド成果物をnginx等のWebサーバーに設置し、単独で動作させることが可能である。
将来的にはmsw.ts
のworker.start()
をif (process.env.NODE_ENV === 'development') {}
で囲む等で本物のAPIサーバーと併用することもできるようだ。