nuxt3」タグアーカイブ

code on a screen

Nuxt3でExpressを使ってみる

はじめに

Nuxt3には、nitro(+h3)というサーバエンジンが標準で備わっているため、server/apiやserver/routeディレクトリにハンドラファイルを置くだけでAPIが簡単に実装できます。しかし、馴染みのあるexpressフレームワークを使いたいという場合もあるのではと思います。

そこで、今回はNuxt3にexpressフレームワークを導入してみます。

Nuxt3とExpressのインストール

まずは、最新のnuxtとexpressをインストールします。

今回の環境は以下のようになっています。

  • macOS 10.15.7
  • NodeJS 16.15.0
  • npm 8.19.2
  • nuxt3 rc11
  • express 4.18.1

serverHandlerの作成

nuxt3では、nuxt.config.tsのserverHandlersにハンドラを設定します。今回の設定例は、以下のようになります。/serverというパスに対するリクエストは、/myapi/index.tsのミドルウェアで処理するとします。今回で言えば、expressになります。

ここでの設定は、実際にはh3のミドルウェアとしてマウントされます。h3は、expressやconnectとの互換を最大限に考慮しているとあるので、expressも普通に使えるようです。

routeの記述ついて、h3がradix3というライブラリを内部で使っているのでその記述形式に準じます。

参考リンク

expressの設定

続いてexpressのミドルウェアをserverHandlerとして設定する部分です。

以上でhttp://localhost:3000/server/helloで結果が返るようになるはずです。

試してみると正常に結果を取得できているようです。

node-server向けにビルド

プロダクション向けのビルドでも挙動が問題ないか確認しておきます。同じように結果が返ってきているようです。

APIのエラー時の挙動はどうなるか?

APIでjson形式で結果を取得できるようになりましたが、サーバーエラー時にhtml形式で結果が返ってきてしまいます。どうもエラーページはnitroがハンドルしているようで、nitroのエラーハンドラ内でjsonリクエストであると判断した場合は、content-typeapplication/jsonとして返る?ようです。jsonリクエストであると判断する条件は、以下のようです。

  • ヘッダacceptがapplication/jsonを含む
  • ヘッダuser-agentが、curl/、httpie/を含む
  • リクエストパスが.jsonで終わっている
  • リクエストパスに/api/が含まれる

確認のためwgetとcurlの2つのツールでAPIにアクセスしてみます。curlは、nitroのデフォルトのエラーハンドリングではjsonリクエストとして解釈されるようです。

json形式で受け取りたい場合は、1つの方法として、fetchのリクエストヘッダでacceptを設定すれば良さそう?です。

まだRC版で開発も活発のため変更もあるかもしれませんが、現在の最新版での動作を確認してみました。参考になれば幸いです。

参考リンク

data codes through eyeglasses

Nuxt3でvee-validate4(Composable API)を使う

引き続きNuxt3のトピックです。

Vue3のUIフレームワークであるvee-validateの組み合わせでフォームのバリデーションを組んでみます。というのも、vee-validate4の使用について少しハマってしまったので、その備忘録をかねて記述しています。

インストールと設定

Nuxt3とvee-validate4をインストールします。

今回は、i18nとルール、それからsassも一緒に入れておきます。

また、プラグイン定義でルールやロケールを設定します。

Filedのバリデーション

実際の使用例を見てみてます。今回の記事では、Composable APIを使うケースを想定しています。

useFieldでフォームフィールドごとの定義をしています。useFieldは、valueやerrorMessageといったオブジェクトを返します。

実際に動かした画面は以下のようになります。

Formのバリデーション

続いてFormのケースです。useFormというComposable APIを使います。

useFieldで定義していたバリデーションをuseFormで指定しています。useFieldは、useFormのformを自動的に検出してくれます。実際には、provide/injectの仕組みが内部で使用されており、useFormやuseFieldの呼び出し時にそれぞれ固有のSymbolでコンテキストがprovideされています。useFieldは、useFormでprovideされたformコンテキストを自身のコンポーネント内でinjectしています。そのため、上記の例で言うと、useFieldを先に呼び出し、useFormを後で呼び出すとuseFieldがformコンテキストを探せず期待した動きにならないことがあります(私自身ややハマってしまった)。初回表示時にuseFormがfieldを見つけられずエラーと扱ってしまいます。

実際に上記例を動かすと、ページ表示時にバリデーションエラーが表示されてしまい期待した動きになりませんでした。

まとめ

Nuxt3とvee-validateの組み合わせを試してみました。Composable APIで簡単にフォームバリデーションを導入することができます。

本サンプルは以下になります。

https://github.com/moritetu/nuxt3-vee-validate-sample

