書いている人にフロントエンドの知識は無い。bootstrapすげええで頭の中の時代が止まってる。ES6 の構文も知らない。やばい。
[追記]先にリアクティブプログラミングについて調べた方がいい。
環境の準備
create-cycle-app を入れる
npm install -g create-cycle-app
コマンドでcreate-cycle-app を叩く
create-cycle-app my-awesome-cycle-app
ES6で書くかtypescript で書くか?等色々聞かれる。コマンドが自動的にnpm install とか行ってくれて、最終的に以下のような構造を持つディレクトリが出来上がる。
my-awesome-cycle-app/
├── node_modules/
├── public/
│ ├── favicon.ico
│ └── index.html
├── src/
│ ├── app.js
│ ├── app.test.js
│ └── index.js
└── package.json
出てきたコードを見る
import {div} from '@cycle/dom'
import xs from 'xstream'
export function App (sources) {
const vtree$ = xs.of(
div('My Awesome Cycle.js app')
)
const sinks = {
DOM: vtree$
}
return sinks
}
import {run} from '@cycle/xstream-run'
import {makeDOMDriver} from '@cycle/dom'
import {App} from './app'
const main = App
const drivers = {
DOM: makeDOMDriver('#app')
}
run(main, drivers)
動作確認
npm start
でサーバーが立ち上がる。デフォルトでlocalhost:8000 に立ち上がるので、見に行く
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
<link rel="icon" href="/favicon.ico" type="image/x-icon">
<title>My Awesome Cycle.js app</title>
</head>
<body><script type="text/javascript" src="//localhost:35729/livereload.js?snipver=1" async="" defer=""></script>
<div id="app"></div>
<script src="bundle.js"></script>
</body>
</html>
すげーライブプレビューのjsが動いてたり、bundle.js が動的にdiv id="app" の中身を書き換えてるのかすげーという事を確認する。試しにapp.js のdiv()
のところを書き換えて見る。
div('Live it Up!')
上書き保存したら自動でページがリロードされ、文字が変わった。コレは便利だー。
動作原理を知る
run(main, drivers)
import {run} from '@cycle/xstream-run'
run(main, drivers) という関数が読み込まれる。このmain にエントリーポイントとなる関数、drivers にドライバーの配列を渡すと良い
driver って何やねん
って事がhttps://cycle.js.org/drivers.html に書いてあった。日本語訳はhttp://qiita.com/masakielastic/items/6edba9ba505dc405f380 に書いてあった。
はじめは意味がわからなかったが、以下の喩えで理解した。
オペレーションシステムにおいて、ドライバーはハードウェアデバイスを使うためのソフトウェアインターフェイスであり、外の世界における副作用を引き受けます。
Cycle.js において、アプリケーションを囲む実行世界のための「オペレーションシステム」として考えることができます。おおまかに言えば、DOM、コンソール、JavaScript と JS API は Web のためのオペレーションシステムを想定します。我々はブラウザーと Node.js のようなほかの環境とのインターフェイスをもつソフトウェアアダプターを必要とします。Cycle.js ドライバーは外の世界 (ユーザーと JavaScript 実行環境) と Cycle.js のツールで構築されたアプリケーションの世界のあいだのアダプターとして存在します。
makeDOMdriver
import {makeDOMDriver} from '@cycle/dom'
makeDOMDriver(container, options)という関数を読み込む。https://github.com/cyclejs/cyclejs/tree/master/dom#makeDOMDriver によると、コレは、containerというid名を持つdiv要素をbody直下に作成し(body直下じゃないかも。間違ってたらご指摘ください) そのDOMとcyclejs間でやり取りが出来るようになるドライバーを作成する。
main
main はdrivers からsources という入力を受け取って、sink という戻り値を返す。
ユーザーの入力により発生するDOMイベントを、domDriverが受け取り、その情報をmain にsourceとして渡す。main は受け取った情報を元にアレコレやって、sink という戻り値を返す。domDriver がそれを受け取り、実際のDOMの書き換えを行う。で、当然DOMを書き換えたらDOMイベントはまた発生するわけで。こうやってdriversとmainの間で情報がぐるぐる周り続ける。だからcycle.js 偉い人が考えるフレームワークは本当に良く出来てるな。すごい。
sinks とdrivers
上記のコードでは、sinks.DOMとdrivers.DOMしかないが、他にもHTTP通信を担うsinks.HTTPとdrivers.HTTP やドライバーを自作して独自の通信を担うMYAPI 的なものを定義して使うことも出来る。
構造を理解したところで、getting started のコードを叩いてみる。
app.js を以下のように変更する
import {div, input, p} from '@cycle/dom'
import xs from 'xstream'
export function App (sources) {
const vtree$ = sources.DOM.select('input').events('click')
.map(ev => ev.target.checked)
.startWith(false)
.map(toggled =>
div([
input({attrs: {type: 'checkbox'}}),
'Toggle me',
p(toggled ? 'ON' : 'off')
])
)
const sinks = {
DOM: vtree$
}
return sinks
}
sources.DOM というのはdrivers.DOM から来ている。仮想DOMにあるinput 要素がクリックされればON OFF が切り替わるという簡単なもの。
gettingstarted にしたがってxstream を使っているが、ReactiveX 等、別のstream ライブラリを使うことも出来る。この辺は規模やアプリタイプで変えると良いらしい。
そもそも私はリアクティブプログラミングについて理解していないので、先にそちらを調べたほうが良さそうだ。ということでcyclejs入門をここで一旦断念した。