Observable Framework 1.12.0-alpha.3 GitHub️ 2.4k

Page loaders

Page loaders are a special type of data loader for dynamically generating (or “server-side rendering”) pages. Page loaders are programs that emit Markdown to standard out, and have a double extension starting with .md, such as .md.js for a JavaScript page loader or .md.py for a Python page loader.

By “baking” dynamically-generated content into static Markdown, you can further improve the performance of pages since the content exists on page load rather than waiting for JavaScript to run. You may even be able to avoid loading additional assets and JavaScript libraries.

For example, to render a map of recent earthquakes into static inline SVG using D3, you could use a JavaScript page loader as quakes.md.js:

import * as d3 from "d3-geo";
import * as topojson from "topojson-client";

const quakes = await (await fetch("https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson")).json();
const world = await (await fetch("https://cdn.jsdelivr.net/npm/[email protected]/land-110m.json")).json();
const land = topojson.feature(world, world.objects.land);

const projection = d3.geoOrthographic().rotate([110, -40]).fitExtent([[2, 2], [638, 638]], {type: "Sphere"});
const path = d3.geoPath(projection);

process.stdout.write(`# Recent quakes

<svg style="max-width: 640px; width: 100%; height: auto;" viewBox="0 0 640 640" width="640" height="640" xmlns="http://www.w3.org/2000/svg" fill="none">
  <path stroke="currentColor" stroke-opacity="0.1" d="${path(d3.geoGraticule10())}"></path>
  <path stroke="currentColor" stroke-width="1.5" d="${path({type: "Sphere"})}"></path>
  <path stroke="var(--theme-foreground-faint)" d="${path(land)}"></path>
  <path stroke="var(--theme-red)" stroke-width="1.5" d="${path(quakes)}"></path>
</svg>
`);

See the data loaders documentation for more on execution, routing, and caching.

Page loaders often use parameterized routes to generate multiple pages from a single program.

When using page loaders, keep an eye on the generated page size, particularly with complex maps and data visualizations in SVG. To keep the page size small, consider server-side rendering a low-fidelity placeholder and then replacing it with the full graphic using JavaScript on the client.

To allow importing of a JavaScript page loader without running it, have the page loader check whether process.argv[1] is the same as import.meta.url before running:

if (process.argv[1] === fileURLToPath(import.meta.url)) {
  process.stdout.write(`# Hello page`);
}