<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Showdown on blog.iankulin.com</title><link>https://blog.iankulin.com/tags/showdown/</link><description>Recent content in Showdown on blog.iankulin.com</description><generator>Hugo</generator><language>en-AU</language><lastBuildDate>Fri, 24 Nov 2023 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.iankulin.com/tags/showdown/index.xml" rel="self" type="application/rss+xml"/><item><title>Adding Front Matter To mdserver</title><link>https://blog.iankulin.com/adding-front-matter-to-mdserver/</link><pubDate>Fri, 24 Nov 2023 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/adding-front-matter-to-mdserver/</guid><description>&lt;p&gt;The very first issue I opened on &lt;a href="https://blog.iankulin.com/displaying-markdown-as-html/"&gt;mdserver&lt;/a&gt; - my server project that serves HTML from markdown files - was that the title of the page (which shows in the browser tab, and is used for browser bookmarks) needed to be set &lt;em&gt;inside&lt;/em&gt; the markdown file, rather than generated from the file name. I didn&amp;rsquo;t invent this idea - I&amp;rsquo;ve seen this sort of metadata in the top of Jekyll and Hugo markdown. Here&amp;rsquo;s an example from the &lt;a href="https://jekyllrb.com/docs/front-matter/"&gt;Jekyll website&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;layout: post
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;title: Blogging Like a Hacker
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can&amp;rsquo;t really see in this example, but the format is YAML. Although I might be interested in using it for other things (such as selecting a template) later, for now, all I need is a title. The process would be that the server would extract the title from the front matter, then inject that into the template HTML so the page had a proper title.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m using the &lt;a href="https://showdownjs.com/"&gt;Showdown&lt;/a&gt; library to do the conversion from markdown. Here&amp;rsquo;s a short demo of how that works:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; showdown &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; require&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#39;showdown&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; converter &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;new&lt;/span&gt; showdown&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;Converter&lt;span style="color:#eceff4"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; markdown &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;`
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a3be8c"&gt;# heading
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a3be8c"&gt;Some random Text
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a3be8c"&gt;* list item
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a3be8c"&gt;* another`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; rawHtml &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; converter&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;makeHtml&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;markdown&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;log&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;rawHtml&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This would output:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;h1&lt;/span&gt; &lt;span style="color:#8fbcbb"&gt;id&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;=&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#34;heading&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;&amp;gt;&lt;/span&gt;heading&lt;span style="color:#eceff4"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;h1&lt;/span&gt;&lt;span style="color:#eceff4"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;p&lt;/span&gt;&lt;span style="color:#eceff4"&gt;&amp;gt;&lt;/span&gt;Some random Text&lt;span style="color:#eceff4"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;p&lt;/span&gt;&lt;span style="color:#eceff4"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;ul&lt;/span&gt;&lt;span style="color:#eceff4"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;li&lt;/span&gt;&lt;span style="color:#eceff4"&gt;&amp;gt;&lt;/span&gt;list item&lt;span style="color:#eceff4"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;li&lt;/span&gt;&lt;span style="color:#eceff4"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;li&lt;/span&gt;&lt;span style="color:#eceff4"&gt;&amp;gt;&lt;/span&gt;another&lt;span style="color:#eceff4"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;li&lt;/span&gt;&lt;span style="color:#eceff4"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;ul&lt;/span&gt;&lt;span style="color:#eceff4"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Showdown is an 827K dependency, so I figured it might already deal with front matter, or would at least have some sort of extension hooks so I could write something to scrape the title out. In fact it has both.&lt;/p&gt;
&lt;p&gt;To enable front matter, you just have to set a flag in the converter, then there&amp;rsquo;s a .getMetadata() method on the converter to get an object of all the metadata. Let&amp;rsquo;s flesh out my demo code a bit to show this, I&amp;rsquo;ll highlight the changes.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; showdown &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; require&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#39;showdown&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; converter &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;new&lt;/span&gt; showdown&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;Converter&lt;span style="color:#eceff4"&gt;({&lt;/span&gt;metadata&lt;span style="color:#81a1c1"&gt;:&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;true&lt;/span&gt;&lt;span style="color:#eceff4"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; markdown &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;`
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a3be8c"&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a3be8c"&gt;title: Test Title
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a3be8c"&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a3be8c"&gt;# heading
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a3be8c"&gt;Some random Text
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a3be8c"&gt;* list item
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a3be8c"&gt;* another`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; rawHtml &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; converter&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;makeHtml&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;markdown&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#616e87;font-style:italic"&gt;//console.log(rawHtml);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;console&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;log&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;converter&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;getMetadata&lt;span style="color:#eceff4"&gt;().&lt;/span&gt;title&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This simply outputs &lt;code&gt;Test Title&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re wondering if that YAML pollutes the HTML output at all, it does not. The HTML from this second example is exactly the same as the first example above without the YAML.&lt;/p&gt;</description></item><item><title>Displaying markdown as HTML</title><link>https://blog.iankulin.com/displaying-markdown-as-html/</link><pubDate>Wed, 08 Nov 2023 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/displaying-markdown-as-html/</guid><description>&lt;p&gt;In the spirit of over-complicating things, when I wanted to collect all the links to the services on my homelab into one place, I decided I needed to write them in markdown, and have them converted on the fly into HTML by a server. Then when I couldn&amp;rsquo;t find exactly what I was after (&lt;a href="http://harpjs.com/"&gt;Harp&lt;/a&gt; was closest) of course, I decided to write it.&lt;/p&gt;
&lt;img src="https://blog.iankulin.com/images/distracted.jpg" width="1000" alt=""&gt;
&lt;h3 id="markdown"&gt;Markdown&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Markdown"&gt;Markdown&lt;/a&gt; has definitely been having it&amp;rsquo;s moment over the last couple of years. It&amp;rsquo;s a simple open format mark-up language that is quite readable in it&amp;rsquo;s source form. Although it&amp;rsquo;s now very fashionable as an input for static site generators, most people will have run in to it when adding simple formatting to forum comments or on instant messaging platforms.&lt;/p&gt;
&lt;p&gt;It supports text formatting such as bold, italic and underlining as well as links, and in some extended versions, tables and so on.&lt;/p&gt;
&lt;h3 id="middleware"&gt;Middleware&lt;/h3&gt;
&lt;p&gt;My plan for tackling this is to have a simple Node.js/Express web server that&amp;rsquo;s serving static files from a public sub-directory. As it receives requests for each file, it checks if it&amp;rsquo;s a markdown file (which normally if served directly to a browser would trigger it to be downloaded instead of displayed). If it is markdown, it&amp;rsquo;s translated into HTML and passed to the browser.&lt;/p&gt;
&lt;p&gt;This is easily accomplished in a simple Express server which has the concept of &amp;lsquo;&lt;a href="https://expressjs.com/en/guide/using-middleware.html"&gt;middleware&lt;/a&gt;&amp;rsquo;. This are just layers of processing that each request goes through. If a layer can deal with a request it does, otherwise it passes it off to the next layer. You&amp;rsquo;ll often see this type of pattern (usually with more layers) in an Express app, where each of the &lt;code&gt;app.use&lt;/code&gt; declarations is another middleware layer:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; app &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; express&lt;span style="color:#eceff4"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;use&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;mdParser&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;use&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;express&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;static&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;publicDirectory&lt;span style="color:#eceff4"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this case, &lt;code&gt;mdParser&lt;/code&gt; is my middleware function that checks if a file is markdown, then if it is returns a HTML version of the file to the browser, or if not, just lets the request go through to the next layer. A simple version might look like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; express &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; require&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#34;express&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; fs &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; require&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#39;fs&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; path &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; require&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#39;path&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; showdown &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; require&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#39;showdown&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; converter &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;new&lt;/span&gt; showdown&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;Converter&lt;span style="color:#eceff4"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; publicDirectory &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#39;public&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; staticRoot &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; path&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;join&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;__dirname&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; publicDirectory&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#616e87;font-style:italic"&gt;// middleware for processing markdown files
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;function&lt;/span&gt; mdParser&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;req&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; res&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; next&lt;span style="color:#eceff4"&gt;)&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;if&lt;/span&gt; &lt;span style="color:#eceff4"&gt;(&lt;/span&gt;req&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;url&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;endsWith&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#39;.md&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;))&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; mdFilePath &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; path&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;join&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;staticRoot&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; req&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;url&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fs&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;readFile&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;mdFilePath&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#39;utf8&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; &lt;span style="color:#eceff4"&gt;(&lt;/span&gt;err&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; data&lt;span style="color:#eceff4"&gt;)&lt;/span&gt; &lt;span style="color:#eceff4"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;if&lt;/span&gt; &lt;span style="color:#eceff4"&gt;(&lt;/span&gt;err&lt;span style="color:#eceff4"&gt;)&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;status&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#b48ead"&gt;404&lt;/span&gt;&lt;span style="color:#eceff4"&gt;).&lt;/span&gt;send&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#39;File not found&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#eceff4"&gt;}&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;else&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; htmlContent &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; converter&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;makeHtml&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;data&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res&lt;span style="color:#eceff4"&gt;.&lt;/span&gt;send&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;htmlContent&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#eceff4"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#eceff4"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#eceff4"&gt;}&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;else&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; next&lt;span style="color:#eceff4"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#eceff4"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The actual heavy lifting of converting the markdown into HTML is done in line 20 with a library called &lt;a href="https://showdownjs.com/"&gt;ShowDown&lt;/a&gt;. There are a few of these floating around, I tried &lt;a href="https://marked.js.org/"&gt;Marked&lt;/a&gt; first, but it didn&amp;rsquo;t immediately work how I expected without reading any documentation, so I moved on ¯\_(ツ)_/¯&lt;/p&gt;
&lt;h3 id="templating"&gt;Templating&lt;/h3&gt;
&lt;p&gt;This simple version works - the markdown is correctly displayed in the browser, but there&amp;rsquo;s a couple of things going on that are not great.&lt;/p&gt;
&lt;p&gt;The first is that it&amp;rsquo;s not actually well formed HTML. If we load a markdown file containing this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Test.md
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;* A sample mark down file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It looks like this:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2023-10-22-at-7.42.46-am.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2023-10-22-at-7.42.46-am.png" width="900" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;But if we view the page source, it&amp;rsquo;s this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;h1 id=&amp;#34;testmd&amp;#34;&amp;gt;Test.md&amp;lt;/h1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;ul&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;li&amp;gt;A sample mark down file&amp;lt;/li&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/ul&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;No &lt;code&gt;DOCTYPE, &amp;lt;html&amp;gt;, &amp;lt;head&amp;gt;&lt;/code&gt; etc. Since forever, browsers have been expected to deal gracefully with malformed HTML, and they generally do, but as someone who still feels bound by the ethics printed on my 1991 &lt;a href="https://www.acs.org.au/content/dam/acs/rules-and-regulations/Code-of-Ethics.pdf"&gt;ACS membership certificate&lt;/a&gt;, I can&amp;rsquo;t accept this low standard.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a second related problem I don&amp;rsquo;t like, that&amp;rsquo;s that the title of this page (displayed in the browser tab, and used if we bookmark the page) is &amp;ldquo;http://127.0.0.1:3000&amp;rdquo; instead of what I would like it to be - probably &amp;ldquo;Test&amp;rdquo;. This is not Showdown&amp;rsquo;s fault, it doesn&amp;rsquo;t really have any way of guessing what we&amp;rsquo;d like for the title.&lt;/p&gt;
&lt;p&gt;As usual, these are a class of problem that&amp;rsquo;s long been solved, in this case with templates. Essentially what I need to do is take the generated (but not correctly formed) HTML output from Showdown, and insert it in the middle of some boilerplate HTML. Perhaps the template could look like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;!DOCTYPE html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;html lang=&amp;#34;en&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;head&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;meta charset=&amp;#34;UTF-8&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;title&amp;gt;{{title}}&amp;lt;/title&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/head&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;body&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;main&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {{content}}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/main&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/body&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;d put the title I wanted for the page in &lt;code&gt;{{title}}&lt;/code&gt; and the converted markdown into &lt;code&gt;{{content}}&lt;/code&gt;. These double curly braces are a reasonably common convention for templating.&lt;/p&gt;
&lt;p&gt;If I load the template file (which can include all sorts of lovely CSS and JS) into &lt;code&gt;templateData&lt;/code&gt; at start up, I can just use a string replace when I need to serve the file at request time:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;if&lt;/span&gt; &lt;span style="color:#eceff4"&gt;(&lt;/span&gt;useTemplate&lt;span style="color:#eceff4"&gt;)&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1"&gt;//&lt;/span&gt; Replace placeholders with title &lt;span style="color:#81a1c1;font-weight:bold"&gt;and&lt;/span&gt; content 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; title &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; path&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;basename&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;mdFilePath&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; templatedHtml &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; templateData&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;replace&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#39;{{title}}&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; title&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;replace&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#39;{{content}}&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; htmlContent&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;send&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;templatedHtml&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;}&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;else&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;send&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;htmlContent&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m just using the file name for the title here, I&amp;rsquo;ll think about &lt;a href="https://github.com/IanKulin/mdserver/issues/1"&gt;how to improve that&lt;/a&gt; in a later installment.&lt;/p&gt;
&lt;p&gt;Now the output looks like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;!DOCTYPE html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;html lang=&amp;#34;en&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;head&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;meta charset=&amp;#34;UTF-8&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;title&amp;gt;test.md&amp;lt;/title&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/head&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;body&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;main&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;h1 id=&amp;#34;testmd&amp;#34;&amp;gt;Test.md&amp;lt;/h1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;ul&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;li&amp;gt;A sample mark down file&amp;lt;/li&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/ul&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/main&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/body&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Which, while &lt;a href="https://github.com/IanKulin/mdserver/issues/2"&gt;not well indented&lt;/a&gt;, at least meets the HTML specification.&lt;/p&gt;
&lt;h3 id="done"&gt;Done&lt;/h3&gt;
&lt;p&gt;I really enjoyed making this - it&amp;rsquo;s one of those compact sized projects you can start and finish on a Saturday between house jobs, and although small, it does address a genuine use case - if I&amp;rsquo;d found this when I was searching for something I would have used it as is.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://github.com/IanKulin/mdserver/blob/e9a09c4381e9bda373b86701f90cf165ea0d0e7e/server.js"&gt;code&amp;rsquo;s up on github&lt;/a&gt; if you want a look. To make it a finished product it probably needs some hardening. Also, since I need to learn how to build Docker containers, this would be a good project for that, so stand by for a future installment.&lt;/p&gt;</description></item></channel></rss>