yt coffee

Study hard, play harder.

Jupyter Notebook でブログを書けるようにした

  • 2019-01-15 11:17
  • #ブログ開発記

Commit: yuku/yuku.github.io@1c18e26

ブログで Jupyter Notebook を表示できるようにしました。今後機械学習やデータ分析のログなどを公開するのに使っていこうと思います 💪🏼

In [1]:
print("Hello world")
Hello world

以降実装の詳細などを備忘録として残します。

Next.js で ipynb ファイルを表示する

大きく分けて 2 つの処理が必要です:

  1. Webpack を使って ipynb ファイルを読めるようにする
  2. 読み込んだ ipynb を React Component にする

ipynb ファイルを読めるようにする

Next.js はファイルの解決に Webpack を使っているので ipynb-loader を使うことができます。この loader は内部的で jupyter/nbconvert を呼び出し、その結果を返すだけのものです。 jupyter/nbconvert は ipynb ファイルを HTML や Markdown などに変換する機能を提供します。

ipynb-loader もとい jupyter/nbconvert を使うにあたって HTML で出力するのか、それとも Markdown で出力するのか、という点が問題になりました。

HTML で出力する場合 Jupyter Notebook 特有の In [1] というプロンプトを表示することができますが、その一方で LaTex 記法など一部の機能を使うことが難しくなります。1

Markdown として出力する場合 MDX と同じ処理ができるだけでなく、なんなら Jupyter Notebook がサポートしていないような Markdown 記法も使えるようになる点がメリットですが、入力と出力の対応関係が失われてしまうので Jupyter Notebook を表示している感が失われてしまいます。

結局 ipynb 形式でブログを書きたいときというのは、入力と出力の対応を明示したいときで、例えば LaTex を使いたいのであれば MDX 形式で書けばいいという結論に達し、 HTML で受けることにしました。

React Component にする

Next.js は React Component を import することを期待するので、 Webpack の立場でいえば React Component を export するような文字列を生成する必要があります。

React Component を文字列として表現するには JSX が便利です。残念ながらこの目的を達成できる Webpack loader が見つからなかったので、 facebook が公開している htmltojsx という npm パッケージを使って自分で実装しました:

const HTMLtoJSX = require("htmltojsx")
const converter = new HTMLtoJSX({ createClass: false })

module.exports = function (content) {
  // content には ipynb-loader が返した HTML が入っている
  return `
  import React from "react"
  export default () => ${converter.convert(content)}
  `
}

その他

  • これまで MDX ファイルに記述したメタデータを集めたメタデータ(entries.ts)を作っていましたが、 ipynb にはそういったメタデータをもたせることができないので、結局 entries.ts を自動生成するのを諦めて手動で管理することにしました。
  • ipynb から HTML を生成するのに jupyter/nbconvert を使うようにしたせいでアーキテクチャが無駄に複雑になってしまい、自動デプロイを維持するために Travis CI から CircleCI に乗り換えることになりました。 ipynb は所詮 JSON なので JavaScript で再実装してもいいかも知れません。その場合 Markdown を HTML に変換する部分を MDX と共通化できそうです。

おわりに

次の仕事では pyspark とか使ってがんがんデータ分析などをやる予定なので、その過程で得た知見をこの機能を使ってブログに公開していきたいです。

余談として、今回初めて Webpack loader を書いてみましたが、思ったより簡単だったという印象です。今回の実装を通じて図らずも Webpack そのものに対する理解もだいぶ深まった気がするので、 Webpack 何やってるか分からんなーという人も一度書いてみるといいかも知れません。


  1. Jupyter Notebook では LaTex 記法の実装に MathJax を使っていますが、このブログでは極力ブラウザ上では JSを走らせない方針にしているため。 MDX では remark-mathrehype-katex を使って実装しています。