Use a template engine
In this guide you will learn how to use a template engine, like EJS and Handlebars, to create server-rendered HTML views.
Related example
$ encore app create --example=ts/template-engine
Serving a specific template file
Breakdown of the example:
- We import a NPM package for rendering templates, in this case EJS.
- We have a Raw Endpoint to handle template rendering, in this case we are serving a specific template file (
person.html
) under/person
. - We make use of the EJS to render the template with the given data.
- We set the
content-type
header totext-html
and then respond with the generated HTML.
template/template.tstemplate/views/person.htmlimport { api } from "encore.dev/api"; import ejs, { Options } from "ejs"; const BASE_PATH = "./template/views"; const ejsOptions: Options = { views: [BASE_PATH] }; export const serveSpecificTemplate = api.raw( { expose: true, path: "/person", method: "GET" }, async (req, resp) => { const viewPath = `${BASE_PATH}/person.html`; const html = await ejs.renderFile( viewPath, // Supplying data to the view { name: "Simon" }, ejsOptions, ); resp.setHeader("content-type", "text/html"); resp.end(html); }, );
Serving from a dynamic path
This example is similar to the one above, but in this case we use a fallback path to serve a template file based on the path. We use the currentRequest
function to get the path
and then render the template file based on the path
. If no path is provided, we default to index.html
.
import { api } from "encore.dev/api"; import { APICallMeta, currentRequest } from "encore.dev"; import ejs, { Options } from "ejs"; const BASE_PATH = "./template/views"; const ejsOptions: Options = { views: [BASE_PATH] }; export const servePathTemplate = api.raw( { expose: true, path: "/!path", method: "GET" }, async (req, resp) => { const { path } = (currentRequest() as APICallMeta).pathParams; const viewPath = `${BASE_PATH}/${path ?? "index"}.html`; const html = await ejs.renderFile(viewPath, ejsOptions); resp.setHeader("content-type", "text/html"); resp.end(html); }, );
Serving inline HTML
In this example we are serving inline HTML with EJS. We use the ejs.render
function to render the inline HTML with the given data.
import { api } from "encore.dev/api"; import ejs, { Options } from "ejs"; const inlineHTML = ` <!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <link rel="stylesheet" href="/public/styles.css" > </head> <body> <h1>Static Inline HTML Example</h1> <h1>Name: <%= name %>!</h1> </body> </html> `; export const serveInlineHTML = api.raw( { expose: true, path: "/html", method: "GET" }, async (req, resp) => { const html = ejs.render(inlineHTML, { name: "Simon" }); resp.setHeader("Content-Type", "text/html"); resp.end(html); }, );
Static files
In the above example we are fetching a stylesheet from the /public
path. We can use the api.static
function to serve all files in the ./assets
directory under the /public
path prefix:
// Serve all files in the ./assets directory under the /public path prefix. export const assets = api.static({ expose: true, path: "/public/*path", dir: "./assets", });
Learn more about serving static files in the Static Files guide.