著者は、 Write for DOnations プログラムの一環として、 Open Sourcing MentalIllnessを選択して寄付を受け取りました。

序章

シングルページアプリケーション(SPA)は、クライアント側で単一のindex.htmlページとしてレンダリングされるアプリケーションです。 従来、SPAにはロード時にHTMLがほとんど含まれていませんでした。 代わりに、 Vue.js のようなフレームワークを使用すると、特定の条件が満たされたときにJavaScriptを介してコンテンツをHTMLラッパーに挿入できます。 これにより、動的でカスタマイズ可能なアプリケーションが作成されますが、検索エンジン最適化(SEO)の問題も発生します。これは、Webクローラーはサーバーからのファイルのみを分析でき、動的に生成されたルート上の重要なHTMLはすべて分析されたことはありません。

Nuxt.js は、サーバー側レンダリングでこの問題を解決できるVue.jsアプリケーションのフレームワークです。これは、サーバー上でアプリケーションをレンダリングしてからクライアントに送信する戦略です。 Nuxtを使用すると、すべてのルートがpagesディレクトリの.vueファイルから生成されます。 これらのページ内で、REST APIからデータをフェッチし、それをコンポーネントのtemplateに挿入できます。 template内のすべてのデータとHTMLは、生成された.htmlファイルをクライアントに送信するNuxtサーバーによってレンダリングされます。 その.htmlはサーバーによって提供されるため、Webクローラーは任意のルートで重要なHTMLをすべて分析できます。

このチュートリアルでは、空港に関する情報を含むサンプルWebアプリケーションをセットアップします。 このアプリは、 About ページと、データセット内の空港ごとに動的に生成されたページを提供します。 次に、Nuxt.jsを使用して、ページルートを生成し、レイアウトコンポーネントを作成し、ページ固有のメタデータを設定します。

前提条件

ステップ1—サンプルアプリケーションにNuxtをインストールする

このステップでは、コンピューターのターミナルのコマンドを使用してNuxtプロジェクトを作成します。 このnpxコマンドは、プロンプトで指定した情報に従って新しいVue.jsプロジェクトを生成する外部スクリプトを実行します。 これは、VueCLIを使用して新しいVueプロジェクトを生成するときのvuecreateコマンドに似ています。 次に、サンプルアプリケーションをセットアップします。これを使用して、チュートリアルの後半でNuxt機能をテストします。

ターミナルで、次のnpxコマンドを実行します。 このコマンドは、現在作業しているディレクトリにプロジェクトを生成します。

  1. npx create-nuxt-app favorite-airports

create-nuxt-appを初めて実行する場合は、最初にインストールする必要のあるパッケージのリストを示すプロンプトが表示されます。 yと入力し、ENTERを押して続行します。

Output
Need to install the following packages: create-nuxt-app Ok to proceed? (y) y

必要なパッケージがインストールされると、最初のプロンプトが表示されます。

Output
create-nuxt-app v4.0.0 ✨ Generating Nuxt.js project in favorite-airports ? Project name: (favorite-airports)

アプリの名前を入力するか、ENTERを押してデフォルトを選択します。 次のブロックで強調表示されているオプションを選択して、プロンプトを個別に処理し続けます。

Output
✨ Generating Nuxt.js project in favorite-airports ? Project name: favorite-airports ? Programming language: JavaScript ? Package manager: Npm ? UI framework: None ? Nuxt.js modules: Axios - Promise based HTTP client ? Linting tools: None ? Testing framework: None ? Rendering mode: Universal (SSR / SSG) ? Deployment target: Server (Node.js hosting) ? Development tools: None ? What is your Github username? ? Version control system: Git

それが完了したら、ディレクトリをfavorite-airportsに変更し、ローカル開発サーバーを起動します。

  1. cd favorite-airports
  2. npm run dev

これにより、指定されたアドレスでアクセスできるローカルサーバーが起動します。 ブラウザで、http://localhost:3000/に移動します。 次のように表示されます。