参考リンク

data codes through eyeglasses

Nuxt3 ページごとにタイトルを変える

Nuxt3でページごとにタイトルを変える方法について記述します。正式リリースされていないので変わる可能性もゼロではないですが。

https://v3.nuxtjs.org/guide/features/head-management#title-templates

useHeadとtitleTemplateを使う

app.vueでtitleTemplateを使います。pagesディレクトリにページごとにコンポーネントを置く想定です。config.public.appNameにアプリケーション名を定義したとします。

続いて、以下のようにページに定義します。

definePageMetaを使う

pageでtitleを定義して、例えばレイアウトとかでuseHeadで設定する。

pageでdefinePageMetaで定義する。

レイアウトでmetaデータを取得しuseHeadで設定します。

code on a screen

Nuxt3でページにstyleを適用する

Nuxt3でページにスタイルを指定する方法についてです。

Headタグ使う

SFC内に以下のように記述する事でスタイル指定が可能です。

useHeadを使う

Composable APIを使ってscript setupに書くこともできます。

useHeadとStyleタグの両方を指定しても問題ないようです。両方の指定が出力されます。

参考リンク

 

code on a screen

Nuxt3での簡易の認証フローを構築する

Nuxt3でアクセストークンを使った簡易な認証フローの構築をしてみます。

簡易な認証フローでは、route middlewareを使います。route middlewareはNuxt2にも同様にあった仕組みです。サーバーサイド(SSRサーバ初回アクセス時)、クライアントサイドで動作し、ページ遷移時に認証などのフィルタを挟んだりすることができます。ページコンポーネントに以下のように記述することで、ミドルウェアを宣言的に適用することができます。

参照:ミドルウェアディレクトリ 

なお、server/middlewareという仕組みもありますが、これはサーバーリクエストごとに動作するミドルウェアです。ドキュメントにもあるように、何らかのチェックやヘッダの操作、ロギングなどに使用する用途のようです。expressでrouteをマウントしても呼ばれます。Nuxt3の内部で使われているh3 httpフレームワークのミドルウェアとして登録されます。

https://v3.nuxtjs.org/guide/features/server-routes#server-middleware

そのため今回は、route middlewareの仕組みを使って構築してみます。

テスト環境

  • nuxt@3.0.0-rc.8

今回のフロー

以下のような構成にしてみます。nuxt-auth moduleもcookieを使った同様の機構があります。

  • トークンはcookieに保存、ログイン時にcookieに書き込む。クライアント側でもread/writeするのでHttpOnly属性はなし。
  • SSR時は、cookieからトークンを読み出して使う。
  • route middlewareでは、cookieから値を読み出しログイン済みかどうかをチェックする。

この他、以下の仕組みを使うので補足します。

route middleware

route middlewareですが、middlewareディレクトリに配置すると自動でインポートされます。.globalというサフィックスをつけることで、全体に対して適用することができます。

  • middleware/auth.ts
    • definePageMetaでページコンポーネントに対してミドルウェアを適用する
  • middleware/auth.global.ts
    • 全体に渡ってミドルウェアが適用される

useCookie

useCookieというcomposableライブラリを使用します。useCookieは、サーバサイドとクライアントサイドで使えます。useCookieによる返り値に対しvalueを書き込みすることで、裏でNuxtが上手いこと処理をしてくれます(具体的には後述の通り)。

これにより、SSR時でもアクセストークンを取得し、フェッチリクエスト時にヘッダにトークンを埋め込むことができるようにします。

クライアントサイドの動作

クライアントサイドでは、document.cookieより指定したcookieを取得します。そのため、HttpOnlyが指定されたcookieは使えません。useCookieにより得たcookieはrefオブジェクトとなっており、valueに値を書き込むことでdocument.cookieにシンクされます。

サーバサイドの動作

サーバサイドでは、フックのタイミングでレスポンスヘッダにcookieが書き込まれます。

route middlewareを使った例

では、実際に構築してみます。フローを確認するためのサンプルなので、エラーチェックやその他バリデーションなど厳格さは欠いていますことご容赦ください。

server/api/login.ts

今回は、トークンを返すだけの簡易な処理としています。

server/api/posts.ts

ログイン後に何らかの投稿記事一覧を返す処理とします。リクエストヘッダから、Authorizationヘッダを読みトークンを確認します。トークンがあれば、ひとまず記事一覧を返すとします。

middleware/auth.global.ts

useCookieを使っています。ログインに成功すると、cookieに値を書き込みます。同時にdocument.cookieにも書き込まれます。

pages/login.vue

pages/dashboard.vue

以下のような感じで動きます。

 参考リンク