API Reference
PRPL has a deliberately small API surface area to minimize the gap between a hello world and real world
implementation. There are just two interfaces that can be used in HTML source files: page
and
list
.
Page tags
A PRPL page tag looks like this, with required type
and src
attributes:
<prpl type="page" src="content"></prpl>
PRPL page tags are used when you have an HTML source file or "template", and you want to render many pages using that template but with different content. For example:
Given this source HTML file in src/index.html
:
<!DOCTYPE html>
<prpl type="page" src="content">
<head>
<title>[title]</title>
</head>
<body>
<main>
<h1>[title]</h1>
[body]
</main>
</body>
</prpl>
and this content markdown file in content/hello-world.md
:
<!--
title: Hello world!
slug: /hello-world
-->
This is my first note
the output is this file in dist/hello-world.html
:
<!DOCTYPE html>
<head>
<title>Hello World!</title>
</head>
<body>
<main>
<h1>Hello World!</h1>
<p>This is my first note</p>
</main>
</body>
- The
src
attribute in the page tag points to a directory of markdown or HTML content files - An output file will be generated for each file in the content directory
- The location in the file system of the source file determines the location of the output files
See the source code handling page tags in @prpl/core.
List tags
A PRPL list tag looks like this, with required attributes type
and src
and optional attributes sort-by
,
direction
and limit
:
<prpl type="list" src="content"></prpl>
PRPL list tags are used when you have an HTML source file or "template", and you want to render a list within that same template using content files. For example:
Given this source HTML file in src/index.html
:
<!DOCTYPE html>
<head>
<title>My home page</title>
</head>
<body>
<main>
<ul>
<prpl type="list" src="content">
<li>
<a href="[slug]">[title]</a>
</li>
</prpl>
</ul>
</main>
</body>
and this content markdown file in content/hello-world.md
:
<!--
title: Hello world!
slug: /hello-world
-->
This is my first note
the output is this file in dist/index.html
:
<!DOCTYPE html>
<head>
<title>My home page</title>
</head>
<body>
<main>
<ul>
<li>
<a href="/hello-world">Hello world!</a>
</li>
</ul>
</main>
</body>
- The
src
attribute in the page tag points to a directory of markdown or HTML content files - A DOM tree will be generated for each file in the content directory
Sort, direction and limit
The list
tag using the optional attributes sort-by
, direction
and limit
looks like this:
<prpl type="list" src="content" sort-by="title" direction="asc" limit="2"></prpl>
sort-by
is a metadata key in your content filedirection
is the direction to sort by, eitherasc
ordesc
for ascending and descendinglimit
is the number of items to list
Additional notes:
sort-by
uses theArray.prototype.sort()
web API- The only special cases handled at present are dates, if the metadata key is
date
ortime
See the source code handling list tags in @prpl/core.
Content metadata
Every content file must have metadata or "frontmatter" at the top of the file with required keys title
and slug
:
<!--
title: Hello world!
slug: /hello-world
-->
You can define as many keys as you like and consume them within page
and list
tags.
Serve and build CLI commands
PRPL can be used from the command line with these commands:
prpl
to interpolate your site.@prpl/core
must be installed to run this commandprpl-server
to run the dev server locally.@prpl/server
must be installed to run this command
CommonJS node interface
PRPL can also be used within Node via CommonJS modules. A build script might look like:
const { interpolate } = require('@prpl/core');
async function build() {
await interpolate();
}
build();
ESM node interface
PRPL can also be used within Node via ECMAScript modules. A build script might look like:
import { interpolate } from '@prpl/core';
await interpolate();
Options
PRPL has no configuration files, but there are a few options that can be passed to the core interpolate
function:
import { interpolate } from '@prpl/core';
// Default options
const options = {
noClientJS: false,
templateRegex: (key) => new RegExp(`\\[${key}\\]`, 'g'),
markedOptions: {}
};
async function build() {
await interpolate({ options });
}
build();
noClientJS
will output zero client-side JavaScript. Your site will no longer take advantage of the prefetch and router systems PRPL offers and will use the browser's native routing and caching systems insteadtemplateRegex
lets you define the how you want PRPL to look for things to replace during interpolation. The default is[my-metadata-key]
, but you can define{my-metadata-key}
or{{ my-metadata-key }}
or whatever suits your preferencemarkedOptions
are options you can pass tomarked
, the only dependency of@prpl/core
Events
PRPL's routing system dispatches a
CustomEvent, prpl-render
, which fires at the end of
HTML diffing during a page navigation.
It can be listened for like any regular event. For example, you can listen for prpl-render
and dynamically build a
table of contents at runtime:
function generateContents() {
const contentsElement = document.querySelector('.table-of-contents');
while (contentsElement.firstChild) {
contentsElement.removeChild(contentsElement.lastChild);
}
const contents = document.querySelectorAll('h2[id]');
const fragment = document.createDocumentFragment();
contents.forEach((content) => {
const listItem = document.createElement('li');
const item = document.createElement('a');
const slug = `${window.location.pathname}#${content.getAttribute('id')}`;
item.textContent = content.textContent;
item.setAttribute('href', slug);
listItem.appendChild(item);
fragment.appendChild(listItem);
});
contentsElement.appendChild(fragment);
}
window.addEventListener('load', generateContents);
window.addEventListener('prpl-render', generateContents);
Do note that if you are listening for prpl-render
, you probably also want to listen to load
in case the page is
refreshed or the routing system gracefully degrades to native router browsing.
See plugins next.