前回、 上記記事を書きましたが、これを発展させて Jupyter Notebook のような、プログラムを実行しながら可視化してノートを書けるものを作りました。
リポジトリからhtmlとjsファイルをダウンロードしてローカルで実行する形式ですが、デモサイトを以下に用意しています。
すぐに確認したい方はどうぞ。
サイト内のドロップダウンリストから「JS Notebook (Markdown)」を選択して、「👀View」ボタンをクリックしてください。
https://shellyln.github.io/menneu/playground.html
※デモサイトでは、ユーザー入力のJavaScriptは実行されないようになっています。
実行イメージ
編集イメージ
タイトルにメモ帳と書きましたが、流石に見辛いのでMeryを使用しました。
(メモ帳でも無理ではないです、知らんけど)
記法について
基本はマークダウンですが、%%%( ... )
でLispのスクリプトを展開します。
また、Lispのスクリプト内では、LSXの記法により、DOMツリーが表現できます。
LSXの名前からお察しかもしれませんが、これはJSXの代替記法となっており、標準のhtmlタグ以外に、コンポーネントを処理できます。
下のイメージ内のMath
、Chart
、Notebook
、Js
、Lisp
がコンポーネントです。
-
注意: LSXが有効なのは
%%%( ... )
のブロック内です。
コードブロックのLisp(%%%(Notebook """Lisp ... """)
)では利用できません。
※ 実物のコードはリポジトリ、またはデモサイトから参照ください。
マークダウンのコードブロックをJs
・Lisp
で囲むことで、コードを実行したうえでhtml化します。
%%%(Notebook """Js@{(module "foo")}
```javascript
const x = 12345;
module.exports = function() {
return x;
}
return x;
``` <--- バッククォート × 3 です。
""")
上記のコードブロックは、Js
の属性として module: "foo"
が渡されています。
このブロックで、CommonJS
形式でエクスポートした値・関数などは、他のブロックから require('foo')
でインポートできます。
Lisp
ブロックでも同様にインポート・エクスポートの記述ができます。
さらに JavaScript間、Lisp間だけでなく、両者の間で相互のインポート・エクスポートが可能です。
エクスポートされた値は、コードブロック外のLispコードでもrequire
が可能となっています。
この機能を使用して、コードブロック内の結果を表やグラフとして可視化しています。
保存
gitリポジトリにコミットすれば、履歴管理も完璧です。
長所
- ダウンロードして、メモ帳で開くだけなので編集が手軽。
- 所詮テキストでしかないので、コピペが楽。
欠点
- 所詮テキストでしかないので、実行結果をキャッシュしておけない。
htmlを開くたびに再計算されるので、もし、非常に長時間掛かる処理があると無理がある。 - 可視化の方法が、今のところChart.jsのグラフとMarkdown・htmlの表しかない。
- コードブロック内のコードはデバッグできない。
追記 (20118/10/7)
各Markdownエディタの lisp
ハイライト対応があまりに酷いので、 コードブロックの言語に js
と書くことができるようにしました。
VSCodeではなぜか、割ときれいにハイライトされます。(Bracketsではいまいち)
混乱するのでお勧めはしません。
%%%(Notebook """Lisp@{(module "boo")}
```js <--- Lispのブロックですが、ここに「lisp」ではなく「js」と書けます
($concat "abc" "def")
($defun fac (n)
($if (== n 0)
1
(* n ($self (- n 1))) ) )
($defun multipy (x y)
(* x y) )
(multipy 4 (fac 3))
``` <--- バッククォート × 3 です。
""")
CDNから利用できるようになりました (2018/10/16更新)
以下のhtmlでリポジトリからファイルをダウンロードせずにお試しできます。
<!DOCTYPE html><head><meta charset="UTF-8">
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.13.0"></script>
</head><body><script type="text/markdown">
# JS Notebook
%%%(script (@ (src "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML") (crossorigin "anonymous") (async)))
</script>
<script src="https://cdn.jsdelivr.net/npm/menneu-md-notebook@0.0.2/articles/js/notebook.js"></script>
<script src="https://cdn.jsdelivr.net/npm/menneu-md-notebook@0.0.2/articles/js/menneu.min.js" onload="start({title: 'My Notebook 1'})"></script>
</body>