Add templates to a project

Install the template library into a Node project, write a template for a PDF, preview it while you edit it, and render it from your own code. Experimental.

Define each PDF or XLSX file your Node project produces in a file of its own, see it while you edit it, and render it from your own server. Do this when your project sends quotes, letters or price lists.

A file defined in code this way — the params it takes, sample params, and how it draws itself — is called a template. The library works on its own: it needs no Commentware server and no extension. It is experimental: its functions, config options and commands may change or be removed in any release, with no notice first, and its preview’s page carries an Experimental label.

Prerequisites

  • Node 24 or later, and a project with a package.json whose code is TypeScript or JavaScript with React’s JSX. A TypeScript project sets "jsx": "react-jsx" in its tsconfig.json.
  • A package manager. npm comes with Node.

Install the library

  1. Point the @commentware-private scope at the package registry, https://registry.commentware.com, so that your package manager fetches the library from it rather than from npm. Run the command for your package manager, or for yarn and bun write the file it shows:

    pnpm config set @commentware-private:registry=https://registry.commentware.com/

    It writes ~/.npmrc, the file the install below reads. No flag: that is where this command goes by default.

  2. In your project, add the library and the four packages your templates are built with:

    pnpm add @commentware-private/documents react react-dom zod exceljs
  3. A PDF is printed by Chrome. If you want the library to use a Chrome or Chromium you already have, name it in browser.executablePath and skip this step. Otherwise, download the Chrome for Testing build it uses:

    npx commentware-documents install-browser

    It prints each download, about 650 MB in all, and ends with Chrome for Testing is installed. On a machine that already has the build, it prints that line alone.

Write a template

  1. At the root of your project, create the config file that names the directory your templates are in:

    documents.config.tsts
    import { defineConfig } from "@commentware-private/documents";
    
    export default defineConfig({
      templates: ["src/templates"],
    });
  2. Create a template in that directory. Its id is its path inside the directory without the extension, here thank-you:

    src/templates/thank-you.tsxtsx
    import { z } from "zod";
    import { defineTemplate } from "@commentware-private/documents";
    
    export default defineTemplate({
      schema: z.object({ name: z.string() }),
      supportedOutputs: ["pdf"],
      mockData: { name: "Mira" },
      config: async ({ params }) => ({
        metadata: {
          fileName: `thank-you-${params.name.toLowerCase()}`,
          pdf: { name: "Thank you", width: "148mm", height: "210mm" },
        },
        renderers: {
          pdf: {
            component: async () => (
              <div className="p-[15mm] text-2xl">Thank you, {params.name}.</div>
            ),
          },
        },
      }),
    });

    Tailwind classes work in a template. Every field is in defineTemplate.

Preview the template

  1. From the root of your project, start the preview:

    npx commentware-documents preview

    It prints where it serves and keeps running until you press Ctrl-C:

    Previewing 1 template at http://127.0.0.1:7043/
    Experimental: the template library and these commands may change or go in
    any release, with no notice first.

    If something else holds 7043, start it with --port and a free port.

  2. Open http://127.0.0.1:7043/ and select thank-you. Edit the params on the left, or the template’s file, and the page redraws. Download PDF gives you the file.

    Optional: to see the page as printed pages, select Pages in the toolbar. Each printed page is the size the template’s pdf names, with its margins, and the text stays text, so a Commentware comment pins to it. The preview remembers the choice in this browser.

Render it from your code

  1. Write the index your code renders through. Run it again whenever you add a template or a Tailwind class:

    npx commentware-documents build
    Wrote .documents/templates.ts: 1 template, 4 KB of CSS.

    .documents/ is generated. Add it to your .gitignore.

  2. Render the template where your code needs the file. The params are checked against the template’s schema, and a mismatch is refused with each problem named:

    render.tsts
    import { writeFile } from "node:fs/promises";
    import { createRenderer } from "@commentware-private/documents";
    import { stylesheet, templates } from "./.documents/templates";
    
    const renderer = createRenderer({ templates, stylesheet });
    
    const file = await renderer.render("thank-you", { name: "Ada" }, "pdf");
    await writeFile(file.fileName, file.bytes);
    console.log(`Wrote ${file.fileName}`);
    
    await renderer.close();

    The renderer starts Chrome on the first PDF and keeps it until close(), so a server creates one renderer and renders through it.

Check that it worked

Run render.ts with the TypeScript runner your project uses, tsx in this example:

npx tsx render.ts
Wrote thank-you-ada.pdf

Open thank-you-ada.pdf. It is one A5 page reading “Thank you, Ada.”

Next steps

Documentation

Type to search…

↑↓ navigate↵ selectEsc close