「Vue.js入門」の没ネタ
Twitter で以外と読みたいというリアクションがあったので、没ネタせっかくなのでブログ記事で公開します!
「Vue.js 入門」読まれた方はご存知かと思いますが、Appendix の所で Flow はコラムとして取り上げられています。実はあそこはコラムではなく、 TypeScript といっしょに型システムについてセクションとして書かれていました。
というわけで、コラムになる直前の内容を若干この Medium のブログ記事で読みやすく体裁を整えながらもありのままの状態で以降で公開します!
結構長いので、流し読み的な感じで読んで雰囲気を掴んで貰えればと!
Flow
Flow は Facebook 社が開発した JavaScript 向け静的型チェックツールです。
Flow は一般的には AltJS として位置付けられていますが、既存の JavaScript コードに対して型情報を埋め込み、そのコードに対して静的に型チェックを行うことで検証するため、まさに Flow 公式が謳うチェックツールといえます。
Flowの特徴
Flow の特徴としては主に以下が挙げられます。
段階的に導入できる型注釈
Flow は、JavaScript コードに型情報を注釈(型注釈: type annotation)として埋め込むことによって、型チェックを可能にします。Flow の型チェックによりアプリケーションコードを堅牢にすることができ、かつスマートな実装コードにすることができます。
例えば、与えられた数値の自乗して返す以下のような単純なsquare
関数があるとしましょう。
function square (n) {
return n * n
}
// `2`が自乗された結果`4`が出力される
square(2)
// `NaN`が出力される
console.log(square('2'))
このコードはピュアな JavaScript で実装されたコードですが、square
関数の引数には数値以外の値も渡せてしまうため、数値以外の値を同関数の引数に渡して実行すると期待しない動作になります。このように JavaScript コードを期待する動作にさせるためには、変数や引数などに対して値や型を JavaScript コードでチェックしなければなりません。
Flow の型注釈を変数や引数などに埋め込むことで、このような煩わしいJavaScript コードによる煩わしいチェック処理を Flow によって静的に型チェックすることで省略化することができます。以下は、先のsquare
関数の引数に対して、数値しか渡せないよう型注釈したコードです。
/* @flow */
// 引数に対して`number`(数値)で型注釈。戻り値も型注釈することができる
function square (n: number): number {
return n * n
}
// 渡された値が`number`型であるため、型チェックによるエラーは発生しないsquare(2)
// 渡された値が`string`(文字列)であるため、型チェックでエラーが発生するsquare('2')
Flow による型注釈の記法は、: (型名)
のような形で書きます。Flow による型チェックを有効にするためには、JavaScript コードのファイルの先頭にマジックコメント/* @flow */
(もしくは// @flow
)が必要です。このマジックコメントがない JavaScript コードのファイルは、Flow による型チェックはデフォルトではチェックしない挙動になっているため(注釈1)、JavaScript で書かれた既存のアプリケーションに対して段階的に導入することができます。
注釈1: 設定次第ではマジックコメントがなくても Flow の型チェックするようデフォルトの挙動を変更することができます。
強力な型推論
Flow は OCaml で実装されているため型推論が強力です。Flow では型注釈しない場合は、どのような値も扱うことができるany
型として解釈しますが、型注釈されていない JavaScript コードにおいても、型チェック時にJavaScript コードを解析してコードにおいてエラーが発生する箇所を検出することができます。例えば以下のように、マジックコメントで型チェックを有効にすることで、Flow の型推論によってエラーを検知することができます。
/* @flow */
function square (n) {
return n * n // <- Flowがこの変数`n`部分でエラーが発生するのを検出
}
square(1)
square('2')
square(null)
開発プロジェクトへの Flow 導入
Flow は、Vue.js を利用したアプリケーション開発プロジェクトへ導入することができます。Flow の導入方法としてはいくつかありますが、Vue.js でアプリケーションを開発する場合は、単一ファイルコンポーネント(.vue
)を利用するのが一般的であるため、これに対して Flow による型チェックを対応できる必要があります。
以降では、vue-cli
のwebpack-simple
テンプレートで構築された初期状態のアプリケーション開発環境に対してFlowの導入について解説します。第8章ではwebpack
テンプレートを利用した開発について解説しましたが、これから解説する内容については、第8章ににおいてwebpack
テンプレートで構築した開発環境においても応用できるはずです。
インストール
Vue.js を利用したアプリケーション開発プロジェクトにおいて Flow を導入するためには、以下の NPM で公開されているツール、ライブラリなどをインストールします。
$ npm install --save-dev flow-bin
$ npm install --save-dev flow-typed
$ npm install --save-dev babel-preset-flow-vue
$ npm install --save-dev babel-eslint
$ npm install --save-dev eslint
$ npm install --save-dev eslint-plugin-vue
$ npm install --save-dev eslint-plugin-flowtype-errors
flow-bin
は型チェックするための Flow バイナリ本体がラップされたものです。
flow-typed
は外部ライブラリの Flow 型定義を利用するための CLI ツールです。flow-typed
によって外部ライブラリの Flow 型定義が管理されているレポジトリから必要な型定義をダウンロードして型チェックのために使用します。インストールされる型定義は、node_modules
にインストールされたモジュールから必要な型定義を、型定義レポジトリからダウンロードしてで解決します。管理レポジトリに型定義がなければ自動生成して全てany
型として扱います。
babel-preset-flow-vue
は Flow 関連の Babel プラグインを含んだ Vue.js 向けの Babel プリセットです。このプリセットは、Flow で実装されたコードを Babel で JavaScript コードにトランスパイルするために必要です。
babel-eslint
は、Babel でトランスパイル可能な JavaScript コードを解析するパーサーを ESLine 向けにラップしたものです。webpack-simple
テンプレート(webpack
テンプレートも)で構築された開発プロジェクトにおける単一ファイルコンポーネントのscript
ブロックの JavaScript コードは Babel によってトランスパイルされます。単一ファイルコンポーネントのscript
ブロックで Flow の構文で型付けされた JavaScript コードを型チェックするために必要です。
eslint
は JavaScript コードがある規約に則って書かれているかどう検証するリントツールです。残念ながら執筆時点において、Flow 単体では単一ファイルコンポーネントの.vue
ファイルに対して型チェックできません(注釈2)。ESLint は Flow 向けに対応した ESLint プラグインがあるため、このプラグインを利用することで型チェックできるようになるため、インストールしています。
注釈2: Flow の GitHub リポジトリの Issues にあるダーティーハックな方法か、src
属性で Flow の構文で実装されたコードを引き込むようにすれば可能ですが、コードの可読性や単一ファイルコンポーネントの利点が失われるためお薦めしません。https://github.com/facebook/flow/issues/2691
eslint-plugin-vue
は Vue.js 公式でサポートする単一ファイルコンポーネントをリントするための ESLint プラグインです。このプラグインは、主に単一ファイルコンポーネントのtemplate
ブロックのテンプレートをリントするためのものですが、script
ブロックの JavaScript コードも他のパーサーを指定することでリントできるようになっています。ESLint 向けに提供されるbabel-eslint
をパーサーとして指定することによって、script
ブロックで Flow の構文で実装されたコードを型チェックできるようになります。
eslint-plugin-flowtype-errors
は、Flow の型チェックで検出したエラーをリントのエラーとして検出するための ESLine プラグインです。このプラグインは、Flow の構文で実装されたコードをflow-bin
で型チェックして検出されたエラーを ESLint のエラーとして出力します。
Flow 導入に伴う設定
Flowで型チェックをするために必要なライブラリ、ツールなどをいくつかインストールしましたが、アプリケーションコードの型チェックするためには、いくつか設定が必要です。
Flow の設定
アプリケーションコードを Flow で型チェックをするためには Flow の設定が必要です。
以下のようにflow-bin
によってインストールされた CLI ツールflow
で、Flow の設定ファイルである.flowconfig
を生成します。
$ npx flow init
ここでは、NPM にバンドルされたnpx
によって NPM によってローカルにインストールされたflow-bin
コマンドを実行しています。
生成された Flow の設定ファイル.flowconfig
の内容を以下のように編集します。
[ignore]
.*/node_modules/.*
[include]
[libs]
[lints]
[options]
module.file_ext=.jsmodule.file_ext=.vue
[strict]
[ignore]
セクションには、Flow の型チェックを無視するために、node_modules
を設定します。これは Flow はデフォルトで.flowconfig
が配置されたルートから全てのファイルを探索して型チェックするため、アプリケーションコード以外の本質ではない部分も型チェックすることで大量のエラーが出力されるのを防ぐためです。
[options]
セクションでは、型チェックの対象となるファイルの拡張子として、JavaScript ファイルである.js
と単一ファイルコンポーネントファイルの.vue
を登録しています。ここで.vue
を登録しないと単一ファイルコンポーネントのscript
ブロックも Flow の型チェックの対象に入らないので設定が必要です。
他に様々なセクションがありますが、この解説で使用する開発環境は他の設定は必要ないため、Flow の設定は以上になります。
他のセクションについては、Flow 公式ドキュメントの.flowconfig
のフォーマットについて確認することができます。
Babel の設定
Flow の構文で実装されたアプリケーションコードは、そのままではブラウザでは動作しません。このため Flow の型注釈を取り除く必要があります。
本解説の開発環境では Babel を利用しているため、Babel の Flow 向けのプリセットによってインストールされたプラグインによって取り除くことができます。
これを実現するためには、Babel の設定ファイルである.babelrc
に以下のようにインストールしたプリセット名flow-vue
を追加するだけです。
{
"presets": [
["env", { "modules": false }],
- "stage-3"
+ "stage-3",
+ "flow-vue"
]
}
ESLint の設定
Flow の構文で実装されたアプリケーションコードを ESLint 経由で型チェックするために以下のように ESLint の設定します。
module.exports = {
root: true,
plugins: [
'vue',
'flowtype-errors'
],
parserOptions: {
parser: 'babel-eslint'
},
extends: [
'plugin:vue/base'
],
rules: {
'flowtype-errors/show-errors': 2
}
}
plugins
には、ESLint のプラグインのeslint-plugin-vue
とeslint-plugin-flowtype-errors
のプラグイン名(eslint-plugin
を取った形式)’vue’
と’flowtype-errors’
を設定します。これにより単一ファイルコンポーネントをこれら ESLint のプラグイン経由で Flow の型チェックを実行することができます。
parserOptions.parser
に’babel-eslint’
をパーサーとして設定します。これは単一ファイルコンポーネントのscript
ブロックのコードを Flow で型チェックするためです。このパーサーの指定がなければ単一ファイルコンポーネントを Flow で型チェックすることができません。
extends
には’plugin:vue/base’
を設定します。extends
で指定できるルールはeslint-plugin-vue
ではいくつか提供していますが、この解説では一番ゆるいルールを設定しています。
rules
に’flowtype-errors/show-errors’: 2
を追加します。これにより Flow による型チェックで検出したエラーを ESLint のエラーとして検出することができます。
型チェックするタスクの追加
設定の最後として、Flow の型チェックを実行するコマンドをnpm-script
のタスクとして以下のようにpackage.json
に追加します。
{
...
"scripts": {
"dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
- "build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
+ "build": "cross-env NODE_ENV=production webpack --progress --hide-modules",
+ "lint": "eslint --ext .js,.vue src"
},
...
}
Flow の型チェックは、ESLint 経由で実行するため、lint
タスクとして追加しています。
外部ライブラリの型定義ファイルを導入する
アプリケーション開発では Vue.js 本体、Vue Router などの公式ライブラリ以外に、NPM で公開されている様々な JavaScript の外部ライブラリをインポートして開発します。そのため、Flow で型チェックするためにインポートする外部ライブラリをの型を解決する必要があります。
以下のように、flow-typed
コマンドで外部ライブラリの型定義を導入することができます。
$ npx flow-typed install
インストールが完了すると、以下のようにプロジェクト直下にflow-typed
ディレクトリ配下に型定義ファイルが生成されます。
.
├── src.
├── flow-typed
│ └── npm
│ ├── webpack_vx.x.x.js
│ ├── webpack-dev-server_vx.x.x.js
│ ├── vue_vx.x.x.js
│ ├── vue-template-compiler_vx.x.x.js
│ ├── vue-loader_vx.x.x.js
│ ├── flow-typed_vx.x.x.js
│ ├── flow-bin_v0.x.x.js
│ ├── file-loader_vx.x.x.js
│ ├── eslint_vx.x.x.js
│ ├── eslint-plugin-vue_vx.x.x.js
│ ├── eslint-plugin-flowtype-errors_vx.x.x.js
│ ├── css-loader_vx.x.x.js
│ ├── cross-env_vx.x.x.js
│ ├── babel-preset-stage-3_vx.x.x.js
│ ├── babel-preset-flow-vue_vx.x.x.js
│ ├── babel-preset-env_vx.x.x.js
│ ├── babel-loader_vx.x.x.js
│ ├── babel-eslint_vx.x.x.js
│ └── babel-core_vx.x.x.js
.
上記のように、flow-typed
はnode_modules
ディレクトリにインストールされている型定義ファイルを生成します。
Flowで型チェックを実行する
Flow で型チェックするための設定がひと通り完了したので、Flow で型チェックできるかどうか確認してみましょう。
以下のように、本解説の開発環境に配置されたコードに Flow の型注釈とマジックコメントを埋め込みます。
`src/main.js`:
+/* @flow */
import Vue from 'vue'
import App from './App'
+const x: number = 'hello'
+console.log(x)
new Vue({
el: '#app',
render: h => h(App)
})
`src/App.vue`:
<template>
...
</template>
<script>
+/* @flow */
export default {
name: 'app',
data () {
+ const x: number = 'hello'
return {
msg: 'Welcome to Your Vue.js App'
}
}
}
</script>
<style>
...
</style>
編集が済んだら、npm run lint
で型チェックを実行してみましょう。筆者の環境では以下のように出力されます。
> flow-app-simple@1.0.0 lint /Users/path/to/flow-app-simple
> eslint --ext .js,.vue src
/Users/path/to/flow-app-simple/src/App.vue
27:23 error string: This type is incompatible with 'number'. See line 27 flowtype-errors/show-errors
/Users/path/to/flow-app-simple/src/main.js
5:19 error string: This type is incompatible with 'number'. See line 5 flowtype-errors/show-errors
✖ 2 problems (2 errors, 0 warnings)
JavaScript ファイルだけでなく、単一ファイルコンポーネントも ESLint 経由で Flow で型チェックできているのをコンソールの出力から確認できます。
以上で、Flow を利用して Vue.js のアプリケーションを開発可能な環境を構築しました。後は、Flow の構文を利用してアプリケーションを実装するだけです。
制限事項
これまでの解説で Vue.js のアプリケーション開発環境に Flow を導入ることで、アプリケーションコードを型チェックすることが可能になりましたが、いくつか制限事項があります。
生成された Vue.js 関連の型定義
flow-typed
によって、Vue.js 本体、Vue.js 関連ライブラリの型定義が生成することで Flow による型チェックを導入することが可能になりました。
しかしながら、flow-typed
で外部ライブラリ向けの型定義を管理するためのレポジトリに Vue.js 公式で提供していません。また、Vue.js 本体、Vue.js 関連ライブラリにおいてflow-typed
によって型定義が自動生成されるようFlow で実装していないため、flow-typed
ディレクトリ配下に生成されたVue.js 関連の型定義は全てany
型として定義されています。
このため、アプリケーションコードにおいて、Vue.js の API を利用したコードにおいて型注釈の恩恵を受けることができません。(注釈3)
注釈3: 筆者はflow-typed
による Vue.js の API の型定義を公開できるようサポートしようとしましたが、いくつか Flow に機能が足りないため、Facebook 社側でも Flow にその機能をサポートする気配がないため、現在ペンディング状態となっています。https://github.com/vuejs/vue/pull/5027
こうした状況から、Vue.js のアプリケーション開発においては、現時点ではアプリケーション固有のコードのみに Flow の型チェックを利用することを推奨します。
エディタ
一般的に、静的型付き言語のような型をサポートするような言語では、エディタなどの IDE において型の補完により生産性の高い開発が可能になります。Flow においても、Visual Studio Code、Atom-IDE、そして Web Storm などの型を補完できるエディタ、IDE によって生産性の高い開発をすることが可能です。
Vue.js においては前項でも解説したとおり、Flow 向けに型定義がサポートされていないため、これらエディタ、IDE において Vue.js の API の型の補完ができません。どうしても型の補完による生産性の高い開発を望む場合は、Flow ではなく以降で解説する TypeScript を利用することを推奨します。
いかがでしたでしょうか?
Flow で Vue.js アプリケーションの開発は、かなりいばらの道感満載です!
なぜ、Flow がコラム扱いになってしまったかは、Vue.js で特に Flow を使ったことがある人はお分かりでしょう!
自分の Flow 使ってて辛さは実感していたのですが、執筆してみるとさらに辛くて。。。
ちなみに、レビュー時にもこんな感じで指摘され、
追い打ちで
そして、自分の手でコラム化した次第です。
そのときの様子が、Twitterにあります。
労力かけたものがボツになると結構悲しいものですが、よりよい書籍にするためには、仕方がないことですよね。
最後に
ここまで最後まで読んで頂いたみなさまで、もし「Vue.js入門」をまだ購入されていないようでしたら、ぜひ本書をご購入いただけますよう重ねて申し上げます!🙏
Amazonで川口 和也, 喜多 啓介, 野田 陽平, 手島 拓也, 片山 真也のVue.js入門 基礎から実践アプリケーション開発まで。アマゾンならポイント還元本が多数。川口 和也, 喜多 啓介, 野田 陽平, 手島 拓也, 片山…www.amazon.co.jp
以上、没ネタでした。