You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					493 lines
				
				15 KiB
			
		
		
			
		
	
	
					493 lines
				
				15 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								# point-of-view
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[](https://www.npmjs.com/package/point-of-view)
							 | 
						||
| 
								 | 
							
								[](https://snyk.io/test/github/fastify/point-of-view)
							 | 
						||
| 
								 | 
							
								[](https://standardjs.com/)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Templates rendering plugin support for Fastify.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								`point-of-view` decorates the reply interface with the `view` method for managing view engines, which can be used to render templates responses.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Currently supports the following templates engines:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								- [`ejs`](https://ejs.co/)
							 | 
						||
| 
								 | 
							
								- [`nunjucks`](https://mozilla.github.io/nunjucks/)
							 | 
						||
| 
								 | 
							
								- [`pug`](https://pugjs.org/api/getting-started.html)
							 | 
						||
| 
								 | 
							
								- [`handlebars`](https://handlebarsjs.com/)
							 | 
						||
| 
								 | 
							
								- [`mustache`](https://mustache.github.io/)
							 | 
						||
| 
								 | 
							
								- [`art-template`](https://aui.github.io/art-template/)
							 | 
						||
| 
								 | 
							
								- [`twig`](https://twig.symfony.com/)
							 | 
						||
| 
								 | 
							
								- [`liquid`](https://github.com/harttle/liquidjs)
							 | 
						||
| 
								 | 
							
								- [`doT`](https://github.com/olado/doT)
							 | 
						||
| 
								 | 
							
								- [`eta`](https://eta.js.org)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								In `production` mode, `point-of-view` will heavily cache the templates file and functions, while in `development` will reload every time the template file and function.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								_Note that at least Fastify `v2.0.0` is needed._
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								_Note: [`ejs-mate`](https://github.com/JacksonTian/ejs-mate) support [has been dropped](https://github.com/fastify/point-of-view/pull/157)._
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								_Note: [`marko`](https://markojs.com/) support has been dropped. Please use [`@marko/fastify`](https://github.com/marko-js/fastify) instead._
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#### Benchmarks
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The benchmark were run with the files in the `benchmark` folder with the `ejs` engine.
							 | 
						||
| 
								 | 
							
								The data has been taken with: `autocannon -c 100 -d 5 -p 10 localhost:3000`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								- Express: 8.8k req/sec
							 | 
						||
| 
								 | 
							
								- **Fastify**: 15.6k req/sec
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Install
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								npm install point-of-view --save
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<a name="quickstart"></a>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Quick start
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								`fastify.register` is used to register point-of-view. By default, It will decorate the `reply` object with a `view` method that takes at least two arguments:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								- the template to be rendered
							 | 
						||
| 
								 | 
							
								- the data that should be available to the template during rendering
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This example will render the template and provide a variable `text` to be used inside the template:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								const fastify = require("fastify")();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fastify.register(require("point-of-view"), {
							 | 
						||
| 
								 | 
							
								  engine: {
							 | 
						||
| 
								 | 
							
								    ejs: require("ejs"),
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fastify.get("/", (req, reply) => {
							 | 
						||
| 
								 | 
							
								  reply.view("/templates/index.ejs", { text: "text" });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fastify.listen(3000, (err) => {
							 | 
						||
| 
								 | 
							
								  if (err) throw err;
							 | 
						||
| 
								 | 
							
								  console.log(`server listening on ${fastify.server.address().port}`);
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								If your handler function is asynchronous, make sure to return the result - otherwise this will result in an `FST_ERR_PROMISE_NOT_FULFILLED` error:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								// This is an async function
							 | 
						||
| 
								 | 
							
								fastify.get("/", async (req, reply) => {
							 | 
						||
| 
								 | 
							
								  // We are awaiting a functioon result
							 | 
						||
| 
								 | 
							
								  const t = await something();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Note the return statement
							 | 
						||
| 
								 | 
							
								  return reply.view("/templates/index.ejs", { text: "text" });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Configuration
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								`fastify.register(<engine>, <options>)` accepts an options object.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Options
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								- `engine`: The template engine object - pass in the return value of `require('<engine>')`. This option is mandatory.
							 | 
						||
| 
								 | 
							
								- `layout`: Point-of-view supports layouts for **EJS**, **Handlebars**, **Eta** and **doT**. This option lets you specify a global layout file to be used when rendering your templates. Settings like `root` or `viewExt` apply as for any other template file. Example: `./templates/layouts/main.hbs`
							 | 
						||
| 
								 | 
							
								- `propertyName`: The property that should be used to decorate `reply` and `fastify` - E.g. `reply.view()` and `fastify.view()` where `"view"` is the property name. Default: `"view"`.
							 | 
						||
| 
								 | 
							
								- `root`: The root path of your templates folder. The template name or path passed to the render function will be resolved relative to this path. Default: `"./"`.
							 | 
						||
| 
								 | 
							
								- `includeViewExtension`: Setting this to `true` will automatically append the default extension for the used template engine **if ommited from the template name** . So instead of `template.hbs`, just `template` can be used. Default: `false`.
							 | 
						||
| 
								 | 
							
								- `viewExt`: Let's you override the default extension for a given template engine. This has precedence over `includeViewExtension` and will lead to the same behavior, just with a custom extension. Default `""`. Example: `"handlebars"`.
							 | 
						||
| 
								 | 
							
								- `defaultContext`: The template variables defined here will be available to all views. Variables provided on render have precendence and will **override** this if they have the same name. Default: `{}`. Example: `{ siteName: "MyAwesomeSite" }`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Example:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								fastify.register(require("point-of-view"), {
							 | 
						||
| 
								 | 
							
								  engine: {
							 | 
						||
| 
								 | 
							
								    handlebars: require("handlebars"),
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								  root: path.join(__dirname, "views"), // Points to `./views` relative to the current file
							 | 
						||
| 
								 | 
							
								  layout: "./templates/template", // Sets the layout to use to `./views/templates/layout.handlebars` relative to the current file.
							 | 
						||
| 
								 | 
							
								  viewExt: "handlebars", // Sets the default extension to `.handlebars`
							 | 
						||
| 
								 | 
							
								  propertyName: "render", // The template can now be rendered via `reply.render()` and `fastify.render()`
							 | 
						||
| 
								 | 
							
								  defaultContext: {
							 | 
						||
| 
								 | 
							
								    dev: process.env.NODE_ENV === "development", // Inside your templates, `dev` will be `true` if the expression evaluates to true
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								  options: {}, // No options passed to handlebars
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Rendering the template into a variable
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The `fastify` object is decorated the same way as `reply` and allows you to just render a view into a variable instead of sending the result back to the browser:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								// Promise based, using async/await
							 | 
						||
| 
								 | 
							
								const html = await fastify.view("/templates/index.ejs", { text: "text" });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Callback based
							 | 
						||
| 
								 | 
							
								fastify.view("/templates/index.ejs", { text: "text" }, (err, html) => {
							 | 
						||
| 
								 | 
							
								  // Handle error
							 | 
						||
| 
								 | 
							
								  // Do something with `html`
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Registering multiple engines
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Registering multiple engines with different configurations is supported. They are dinguished via their `propertyName`:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								fastify.register(require("point-of-view"), {
							 | 
						||
| 
								 | 
							
								  engine: { ejs: ejs },
							 | 
						||
| 
								 | 
							
								  layout: "./templates/layout-mobile.ejs",
							 | 
						||
| 
								 | 
							
								  propertyName: "mobile",
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fastify.register(require("point-of-view"), {
							 | 
						||
| 
								 | 
							
								  engine: { ejs: ejs },
							 | 
						||
| 
								 | 
							
								  layout: "./templates/layout-desktop.ejs",
							 | 
						||
| 
								 | 
							
								  propertyName: "desktop",
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fastify.get("/mobile", (req, reply) => {
							 | 
						||
| 
								 | 
							
								  // Render using the `mobile` render function
							 | 
						||
| 
								 | 
							
								  return reply.mobile("/templates/index.ejs", { text: "text" });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fastify.get("/desktop", (req, reply) => {
							 | 
						||
| 
								 | 
							
								  // Render using the `desktop` render function
							 | 
						||
| 
								 | 
							
								  return reply.desktop("/templates/index.ejs", { text: "text" });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Providing a layout on render
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Point-of-view supports layouts for **EJS**, **Handlebars**, **Eta** and **doT**.
							 | 
						||
| 
								 | 
							
								These engines also support providing a layout on render.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								**Please note:** Global layouts and provding layouts on render are mutually exclusive. They can not be mixed.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								fastify.get('/', (req, reply) => {
							 | 
						||
| 
								 | 
							
								  reply.view('index-for-layout.ejs', data, { layout: 'layout.html' })
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Setting request-global variables
							 | 
						||
| 
								 | 
							
								Sometimes, several templates should have access to the same request-sceific variables. E.g. when setting the current username.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								If you want to provide data, which will be depended on by a request and available in all views, you have to add property `locals` to `reply` object, like in the example below:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								fastify.addHook("preHandler", function (request, reply, done) {
							 | 
						||
| 
								 | 
							
								  reply.locals = {
							 | 
						||
| 
								 | 
							
								    text: getTextFromRequest(request), // it will be available in all views
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  done();
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Properties from `reply.locals` will override those from `defaultContext`, but not from `data` parameter provided to `reply.view(template, data)` function.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Minifying HTML on render
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								To utilize [`html-minifier`](https://www.npmjs.com/package/html-minifier) in the rendering process, you can add the option `useHtmlMinifier` with a reference to `html-minifier`,
							 | 
						||
| 
								 | 
							
								and the optional `htmlMinifierOptions` option is used to specify the `html-minifier` options:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								// get a reference to html-minifier
							 | 
						||
| 
								 | 
							
								const minifier = require('html-minifier')
							 | 
						||
| 
								 | 
							
								// optionally defined the html-minifier options
							 | 
						||
| 
								 | 
							
								const minifierOpts = {
							 | 
						||
| 
								 | 
							
								  removeComments: true,
							 | 
						||
| 
								 | 
							
								  removeCommentsFromCDATA: true,
							 | 
						||
| 
								 | 
							
								  collapseWhitespace: true,
							 | 
						||
| 
								 | 
							
								  collapseBooleanAttributes: true,
							 | 
						||
| 
								 | 
							
								  removeAttributeQuotes: true,
							 | 
						||
| 
								 | 
							
								  removeEmptyAttributes: true
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								// in template engine options configure the use of html-minifier
							 | 
						||
| 
								 | 
							
								  options: {
							 | 
						||
| 
								 | 
							
								    useHtmlMinifier: minifier,
							 | 
						||
| 
								 | 
							
								    htmlMinifierOptions: minifierOpts
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								To utilize [`html-minify-stream`](https://www.npmjs.com/package/html-minify-stream) in the rendering process with template engines that support streams,
							 | 
						||
| 
								 | 
							
								you can add the option `useHtmlMinifyStream` with a reference to `html-minify-stream`, and the optional `htmlMinifierOptions` option is used to specify the options just like `html-minifier`:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								// get a reference to html-minify-stream
							 | 
						||
| 
								 | 
							
								const htmlMinifyStream = require('html-minify-stream')
							 | 
						||
| 
								 | 
							
								// optionally defined the html-minifier options that are used by html-minify-stream
							 | 
						||
| 
								 | 
							
								const minifierOpts = {
							 | 
						||
| 
								 | 
							
								  removeComments: true,
							 | 
						||
| 
								 | 
							
								  removeCommentsFromCDATA: true,
							 | 
						||
| 
								 | 
							
								  collapseWhitespace: true,
							 | 
						||
| 
								 | 
							
								  collapseBooleanAttributes: true,
							 | 
						||
| 
								 | 
							
								  removeAttributeQuotes: true,
							 | 
						||
| 
								 | 
							
								  removeEmptyAttributes: true
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								// in template engine options configure the use of html-minify-stream
							 | 
						||
| 
								 | 
							
								  options: {
							 | 
						||
| 
								 | 
							
								    useHtmlMinifyStream: htmlMinifyStream,
							 | 
						||
| 
								 | 
							
								    htmlMinifierOptions: minifierOpts
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								To filter some paths from minification, you can add the option `pathsToExcludeHtmlMinifier` with list of paths
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								// get a reference to html-minifier
							 | 
						||
| 
								 | 
							
								const minifier = require('html-minifier')
							 | 
						||
| 
								 | 
							
								// in options configure the use of html-minifier and set paths to exclude from minification
							 | 
						||
| 
								 | 
							
								const options = {
							 | 
						||
| 
								 | 
							
								  useHtmlMinifier: minifier,
							 | 
						||
| 
								 | 
							
								  pathsToExcludeHtmlMinifier: ['/test']
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fastify.register(require("point-of-view"), {
							 | 
						||
| 
								 | 
							
								  engine: {
							 | 
						||
| 
								 | 
							
								    ejs: require('ejs')
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								  options
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// This path is excluded from minification
							 | 
						||
| 
								 | 
							
								fastify.get("/test", (req, reply) => {
							 | 
						||
| 
								 | 
							
								  reply.view("./template/index.ejs", { text: "text" });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Engine-specific settings
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<!---
							 | 
						||
| 
								 | 
							
								// I don't think this is needed - see https://github.com/fastify/point-of-view/issues/280
							 | 
						||
| 
								 | 
							
								## EJS
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								To use include files please extend your template options as follows:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								// get a reference to resolve
							 | 
						||
| 
								 | 
							
								const resolve = require("path").resolve;
							 | 
						||
| 
								 | 
							
								// other code ...
							 | 
						||
| 
								 | 
							
								// in template engine options configure how to resolve templates folder
							 | 
						||
| 
								 | 
							
								options: {
							 | 
						||
| 
								 | 
							
								  filename: resolve("templates");
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								and in ejs template files (for example templates/index.ejs) use something like:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```html
							 | 
						||
| 
								 | 
							
								<%- include('header.ejs') %>
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								with a path relative to the current page, or an absolute path. Please check this example [here](./templates/layout-with-includes.ejs)
							 | 
						||
| 
								 | 
							
								--->
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Mustache
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								To use partials in mustache you will need to pass the names and paths in the options parameter:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								  options: {
							 | 
						||
| 
								 | 
							
								    partials: {
							 | 
						||
| 
								 | 
							
								      header: 'header.mustache',
							 | 
						||
| 
								 | 
							
								      footer: 'footer.mustache'
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Handlebars
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								To use partials in handlebars you will need to pass the names and paths in the options parameter:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								  options: {
							 | 
						||
| 
								 | 
							
								    partials: {
							 | 
						||
| 
								 | 
							
								      header: 'header.hbs',
							 | 
						||
| 
								 | 
							
								      footer: 'footer.hbs'
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								To use layouts in handlebars you will need to pass the `layout` parameter:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								fastify.register(require("point-of-view"), {
							 | 
						||
| 
								 | 
							
								  engine: {
							 | 
						||
| 
								 | 
							
								    handlebars: require("handlebars"),
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								  layout: "./templates/layout.hbs",
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fastify.get("/", (req, reply) => {
							 | 
						||
| 
								 | 
							
								  reply.view("./templates/index.hbs", { text: "text" });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Nunjucks
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								You can load templates from multiple paths when using the nunjucks engine:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								fastify.register(require("point-of-view"), {
							 | 
						||
| 
								 | 
							
								  engine: {
							 | 
						||
| 
								 | 
							
								    nunjucks: require("nunjucks"),
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								  templates: [
							 | 
						||
| 
								 | 
							
								    "node_modules/shared-components",
							 | 
						||
| 
								 | 
							
								    "views",
							 | 
						||
| 
								 | 
							
								  ],
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								To configure nunjucks environment after initialisation, you can pass callback function to options:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								options: {
							 | 
						||
| 
								 | 
							
								  onConfigure: (env) => {
							 | 
						||
| 
								 | 
							
								    // do whatever you want on nunjucks env
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Liquid
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								To configure liquid you need to pass the engine instance as engine option:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								const { Liquid } = require("liquidjs");
							 | 
						||
| 
								 | 
							
								const path = require("path");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const engine = new Liquid({
							 | 
						||
| 
								 | 
							
								  root: path.join(__dirname, "templates"),
							 | 
						||
| 
								 | 
							
								  extname: ".liquid",
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fastify.register(require("point-of-view"), {
							 | 
						||
| 
								 | 
							
								  engine: {
							 | 
						||
| 
								 | 
							
								    liquid: engine,
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fastify.get("/", (req, reply) => {
							 | 
						||
| 
								 | 
							
								  reply.view("./templates/index.liquid", { text: "text" });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### doT
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								When using [doT](https://github.com/olado/doT) the plugin compiles all templates when the application starts, this way all `.def` files are loaded and
							 | 
						||
| 
								 | 
							
								both `.jst` and `.dot` files are loaded as in-memory functions.
							 | 
						||
| 
								 | 
							
								This behaviour is recommended by the doT team [here](https://github.com/olado/doT#security-considerations).
							 | 
						||
| 
								 | 
							
								To make it possible it is necessary to provide a `root` or `templates` option with the path to the template directory.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								const path = require("path");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fastify.register(require("point-of-view"), {
							 | 
						||
| 
								 | 
							
								  engine: {
							 | 
						||
| 
								 | 
							
								    dot: require("dot"),
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								  root: "templates",
							 | 
						||
| 
								 | 
							
								  options: {
							 | 
						||
| 
								 | 
							
								    destination: "dot-compiled", // path where compiled .jst files are placed (default = 'out')
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fastify.get("/", (req, reply) => {
							 | 
						||
| 
								 | 
							
								  // this works both for .jst and .dot files
							 | 
						||
| 
								 | 
							
								  reply.view("index", { text: "text" });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<!---
							 | 
						||
| 
								 | 
							
								// This seems a bit random given that there was no mention of typescript before.
							 | 
						||
| 
								 | 
							
								### Typing
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Typing parameters from `reply.locals` in `typescript`:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```typescript
							 | 
						||
| 
								 | 
							
								interface Locals {
							 | 
						||
| 
								 | 
							
								  appVersion: string;
							 | 
						||
| 
								 | 
							
								  isAuthorized: boolean;
							 | 
						||
| 
								 | 
							
								  user?: {
							 | 
						||
| 
								 | 
							
								    id: number;
							 | 
						||
| 
								 | 
							
								    login: string;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								declare module "fastify" {
							 | 
						||
| 
								 | 
							
								  interface FastifyReply {
							 | 
						||
| 
								 | 
							
								    locals: Partial<Locals> | undefined;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								app.addHook("onRequest", (request, reply, done) => {
							 | 
						||
| 
								 | 
							
								  if (!reply.locals) {
							 | 
						||
| 
								 | 
							
								    reply.locals = {};
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  reply.locals.isAuthorized = true;
							 | 
						||
| 
								 | 
							
								  reply.locals.user = {
							 | 
						||
| 
								 | 
							
								    id: 1,
							 | 
						||
| 
								 | 
							
								    login: "Admin",
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								app.get("/data", (request, reply) => {
							 | 
						||
| 
								 | 
							
								  if (!reply.locals) {
							 | 
						||
| 
								 | 
							
								    reply.locals = {};
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // reply.locals.appVersion = 1 // not a valid type
							 | 
						||
| 
								 | 
							
								  reply.locals.appVersion = "4.14.0";
							 | 
						||
| 
								 | 
							
								  reply.view<{ text: string }>("/index", { text: "Sample data" });
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								-->
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Miscellaneous
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Using point-of-view as a dependency in a fastify-plugin
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								To require `point-of-view` as a dependency to a [fastify-plugin](https://github.com/fastify/fastify-plugin), add the name `point-of-view` to the dependencies array in the [plugin's opts](https://github.com/fastify/fastify-plugin#dependencies).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								fastify.register(myViewRendererPlugin, {
							 | 
						||
| 
								 | 
							
								  dependencies: ["point-of-view"],
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Forcing a cache-flush
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								To forcefully clear cache when in production mode, call the `view.clearCache()` function.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								fastify.view.clearCache();
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<a name="note"></a>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Note
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								By default views are served with the mime type 'text/html; charset=utf-8',
							 | 
						||
| 
								 | 
							
								but you can specify a different value using the type function of reply, or by specifying the desired charset in the property 'charset' in the opts object given to the plugin.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Acknowledgements
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This project is kindly sponsored by:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								- [nearForm](https://nearform.com)
							 | 
						||
| 
								 | 
							
								- [LetzDoIt](https://www.letzdoitapp.com/)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## License
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Licensed under [MIT](./LICENSE).
							 |