PlutoStaticHTML

Convert Pluto notebooks to pure HTML (without Javascript). This allows Pluto notebooks to be embedded in Documenter, Franklin and (optionally) to be styled manually via CSS. Also, it is possible to hide code blocks making it easy to show Julia generated output without showing code. Typically, converting Pluto notebooks to HTML is useful for things like

For a quick preview, this package is used for the tutorials at TuringGLM.jl. Also, I'm using this package for my own blog, for example: https://huijzer.xyz/posts/frequentist-bayesian-coin-flipping/.

API overview

The most important method is build_notebooks (API).

Note

build_notebooks ensures that the original notebook will not be changed.

In general, the idea is to

  1. Create a bunch of Pluto notebooks.
  2. Get the name of the directory dir which contains your Pluto notebooks.
  3. Choose one or more appropriate output_formats depending on how the output will be used. The output format can be html_output, documenter_output, franklin_output or pdf_output.
  4. Pass the paths to build_notebooks which, depending on output_format, writes HTML or Markdown outputs to files.
  5. Read the output from the files and show them on a website via either your own logic or Documenter or Franklin.

Note that this is a very nice development workflow because developing in Pluto notebooks is easy and allows for quick debugging. Also, Pluto has a lot of conversions built-in. This package will take the converted outputs, such as plots or tables, from Pluto which ensures that what you see in Pluto is what you see in the HTML output.

As an extension of Pluto, this package provides # hide and # hideall comments like Franklin and Documenter. A # hideall somewhere in a Pluto code block will hide the code (but not the output). A # hide behind a line in a code block will hide the line. Also, by default, this package hides all Markdown code blocks since readers are probably only interested in reading the output of the Markdown code block. This and more options can be tuned via OutputOptions.

See below for more specific instructions on

Documenter.jl

The output_format=documenter_output is used at various places which can all serve as an example:

Warn

Avoid calling the conversion from inside a Documenter.jl code block. For some reason, that is likely to freeze or hang; probably due to stdout being flooded with information. Instead generate Markdown files via docs/make.jl and point to these files in pages.

Franklin.jl

For output_format=franklin_output examples, see

Specifically, use the following KaTeX options:

const options = {
  delimiters: [
    {left: "$$", right: "$$", display: true},
    {left: "\\begin{equation}", right: "\\end{equation}", display: true},
    {left: "\\begin{align}", right: "\\end{align}", display: true},
    {left: "\\begin{alignat}", right: "\\end{alignat}", display: true},
    {left: "\\begin{gather}", right: "\\end{gather}", display: true},
    {left: "\\(", right: "\\)", display: false},
    {left: "\\[", right: "\\]", display: true}
  ]
};

document.addEventListener('DOMContentLoaded', function() {
  renderMathInElement(document.body, options);
});

Note that $x$ will not be interpreted as inline math by this KaTeX configuration. This is to avoid conflicts with using the dollar symbol to represent the dollar (currency). Instead, PlutoStaticHTML.jl automatically converts inline math from $x$ to \($x\). With above KaTeX settings, Franklin.jl will interpret this as inline math. By default, Documenter.jl will also automatically interpret this as inline math.

Parallel build

To speed up the build, this package defines build_notebooks. This function evaluates the notebooks in parallel by default. Also, it can use Caching to speed up the build even more.

