Guide ·Markdown source ·View on GitHub
Framework hosts
Hosts own routes, page metadata and implementation loaders. The adapters preserve portable source semantics and diagnostics; they do not add a CMS or editor.
Next.js App Router
Install @publisle/adapter-next with the core packages and React. The adapter
is server-first: loadPublication reads local Markdown/JSON, prepares it with
the host registry, and compiles a publication artifact without Vite.
// app/page.tsx
import { loadPublication, PublisleArticle } from "@publisle/adapter-next";
import { coreBlockDefinitions } from "@publisle/blocks-core";
import { createRegistry } from "@publisle/core";
import { join } from "node:path";
export default async function Page() {
const publication = await loadPublication(
join(process.cwd(), "article.json"),
{ registry: createRegistry(coreBlockDefinitions) },
);
return <PublisleArticle publication={publication} instanceId="article" />;
}PublisleArticle renders namespaced HTML for its explicit instanceId. A
static page has no Publisle client import. For an interactive article, pass
the reader manifest and host-owned implementation loaders through a client
component:
// app/interactive/Reader.tsx
"use client";
import {
ClientAttachment,
type ClientAttachmentProps,
} from "@publisle/adapter-next/client";
export default function Reader({
manifest,
instanceId,
}: Pick<ClientAttachmentProps, "manifest" | "instanceId">) {
return (
<ClientAttachment
manifest={manifest}
instanceId={instanceId}
implementations={{ "host:counter": () => import("./Counter") }}
/>
);
}The server route renders Reader as a child of PublisleArticle, using
publicationReaderManifest(publication). ClientAttachment attaches the
shared controller after hydration and disposes it when React unmounts or
navigation replaces the article. See the static Next example
and its interactive route.
Astro uses publisleAstro() in its config and publisleLoader(files, options) in a
content collection. Files map stable host collection IDs to local paths.
@publisle/adapter-astro/Article.astro emits publication HTML with no script.
Hosts add islands explicitly and call attachArticle(root, manifest, environment)
from ./runtime, retaining its returned disposal function for removal/navigation.
The Astro example has a static route
and an interactive host whose
custom element disposes automatically when disconnected.
Vue
Install @publisle/adapter-vue, Vue and Vite. publisleVue is an optional Vite
integration. It uses vueTarget to emit native Vue modules, so a Markdown
module can be imported directly by a Vue entry point:
// vite.config.ts
import { defineConfig } from "vite";
import { publisleVue } from "@publisle/adapter-vue";
import { coreBlockDefinitions } from "@publisle/blocks-core";
import { createRegistry } from "@publisle/core";
export default defineConfig({
plugins: [
await publisleVue({ registry: createRegistry(coreBlockDefinitions) }),
],
});// src/main.ts
import { createApp, h } from "vue";
import Article from "./article.md";
createApp({
render: () => h("main", null, [h(Article, { instanceId: "article" })]),
}).mount("#app");Generated modules use Vue components and SSR; only referenced islands import the
controller runtime. For an existing PublicationArtifact, use
PublisleArticle from @publisle/adapter-vue; it renders the artifact and
attaches host implementation loaders after mounting. Both paths dispose on
unmount and repeated placements keep independent instance state. See the
Vue entry point and Vite config.
pnpm --filter @publisle/example-next build
pnpm --filter @publisle/example-astro build
pnpm --filter @publisle/example-vue build
pnpm test:distribution
pnpm test:acceptanceProduction browser tests verify static delivery, repeated placements, independent island state, ABI inputs and cleanup. A static Next page still includes Next's own framework scripts; no Publisle client runtime is required. Static Astro pages emit no JavaScript.
The independent Python renderer reads portable JSON directly:
python3 -B tools/python/render.py packages/contracts/fixtures/static-rendering.json
pnpm test:pythonIt supports a declared v1 static subset: prose, rich text/direction, lists, quotes/code, figures/tables, labels, authored notes and numeric references. It escapes HTML and refuses executable URLs. Math, interactive/custom behavior and unsupported versions use readable fallback with diagnostics. It executes neither migrations nor plugins and does not implement full CSL. Its shared fixture is compared with the TypeScript renderer for supported semantics.