作りたいものがありすぎる

40歳を過ぎてプログラミングを始めた人の顛末とこれからなど

【輪読会資料】基礎から学ぶVue.js CHAPTER7 より大規模なアプリ開発 読書メモ

以下の記事は2019/3/28 コワーキングスペース秋葉原Weeybleで行われる輪読会
[秋葉原] 基礎から学ぶVue.js輪読会 ch7 より大規模なアプリ開発(初心者歓迎!)のための読書メモとなります。
以下の書籍の CHAPTER7 より大規模なアプリ開発 のメモです。

基礎から学ぶ Vue.js

基礎から学ぶ Vue.js

CHAPTER 7 より大規模なアプリケーション開発

SECTION 33 アプリケーションを拡張しよう

Vue.js本体は画面の描画に関わる機能しか備えていないが、以下の様なエコシステムを導入すると機能を拡張できる。

Vuex

複数のコンポーネントでデータを共有したり、アプリケーション全体の状態を一元管理する状態管理用のライブラリ

Vue Router

コンポーネントで構造化された複数の画面をURLと紐づけるSPA(Single Page Application)構築の為のルーティング用のライブラリ

Vuex と Vue Routerは機能として独立しており、状況に応じて片方だけでも構築が可能。 それぞれの特徴はCHAP8,CHAP9で解説している。

ここでは単一ファイルコンポーネントを使ったコンポーネント構築とVueCLIを使ったビルド環境の導入を前提としての説明をする。

SECTION 34 Vue CLIとは

Vue CLIとはVue.jsを使ったコマンドラインインターフェース、Vue.jsの開発環境構築が簡単にできる

ソースコードを分けて管理

分割して作ったファイルをコンパイル時等に結合して一つのファイル化させる方法

モジュール化でさらに快適に!

モジュール化で作られたファイルは多くの機能から必要なものだけピックアップして組み込める。
Vue.jsのモジュール化は「単一ファイルコンポーネント」を採用している。
単純に結合しても動くわけではなく、補完する機能として代表的なものに「webpack」といったバンドルツールがある。
webpack以外にも多くのツールの複雑な設定を自動管理してくれるのが「Vue CLI」となる

webpackとは

モジュール化した複数のファイルをまとめるバンドルツール、他にも[Rollup]や[Parcel]といった別種が存在する。詳細は公式サイトを参照の事 webpack 公式サイト

モジュール化の際は、必要なリソースだけをバンドルするようになっているので、自動的に余計なものが付かないで最小単位で出力されるようになっている。

SECTION 35 単一ファイルコンポーネントとは

「単一ファイルコンポーネント」はコンポーネントの定義方法の一つでSFC(Single File Components) とも言われる
一つのファイルで管理しきれないHTML,JavaScript,CSSを[.vue]という拡張子のファイルにまとめて管理する。

単一ファイルコンポーネントの例
Example.vue

<template>
  <div class="example">
    <span class="title">{{ text }}</span>
  </div>
</template>

<script>
  export default {
    name: 'Example',
    data() {
      return {
        text: 'example'
      }
    }
  }
</script>

<!-- scoped CSS -->
<style scoped>
  .title {
    color: #ffbb00;
  }
</style>

こいつをビルド環境でプレーンなJavaScriptにプリコンパイルする

スコープ付きCSS(Scoped CSS)

<style>タグでscoped オプションを付けるとスコープ付きCSSを利用できる。(<style scoped>)このテンプレート内でしかスタイルが適用されないようにできる。

出力される際には以下の様なユニーク属性で管理される

<div class="example" data-v-xxxxx>
  <span class="title" data-v-xxxxx> hoge </span>
