入る前に、
1であるこちらを先に確認して、CSR,SSRについて理解した上で読むことをおすすめします。
Nuxt.jsとは?
vue.jsのフレームワークベースの開発環境の構築に役立つフレームワークである。
フレームワークのためのフレームワークと言うのは難しいかもしれませんが、解いてみると、Vue.jsプロジェクトで使用されるいくつかの有用なライブラリを基本的に搭載しているフレームワークと見ればよい。
Nuxt.jsに含まれる機能は以下の通りになる。
- Vue 2 (2022/05時点→3は秋ぐらい予定)
- Vue Router
- Vuex
- Vue Server Render
- vue-meta
- vue-loader
- babel-loader
- webpack
Nuxt.jsの特徴
Vue.js + ライブラリ構造なので、Nuxt.jsは次のような特徴を持ってます。
- Vue ファイルが使える
- コード分割の自動化
- サーバーサイドレンダリング
- 非同期データ基盤、強いRoutingシステム
- 静的ファイルの転送
- ES2015+ サポート
- js & css コードバンドリング及び圧縮
- エレメント管理(title, metaなど)
- 開発時のHot Module管理
- CSS pre-processor 提供(SASS, LESS, Stylusなど)
- Pre-Rendering
- pages ディレクトリを使ったて安いRouting
- webpackなどを使った簡単な設定
Nuxt.jsはいつ使うのか?
決定的にSEOを改善したいと思う時、
ディレクトリ構成
- assets
- css, image, fontなどのリソースを含まれてる
- scriptで動作するロジックとは別部分であり、デザイン的に見せるファイルなどが入っている
- components
- アプリケーションで使われるコンポネントが入ってる
- 該当パスで配置あれてるコンポネントはNuxt.jsの非同期関数である
asyncData
またはfetch
は使えない
- layouts
- アプリケーション全体に対するレイアウトを含まれてる。
- 基本的には
default.vue
が準備されてる。 - ディレクトリ名変更不可
- middleware
- アプリケーションで使うmiddlewareを配置
- middlewareはページまたは、レイアウトがレンダリングされる前に実行される。
- middlewareをページや、レイアウトにバインディングしたら、該当ページや、レイアウトが実行されるたびに実行される。
- node_modules
- Nuxtフレームワークのメイン機能を拡張、統合、追加できる。
- ユーザーが直接モジュールを作成できる。
- pages
- 実際アプリケーションのページ構成を含まれてる。
- このディレクトリの構造によって、Routerが自動的に作られる。
-
index.vue
として指定されたファイル名は省略できる。
- plugins
- アプリケーションにバインディングされる外部または、内部のプラグインを配置
- アプリケーションがインスタンス化される前に実行され、Global的な構成要素を登録し、関数または、常数を入れることが可能
- store
- アプリケーションで使う
vuex store
のファイルを配置 - 基本的には非活性化状態
-
store
ディレクトリにindex.js
フィアルを作成することで、store
機能が活性化状態になる。 - 構成によってモジュール形式の
store
が作成できる
- アプリケーションで使う
- content
- オプション、
-
@nuxt/contet
モジュールを使ってアプリケーションを拡張可能 -
markdown
,json
,yaml
,xml
,csv
などのファイルをInputしたり、管理できる。
Nuxt.jsと、Vue.jsのディレクトリ比較
// Vue.js
npm i -g @vue/cli
vue create <project name>
cd <project name>
vue add vuex
vue add router
// Nuxt.js
npm init nuxt-app <project-name>
上記のコマンドで作られて2つのPJのディレクトリを比較してみよう。
基本的にVue.jsのPJにはVuexと、Vue Routerを追加した状態で,NuxtではUIFW以外は特に入れたものはない状態である。
Vue.jsではsrc
フォルダ配下に入ってる内容が、Nuxt.jsでは全般的にRootレベルとして上がっている。
Vue.jsと、Nuxt.jsが両方とも持ってるディレクトリを線を利用して表示してみた。
Vue.jsのPJではRouter関連ディレクトリがrouter
, view
があるが、Nuxt.jsでは pages
ディレクトリ一つが全部まとめて処理する。
Vue.jsのPJではRouterを設定するにはrouter/index.js
で直接Routerの登録が必要だが、Nuxt.jsでは pages
フォルダの構造通りにRouterが自動作成される。
Vue.jsでは見えないmiddleware
, layouts
, plugins
が確認できる。
Nuxt.jsのレンダリングモード
Nuxt.jsはSingle Page Application (SPA)、Universal Application, Static Applicationをサポートしている。
これは、nuxt.config.js
で、mode
Perpertyを使って設定可能である。(mode:'spa', 'universal')
上記のスクショ(公式ドキュメント)上だと、universal
について、Isomorphic application (server-side rendering + client-side navigation)
のように説明している。これはどんな意味でしょう
SSRをmodeとして指定する方法はdeprecatedになった。 build : { ssr: true/false} の方法に変えた。
server-side rendering + client-side navigation
これはどんな意味でしょう
これはこの前の記事で話した新しい方法のSSR、要するにUniversal Appの動作方法を意味してる。
過去に、ぺーじを移動するたびに、リフレッシュすることを保管するために新しく登場したレンダリング方法として言える。
最初の画面だけ、過去のサーバーレンダリングように完成されたHTMLを表示され(SSR),今後は、Ajaxを利用して、動的Routingを使って必要なデータのみ持ってこれたらどうだろう(CSN)というアイディアから登場したレンダリング方法である。
Universal Appの動作方法は上記のイメージのようになる。
最初のRequestが届いたらサーバーサイドではnuxtServerInit
, middleware Validate(), asyncData(), fetch()
などのプロセスが動いた後、レンダリングしたイメージをResponseする(各プロセス内容は下で再度説明する。)
- ここかでが、SSR(Server side Rendering)の部分である。
- このアツ、
nuxt-link
タグとしてNavigateがおこなわれるけど、これをCSN(Client−Side Navigation)だという。
CSNについて
CSNは大きく、Pre-fetch + Hydration家庭として動作してる。
Nuxt.jsはUniversalモードで基本的にRequestしたURLを使って、ロードするべきのページだけサーバーでレンダリングしClient側にResponseする。
Requestが行われるたびに、サーバーでレンダリングするのであれば当然リフレッシュが発生し、既存のSSRと同じ状態になる。しかし、Nuxt.jsのUniversalモードではリフレッシュが発生しないのは、Pre-fetch
のおかげである。
Pre-fetchはCSN(Client-Side Navigation)の流れの一つである。要するに、Universal Appだけ使える方法ではなく、Vue-CLIのようなSPAでもサポートできる機能で有ること。
Pre-fetch
先にデータを準備する意味。
言葉通りに、レンダリングが必要になる次のページを先に準備しておきこと、
Nuxt.jsはこれをどうわかって準備できるのだろう。
これはNuxt.jsの機能の一つである nuxt-link
を介して行われます。 (Vue Routerの route-link
と同じだと見ることができます。
Nuxt.jsは、最初のサーバーでデータと一緒にHTMLをレンダリングし、それから viewport
(画面に表示されるページ)の nuxt-link
から次のページを予測してバックグラウンドでジャンクファイルをダウンロードします。 。
このとき、あらかじめ持ってくるデータの形式は js
である。
Nuxt.jsは自動的に code splitting(ファイル容量を減らすためにコードを難難にすること)
を適用するので、新しいページをレンダリングしたい時はサーバーに毎回レンダリングしたHTMLを要求する代わりに、ブラウザがレンダリングできるように助けるjs
ファイルを要求する。
要約すると、ユニバーサルアプリが瞬時にページをロードできる理由は、次のページのデータ .js
を事前に取得する(Pre-fetch)ためです。
Hydration
レンダリング過程を終え、ブラウザに渡されたHTMLファイルの上に残ったJavaScriptコードを実行する動作である。
ハイドレーションにより、SSRアプリは既存のSPAと同じ動作と反応性を保証できるようになる。用語そのまま不完全なHTMLファイルという「乾いた土地」にJavaScriptという「水」を振りかけること。
- Universal Appは、Server Side RenderingとClient Side Navigationプロセスを介して動作する。
- Server Side Renderingは、私たちが知っているサーバーでHTMLをレンダリングする方法である。
- Server Side Rendering後、view portのnuxt-linkタグを介して次のページを事前にダウンロードしてくる(Pre-fetch)
- あらかじめダウンロードしてきたため、リロードせずにページ移動が可能だ。
- ページ移動後の動作はハイドレーションと呼ばれる。
- ハイドレーションにより、Universal AppはSPAと同じ動作と反応性を保証できる。
Isomorphic Application
Isomorphicは直訳すると、「同じ構造の」という意味。
通常Isomorphic Javascriptという言葉でよく使われますが、一般的には同型JavaScriptに翻訳します。サーバーとクライアントに同じ言語が使われるという意味で考えればよい。
nuxtServerInit, middleware, validate(), asyncData(), fetch()
などの過程を最初の要求では、サーバーサイドで処理するロジックが同じ javascript で作成されたことを意味する。
ここで話すサーバーサイドの サーバー
は API を意味するバックエンドサーバーではなく、 Nuxt.js に組み込まれた Express(Node.js) サーバーを言う。 Nuxt.jsはSSRを実装するためのExpressサーバーを内蔵している。
Express(Node.js)サーバーとクライアントが同じようにJavascriptで構成されているため、Isomorphic Javascript / Universal SSRという。
実際にコーディングするときは、そのコードをサーバー/クライアントの両方で実行できることを常に念頭に置いて作業する必要がある。
Static App
Nuxt.jsはUniversal App、SPAに加えてStatic Appをサポートしている。
Static App はすべての page が pre-rendering (プリランダリング) されたビルドを生成し、 server は含まない。つまり、完成した静的HTMLを生成して配布する方式だ。
フリーランダリング
サーバーの介入なしに事前にレンダリングされたすべてのページのHTMLファイルをクライアントに提供する。
Static Appを実装するには、 nuxt.config.js
に target:'static'
を追加するだけ
デプロイ時に npm run generate
を行うと dist
(default) にすべてのページがレンダリングされたビルドが生成される。
しかし、idのようなパラメータを渡してルーティングするページは、パラメータが決まった値ではないため、プリレンダリングされず、urlアクセスが不可能な問題が発生する。
これを解決するためには nuxt.config.js
の generate property
オプションを利用することができる。
たとえば posts
というリストページがあり、posts/[id]
が詳細ページとする場合
generate: {
routes: function () {
return [
'/posts/id値'
]
}
},
その id 値を入れて generate してくれれば id 値のフォルダと一緒に index.html
が別々に生成されることが分かる。
しかし、すべてのid値をconfigファイルに入れて管理するには無理があり、これはサーバーから値を受け取って設定することができる。
const axios = require('axios');
generate: {
routes: function () {
return axios.get('http://test.com/posts')
.then(res => {
const routes = []
for (const key in res.data) {
routes.push('/posts/' + key)
}
return routes
})
}
},
Nuxt.jsのLife Cyle
何かすごく複雑に見えるイメージだが、上記内容を全て読んできたら理解しやすい。
まず、真ん中に描かれた線を見てみましょう。
中線を基準に、上側はVueコンポーネントができる前、下はその後になる。
もっと簡単に言えば、上はServer Side、下はClient Sideです。
Vue Componentが発生する前に、Server Sideでページがレンダリングされる前にすべきことを行います。
当然のことですが、サーバーサイドではVue Componentがまだ生成される前であるため、thisを使用することはできません。
前述のmiddleware
、validate()
、asyncData()
を実行します。
まとめ
今回は、Nuxt.jsと、Vue.jsのディレクトリの比較、各ディレクトリの役割、レンダリング、LifeCycleについて書いてみました。
最近、Nuxtのバージョンは2.15以上、Vueは3バージョンが、Currentになりましたので、内容が少し古いかもしれませんが、そこまで大きい差分は発生してないし、バージョンによって大きいな動作の異なりはないと思います。
そしてこのような背景を身についているのであれば、今後の新しいバージョンにも早速対応できると思います。
次の記事では、簡単な使い方として、Routingと、Vuexの動作方法、非同期データ扱い方法などについて整理してみようと思います。