v1.0.0

Markdown copies

AI tools read Markdown better than HTML. bongo can write a Markdown copy of each page next to its HTML, such as /config.md for /config/. This site does it: open the Copy page menu at the top of this page.

Make a copy of each page

Put a <bongo:alternate> element of type text/markdown in the <head> of your layout:

layouts/html.hbshbs
<head>
	<meta charset="utf-8"/>
	<title>{{ $page.title }}</title>
	<bongo:alternate type="text/markdown" />
</head>

For each page from a Markdown file, bongo:

  • writes the copy at the route of the page plus .md: /config/ gives /config.md, and / gives /index.md.
  • puts <link rel="alternate" type="text/markdown" href="/config.md"/> in place of the element, so that tools find the copy.

The element can also link other versions of a page, such as a feed. See Alternates.

What a copy holds

A copy holds the title and the summary from the frontmatter, then the Markdown of the page as you wrote it:

/config.mdmd
# Config

> The fields of bongo.config.ts, and how plugins merge into the config.

The config file, `bongo.config.ts`, sets the site metadata, …

bongo reads the source file again when it writes the copy, so a build does not keep every page's Markdown in memory. bongo dev makes a copy the first time that you open it.

Choose the pages

  • A page from an .html or .hbs file has no Markdown to copy. It gets no copy and no <link>, so one layout can serve every page.
  • To make copies for some Markdown pages only, put the element in the layout of their folder, or in an {{#if}} block.
  • Two pages that name the same copy, or a copy that lands on another file of the site, fail the build.

Add Copy page and View as Markdown

A page cannot read its own alternates, because bongo finds the element only after the layouts render. $utils.url.ext() gives the same URL that the element uses:

layouts/html.hbshbs
{{#var md = $utils.url.ext($page.path, 'md')}}
<a href="{{ md }}" target="_blank">View as Markdown</a>
<button type="button" data-copy-page="{{ md }}">Copy page</button>
assets/main.tsts
document.addEventListener('click', event => {
	let button = event.target instanceof Element && event.target.closest<HTMLElement>('[data-copy-page]');
	if (!button) return;
	let text = fetch(button.dataset.copyPage ?? '')
		.then(res => res.text())
		.then(text => new Blob([text], { type: 'text/plain' }));
	navigator.clipboard.write([new ClipboardItem({ 'text/plain': text })]);
});

Safari allows a write to the clipboard only while the click is current. Thus the script gives ClipboardItem the fetch as a promise, and does not wait for the fetch first.

Check it

  • bongo dev serves each copy. Open one, such as /config.md.
  • bongo build writes each copy to public/, next to the HTML of its page.

To list every copy in one file for AI tools, see Create an llms.txt.

Edit this page on GitHub MIT license · bongo v1.0.0

    Type to search page titles and sections.