Skip to content

Commit 21e1b4d

Browse files
View engine changes
1 parent 1cea7fb commit 21e1b4d

File tree

4 files changed

+120
-71
lines changed

4 files changed

+120
-71
lines changed

README.md

Lines changed: 44 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -34,23 +34,6 @@ Optional dependencies
3434

3535
## Setup
3636

37-
### Templates and views
38-
39-
Vision and nunjucks both need to be configured to search in the `forms-engine-plugin` views directory when looking for template files.
40-
41-
For vision this is done through the `path` [plugin option](https://github.com/hapijs/vision/blob/master/API.md#options)
42-
For nunjucks it is configured through the environment [configure options](https://mozilla.github.io/nunjucks/api.html#configure).
43-
44-
The `forms-engine-plugin` path to add can be imported from:
45-
46-
`import { VIEW_PATH } from '@defra/forms-engine-plugin'`
47-
48-
Which can then be appended to the `node_modules` path `node_modules/@defra/forms-engine`.
49-
50-
The main template layout is `govuk-frontend`'s `template.njk` file, this also needs to be added to the `path`s that nunjucks can look in.
51-
52-
See example below for more detail.
53-
5437
### Form config
5538

5639
The `form-engine-plugin` uses JSON configuration files to serve form journeys.
@@ -114,12 +97,10 @@ TODO
11497
```
11598
import hapi from '@hapi/hapi'
11699
import yar from '@hapi/yar'
117-
import vision from '@hapi/vision'
118100
import crumb from '@hapi/crumb'
119101
import inert from '@hapi/inert'
120102
import pino from 'hapi-pino'
121-
import nunjucks from 'nunjucks'
122-
import plugin, { prepareNunjucksEnvironment, context, VIEW_PATH } from '@defra/forms-engine-plugin'
103+
import plugin from '@defra/forms-engine-plugin'
123104
124105
const server = hapi.server({
125106
port: 3000
@@ -138,51 +119,7 @@ await server.register({
138119
}
139120
})
140121
141-
// Paths array to tell `vision` and `nunjucks` where template files are stored.
142-
// This can include `server/views`, or change it to where your local template are stored.
143-
const path = [
144-
`node_modules/@defra/forms-engine-plugin/${VIEW_PATH}`,
145-
'server/views'
146-
]
147-
148-
await server.register({
149-
plugin: vision,
150-
options: {
151-
engines: {
152-
html: {
153-
compile: (src, options) => {
154-
const template = nunjucks.compile(src, options.environment)
155-
156-
return (context) => {
157-
return template.render(context)
158-
}
159-
},
160-
prepare: (options, next) => {
161-
// Nunjucks also needs an additional path configuration
162-
// to use the templates and macros from `govuk-frontend`
163-
const environment = nunjucks.configure(
164-
[
165-
...path,
166-
'node_modules/govuk-frontend/dist'
167-
]
168-
)
169-
170-
// Applies custom filters and globals for nunjucks
171-
// that are required by the `forms-engine-plugin`
172-
prepareNunjucksEnvironment(environment)
173-
174-
options.compileOptions.environment = environment
175-
176-
return next()
177-
}
178-
}
179-
},
180-
path,
181-
context
182-
}
183-
})
184-
185-
// Registers the `forms-engine-plugin`
122+
// Register the `forms-engine-plugin`
186123
await server.register({
187124
plugin
188125
})
@@ -201,7 +138,11 @@ The forms plugin is configured with [registration options](https://hapi.dev/api/
201138
- `formSubmissionService` - used prepare the form during submission (ignore - subject to change)
202139
- `outputService` - used to save the submission
203140
- `controllers` (optional) - Object map of custom page controllers used to override the default. See [custom controllers](#custom-controllers)
204-
- `cacheName` (optional) - The cache name to use. Defaults to hapi's [default server cache]. Recommended for production. See [here](#custom-cache) for more details
141+
- `filters` (optional) - A map of custom template filters to include
142+
- `cacheName` (optional) - The cache name to use. Defaults to hapi's [default server cache]. Recommended for production. See [here]
143+
(#custom-cache) for more details
144+
- `pluginPath` (optional) - The location of the plugin (defaults to `node_modules/@defra/forms-engine-plugin`)
145+
205146

206147
### Services
207148

@@ -211,6 +152,25 @@ TODO
211152

212153
TODO
213154

155+
### Custom filters
156+
157+
Use the `filter` plugin option to provide custom template filters.
158+
Filters are available in both [nunjucks](https://mozilla.github.io/nunjucks/templating.html#filters) and [liquid](https://liquidjs.com/filters/overview.html) templates.
159+
160+
```
161+
const formatter = new Intl.NumberFormat('en-GB')
162+
163+
await server.register({
164+
plugin,
165+
options: {
166+
filters: {
167+
money: value => formatter.format(value),
168+
upper: value => typeof value === 'string' ? value.toUpperCase() : value
169+
}
170+
}
171+
})
172+
```
173+
214174
### Custom cache
215175

216176
The plugin will use the [default server cache](https://hapi.dev/api/?v=21.4.0#-serveroptionscache) to store form answers on the server.
@@ -321,3 +281,21 @@ There are a number of `LiquidJS` filters available to you from within the templa
321281
}
322282
]
323283
```
284+
285+
## Templates and views: Extending the default layout
286+
287+
TODO
288+
289+
To override the default page template, vision and nunjucks both need to be configured to search in the `forms-engine-plugin` views directory when looking for template files.
290+
291+
For vision this is done through the `path` [plugin option](https://github.com/hapijs/vision/blob/master/API.md#options)
292+
For nunjucks it is configured through the environment [configure options](https://mozilla.github.io/nunjucks/api.html#configure).
293+
294+
The `forms-engine-plugin` path to add can be imported from:
295+
296+
`import { VIEW_PATH } from '@defra/forms-engine-plugin'`
297+
298+
Which can then be appended to the `node_modules` path `node_modules/@defra/forms-engine`.
299+
300+
The main template layout is `govuk-frontend`'s `template.njk` file, this also needs to be added to the `path`s that nunjucks can look in.
301+

src/server/plugins/engine/index.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { type Environment } from 'nunjucks'
22

3+
4+
import { engine } from '~/src/server/plugins/engine/helpers.js'
35
import { plugin } from '~/src/server/plugins/engine/plugin.js'
6+
import { type FilterFunction } from '~/src/server/plugins/engine/types.js'
47
import {
58
checkComponentTemplates,
69
checkErrorTemplates,
@@ -19,15 +22,27 @@ const globals = {
1922
}
2023

2124
export const VIEW_PATH = 'src/server/plugins/engine/views'
25+
export const PLUGIN_PATH = 'node_modules/@defra/forms-engine-plugin'
2226

23-
export const prepareNunjucksEnvironment = function (env: Environment) {
27+
export const prepareNunjucksEnvironment = function (
28+
env: Environment,
29+
additionalFilters?: Record<string, FilterFunction>
30+
) {
2431
for (const [name, nunjucksFilter] of Object.entries(filters)) {
2532
env.addFilter(name, nunjucksFilter)
2633
}
2734

2835
for (const [name, nunjucksGlobal] of Object.entries(globals)) {
2936
env.addGlobal(name, nunjucksGlobal)
3037
}
38+
39+
// Apply any additional filters to both the liquid and nunjucks engines
40+
if (additionalFilters) {
41+
for (const [name, filter] of Object.entries(additionalFilters)) {
42+
env.addFilter(name, filter)
43+
engine.registerFilter(name, filter)
44+
}
45+
}
3146
}
3247

3348
export default plugin

src/server/plugins/engine/plugin.ts

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import {
66
type ResponseToolkit,
77
type RouteOptions
88
} from '@hapi/hapi'
9+
import vision from '@hapi/vision'
910
import { isEqual } from 'date-fns'
1011
import Joi from 'joi'
12+
import nunjucks from 'nunjucks'
1113

1214
import { PREVIEW_PATH_PREFIX } from '~/src/server/constants.js'
1315
import {
@@ -21,6 +23,12 @@ import {
2123
proceed,
2224
redirectPath
2325
} from '~/src/server/plugins/engine/helpers.js'
26+
import {
27+
PLUGIN_PATH,
28+
VIEW_PATH,
29+
context,
30+
prepareNunjucksEnvironment
31+
} from '~/src/server/plugins/engine/index.js'
2432
import {
2533
FormModel,
2634
SummaryViewModel
@@ -33,7 +41,10 @@ import { getFormSubmissionData } from '~/src/server/plugins/engine/pageControlle
3341
import { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers.js'
3442
import * as defaultServices from '~/src/server/plugins/engine/services/index.js'
3543
import { getUploadStatus } from '~/src/server/plugins/engine/services/uploadService.js'
36-
import { type FormContext } from '~/src/server/plugins/engine/types.js'
44+
import {
45+
type FilterFunction,
46+
type FormContext
47+
} from '~/src/server/plugins/engine/types.js'
3748
import {
3849
type FormRequest,
3950
type FormRequestPayload,
@@ -57,22 +68,65 @@ export interface PluginOptions {
5768
services?: Services
5869
controllers?: Record<string, typeof PageController>
5970
cacheName?: string
71+
pluginPath?: string
72+
filters?: Record<string, FilterFunction>
6073
}
6174

6275
export const plugin = {
6376
name: '@defra/forms-engine-plugin',
64-
dependencies: ['@hapi/vision', '@hapi/crumb', '@hapi/yar', 'hapi-pino'],
77+
dependencies: ['@hapi/crumb', '@hapi/yar', 'hapi-pino'],
6578
multiple: true,
66-
register(server, options) {
79+
async register(server, options) {
6780
const {
6881
model,
6982
services = defaultServices,
7083
controllers,
71-
cacheName
84+
cacheName,
85+
pluginPath = PLUGIN_PATH,
86+
filters
7287
} = options
7388
const { formsService } = services
7489
const cacheService = new CacheService(server, cacheName)
7590

91+
// Paths array to tell `vision` and `nunjucks` where template files are stored.
92+
const path = [`${pluginPath}/${VIEW_PATH}`]
93+
94+
await server.register({
95+
plugin: vision,
96+
options: {
97+
engines: {
98+
html: {
99+
compile: (src, options) => {
100+
const template = nunjucks.compile(src, options.environment)
101+
102+
return (context) => {
103+
return template.render(context)
104+
}
105+
},
106+
prepare: (options, next) => {
107+
// Nunjucks also needs an additional path configuration
108+
// to use the templates and macros from `govuk-frontend`
109+
const environment = nunjucks.configure([
110+
...path,
111+
'node_modules/govuk-frontend/dist'
112+
])
113+
114+
// Applies custom filters and globals for nunjucks
115+
// that are required by the `forms-engine-plugin`
116+
prepareNunjucksEnvironment(environment, filters)
117+
118+
options.compileOptions.environment = environment
119+
120+
next()
121+
}
122+
}
123+
},
124+
path,
125+
// Provides global context used with all templates
126+
context
127+
}
128+
})
129+
76130
server.expose('cacheService', cacheService)
77131

78132
server.app.model = model

src/server/plugins/engine/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,3 +313,5 @@ export type PageViewModel =
313313
| FormPageViewModel
314314
| RepeaterSummaryPageViewModel
315315
| FeaturedFormPageViewModel
316+
317+
export type FilterFunction = (value: unknown) => unknown

0 commit comments

Comments
 (0)