On this page:
4.1 Markdown Handling (".md")
4.2 Racket Module Handling (".rkt")
4.3 CSS Handling (".css")
4.4 Literal Path Handling (".literal")
4.5 Default File Handling

4 The Base Workflow

As mentioned, Polyglot actually doesn’t know how to build a website. The Base Workflow provides common logic and sensible defaults for building websites. The Functional Workflow and The Imperative Workflow fill gaps in Markdown processing by extending this workflow.

To understand why the Base Workflow is important, consider what happens to a parsed Markdown file once there are no more app or lib elements to process. If you convert it to HTML, you might get links to resources like blah.html. How does the HTML document get that name, and how do we know the link isn’t broken?

Once app and lib elements have been processed to produce a finished page, the Base Workflow starts a dependency discovery phase where it searches for paths to other files in src, href, and srcset attributes of the HTML elements derived from your Markdown, and in the url() expressions of your CSS. The Base Workflow notices the links that are either absolute paths on your filesystem, or paths relative to your assets directory.

Consider this Markdown:

  * [Contact me](contact.md)

  * [Search the Web](https://duckduckgo.com)

  * ![Generated Image](generate-image.rkt)

During the dependency discovery phase, the Base Workflow will only pick up on contact.md and generate-image.rkt because they are relative paths to assets that are not user-facing.

Each asset referenced is processed according to the rules of their associated workflow, but the Base Workflow offers some reasonable defaults. Each round of processing kicks off another dependency discovery phase, and the whole cycle will repeat until all referenced assets are crawled. The result is a working, linked collection of HTML5 documents, complete with production-ready assets.

Let’s cover the common and default asset processing rules provided by the Base Workflow.

4.1 Markdown Handling (".md")

The Base Workflow does not handle all Markdown processing on its own, just the hard parts. It analyzes the final version of content produced by either The Functional Workflow or The Imperative Workflow, delegates work to resolve all dependencies, rewrites links so that they correctly point to user-facing resources in the distribution, and writes the result as an HTML5 document.

How exactly app and lib elements modify your content before all of this happens depends on the workflow you use.

4.2 Racket Module Handling (".rkt")

You may depend on a Racket module to take full responsibility for generating an asset.

This section requires knowledge of unlike-assets, so you don’t have to read it now. Come back when you need to handle an exceptional case for a single asset referenced by your page, and you don’t want to modify your workflow.

The Racket module must produce a path to a file in a distribution to represent the fulfilled asset. The Base Workflow will trust that path is correct and useful in a finished website.

For example, say you want to create a stylesheet using Racket. You can write Racket code to generate optimized styles and list the module that does it as a dependency.

To do this, write an element to depend on a Racket module.

  <link rel="stylesheet" href="compute-stylesheet.rkt" />

The module generates a simple style sheet with a content-hashed name for cache-busting.


#lang racket
(provide write-dist-file)
(require file/sha1 polyglot)
(define (write-dist-file clear compiler)
  (define css "body{font-size:20px}\n")
  (define port (open-input-string css))
  (define file-name
      (substring (sha1 port) 0 8) ; For cache busting
  (define path (dist-rel file-name))
  (close-input-port port)
  (display-to-file #:mode 'text #:exists 'replace
                   css path)

To integrate with the Base Workflow, the module must provide write-dist-file as an advance/c procedure. Notice that it returns a complete path in a distribution using dist-rel. The procedure writes the stylesheet in the distribution as a side-effect.

In terms of unlike-assets, the path to the stylesheet is the fulfilled unlike-asset/c. The base workflow will accept this path and use it to replace the original reference to the module.

The resulting HTML will look like this:

  <link rel="stylesheet" href="5f9bb103.css" />

The difference between this approach and writing equivalent Racket code in an application element is when the code runs. This code runs after finding dependencies in a page, but before writing HTML5 documents to disk.

4.3 CSS Handling (".css")

In CSS files, the values in url() expressions are treated just like the href, src, and srcset attribute values in HTML elements parsed from Markdown. The Base Workflow does not inspect the url() expressions inside <style> elements.

You can leverage this along with Racket module dependencies to generate assets for presentation.

Consider this stylesheet:

  @font-face {

    font-family: 'UberFont';

    src: url('uberfont.ttf');



  body {

    background-image: url(generate-background.rkt);

    font-family: UberFont;


By the rules discussed, it may become:

@font-face {

  font-family: 'UberFont';

  src: url('82e2ab1f.ttf');



body {

  background-image: url(b7ee41cd.png);

  font-family: UberFont;


Notice that this stylesheet is not minified, and this process does not alter or interpret @import at-rules.

4.4 Literal Path Handling (".literal")

Any dependency paths with extension .literal are placed as-is in the distribution, ironically without the .literal extension.

This means that [Link](doc.html.literal) becomes <a href="doc.html">Link</a>.

If you need .literal to appear in the output, use the extension twice (e.g. doc.literal.literal).

4.5 Default File Handling

Any other files you reference are copied to the distribution such that the file name is the first eight characters of the SHA1 hash of the file content. This is useful for cache busting.