</div>
span.title[data-v-xxxxx] { color: #ff0000; }

これでクラス名の衝突を気にしなくて良くなる。なお、全くクラスの指定がないとパフォーマンスが落ちるので classでスタイル定義をするのが推奨されている。

コンポーネントの扱い

テンプレート内に子コンポーネントが存在する場合、子のルート要素とスロットの要素は親と子の両方のスコープを持つ

<div class="example">
  <child-comp/>
</div>

親と子両方に<style scoped>をを指定した際は以下の様に展開される

<div class="example" data-v-aaaaa>
  <div data-v-aaaaa data-v-bbbbb><!-- このルート要素 -->
    <span data-v-bbbbb>child-comp</span>
  </div>
</div>

この様にルート要素のスタイルはどちらのファイルにも書くことができるので、柔軟にレイアウト変更が可能となる。

スコープをまたぐ設定

お互いにスコープの付いたコンポーネントから子のセレクタ .bを指定したい例
cssの場合

<style scoped>
.a >>> .b {color: #ff0000; }
</style>

scssの場合

<style lang="scss" scoped>
.a /deep/ .b {color: #ff0000; }
</style>

外部ファイルの読み込み

<template src="./template.html"></template>
<style src="./script.js"></style>
<style src="./style1.css"></style>
<style src="./style2.css" lang="scss" scoped></style>

他のマークアップ言語やスタイルシート言語の仕様

cssやscssの他に、[Pug],[Sass]を使用等をすることができる。Vue CLIで作成したプロジェクトなら、パッケージを以下の様にインストールしてから…

npm install pug pug-loader --save-dev

以下の様に書くだけで使用可能

<template lang="pug>
  div#example
    span {{ text }}
</template>

SECTION 36 ES2015モジュールの書き方

ES2015モジュールは .js でファイルを作成するが、モジュールファイルは独自のスコープを持ち、他のファイルとは切り離される、変数の衝突や他の機能への干渉を気にしなくて良くなる反面、モジュール内で定義したデータや関数は他のファイルから直接アクセスできなくなる。

モジュールを定義する

Example.js

// stateオブジェクトはこのモジュール内でしか使用できない
var state = {
  count :1
}

モジュール内のデータや関数を別のファイルに渡すにはエクスポート&インポートが必要
次の例はstateオブジェクトをエクスポートして、外部でインポートできる様にした例

Example.js

var state = {
  count :1
}
// デフォルトのインポート文で呼ばれた時に返すデータ
export default state

モジュールを使用する

前述のExample.jsstateオブジェクトをExampleという変数名でインポートした例
main.js

import Example from './Example.js'
console.log(Example.count)  // => 1と出力

このような書き方は Vuex, Vue Router ファイルを書く際に必要なので覚えておくこと!

SECTION 37 Node.jsの導入

node.jsJavaScriptの実行環境、サーバーサイドでJSを動かす際に必須
npmはJSのパッケージ管理ツール、node.jsに一体化して付いてくる。 PHPでいう所のcomposer的な奴

以下からインストール
node.js 日本語公式サイト windows10の場合はそのまま画面の指示に従いインストール
コマンドプロンプトで以下のコマンドでバージョンを出してインストールされたか確認する。
今回は推奨版10.15.3 LTS をインストールした

node -v
v10.15.3
npm -v
6.4.1

Babelとは

ECMAScript準拠およびJSXのトランスパイラ、Vue CLIはデフォルトでBabelをインストールしてトランスパイルを行う。

トランスパイル(transpile)
一言で言えば、ある言語で書かれたコードを元に別の言語のコードを生成すること。

BabelはES2015のコードを古いES5のコードに変換してくれる

ES2015のコード トランスパイル ES5のコード
const count = 1 => var count = 1

Babelの目的やメリットは最新の記法を使って書ける様にすることにある

SECTION 38 Vue CLIの導入

Vue CLIをインストール

npm install -g vue-cli

バージョンを確認

vue --version
2.9.6

プロジェクト作成コマンドのひな形

vue init [テンプレート名] [プロジェクト名]
cd [プロジェクト名]
npm install

テンプレートは[webpack], [webpack-simple]が良く使われる,他にも[PWA],[Electron]等の様々なアプリケーション用のテンプレートが公開されている。
ここでは[webpack]を使って説明をして行く

新しいプロジェクトの作成

アプリを入れたい適当なフォルダに移動(cd)してから次のコマンドを実行
(Git bashで操作)
作ったフォルダ自体が localhost:8080 の実行環境になってそのまま開発環境のsever化してくれるので、本当にフォルダの場所とか適当で良い様です。

# htdocsに移動
$ cd /c/xampp/htdocs

# プロジェクトの作成
vue init webpack vue-my-app
$ vue init webpack vue-my-app
# 質問が出るので色々選択しながら進む、今回は以下の設定で進んだ。
? Project name (vue-my-app)
? Project name vue-my-app
? Project description (A Vue.js project)
? Project description A Vue.js project
? Author (Taro Yamada <yamada@gmail.com>)
? Author Taro Yamada <yamada@gmail.com>
? Vue build runtime
? Install vue-router? (Y/n) n
? Install vue-router? No
? Use ESLint to lint your code? (Y/n) n
? Use ESLint to lint your code? No
? Set up unit tests (Y/n) n
? Set up unit tests No
? Setup e2e tests with Nightwatch? (Y/n)
? Setup e2e tests with Nightwatch? Yes
? Should we run `npm install` for you after the project has been created? (recom
? Should we run `npm install` for you after the project has been created? (recom
mended) npm

すると htdocsフォルダ内に vue-my-appフォルダが作られ、中に色々ファイルが作られる

$ ls -a vue-my-app/
./   .babelrc       .gitignore     build/   index.html     package.json       README.md  static/
../  .editorconfig  .postcssrc.js  config/  node_modules/  package-lock.json  src/       test/

フォルダとファイルの構成

[webpack]を使用した際、いろんなファイルやフォルダが作られるが、基本的に[src]フォルダ以下の物しか使わない
単一ファイルコンポーネントの[.vue]ファイルは慣例的に src/componentsにまとめる

src/main.js でコンストラクタの呼び出しが行われている

/* eslint-disable no-new */
new Vue({
  el: '#app',
  render: h => h(App)
})

開発サーバーを起動する

vue-my-appフォルダ内に cd してから以下のコマンドを入れてサーバーを起動する

npm run dev

ブラウザでhttp://localhost:8080/にアクセスしてVue.jsのロゴとWelcome to Your Vue.js App のメッセージが出力されればOK!
サーバーを起動させたコンソールは開きっぱなしにしておくこと

ホットリロード

ホットリロードはブラウザリロード不要でファイル変更の際に更新してくれる機能
vue-my-app/src/components/HelloWorld.vueファイル内のmsg: 'Welcome to Your Vue.js App'を編集して上書きすると即座ぶブラウザが更新されるのが確認できる。超便利!

プロジェクトをビルドする

実際に運用モードとしてビルドするには以下のコマンドを入れる

npm run build

数分かかる。ビルドが終わると[dist]フォルダが作成される。
この[dist]フォルダだけを本番サーバーにアップロードすれば、ローカルからのビルドとデプロイが完了する。
ちなみに以下のサポートページで、静的サイト向けの高機能なホスティングサービスNetlifyの自動デプロイの方法についての記述がある。
Vue.js+Netlifyで自動デプロイ

開発時のAPIのパス統一やクロスドメイン対策

本番環境と開発環境でAPIのパスが異なる場合や、別ドメインAPIからデータを取得する際はプロキシ設定が必要となる。config/index.jsに以下の様に記述することで切り替えができる

before config/index.js

    proxyTable: {},

after config/index.js

    proxyTable: {
      '/api' : {
        taget: 'http://localhost:8081',
        changeOrigin: true,
        pathRewrite: {
          '^api'; '/vue-my-app/api'
        }
      }
    },

例えばAPI/api/userを叩くと 異なるドメインから user のAPIを取得できるように実装がされているとする。

プロキシを使うと以下へのアクセスは

http://localhost:8080/api/user

以下の様に変更できる

http://localhost:8081/vue-my-app/api/user

より詳細はwebpackのドキュメントを参照のこと

SECTION 39 Vue.jsプラグイン

CHAPTER1で紹介されたElement,Awesome Vue,VueCurated等のUIコンポーネントや、Vuex,Vue RouterはVue.jsプラグインとして作成されている。
ここではVue.jsプラグインの使い方と自作プラグインの作成方法の紹介となる。

Vue.jsプラグインの使い方

コンストラクタを使用する前にグローバルメソッドのVue.useを使用してVue.jsに登録する

src/main.js の上の行に書く?

// VueとVuexのモジュールを読み込む
import Vue from 'vue'
import Vuex from 'vuex'
// VueにVuexを登録
Vue.use(Vuex)

スタンドアロン版でプラグインを使用する場合

Vuexの様な公式提供の奴はVue.useを使わずとも良い。
Vue.js本体を読み込んだ後にプラグインのファイルを読み込む

公開されているリソースはプラグインだけじゃない

コンポーネントやカスタムディレクティブとして登録するのものある

プラグインを自作してみる

入門向けではないが一応説明、大規模アプリの開発リソースの再利用の際にプラグイン作成できると便利だそうな。
具体的にどのファイルのどこに書けばいいのか分らずなのだが、それはここまで読んだ内容を理解してないせいか、後の章で書かれるかだと思います。

スクロール数値を共有するプラグイン

var windowPlugin = {
  install: function(Vue) {
    // プラグインデータ用にVueインスタンスを利用する
    var store = new Vue({
      data: {
        scrollY: 0
      }
    })
    // ウィンドウのスクロールイベントをハンドル
    var timer = null
    window.addEventListener('scroll', function() {
      if (timer === null) {
        timer = setTimeout(function() {
          // 200ms間隔でscrollYプロパティに代入
          store.scrollY = window.scrollY
          clearTimeout(timer)
          timer = null
        }, 200)
      }
    })
    // インスタンスプロパティに登録
    Vue.prototype.$window = store.$data
  }
}

プラグインを登録

Vue.use(windowPlugin)

すべての Vue インスタンスで使用可能

Vue.component('my-component', {
  template: '<div>{{ scrollY }}</div>',
  computed: {
    scrollY: function() {
      return this.$window.scrollY
    }
  }
})

SECTION 40 ES2015で書いてみよう

新しいJavaScriptの書き方、ES2015(ES6)は対応してないブラウザがあるが、既に説明した通り、Babelが古いJS形式にトランスパイルしてくれるので、Vue CLIではES2015形式で遠慮せずに書ける。ここではES2015の書き方の説明となる。

正直ちゃんと追って無かったので、この知識はありがたい。

変数宣言

ES5

var x = 0

ES2015

// 再代入可能
let x = 0

// 定数 再代入不可
const x = 0

ES2015はスコープで仕切られる
ES5

{
  var x = 1
}
console.lod(x) // 1

ES2015

{
  let x = 1
}
console.lod(x) // not defined

constで宣言した配列は空配列を再代入できない。か、 lengthを0にすると配列を空にできる

const array = [1, 2]
array.push(3)
console.log(array) // -> (3) [1, 2, 3]
array.length = 0
console.log(array) // -> []

関数とメソッドの書き方

functionの省略

ES5

new Vue({
  methods: {
    handleClick: function() { ... }
  }
})

function は書かなくても良い
ES2015

new Vue({
  methods: {
    handleClick() { ... }
  }
})

アロー関数

functionを省略して => で書ける関数thisの扱いが従来の関数と異なり、アロー関数式で宣言された関数は、宣言された時点で、thisを確定(=束縛)させてしまう。
その為メソッド内のthisが必要な場面では使用できないが無名関数の定義で便利とのこと
【JavaScript】アロー関数式を学ぶついでにthisも復習する話

let normalFunc = function(x){
    console.log(x);
}
normalFunc('今までの関数');

let arrowFunc = (y) => {
    console.log(y);
}
arrowFunc('アロー関数式');

STEP1

const newArray = array.map(el => {
  return el * 2
})

STEP2 returnを省略

const newArray = array.map(el => el * 2)

慣れの問題だが、ここまで省略されると認識し辛いなぁ

STEP3 複数の引数

const newArray = array.map((el, index) => el * 2)

STEP4 オブジェクトの return

const newArray = array.map(el => ({ value: el * 2 }))

簡単な奴から使って慣れると良いよ。と作者もおっしゃってます。

テンプレートリテラル

クォーテーションで囲んでバックスラッシュで改行
ES5

var name = 'hoge'
var template = '\
  <div class="template">\
    <strong>' + this.name + '</strong>\
  </div>'
console.log(template)

バッククォートで囲むだけで改行含めて受け付けてくれる
ES2015

const name = 'hoge'
const template = `
  <div class="template">
    <strong>${ name }</strong>
  </div>`
console.log(template)

オブジェクトプロパティのショートハンド

ES2015では変数名とプロパティが同じなら省略して書ける
ES5

const newObject = {a: a, b: b}

ES2015

const newObject = {a, b}

分割代入

べんりー
ES2015

// 配列要素1,2をそれぞれ変数a,bに代入
const [a, b] = [1, 2]
console.log(a) // -> 1
// nameプロパティだけ代入
const { name } = { id: 1, name: 'りんご' }
console.log(name) // -> りんご

引数のオブジェクトを分割して受け取ることも可能
ES2015

function myFunction({ id, name }) {
  console.log(name) // -> りんご
}
myFunction({ id: 1, name: 'りんご' })

v-forディレクティブでも使える

<ul>
  <li v-for="{ id, name } in list" :key="id">...</li>
</ul>

スプレッド演算子

配列、オブジェクトのリテラルを展開する  ...hoge
ES2015

const array = [1, 2, 3]
// バラバラの3つの引数として渡す
myFunction(...array)
// arrayを展開して4を加えた新しい一次配列を作成
const newArray = [...array, 4] // -> (4) [1, 2, 3, 4]

配列メソッド

findメソッド

条件に一致した最初の要素の値を1つ返す
(そういえばこういう処理、スゲー大変だった気がする)

ES2015

const array = [
  { id: 1, name: 'りんご' },
  { id: 2, name: 'ばなな' }
]
const result = array.find(el => el.id === 2)
console.log(result) // -> { id: 2, name: 'ばなな' }

見つからない場合は undefind が返る

findindex

条件に一致した最初の要素のインデックスを1つ返す

const array = [
  { id: 1, name: 'りんご' },
  { id: 2, name: 'ばなな' }
]
const result = array.findIndex(el => el.id === 2)
console.log(result) // -> 1  (indexは0始まりなので2番目は1)

Promise

非同期処理を抽象化したオブジェクト。(もうajaxとかじゃない!)
Promiseで非同期処理の完了を知ることができる。
引数としてresolve(解決した)と、reject(拒否した)のコールバック関数を受け取る。
( $.ajaxの .done .fail みたいな感じか )

成功を知る例

function myFunction() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // 成功したことを通知
      resolve('success!')
    }, 1000)
  })
}
// 1秒後にmyFunctionが終わった知らせを受けてthenの処理が行われる
myFunction().then(value => {
  console.log(value) // -> success!
})

拒否(失敗)した事を知る例、かつ成功、失敗の両方の処理を書いた例

function myFunction(num) {
  return new Promise((resolve, reject) => {
    if (num < 10) {
      resolve('success!')
    } else {
      reject('error!')
    }
  })
}
myFunction(100).catch(value => {
  console.log(value) // -> error!
})

成功、拒否、どちらでも処理する際はfinallyを使う

myFunction().then().catch().finally(() => {
  // 成功でも失敗でも行われる
})

Gitリポジトリからcloneして動かす際

プロジェクトフォルダをそのままリモートリポジトリに上げる。 別の環境でnode.jsをインストールして任意のフォルダで以下の操作をするだけでOK

git clone **url**
npm install
npm run dev

これだけで動く

□まとめ

  • Vue CLI はVue.jsプロジェクトのベースを構築してくれる
  • Vue CLI で単一ファイルコンポーネントを手軽に使用できる
  • ES2015以降のECMAScriptを使ったコーディングが可能、基本を把握しておく