Contents

This post is rendered directly from a Jupyter notebook (.ipynb) — no manual copy-paste. Every interactive chart, table, and code block below comes straight from the executed notebook cells.

How it works: Jekyll + Cloudflare Pages notebook support

Cloudflare Pages does not provide a Python/Jupyter environment at build time, so plugins that call jupyter nbconvert during the Jekyll build will fail. The solution is to pre-convert notebooks locally and commit the HTML.

The pipeline has three parts:

1. Pre-build the notebook locally

Run ./scripts/build_notebooks.sh after executing your notebook. It calls jupyter nbconvert --to html on every notebooks/*.ipynb and writes the output to notebooks/html/.

./scripts/build_notebooks.sh
# then commit notebooks/ and notebooks/html/ together

2. A custom Jekyll tag serves the pre-built HTML

_plugins/jupyter_notebook_tag.rb registers a {% jupyter_notebook %} Liquid tag. At build time it generates a plain <iframe> pointing to the static HTML file at /notebooks/html/notebook-name.html. No jupyter, no Python — just a URL in Ruby.

3. Use the tag in any post

{::nomarkdown}
{% jupyter_notebook "/notebooks/my-notebook.ipynb" %}
{:/nomarkdown}

The {::nomarkdown} block prevents Kramdown from mangling the iframe tag. The path mirrors the .ipynb location — the plugin maps it to notebooks/html/my-notebook.html automatically.

For interactive Plotly charts to work, cell outputs must be stored in the notebook before committing. Use fig.to_html() instead of fig.show():

from IPython.display import HTML, display
display(HTML(fig.to_html(full_html=False, include_plotlyjs='cdn')))
# subsequent charts: include_plotlyjs=False