The Nuxt.js default splash screen

プロジェクトが実行されているので、このチュートリアルでデータとして使用するオブジェクト配列を追加することで、サンプルアプリをセットアップできます。

ターミナルを開き、プロジェクトのルートディレクトリ(favorite-airports)で次のコマンドを実行します。

  1. mkdir data

これにより、dataディレクトリが作成されます。 選択したテキストエディタで、dataディレクトリにairports.jsという名前のファイルを作成して開き、次のファイルを追加します。

お気に入り-airports/data / airports.js
export default [
  {
    name: 'Cincinnati/Northern Kentucky International Airport',
    abbreviation: 'CVG',
    city: 'Hebron',
    state: 'KY'
  },
  {
    name: 'Seattle-Tacoma International Airport',
    abbreviation: 'SEA',
    city: 'Seattle',
    state: 'WA'
  },
  {
    name: 'Minneapolis-Saint Paul International Airport',
    abbreviation: 'MSP',
    city: 'Bloomington',
    state: 'MN'
  },
  {
    name: 'Louis Armstrong New Orleans International Airport',
    abbreviation: 'MSY',
    city: 'New Orleans',
    state: 'LA'
  },
  {
    name: 'Chicago O\'hare International Airport',
    abbreviation: 'ORD',
    city: 'Chicago',
    state: 'IL'
  },
  {
    name: 'Miami International Airport',
    abbreviation: 'MIA',
    city: 'Miami',
    state: 'FL'
  }
]

これは、米国内のいくつかの空港で構成されるオブジェクトの配列です。 このデータを使用して、アプリのページを動的に生成します。

このファイルを保存して閉じます。

次に、CSSフレームワーク Taiwind をインポートして、アプリケーションにスタイルを追加します。 これを行うには、エディターでNuxt構成ファイルnuxt.config.jsを開き、次の強調表示されたコードを追加します。

お気に入り-airports/nuxt.config.js
export default {
  // Global page headers: https://go.nuxtjs.dev/config-head
  head: {
    title: 'favorite-airports',
    htmlAttrs: {
      lang: 'en'
    },
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: '' },
      { name: 'format-detection', content: 'telephone=no' }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
      { rel: 'stylesheet', type: 'text/css', href: 'https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css' }
    ]
  },
...
}

構成ファイルを保存して閉じます。

これで、Nuxtがインストールされ、プロジェクトが生成され、Nuxt機能を試すように設定されました。 次のステップでは、pagesディレクトリ内に.vueファイルを配置することにより、さまざまなタイプのルートを自動的に作成します。

ステップ2—pagesディレクトリを介したルートの生成

従来のVue.jsアプリとは異なり、Nuxtのルートはルーターファイルを介して生成されません。 代わりに、pagesディレクトリから生成されます。 このディレクトリ内の各.vueファイルはルートを生成します。 このステップでは、 About ページを作成し、空港ごとに動的にページを生成することで、この機能を試してみます。

pagesディレクトリを見てください。 そこにはすでにindex.vueというページがあります。 これは、静的なindex.htmlページを持つことと同じです。 このindex.vueページには、ローカル開発サーバーを実行したときにブラウザーでレンダリングされたHTMLを保持する単一の<Tutorial />コンポーネントが含まれています。 これは次のように表示されます。

お気に入り-airports/pages / index.vue
<template>
  <Tutorial />
</template>

<script>
export default {
  name: 'IndexPage'
}
</script>

次に、独自の静的Nuxtルートを作成して、これを拡張します。 ターミナルで、pagesディレクトリにabout.vueというファイルを作成して開きます。 拡張子の前のファイル名はURLパスになるため、この場合のURLはyour_site/aboutになります。 このabout.vueファイル内に、以下を追加します。

お気に入り-airports/pages / about.vue
<template>
  <div class="container mx-auto my-5">
    <h1 class="text-2xl leading-7 font-semibold">This is the About Page</h1>
    <p>This page contains the about information of this application. This is a static route created by Nuxt via the `about.vue` file in the pages directory</p>
  </div>
