MobX + Babel + webpack + Flow
地元の勉強会のための準備です。
前提
$ node -v v8.2.1 $ npm -v 5.3.0
準備。
$ npm init
MobX
インストールします。
$ npm i mobx -D
MobXを使ったストアのサンプル。このチュートリアル分かりやすいです。
MobX: Ten minute introduction to MobX and React
import { autorun, observable, action, computed } from 'mobx'; export default class TodoStore { @observable todos = []; @observable pendingRequests = 0; constructor() { autorun(() => console.log(this.report)); } @computed get completedTodosCount() { return this.todos.filter( todo => todo.completed === true ).length; } @computed get report() { if (this.todos.length === 0) { return "<none>"; } else { return `Next todo: "${this.todos[0].task}". ` + `Progress: ${this.completedTodosCount}/${this.todos.length}`; } } @action addTodo(task) { this.todos.push({ task, completed: false, assignee: null }); } }
デバッガー
mobx-remotedevを使います。
GitHub - zalmoxisus/mobx-remotedev: MobX DevTools extension
上のリンク先にも書いてある通り、まずはChromeの拡張機能である redux-devtools-extension をインストールします。
GitHub - zalmoxisus/redux-devtools-extension: Redux DevTools extension.
mobx-remotedevをインストールします。
$ npm i mobx-remotedev -D
TodoStoreに @remotedev
を追記します。
import remotedev from 'mobx-remotedev/lib/dev'; @remotedev export default class TodoStore { ・・・
babel
上のコードには、export、class、import、getter、デコレータなどが使われています。当然このままではブラウザでは動かないので、Babelでコンパイルする必要があります。
$ npm i babel-cli babel-preset-es2015 babel-preset-stage-1 babel-plugin-transform-decorators-legacy babel-plugin-transform-class-properties -D
.babelrcを用意します。
{ "presets": [ "es2015", "stage-1" ], "plugins": [ "transform-decorators-legacy", "transform-class-properties" ] }
package.jsonに build
タスクを定義してbabelを実行するようにします。
"scripts": { "build": "babel src -d dist" }
これでコンパイルできます。
$ npm run build
webpack
次は、webpackを使って依存関係を解決したjsファイルを作ります。
$ npm i webpack babel-loader -D
loaderとして babel-loader を使用する。 .babelrc を削除して webpack.config.js を作る。
module.exports = { context: __dirname + "/src", entry: { "application": "./index.js" }, output: { path: __dirname + "/dist", filename: "[name].js" }, module: { rules: [ { exclude: /node_modules/, loader: require.resolve("babel-loader"), options: { plugins: [ "transform-decorators-legacy", "transform-class-properties" ], presets: ["es2015", "stage-1"] } } ] } }
webpackのentryとなるjsファイルを用意する。
import TodoStore from './TodoStore'; const observableTodoStore = new TodoStore(); window.observableTodoStore = observableTodoStore;
package.jsonの build をbabelからwebpackを使うように変更する。
"scripts": { "build": "webpack" }
これでBabelを使ってコンパイルして、webpackを使って依存関係を解決したJavaScriptファイルを作成できる。
$ npm run build
おしまい
dist/application.js
として出力されるので、これをhtmlで読み込めばTodoStoreを使えます!
package.jsonはこんな状態。
{ "name": "mobx-todo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build": "webpack" }, "devDependencies": { "mobx": "^3.2.1", "babel-cli": "^6.24.1", "babel-loader": "^7.1.1", "babel-plugin-transform-class-properties": "^6.24.1", "babel-plugin-transform-decorators-legacy": "^1.3.4", "babel-preset-es2015": "^6.24.1", "babel-preset-stage-1": "^6.24.1", "mobx-remotedev": "^0.2.8", "webpack": "^3.3.0" } }
Flow (おまけ)
Flowで型チェックしてみる。
$ npm i flow-bin flowtype babel-preset-flow -D
TodoStoreを書き換える。
// @flow import { autorun, observable, action, computed } from 'mobx'; import remotedev from 'mobx-remotedev/lib/dev'; type Task = { task: string, completed: boolean, assignee: ?string, } @remotedev export default class TodoStore { @observable todos: Array<Task> = []; @observable pendingRequests: number = 0; constructor() { autorun(() => console.log(this.report)); } @computed get completedTodosCount(): number { return this.todos.filter( todo => todo.completed === true ).length; } @computed get report(): string { if (this.todos.length === 0) { return "<none>"; } else { return `Next todo: "${this.todos[0].task}". ` + `Progress: ${this.completedTodosCount}/${this.todos.length}`; } } @action addTodo(task: string): void { this.todos.push({ task, completed: false, assignee: null }); } }
webpack.config.jsを書き換える。
@@ -15,9 +15,10 @@ module.exports = { options: { plugins: [ "transform-decorators-legacy", - "transform-class-properties" + "transform-class-properties", + "transform-flow-strip-types" ], - presets: ["es2015", "stage-1"] + presets: ["es2015", "stage-1", "flow"] } } ]
package.jsonにflowタスクを追加します。
"scripts": { "build": "webpack", "flow": "flow" }
Flowで型チェック
$ npm run flow