A small proof of concept on creating formatted documents using web development tools.
An attempt at making a passable alternative to Asciidoctor or LaTeX documents using HTML+CSS and web development tools.
While it is primitive at the moment, this approach does show promise.
Skip straight to the rendered demo page, or take a look at the code on github.
I’ve been making some large documents at work using Asciidoctor.
Overall I feel its better than LaTeX, but it does have some sticking points I do not like.
LaTeX counters some of these shortcomings while introducing others. I won’t address it here other than to say Asciidoc and LaTeX are both strong competitors, but neither really satisfy me.
While working on this, I realized that HTML+CSS+JS and the browser also represent a way to render formatted content from code. That stack (and all the related frameworks available ala React/Svelte/Django/etc.) has probably had multiple orders of magnitude more human effort and money put into them than either LaTeX or Asciidoc have. So why not try and leverage it?
The HTML+CSS+JS approach gives you:
I again chose to use the Svelte Framework as my main tool for this proof of concept, as I’ve used it a few times before. There’s no huge advantage here for Svelte over the other frameworks to my eyes - I used it out of familiarity.
Svelte has an extension called mdsvex that can transform markdown files into Svelte components, with some hooks for the user to inject custom formatting. This allows us to mimic some of the ease of use of Asciidoc in that the user only needs to edit markdown files, but now has the ability to go deeper where needed, directly including Svelte components and HTML+CSS+JS directly in their documents.
The top level document is located in ./src/App.svelte
.
It loads the title page and table of contents are rendered from components in ./src/lib
.
It also loads Content.svelte
which loads content.md
via mdsvex
.
Content.svelte
is wrapped in a src/lib/Paginator.svelte
component, which renders the contents to an invisible div, and then goes through the children of that div and copies them over to a visible div, while inserting page breaks.
The paginator also sets page numbers for src/lib/SectHead.svelte
instances it finds in the content.
These page numbers are then fed back to the table of contents to set the page numbers for sections correctly.
There’s also src/lib/Layout.svelte
which leverages components in src/lib/md_components/
to customize the mdsvex
converted content of content.md
.
Part of that layout is replacing h1
, h2
, etc. tags with SectHead.svelte
components, so they show up in the table of contents.
CSS has a @media print
tag that can be used to set the CSS when printing the website.
Firefox appears to play well with this when setting the page dimensions to match the size of the page <div>
’s I use in the document.
Firefox (or Chrome) print to PDF can then be used to output a document that is identical to the browser version.
There are several outstanding issues in this demo:
content.md
file (and other stuff too. Table of Contents also acts weird in HMR).content.md
file at the moment
*.md
files in the doc
directory and rendering them in order of filenames.10_TitlePage.svelte
, …, 40_Chapter1.md
, etc.App.svelte
file
doc
folder and have a top level app that auto renders them and all *.md
files there also.<p></p>
href=#My Section
) work, currently used in the TOC.As seen in [xref](#my_table)
-> As seen in Table 3.2
As a proof of concept I consider this a success, as it proves this is a viable path forward.
I’m not sure I will pursue this further as the workflow is currently more painful than Asciidoc or LaTeX. I do however think this could be a strong contender with some more work turning this project into more of a framework to hide more of the gory details in this version.
The power of HTML+CSS+JS I think far out strips any other existing code->formatted document tool. While far from perfect, it seems like the obvious choice to leverage the existing work on web development for creating text documents.
Check out a rendered demo page (print it to PDF!), or take a look at the code on github.