Although Capri is primarily a static site generator, you can also use it to dynamically generate HTML on a server or in a serverless environment.
Under the hood, Capri performs an SSR build when generating pages. Normally, this SSR bundle is deleted at the end of the build process.
In order to render pages dynamically on demand, we have to get hold of this bundle before it gets deleted.
This can be done by setting Capri's target
option in the vite.config.ts
file:
export default {
plugins: [
react(),
capri({
prerender: false,
target: "src/ssr.js",
}),
],
};
This will generate a copy of the SSR bundle at src/ssr.js
.
We also set prerender
to false
to disable the generation of static pages
during the build.
During runtime, we can then import the generated bundle:
import { loadSSRModule } from "capri";
// We need to pass an absolute path
const resolve = (p: string) => new URL(p, import.meta.url).pathname;
async function createApp() {
const ssr = await loadSSRModule(resolve("./ssr.js"));
// We can now use ssr() to render pages ...
}
Finally, we call the ssr()
function with the requested URL. We can pass an optional RenderContext
, to support setting HTTP headers and the status code from inside our app.
app.use("*", async (req, res) => {
// Implement the RenderContext interface and map the calls to
// their Express counterparts:
const context: RenderContext = {
status: (code) => res.status(code),
getHeader: (name) => req.get(name),
setHeader: (name, value) => res.setHeader(name, value),
};
const html = await ssr(req.originalUrl, context);
if (res.statusCode === 200) {
res.send(html);
}
res.end();
});
You can find the complete example (including a dev-server with live reload) on GitHub or run it directly on StackBlitz:
Capri also supports Cloudflare Pages and Vercel deployments.
Here's an example that runs as Vercel Edge Function.