Skip to main content
Version: 4.x

Server-Side Rendering

Regular Templates

Regular Web Applications rely on templates to dynamically generate HTML pages on the server. These templates are text files that contain static content as well as a special syntax describing how the data should be inserted dynamically. During an HTTP request, the application loads and renders the template using the given contextual data and sends back the page to the client.

This technique is known as Server-Side Rendering (or SSR).

Here is an example of what a template might look like:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% title %}</title>
</head>
<body>
{% for user in users %}
* {{ user.name }}
{% else %}
No users have been found.
{% endfor %}
</body>
</html>

Rendering Templates

FoalTS provides a minimalist template engine to render templates. This engine replaces all the occurrences of {{ myVariableName }} with the given values.

Here is an example showing how to use it:

templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
Hello {{ name }}!
</body>
</html>

src/app/app.controller.ts

import { Get, render } from '@foal/core';

export class AppController {
@Get('/')
index() {
return render('./templates/index.html', {
name: 'Alix',
title: 'Home'
});
}
}

Output (GET /)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Home</title>
</head>
<body>
Hello Alix!
</body>
</html>

Using Another Template Engine

External template engines, such as EJS or pug, are also supported and can be configured for the current project using the configuration key settings.templateEngine.

Here is an example showing how to configure config/default.json (or config/default.yml) with twig, a JS implementation of the Twig PHP templating language.

npm install twig
settings:
templateEngine: twig

Then the render function uses this engine under the hood to render the templates.

Note: Only Express compatible template engines are supported (which represents the large majority of those available on npm).

templates/index.html (Twig example)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Users</title>
</head>
<body>
<ul>
{% for user in users %}
<li>{{ user.name }}</li>
{% endfor %}
</ul>
</body>
</html>

src/app/app.controller.ts (Twig example)

import { Get } from '@foal/core';

export class AppController {
@Get('/')
index() {
return render('./templates/index.html', {
users: [
{ name: 'John' },
{ name: 'Mary' }
]
});
}
}

Output (GET /) (Twig example)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Users</title>
</head>
<body>
<ul>
<li>John</li>
<li>Mary</li>
</ul>
</body>
</html>

Path Resolution

By default, the render function loads templates from the project root directory.

// |- config
// |- src
// '- templates
// '- login.html
render('./templates/login.html', { /* ... */ })

But the path can also be relative to the controller file. The render function accepts a third parameter dirname for this purpose.

/* login.controller.ts */

// |- config
// '- src
// '- app
// '- controllers
// |- templates
// | '- login.html
// '- login.controller.ts
render('./templates/login.html', { /* ... */ }, __dirname)

JSX Server-Side Rendering

To compile JSX files, you need to update the tsconfig.json as follows:

{
"compilerOptions": {
...
"jsx": "react",
},
"include": [
"src/**/*.ts"
"src/**/*.tsx"
]
}

Then, add the file extension tsx in every tsconfig.*.json.

Example with tsconfig.app.json

{
"extends": "./tsconfig.json",
"include": [
"src/**/*.ts",
"src/**/*.tsx"
],
"exclude": [
"src/e2e/*.ts",
"src/**/*.spec.ts",
"src/e2e.ts",
"src/test.ts"
]
}

Every file using JSX must now have the extension .tsx.

Example with React

npm install react react-dom

This example shows how to use JSX SSR with React. It assumes that templates directory is in the root, next to src.

view.controller.tsx

import { Get, render } from '@foal/core';
import * as React from 'react';
import * as ReactDOMServer from 'react-dom/server';

export class ViewController {

@Get('/')
async index() {
const content = ReactDOMServer.renderToString(<div>Hello world!</div>);

return render('./templates/index.html', {
content,
});
}

}

./templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Home</title>
</head>
<body>
{{ content }}
</body>
</html>