ポートフォリオ作ったらNuxtJSを理解できたのでやったことを書いてく


今年で30になったプログラマですが、ポートフォリオサイトを作りました。

ポートフォリオサイトはこちら
Storybookはこちら

はじめに

Vue、NuxtJSともに未経験だったので一通りチュートリアルをやったのですが、正直全然理解出来てない感があって「これじゃあ戦力にならんなぁ」と思い、ある程度のサイト作りぐらいは出来るようにするためポートフォリオサイトを作成しました。実際にやってみて、約1ヶ月で困らない程度には理解できたかなと思っています。この程度のポートフォリオサイトであればベライチのhtmlで済む話なのですが、昨今のフロントエンドは状態管理、SSR×SPAなどいろいろやらなければいけないことが多いので基本的な技術は全て使うよう開発をしました。

構成

フロントがNuxtJS、Vue、ホスティングがNetlify、バックエンドが.NET Core、C#をコンテナ化し、ホスティングはHerokuとなっています。

バックエンドは今回の勉強対象外なので、経験のある(なにも調べなくても書ける).NET Coreを使いました。公開しないのであればJSON Serverでも良いかもしれません。

期間


昨年の12/22から開始したので約1ヶ月間、1日1時間程度コツコツと進めました。僕は毎日集中出来るタイプでもなくたまにサボりたくなるので、そんな気分のときはスタイルいじったり、調べ物する日にしたりと気分転換してました。

決め事

最近のフロントエンドはやることが多いです。やることは多いけれども、3大フレームワークで抑えておくべきスキルセットは共通してきたと思うので以下にあげる技術は絶対に取り入れると決めました。

  • HttpClient(axios)
  • SSR(universal)
  • 状態管理(vuex)
  • eslint + prettier
  • jest
  • storybook

jestはカバレッジを100%、storybookはknob addonを使った動的なコンポーネントの変更を出来るようにしています。あとこれは僕の完全な感覚なのですが、vueはtypescriptの導入が一歩遅く導入しているところは多くはないと思うのであえてesで書くようにしました。

雰囲気を掴むためにチュートリアルを一周する

NuxtJSとはなんぞや?というところからVuexまで一通りやります。1日30分、1週間やれば一通り出来ると思います。僕はリポジトリを作ってチュートリアルのやりながらコミットを積んで行きました。

勉強用リポジトリ

カバレッジを100%にする

はじめにカバレッジを100%にしましょう。テストははじめにやらないと一生出来ないのでcreate-nuxt-appの直後にやりましょう。

jest.config.js
coverageThreshold: {
  global: {
    branches: 100,
    functions: 100,
    lines: 100,
    statements: 100
  }
},

これでもう逃げられません。さらに初期設定ではpagecomponentしかテスト対象でないのでstoreやその他もろもろ追加しましょう。

jest.config.js
collectCoverageFrom: [
  '<rootDir>/src/**/*.{js,vue}',
  '!<rootDir>/src/layouts/**/*',
  '!<rootDir>/src/plugins/**/*'
],

Storybookを準備する

これもはじめにやらないとやる気がなくなるので早いうちに準備しておきましょう。正直、初学でテストとStorybookは鬼畜です。非常に辛いのですが、簡単な設計にするようになり、全体的に可読性が自然とよくなるのでここは我慢です。テスト出来るってことはある程度構造化されているってことなんですねー。

Storybookは自動セットアップがあるので私はnpx -p @storybook/cli sb init --type vueしました。後々addonspreview-headなど必要になるので手動セットアップの方がよいかと思いました(僕はここで時間を潰しました)。

storybookガイド

componentを動的に変更するためにknobを入れましょう
npm i -save @storybook/addon-knobs

.storybook/addons.js
import '@storybook/addon-knobs/register'; 

僕が思うstorybookの位置付け的にデザイナーさんとのやりとりツールというイメージだったのでアドオンはknobsしか入れませんでした。

これはどちらでもよいかと思いますがnpm run build-storybookするとstorybook-static/がソース管理対象になるので.gitignoreに追加してもよいかもしれません。

http-serverを入れる

今回はuniversalモードで作るのでNetlifyにnuxt generateでホスティングしました。ローカルで確認するためにhttp-serverを入れます。