</template>

<script>
export default {
  name: 'AboutPage'
}
</script>

このページでは、<div>内に<h1>ヘッダーと<p>要素を作成しました。 次に、Tailwindクラスを使用して各要素にスタイルを追加し、フォントとマージンを設定しました。 <script>要素に、nameプロパティを追加して、Vueアプリでこのページを識別しました。

このファイルを保存して、http://localhost:3000/aboutに移動します。 作成したHTMLがブラウザに表示されます。

The About page created by the user with Nuxt, with a "This is the About Page" header and paragraph content.

静的ルートを作成したので、動的ルートの作成に進むことができます。 このルートには、後で.vueファイルで利用できるパラメーターが含まれます。 URL構造は/airport/:codeになり、:codeはデータセット内の空港コードに置き換えられます。

Vue Router では、routes配列に次のようなオブジェクトが含まれている可能性があります。

const routes = [
  { path: '/airport/:code', component: AirportDetail }
]

ただし、前に示したように、Nuxtのルートはpagesディレクトリを介して生成されます。 動的ルートを作成するには、.vueファイルがアンダースコア(_)で始まる必要があります。 アンダースコアに続くファイルの名前がパラメータ名になります。 これは、/airports/:code:codeに相当します。

ターミナルで、pagesの下にairportという名前の新しいディレクトリを作成します。

  1. mkdir pages/airport

airportディレクトリで、テキストエディタで_code.vueという名前のファイルを作成し、次を追加します。

お気に入り-airports/pages / airport / _code.vue
<template>
  <div class="container mx-auto my-5">
    <h1 class="text-2xl leading-7 font-semibold">This is the Airport Detail Page</h1>
    <p>This page contains the specific information about an airport.</p>
  </div>
</template>

<script>
export default {
  name: 'AirportDetailPage'
}
</script>

このファイルでは、スタイル付きの<h1><p>をページに再度追加していますが、今回は空港に固有のプレースホルダー情報が含まれています。 ファイルを保存して閉じます。

ブラウザを開いてhttp://localhost:3000/airport/cvgにすると、次のように表示されます。

The Airport Detail page, with the h1 header and paragraph element written in the Vue code.

このページを作成すると、airport.abbreviationプロパティがpagesディレクトリのcodeパラメータと一致するデータをフェッチできるようになります。 Nuxtには、ここに関連する2つの追加のフックまたはライフサイクルメソッドがあります。fetchasyncDataです。 fetchメソッドを使用して、ページがレンダリングされる前にネットワーク呼び出しを行うことができます。 asyncDataメソッドは、ページがレンダリングされる前にリアクティブデータをシェーピングするときに使用されます。

asyncData内にあるリアクティブデータは、そのページのdataにマージされます。 例として、次のコードを取り上げます。

export default {
  data() {
    return {
      lastName: 'Grohl'
    }
  },
  asyncData() {
    const firstName = 'Dave'
  }
}

これは、次のように書くのと同じです。

export default {
  data() {
    return {
      firstName: 'Dave',
      lastName: 'Grohl'
    }
  },
}

唯一の違いは、asyncDataがサーバーでレンダリングされるのに対し、dataはクライアントでレンダリングされることです。

asyncDataを試すには、airports.jsデータセットからオブジェクトを返すfilterループを作成します。

お気に入り-airports/pages / airport / _code.vue
...
<script>
import airports from '~/data/airports.js'

export default {
  name: 'AirportDetailPage',
  asyncData ({ route }) {
    const airport = airports.filter(airport => airport.abbreviation === route.params.code.toUpperCase())[0]

    return {
      airport
    }
  }
}
</script>

このコードでは、airports.jsデータをページにインポートし、abbreviationroute.params.codeが一致する場所を除くすべてのオブジェクトを除外します。 これはasyncDataフックで行われるため、airportは、templateで使用できるデータプロパティになります。

