Skip to content

Commit 1861a1e

Browse files
committed
take nunjucks paths and view context from consumer
1 parent 253fdbd commit 1861a1e

8 files changed

Lines changed: 62 additions & 157 deletions

File tree

src/server/plugins/engine/configureEnginePlugin.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,11 @@ export const configureEnginePlugin = async ({
3131
model,
3232
services,
3333
controllers,
34+
nunjucks: {
35+
paths: [] // TODO
36+
}
3437
viewContext: {
35-
baseLayoutPath: 'layout.html'
38+
baseLayoutPath: 'layout.html' // govuk-frontend
3639
}
3740
}
3841
}

src/server/plugins/engine/plugin.ts

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import { existsSync } from 'fs'
2+
import { dirname, join } from 'path'
3+
import { fileURLToPath } from 'url'
4+
15
import { hasFormComponents, slugSchema } from '@defra/forms-model'
26
import Boom from '@hapi/boom'
37
import {
@@ -11,6 +15,9 @@ import vision from '@hapi/vision'
1115
import { isEqual } from 'date-fns'
1216
import Joi from 'joi'
1317
import nunjucks, { type Environment } from 'nunjucks'
18+
import resolvePkg from 'resolve'
19+
20+
import { paths } from '../nunjucks/environment.js'
1421

1522
import { PREVIEW_PATH_PREFIX } from '~/src/server/constants.js'
1623
import {
@@ -65,6 +72,20 @@ import * as httpService from '~/src/server/services/httpService.js'
6572
import { CacheService } from '~/src/server/services/index.js'
6673
import { type Services } from '~/src/server/types.js'
6774

75+
function findPackageRoot() {
76+
const currentFileName = fileURLToPath(import.meta.url)
77+
const currentDirectoryName = dirname(currentFileName)
78+
79+
let dir = currentDirectoryName
80+
while (dir !== '/') {
81+
if (existsSync(join(dir, 'package.json'))) {
82+
return dir
83+
}
84+
dir = dirname(dir)
85+
}
86+
87+
throw new Error('package.json not found in parent directories')
88+
}
6889
export interface PluginOptions {
6990
model?: FormModel
7091
services?: Services
@@ -73,6 +94,9 @@ export interface PluginOptions {
7394
viewPaths?: string[]
7495
filters?: Record<string, FilterFunction>
7596
pluginPath?: string
97+
nunjucks: {
98+
paths: string[]
99+
}
76100
viewContext: {
77101
baseLayoutPath: string
78102
}
@@ -88,24 +112,25 @@ export const plugin = {
88112
services = defaultServices,
89113
controllers,
90114
cacheName,
91-
viewPaths,
92115
filters,
93-
pluginPath = PLUGIN_PATH,
116+
nunjucks: nunjucksOptions,
94117
viewContext
95118
} = options
96119
const { formsService } = services
97120
const cacheService = new CacheService(server, cacheName)
98121

99-
// Paths array to tell `vision` and `nunjucks` where template files are stored.
100-
// We need to include `VIEW_PATH` in addition the runtime path (node_modules)
101-
// to keep the local tests working
102-
const path = [`${pluginPath}/${VIEW_PATH}`, VIEW_PATH]
122+
const packageRoot = findPackageRoot()
123+
const govukFrontendPath = dirname(
124+
resolvePkg.sync('govuk-frontend/package.json')
125+
)
103126

104-
// Include any additional user provided view paths so our internal views engine
105-
// can find any files they provide from the consumer side if using custom `page.view`s
106-
if (Array.isArray(viewPaths) && viewPaths.length) {
107-
path.push(...viewPaths)
108-
}
127+
const viewPathResolved = join(packageRoot, VIEW_PATH)
128+
129+
const paths = [
130+
...nunjucksOptions.paths,
131+
viewPathResolved,
132+
join(govukFrontendPath, 'dist')
133+
]
109134

110135
await server.register({
111136
plugin: vision,
@@ -131,10 +156,7 @@ export const plugin = {
131156
) => {
132157
// Nunjucks also needs an additional path configuration
133158
// to use the templates and macros from `govuk-frontend`
134-
const environment = nunjucks.configure([
135-
...path,
136-
'node_modules/govuk-frontend/dist'
137-
])
159+
const environment = nunjucks.configure(paths)
138160

139161
// Applies custom filters and globals for nunjucks
140162
// that are required by the `forms-engine-plugin`
@@ -146,7 +168,7 @@ export const plugin = {
146168
}
147169
}
148170
},
149-
path,
171+
path: paths,
150172
// Provides global context used with all templates
151173
context
152174
}

src/server/plugins/engine/views/file-upload.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
{% block bodyEnd %}
3636
{{ super() }}
3737
<script type="module" nonce="{{ cspNonce }}">
38-
import { initFileUpload } from '{{ getAssetPath("file-upload.js") }}';
38+
import { initFileUpload } from '{{ getDxtAssetPath("file-upload.js") }}';
3939
if (document.readyState === 'loading') {
4040
document.addEventListener('DOMContentLoaded', initFileUpload);
4141
} else {

src/server/plugins/engine/views/layout.html

Lines changed: 0 additions & 125 deletions
This file was deleted.

src/server/plugins/nunjucks/context.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,13 @@ export function context(request) {
4444
const isResponseOK =
4545
!Boom.isBoom(response) && response?.statusCode === StatusCodes.OK
4646

47+
const consumerViewContext =
48+
request?.server.plugins['forms-engine-plugin'].viewContext(request)
49+
4750
/** @type {ViewContext} */
4851
const ctx = {
49-
...request?.server.plugins['forms-engine-plugin'].viewContext, // take consumers props first so we can override it
52+
// take consumers props first so we can override it
53+
...consumerViewContext,
5054
appVersion: pkg.version,
5155
assetPath: '/assets',
5256
config: {
@@ -64,7 +68,7 @@ export function context(request) {
6468
previewMode: isPreviewMode ? params?.state : undefined,
6569
slug: isResponseOK ? params?.slug : undefined,
6670

67-
getAssetPath: (asset = '') => {
71+
getDxtAssetPath: (asset = '') => {
6872
return `/${webpackManifest?.[asset] ?? asset}`
6973
}
7074
}

src/server/plugins/nunjucks/context.test.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ describe('Nunjucks context', () => {
1616

1717
describe('Asset helper', () => {
1818
it("should locate 'assets-manifest.json' assets", () => {
19-
const { getAssetPath } = context(null)
19+
const { getDxtAssetPath } = context(null)
2020

21-
expect(getAssetPath('example.scss')).toBe(
21+
expect(getDxtAssetPath('example.scss')).toBe(
2222
'/stylesheets/example.xxxxxxx.min.css'
2323
)
2424

25-
expect(getAssetPath('example.mjs')).toBe(
25+
expect(getDxtAssetPath('example.mjs')).toBe(
2626
'/javascripts/example.xxxxxxx.min.js'
2727
)
2828
})
@@ -38,20 +38,20 @@ describe('Nunjucks context', () => {
3838

3939
// Update config for missing manifest
4040
config.set('publicDir', tmpdir())
41-
const { getAssetPath } = context(null)
41+
const { getDxtAssetPath } = context(null)
4242

4343
// Uses original paths when missing
44-
expect(getAssetPath('example.scss')).toBe('/example.scss')
45-
expect(getAssetPath('example.mjs')).toBe('/example.mjs')
44+
expect(getDxtAssetPath('example.scss')).toBe('/example.scss')
45+
expect(getDxtAssetPath('example.mjs')).toBe('/example.mjs')
4646
})
4747
})
4848

4949
it('should return path to unknown assets', () => {
50-
const { getAssetPath } = context(null)
50+
const { getDxtAssetPath } = context(null)
5151

52-
expect(getAssetPath()).toBe('/')
53-
expect(getAssetPath('example.jpg')).toBe('/example.jpg')
54-
expect(getAssetPath('example.gif')).toBe('/example.gif')
52+
expect(getDxtAssetPath()).toBe('/')
53+
expect(getDxtAssetPath('example.jpg')).toBe('/example.jpg')
54+
expect(getDxtAssetPath('example.gif')).toBe('/example.gif')
5555
})
5656
})
5757

src/server/plugins/nunjucks/types.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
* @property {string} [currentPath] - Current path
2121
* @property {string} [previewMode] - Preview mode
2222
* @property {string} [slug] - Form slug
23-
* @property {(asset?: string) => string} getAssetPath - Asset path resolver
23+
* @property {(asset?: string) => string} getDxtAssetPath - Asset path resolver
2424
* @property {FormContext} [context] - the current form context
2525
* @property {PluginOptions['viewContext']} [injectedViewContext] - the current form context
2626
*/

src/typings/hapi/index.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { type ServerYar, type Yar } from '@hapi/yar'
55
import { type Logger } from 'pino'
66

77
import { type FormModel } from '~/src/server/plugins/engine/models/index.js'
8+
import { type context } from '~/src/server/plugins/engine/nunjucks.js'
89
import { type ViewContext } from '~/src/server/plugins/nunjucks/types.js'
910
import {
1011
type FormRequest,
@@ -21,7 +22,7 @@ declare module '@hapi/hapi' {
2122
}
2223
'forms-engine-plugin': {
2324
cacheService: CacheService
24-
viewContext: ViewContext
25+
viewContext: context
2526
}
2627
}
2728

0 commit comments

Comments
 (0)