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>

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>

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>

Additional notes:

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:

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();

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.