データを使用するには、同じファイルのtemplateセクションに次の強調表示された行を追加します。

お気に入り-airports/pages / airport / _code.vue
<template>
  <div class="container mx-auto my-5">
    <h1 class="text-2xl leading-7 font-semibold">This is the Airport Detail Page</h1>
    <p>This page contains the specific information about the <strong>{{ airport.abbreviation }}</strong> airport.</p>
  </div>
</template>
...

このファイルを保存して、空港の略語を動的にレンダリングします。 ブラウザウィンドウを開いてhttp://localhost:3000/airport/cvgにすると、テンプレートに空港コードが表示されます。 /airport/seaなどの別のコードで空港ルートにアクセスして、データが更新されていることを確認してください。

Nuxtで静的ルートと動的ルートを作成したので、これらのairports.jsオブジェクトのデータプロパティの表示に進むことができます。 次のセクションでは、Nuxtでlayoutsを作成し、それらをページに割り当てます。 それが完了したら、このステップで行ったことを活用して、より有用なデータをレイアウトに追加します。

ステップ3—Nuxtレイアウトを作成する

Nuxtでは、ページのレイアウトを作成して、アプリケーションをよりモジュール化することができます。 これは、従来のVue.jsアプリでレイアウトコンポーネントを作成するプロセスと似ていますが、Nuxtでは、ページレベルのlayoutプロパティを介してレイアウトを割り当てます。 このステップでは、動的に生成された空港の詳細ページごとに再利用するレイアウトを作成します。

レイアウトを作成するには、最初にプロジェクトにlayoutsディレクトリを作成します。

  1. mkdir layouts

このディレクトリにAirportDetail.vueという名前のファイルを作成して開きます。 このレイアウトでは、空港に関する情報を含むサイドバーが自動的に追加されます。 これを行うには、次のコードをファイルに追加します。

お気に入り-airports/layouts / AirportDetail.vue
<template>
  <div>
    <Nuxt />
  </div>
</template>

<script>
import airports from '~/data/airports.js'

export default {
  computed: {
    airport() {
      return airports.filter(airport => airport.abbreviation === this.$route.params.code.toUpperCase())[0]
    }
  }
}
</script>

このコードでは、airports.jsファイルをレイアウトにインポートし、computedプロパティを追加して、ルーターのcodeパラメーターを介して空港オブジェクトを取得します。 テンプレートの<Nuxt />要素は、ページのコンテンツが挿入される場所です。 これはVueスロットと同様に機能します。

次に、いくつかのTailwindクラスを活用します。 以下を追加して、レイアウトとスタイルを設定します。

お気に入り-airports/layouts / AirportDetail.vue
<template>
  <div class="container mx-auto grid grid-cols-9 mt-5 gap-5">
    <aside class="col-span-2">
      <!-- sidebar -->
    </aside>
    <main class="col-span-7">
      <!-- main content -->
      <Nuxt />
    </main>
  </div>
</template>
...

このスニペットでは、すべてをcontainerにラップしています。これは、3列幅のgridでもあります。 aside要素はサイドバーであり、main要素はメインコンテンツです。

このグリッドを作成したら、いくつかのTailwindクラスを含むサイドバーを追加します。

お気に入り-airports/layouts / AirportDetail.vue
<template>
  <div class="container mx-auto grid grid-cols-9 mt-5 gap-5">
    <aside class="col-span-2">
      <!-- sidebar -->
      <div class="shadow-md shadow-black mt-5 border p-5 rounded">
        
      </div>
    </aside>
    <main class="col-span-7">
      <!-- main content -->
      <Nuxt />
    </main>
  </div>
</template>
...

これにより、 box-shadow、border、border-radius、 padding、margin-topなどのいくつかのスタイルが追加されます。 このサイドバーの内側に、いくつかの情報を入力します。

