ProvenPin Install

ejs render with partials: working versions (tested 2026-10-16)

Render EJS string and file templates with strict locals, include a partial via include() resolved from a temp dir, and catch a ReferenceError for a missing local.

passed3 passed · 0 failed2026-10-16 02:18 UTC
Status
passed
Last passed
2026-10-16 02:18 UTC
Tests
3 / 3
Language
TypeScript
Runtime
node v22.23.3
pinned versions3
ejs@7.0.1@types/node@26.6.5tsx@4.23.15
run it
npm install --no-audit --no-fund --ignore-scripts=false
npm test
test environment
node v22.23.3
linux 6.17.0-1022-azure
x64
runner: github-actions 38839686104

The code

Exactly the files that passed. Your agent can pull them with get_recipe("ejs-render-partials") (install), or see them on GitHub.

package.json
{
  "name": "ejs-render-partials",
  "private": true,
  "type": "module",
  "scripts": {
    "test": "node --import tsx --test test/*.test.ts"
  },
  "dependencies": {
    "ejs": "7.0.1"
  },
  "devDependencies": {
    "@types/node": "26.6.5",
    "tsx": "4.23.15"
  }
}
src/render.ts
import ejs from "ejs";

export type PageLocals = {
  title: string;
  subtitle: string;
  items: string[];
};

export const strictOptions = {
  strict: true,
  localsName: "locals",
  _with: false,
};

export function renderString(template: string, locals: PageLocals): string {
  return ejs.render(template, locals, { ...strictOptions });
}

export function renderTemplateFile(
  filename: string,
  locals: PageLocals,
  root: string,
): Promise<string> {
  return new Promise((resolve, reject) => {
    ejs.renderFile(
      filename,
      locals,
      { ...strictOptions, root },
      (err, rendered) => {
        if (err) {
          reject(err);
        } else {
          resolve(rendered);
        }
      },
    );
  });
}
test/render.test.ts
import { test } from "node:test";
import assert from "node:assert/strict";
import { mkdtemp, mkdir, writeFile, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import {
  renderString,
  renderTemplateFile,
  type PageLocals,
} from "../src/render.ts";

const locals: PageLocals = {
  title: "Home",
  subtitle: "New arrivals",
  items: ["a", "b"],
};

test("renders a string template with locals", () => {
  const html = renderString("<h1><%= locals.title %></h1>", locals);
  assert.equal(html, "<h1>Home</h1>");
});

test("includes a partial resolved from a temp dir", async () => {
  const root = await mkdtemp(join(tmpdir(), "ejs-partials-"));
  try {
    await mkdir(join(root, "partials"), { recursive: true });
    await writeFile(
      join(root, "page.ejs"),
      "<h1><%= locals.title %></h1>\n<%- include('partials/badge.ejs', { label: locals.subtitle }) %>",
      "utf8",
    );
    await writeFile(
      join(root, "partials", "badge.ejs"),
      '<span class="badge"><%= locals.label %></span>',
      "utf8",
    );

    const html = await renderTemplateFile(join(root, "page.ejs"), locals, root);
    assert.equal(
      html,
      '<h1>Home</h1>\n<span class="badge">New arrivals</span>',
    );
  } finally {
    await rm(root, { recursive: true, force: true });
  }
});

test("throws ReferenceError for a missing local under strict mode", () => {
  assert.throws(
    () => renderString("<%= locals.title %><%= missingLocal %>", locals),
    ReferenceError,
  );
});

Connect to ProvenPin

Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.

terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp

Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.