npm i http-server --save

package.json
"scripts": {
  ...
  "webserver": "http-server ./dist -o -p 8888"
},

これでdist直下のファイルを確認することが出来ました。

拡張を入れる

開発するための必需品です。私はVSCodeを使っているのでVSCodeのプラグインを記載します。

  • Vue.js devtools

Storeの中身など見れるので便利です。必須。
https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd

  • VSCode拡張

ここを参考にさせてもらいました。
https://qiita.com/dayoshix/items/c61a75a971331418c348

Netlifyの準備をする

  • appのパスを変える

npx create-nuxt-app <project-name>をすると<project-name>直下にnuxt appが生成されるのでNetlifyでデプロイエラーになりました。nuxt.configpackage.jsonはrootに持っていき、ソースは別のディレクトリで管理するよう変更しました。

nuxt.config.js
export default {
  ...
  srcDir: 'src/'
  ...
}
  • サーバーサイドレンダリングの対策

nuxt generateではindex.htmlしか生成されないため、リロードすると「Page Not Found」になってしまいます。こちらの対策方法は以下の通りです。

nuxt.config.js
export default {
  ...
  generate: {
    fallback: true
  }
  ...
}

Netlify へデプロイするには?

エラーハンドリングを作る

  • エラーページ

存在しないページには404ページへ、エラーは500ページへなどエラーハンドリングも実装します。nuxtはエラーページという機能を持っているので以下のように実装します。詳しくはこちらに載っています。

layouts/error.vue
<template>
 <div class="container">
    <h1 v-if="error.statusCode === 404">ページが見つかりません</h1>
    <h1 v-else>エラーが発生しました</h1>
    <nuxt-link to="/">ホーム</nuxt-link>
  </div>
</template>
<script>
export default {
  props: {
    error: {
      type: Object,
      default: null
    }
  }
}
</script>

error.statusCodeでh1を切り替えています。リッチナブルにしたい場合はステータスコード毎にcomponentを作ってもいいかもしれませんね。

  • axiosのエラーハンドリング

axiosでエラーが発生した場合はinterceptorsのonErrorヘルパでキャッチしました。これでエラーページへ遷移します。

plugins/axios.js
export default function({ $axios, error }) {
  // ref. https://axios.nuxtjs.org/helpers
  $axios.onError((err) => {
    const code = parseInt(err.response && err.response.status)
    error({ statusCode: code })
  })
}

ライブラリを使う

やっとちゃんとしたコーディングに入れるようになってきました。

  • VeeValidate

フォームのバリデーションがすごく簡単に書けるライブラリです。問い合わせフォームに使いました。

plugins/vee-validate.js
import { extend } from 'vee-validate'
import { required, email } from 'vee-validate/dist/rules'

// No message specified.
extend('email', email)

// Override the default message.
extend('required', {
  ...required,
  message: 'This field is required'
})

上記のファイル作成して実行すると

Babelで変換しないといけないので以下を追加します。

nuxt.config.js
build: {
    transpile: ['vee-validate/dist/rules'],

    extend(config, ctx) {}
    ...
}

VeeValidate公式

  • axios-mock-adapter

axiosのモックを作成するためのライブラリです。テストするためには必須でした。

axios-mock-adapter公式

  • marked

Nuxtを勉強しているはずが、cssにかける時間が多かったのでマークダウンを投入しました。ポートフォリオの詳細ページで利用しています。

  • analytics-module

公式が出しているanalyticsのライブラリです。ものすごく楽です。

妥協する

カバレッジは100%にすると書きましたが、100%にすれば良いんです(ダメ)。v-modelでBranchが100%に出来なかった、、だれか教えてください。。

jest.config.js
module.exports = {
    ...
    coveragePathIgnorePatterns: ['xxx.vue']
}

モックはJsonをそのまま返しちゃえ

var result = JsonSerializer.Deserialize<dynamic>(jsonString);
return Ok(result);

storybookに全てのコンポーネントを反映しなくてよいよね

一通りvueを味わってみて

簡単と言われていましたが、普通に難しかったです。SPAしか開発したことがなかったのでCSRとSSRがわかってなかったことを痛感しました。でもNuxtJS面白いのでおすすめです。

一応Github公開しています