お気に入り-airports/layouts / AirportDetail.vue
<template>
  <div class="container mx-auto grid grid-cols-9 mt-5 gap-5">
    <aside class="col-span-2">
      <!-- sidebar -->
      <div class="shadow-md shadow-black mt-5 border p-5 rounded text-center">
        <p class="text-3xl font-bold">{{ airport.abbreviation }}</p>
        <p>An airport located in {{ airport.city }}, {{ airport.state }}</p>
      </div>
    </aside>
    <main class="col-span-7">
      <!-- main content -->
      <Nuxt />
    </main>
  </div>
</template>
...

このコードは、空港固有の詳細をページに追加し、テキストを中央に配置します。

先に進む前に、airport.nameを値として<h1>を追加します。 これは、<Nuxt />要素の上にあります。これは、次のレイアウトですべてのページに表示されるためです。

お気に入り-airports/layouts / AirportDetail.vue
<template>
  <div class="container mx-auto grid grid-cols-9 mt-5 gap-5">
    <aside>...</aside>
    <main class="col-span-7">
      <!-- main content -->
      <h1 class="text-3xl font-bold mt-5">{{ airport.name }}</h1>
      <Nuxt />
    </main>
  <div>
</template>
...

これで、AirportDetailページの完全なレイアウトができました。 レイアウトファイルを保存して閉じます。

このレイアウトを使用するには、次にlayout: AirportDetailプロパティを使用するページに割り当てます。 テキストエディタでpages/airport/_code.vueを開き、次の強調表示された行を追加します。

お気に入り-airports/pages / airport / _code.vue
...
<script>
import airports from '~/data/airports.js'

export default {
  name: 'AirportDetailPage',
  asyncData ({ route }) {
    const airport = airports.filter(airport => airport.abbreviation === route.params.code.toUpperCase())[0]

    return {
      airport
    }
  },
  layout: 'AirportDetail'
}
</script>

これが完了したら、このファイルを保存して、ブラウザをhttp://localhost:3000/airport/cvgで開きます。 これで、次のことがわかります。

The airport detail page with the layout implemented.

注:ホットリロードは、この変更を常に自動的に実装するとは限りません。 ブラウザでレイアウトが表示されない場合は、CTRL + Cで開発サーバーを停止し、npm run devを再度実行してサーバーを再起動してください。

これが完了すると、適切な空港コードを使用してルートにアクセスすると、サイドバーに情報が自動的に表示されます。

このステップでは、レイアウトを作成してページに割り当て、アプリをDRYのままにしておくことができます。 次に、contextオブジェクトを使用して、ページ固有のプロパティを提供します。

ステップ4—ページ固有のプロパティでサーバーcontextを使用する

Nuxtアプリケーションはサーバー上でレンダリングされるため、ページのrouteparams、さらにはVuexストアにアクセスする方法が明確でない場合があります。 サーバー側のthisを介してVueインスタンス全体にアクセスできないため、NuxtはfetchおよびasyncDataフック。 このステップでは、contextを使用して、空港のページに動的なページの説明を追加します。

このチュートリアルの前のセクションでは、_code.vueファイルでcontextオブジェクトをすでに使用しました。

お気に入り-airports/pages / airport / _code.vue
<script>
  export default {
    asyncData ({ route }) {
      const airport = airports.filter(airport => airport.abbreviation === route.params.code.toUpperCase())[0]

      return {
        airport
      }
    },
    layout: 'AirportDetail'
  }
</script>

ここでは、routeプロパティをcontextオブジェクトから分解しました。これは、それが必要な唯一のプロパティであるためです。 ただし、contextctxなどの標準名を付けることもできます。

お気に入り-airports/pages / airport / _code.vue
<script>
  export default {
    asyncData (context) {
      const airport = airports.filter(airport => airport.abbreviation === context.route.params.code.toUpperCase())[0]

      return {
        airport
      }
    },
    layout: 'AirportDetail'
  }
</script>

contextオブジェクト、fetchメソッド、およびasyncDataメソッドもあります。 X185X]