cycle-ink-driverというライブラリをリリースした.このライブラリを用いると,Cycle.jsとInkを用いてインタラクティヴなコマンドライン・アプリケーションを作ることができる.
Cycle.jsはWebフロントエンドフレームワークではない.Cycle.jsはWebフロントエンドフレームワークではない.大事なので2回言いました.
Cycle.jsを,例えばReactなどと比較するのは間違っている,と再来週のeffect system勉強会で話そうと思っている.Cycle.jsはeffect systemの枠組みを提供しているに過ぎず,viewの部分はReactDOMの代わりにSnabbdom,state管理の部分はReduxの代わりにCycle Stateが提供されており,componentはこうしたeffectを好きに並べ立て,実行時にdriverなりhigher-order componentなりで解決する,というのが最近の個人的な解釈である*1.
実際,Cycle.jsを使いながらも,view部分にSnabbdomではなくReactを用いることができる.componentがSnabbdomに関するeffectではなくReactに関するeffectを要求し,これを解決できればそれで済む話なのだ.これを実現する@cycle/reactに関しては昨年にエントリを書いているので参照されたい.
さて,Inkは,Reactの仕組みを用いて,インタラクティヴなコマンドライン・アプリケーションを作るためのライブラリである.前述の通り,Cycle.jsとReactとの統合は既になされているので,Webフロントエンド・アプリケーションを書きたい場合には,ReactDOMと Cycle ReactDOMを使えばよいのと同じく,CLIアプリケーションを書きたい場合には,Inkとcycle-ink-driverを使えばよい.
| レンダラ | アダプタ | プラットフォーム |
|---|---|---|
| ReactDOM | Cycle ReactDOM | Web |
| Ink | cycle-ink-driver |
CLI |
試しに,Cycle.jsオフィシャルサイトのトップページにあるデモのクローンを作ってみた.

/** @jsx createIncorporatedElement */
import { ReactSource } from '@cycle/react';
import { run } from '@cycle/run';
import { createIncorporatedElement, makeInkDriver } from 'cycle-ink-driver';
import { Box } from 'ink';
import TextInput from 'ink-text-input';
import { Stream } from 'xstream';
const sels = {
name: Symbol('name'),
};
function View({ name }: { name: string }): JSX.Element {
return (
<Box flexDirection="column">
<Box>
Name: <TextInput sel={sels.name} value={name} onChange={() => {}} />
</Box>
{'-'.repeat(20)}
<Box>Hello {name}</Box>
</Box>
);
}
function main({ react }: { react: ReactSource }): { react: Stream<JSX.Element> } {
const name$ = react.select(sels.name).events('change').startWith('');
const view$ = name$.map((name) => View({ name }));
return {
react: view$,
};
}
const drivers = {
react: makeInkDriver(),
};
run(main, drivers);
コード全文はこちらから.
謝辞#
実装にあたって,sliptype/cycle-react-pragmaを参考にした.CycleReact本体にmergeされることを願っている.
脚注#
*1: このあたりの気持ちについては別途エントリを書きたいと考えている.