To use it, pass a dir to write HTML files for all notebook files (the files are recognized by the ".jl" extension and that the file starts with ### A Pluto.jl notebook ###):

julia> using PlutoStaticHTML: build_notebooks

julia> dir = joinpath("posts", "notebooks");

julia> bopts = BuildOptions(dir);

julia> build_notebooks(bopts);
[...]

To run only specific notebooks, specify the files:

julia> files = ["notebook1.jl", "notebook2.jl"];

julia> build_notebooks(bopts, files)
[...]

In CI, be sure to call this before using Franklin serve or optimize.

For more options, such as append_build_context to add Julia and packages version information, you can pass OutputOptions:

julia> oopts = OutputOptions(; append_build_context=true);

julia> build_notebooks(bopts, files, oopts)
[...]

See build_notebooks for more information.

Caching

Using caching can greatly speed up running times by avoiding to re-evaluate notebooks. Caching can be enabled by passing previous_dir via BuildOptions. This previous_dir should point to a location where HTML or Markdown files are from the previous build. Then, build_notebooks will, for each input file file.jl, check:

  1. Whether joinpath(previous_dir, "file.html") exists
  2. Whether the SHA checksum of the current $file.jl matches the checksum of the previous $file.jl. When assuming that Pluto's built-in package manager is used to manage packages, this check ensures that the packages of the previous run match the packages of the current run.
  3. Whether the Julia version of the previous run matches the Julia version of the current run.
Note

Caching assumes that notebooks are deterministic, that is, the notebook will produce the same output from the same input.

Note

The previous_dir provides a lot of flexibility. For example, it is possible to point towards a Git directory with the HTML or Markdown output files from last time. Alternatively, for output_format=html_output it is possible to download the web pages where the notebooks are shown and put these web pages in a directory. This works by extracting the state from the previous run from the output.

LaTeX equations

Pluto uses MathJax by default, so make sure to setup MathJax in Franklin or Documenter. For Franklin, see https://rikhuijzer.github.io/JuliaTutorialsTemplate/. For Documenter, see docs/make.jl in this repository.

API

PlutoStaticHTML.build_notebooksFunction
build_notebooks(
    bopts::BuildOptions,
    [files,]
    oopts::OutputOptions=OutputOptions();
    session=ServerSession()
)

Build Pluto notebook files in dir. Here, files is optional. When not passing files, then all Pluto notebooks in dir will be built.

Example

julia> dir = joinpath(homedir(), "my_project", "notebooks");

julia> bopts = BuildOptions(dir);

julia> oopts = OutputOptions(; append_build_context=true);

julia> files = ["pi.jl", "math.jl"];

julia> build_notebooks(bopts, files, oopts);
source
PlutoStaticHTML.BuildOptionsType
BuildOptions(
    dir::AbstractString;
    write_files::Bool=true,
    previous_dir::Union{Nothing,AbstractString}=nothing,
    output_format::Union{OutputFormat,Vector{OutputFormat}}=html_output,
    add_documenter_css::Bool=true,
    use_distributed::Bool=true,
    compiler_options::Union{Nothing,CompilerOptions}=nothing,
    max_concurrent_runs::Int=4
)

Arguments:

  • dir: Directory in which the Pluto notebooks are stored.
  • write_files: Write files to joinpath(dir, "$file.html").
  • previous_dir::Union{Nothing,AbstractString}=Nothing: Use the output from the previous run as a cache to speed up running time. To use the cache, specify a directory previous_dir::AbstractString which contains HTML or Markdown files from a previous run. Specifically, files are expected to be at joinpath(previous_dir, "$file.html"). The output from the previous run may be embedded in a larger HTML or Markdown file. This package will extract the original output from the full file contents. By default, caching is disabled.
  • output_format: What file to write the output to. By default this is html_output::OutputFormat meaning that the output of the HTML method is pure HTML. To generate Franklin, Documenter or PDF files, use respectively franklin_output, documenter_output or pdf_output. When BuildOptions.write_files == true and output_format == franklin_output or output_format == documenter_output, the output file has a ".md" extension instead of ".html". When BuildOptions.write_files == true and output_format == pdf_output, two output files are created with ".tex" and ".pdf" extensions.
  • add_documenter_css whether to add a CSS style to the HTML when documenter_output=true.
  • use_distributed: Whether to build the notebooks in different processes. By default, this is enabled just like in Pluto and the notebooks are build in parallel. The benefit of different processes is that things are more independent of each other. Unfortunately, the drawback is that compilation has to happen for each process. By setting this option to false, all notebooks are built sequentially in the same process which avoids recompilation. This is likely quicker in situations where there are few threads available such as GitHub Runners depending on the notebook contents. Beware that use_distributed=false will not work with Pluto's built-in package manager.
  • compiler_options: Pluto.Configuration.CompilerOptions to be passed to Pluto. This can, for example, be useful to pass custom system images from PackageCompiler.jl.
  • max_concurrent_runs: Maximum number of notebooks to evaluate concurrently when use_distributed=true. Note that each notebook starts in a different process and can start multiple threads, so don't set this number too high or the CPU might be busy switching tasks and not do any productive work.
source
PlutoStaticHTML.OutputOptionsType
OutputOptions(;
    code_class::AbstractString="language-julia",
    output_pre_class::AbstractString="code-output documenter-example-output",
    hide_code::Bool=false,
    hide_md_code::Bool=true,
    hide_md_def_code::Bool=true,
    add_state::Bool=true,
    append_build_context::Bool=false,
    show_output_above_code::Bool=false,
    replace_code_tabs::Bool=true,
    convert_admonitions::Bool=true
)

Arguments:

  • code_class: HTML class for code. This is used by CSS and/or the syntax highlighter.
  • output_pre_class: HTML class for <pre>.
  • output_class: HTML class for output. This is used by CSS and/or the syntax highlighter.
  • hide_code: Whether to omit all code blocks. Can be useful when readers are not interested in code at all.
  • hide_md_code: Whether to omit all Markdown code blocks.
  • hide_md_def_code: Whether to omit Franklin Markdown definition code blocks (blocks surrounded by +++).
  • add_state: Whether to add a comment in HTML with the state of the input notebook. This state can be used for caching. Specifically, this state stores a checksum of the input notebook and the Julia version.
  • append_build_context: Whether to append build context. When set to true, this adds information about the dependencies and Julia version. This is not executed via Pluto.jl's evaluation to avoid having to add extra dependencies to existing notebooks. Instead, this reads the manifest from the notebook file.
  • show_output_above_code: Whether to show the output from the code above the code. Pluto.jl shows the output above the code by default; this package shows the output below the code by default. To show the output above the code, set show_output_above_code=true.
  • replace_code_tabs: Replace tabs at the start of lines inside code blocks with spaces. This avoids inconsistent appearance of code blocks on web pages.
  • convert_admonitions: Convert admonitions such as !!! note This is a note. from Pluto's HTML to Documenter's HTML. When this is enabled, the documenter_output has proper styling by default.
source