Skip to content

Commit 28a7a35

Browse files
Support version number via prototypeKitVersion local etc (#230)
This PR adds a new locals to migrate the `{{ version }}` number from ``` prototypeKitVersion nhsukFrontendVersion ``` Unblocks #239 <img width="819" height="219" alt="Version numbers displayed in test app" src="https://github.com/user-attachments/assets/a2761401-33d8-4bae-909b-4fcdeaa3b017" /> --- ## Config export I've also added `config` alongside exported `middleware`, `nunjucksFilters` and `utils` ### ES module named export ```mjs import { config } from 'nhsuk-prototype-kit' config.prototypeKitVersion config.nhsukFrontendVersion config.searchPaths ``` ### ES module package export ```mjs import * as config from 'nhsuk-prototype-kit/config' config.prototypeKitVersion config.nhsukFrontendVersion config.searchPaths ``` ### CommonJS package export ```mjs const config = require('nhsuk-prototype-kit/config') config.prototypeKitVersion config.nhsukFrontendVersion config.searchPaths ``` ### CommonJS static properties ```cjs const NHSPrototypeKit = require('nhsuk-prototype-kit') const { config } = NHSPrototypeKit config.prototypeKitVersion config.nhsukFrontendVersion config.searchPaths ```
1 parent a987a00 commit 28a7a35

14 files changed

+169
-82
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
- Add link to "/" from header
1111
- Update error pages to use nhsuk-heading-l
1212
- Support NHS.UK frontend v11.x previews and pre-releases
13+
- Support version number via `prototypeKitVersion` local
1314

1415
## 8.0.1 – 6 Feb 2026
1516

lib/esbuild.config.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
import { join } from 'node:path'
2-
import { cwd } from 'node:process'
3-
41
import { cleanPlugin } from 'esbuild-clean-plugin'
52
import { sassPlugin } from 'esbuild-sass-plugin'
63

7-
import { modulesPath } from './nhsuk-prototype-kit.config.js'
4+
import * as config from './nhsuk-prototype-kit.config.js'
85

96
const { NODE_ENV } = process.env
107

@@ -25,7 +22,7 @@ export default /** @satisfies {BuildOptions} */ ({
2522
cleanPlugin(),
2623
sassPlugin({
2724
embedded: true,
28-
loadPaths: [modulesPath, join(cwd(), 'node_modules')],
25+
loadPaths: config.modulePaths,
2926
silenceDeprecations: ['import'],
3027
quietDeps: true,
3128
sourceMap: true,

lib/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import * as middleware from './middleware/index.js'
2+
import * as config from './nhsuk-prototype-kit.config.js'
23
import { NHSPrototypeKit } from './nhsuk-prototype-kit.js'
34
import * as nunjucksFilters from './nunjucks-filters/index.js'
45
import * as utils from './utils/index.js'
56

67
export default NHSPrototypeKit
7-
export { middleware, nunjucksFilters, utils }
8+
export { config, middleware, nunjucksFilters, utils }
89

910
/**
1011
* @typedef {import('./nhsuk-prototype-kit.js').Options} Options

lib/index.test.cjs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,50 @@ const express = require('express')
55
const nunjucks = require('nunjucks')
66

77
const NHSPrototypeKit = require('./index.cjs')
8+
const { config, middleware, nunjucksFilters, utils } = NHSPrototypeKit
89

910
describe('CommonJS default exports', () => {
1011
it('should export NHSPrototypeKit as default', () => {
1112
assert.ok(NHSPrototypeKit)
1213
assert.equal(typeof NHSPrototypeKit, 'function')
1314
})
1415

16+
it('should export config as static property', () => {
17+
assert.ok(config)
18+
assert.equal(typeof config, 'object')
19+
assert.equal(typeof config.nhsukFrontendPath, 'string')
20+
assert.equal(typeof config.nhsukFrontendVersion, 'string')
21+
assert.equal(typeof config.prototypeKitPath, 'string')
22+
assert.equal(typeof config.prototypeKitVersion, 'string')
23+
assert.ok(config.modulePaths.every((path) => typeof path === 'string'))
24+
assert.ok(config.searchPaths.every((path) => typeof path === 'string'))
25+
})
26+
27+
it('should export middleware as static property', () => {
28+
assert.ok(middleware)
29+
assert.equal(typeof middleware, 'object')
30+
assert.equal(typeof middleware.configure, 'function')
31+
assert.equal(typeof middleware.autoRoutes, 'function')
32+
})
33+
34+
it('should export nunjucksFilters as static property', () => {
35+
assert.ok(nunjucksFilters)
36+
assert.equal(typeof nunjucksFilters, 'object')
37+
assert.equal(typeof nunjucksFilters.addAll, 'function')
38+
assert.equal(typeof nunjucksFilters.formatNhsNumber, 'function')
39+
assert.equal(typeof nunjucksFilters.log, 'function')
40+
assert.equal(typeof nunjucksFilters.startsWith, 'function')
41+
})
42+
43+
it('should export utils as static property', () => {
44+
assert.ok(utils)
45+
assert.equal(typeof utils, 'object')
46+
assert.equal(typeof utils.addNunjucksFilters, 'function')
47+
assert.equal(typeof utils.findAvailablePort, 'function')
48+
assert.equal(typeof utils.getAvailablePort, 'function')
49+
assert.equal(typeof utils.normaliseOptions, 'function')
50+
})
51+
1552
it('should have init method', () => {
1653
assert.equal(typeof NHSPrototypeKit.init, 'function')
1754
})

lib/index.test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import assert from 'node:assert/strict'
22
import { describe, it } from 'node:test'
33

44
import NHSPrototypeKit, {
5+
config,
56
middleware,
67
nunjucksFilters,
78
utils
@@ -13,6 +14,17 @@ describe('ES module named exports', () => {
1314
assert.equal(typeof NHSPrototypeKit, 'function')
1415
})
1516

17+
it('should export config as a named export', () => {
18+
assert.ok(config)
19+
assert.equal(typeof config, 'object')
20+
assert.equal(typeof config.nhsukFrontendPath, 'string')
21+
assert.equal(typeof config.nhsukFrontendVersion, 'string')
22+
assert.equal(typeof config.prototypeKitPath, 'string')
23+
assert.equal(typeof config.prototypeKitVersion, 'string')
24+
assert.ok(config.modulePaths.every((path) => typeof path === 'string'))
25+
assert.ok(config.searchPaths.every((path) => typeof path === 'string'))
26+
})
27+
1628
it('should export middleware as a named export', () => {
1729
assert.ok(middleware)
1830
assert.equal(typeof middleware, 'object')

lib/middleware/index.js

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import cookieParser from 'cookie-parser'
33
import flash from 'express-flash'
44
import session from 'express-session'
55

6+
import * as config from '../nhsuk-prototype-kit.config.js'
7+
68
import { authentication } from './authentication.js'
79
import { autoRoutes } from './auto-routes.js'
810
import { autoStoreData } from './auto-store-data.js'
@@ -42,13 +44,30 @@ function generateSessionName(serviceName) {
4244
return `nhsuk-prototype-kit-${hash}`
4345
}
4446

47+
/**
48+
* Configure locals middleware
49+
*
50+
* @param {Options} options
51+
*/
52+
export function configureLocals(options) {
53+
const { app, serviceName } = options
54+
55+
app.use(setCurrentPageInLocals)
56+
app.use((req, res, next) => {
57+
res.locals.nhsukFrontendVersion = config.nhsukFrontendVersion
58+
res.locals.prototypeKitVersion = config.prototypeKitVersion
59+
res.locals.serviceName = serviceName
60+
next()
61+
})
62+
}
63+
4564
/**
4665
* Configure session middleware
4766
*
48-
* @param {Express} app
49-
* @param {string} serviceName
67+
* @param {Options} options
5068
*/
51-
function configureSession(app, serviceName) {
69+
export function configureSession(options) {
70+
const { app, serviceName } = options
5271
const sessionName = generateSessionName(serviceName)
5372

5473
app.use(
@@ -72,26 +91,21 @@ function configureSession(app, serviceName) {
7291
* @param {Options} options
7392
*/
7493
export function configure(options) {
75-
const app = options.app
76-
const serviceName = options.serviceName || 'Service name goes here'
94+
const { app } = options
7795

7896
// Configure core middleware
7997
app.use(cookieParser())
8098
app.use(bodyParser.urlencoded({ extended: true }))
8199

82100
// Configure session
83-
configureSession(app, serviceName)
101+
configureSession(options)
102+
103+
// Configure locals
104+
configureLocals(options)
84105

85106
// Use flash
86107
app.use(flash())
87108

88-
// Set locals
89-
app.use(setCurrentPageInLocals)
90-
app.use((req, res, next) => {
91-
res.locals.serviceName = serviceName
92-
next()
93-
})
94-
95109
// Add production-specific middleware
96110
if (process.env.NODE_ENV === 'production') {
97111
app.use(productionHeaders)
@@ -132,6 +146,5 @@ export function configure(options) {
132146
}
133147

134148
/**
135-
* @import { Express } from 'express'
136149
* @import { Options } from '../nhsuk-prototype-kit.js'
137150
*/

lib/middleware/reset-session-data.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66
export function resetSessionData(req, res, next) {
77
const { path, method } = req
88

9-
// Current page used for the Reset data feature
10-
res.locals.currentPage = req.originalUrl
11-
129
if (method === 'GET' && path === '/prototype-admin/reset') {
1310
const returnPage = req.query.returnPage || '/'
1411
res.render('reset', {

lib/middleware/reset-session-data.test.js

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -145,17 +145,6 @@ describe('resetSessionData middleware', () => {
145145

146146
assert.equal(next.mock.callCount(), 1)
147147
})
148-
149-
it('should set res.locals.currentPage for all requests', () => {
150-
Object.assign(req, {
151-
originalUrl: '/test-url?param=value',
152-
path: '/some-page'
153-
})
154-
155-
resetSessionData(req, res, next)
156-
157-
assert.equal(res.locals.currentPage, '/test-url?param=value')
158-
})
159148
})
160149

161150
describe('reset-session-data endpoint behavior', () => {

lib/nhsuk-prototype-kit.config.js

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,47 @@
1-
import { dirname } from 'node:path'
1+
import { dirname, join } from 'node:path'
2+
import { cwd } from 'node:process'
23
import { fileURLToPath } from 'node:url'
34

4-
// NHS prototype kit path
5+
import nhsukFrontendPkg from 'nhsuk-frontend/package.json' with { type: 'json' }
6+
7+
import pkg from '../package.json' with { type: 'json' }
8+
9+
/**
10+
* NHS prototype kit path
11+
*/
512
export const prototypeKitPath = dirname(import.meta.dirname)
613

7-
// NHS.UK frontend package path
14+
/**
15+
* NHS prototype kit version
16+
*/
17+
export const prototypeKitVersion = `v${pkg.version}`
18+
19+
/**
20+
* NHS.UK frontend path
21+
*/
822
export const nhsukFrontendPath = fileURLToPath(
923
dirname(import.meta.resolve('nhsuk-frontend/package.json'))
1024
)
1125

12-
// Node modules path
13-
export const modulesPath = dirname(nhsukFrontendPath)
26+
/**
27+
* NHS.UK frontend version
28+
*/
29+
export const nhsukFrontendVersion = `v${nhsukFrontendPkg.version}`
30+
31+
/**
32+
* Node.js module paths
33+
*/
34+
export const modulePaths = Array.from(
35+
new Set([dirname(nhsukFrontendPath), join(cwd(), 'node_modules')])
36+
)
37+
38+
/**
39+
* Nunjucks search paths
40+
*/
41+
export const searchPaths = [
42+
join(prototypeKitPath, 'lib/views'),
43+
join(nhsukFrontendPath, 'dist/nhsuk/components'),
44+
join(nhsukFrontendPath, 'dist/nhsuk/macros'),
45+
join(nhsukFrontendPath, 'dist/nhsuk'),
46+
join(nhsukFrontendPath, 'dist')
47+
]

lib/nhsuk-prototype-kit.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,7 @@ import waitOn from 'wait-on'
88
import { build } from './build/index.js'
99
import * as expressSettings from './express-settings/index.js'
1010
import * as middleware from './middleware/index.js'
11-
import {
12-
nhsukFrontendPath,
13-
prototypeKitPath
14-
} from './nhsuk-prototype-kit.config.js'
11+
import * as config from './nhsuk-prototype-kit.config.js'
1512
import * as nunjucksFilters from './nunjucks-filters/index.js'
1613
import * as utils from './utils/index.js'
1714

@@ -28,6 +25,11 @@ export class NHSPrototypeKit {
2825
this.buildOptions = buildOptions
2926
}
3027

28+
static config = config
29+
static middleware = middleware
30+
static nunjucksFilters = nunjucksFilters
31+
static utils = utils
32+
3133
/**
3234
* This does all setup for both the Express app
3335
* and the Nunjucks environment
@@ -60,13 +62,13 @@ export class NHSPrototypeKit {
6062
// Use assets from NHS.UK frontend
6163
app.use(
6264
'/nhsuk-frontend',
63-
express.static(join(nhsukFrontendPath, 'dist/nhsuk'))
65+
express.static(join(config.nhsukFrontendPath, 'dist/nhsuk'))
6466
)
6567

6668
// Use scripts from lib
6769
app.use(
6870
'/nhsuk-prototype-kit/javascripts',
69-
express.static(join(prototypeKitPath, 'lib/javascripts'))
71+
express.static(join(config.prototypeKitPath, 'lib/javascripts'))
7072
)
7173

7274
// Use assets and images from public, with app fallback
@@ -243,10 +245,10 @@ export class NHSPrototypeKit {
243245

244246
/**
245247
* @typedef {object} Options
246-
* @property {string} [serviceName] - Service name
248+
* @property {string} serviceName - Service name
247249
* @property {Express} app - Express app
248250
* @property {Router} [routes] - Additional custom routes
249-
* @property {string | string[]} [viewsPath] - Additional custom views path
251+
* @property {string | string[]} viewsPath - Additional custom views path
250252
* @property {RequestHandler} [locals] - Middleware to set additional locals
251253
* @property {Environment} nunjucks - Nunjucks environment
252254
* @property {NunjucksFilters | ((env: Environment) => NunjucksFilters)} [filters] - Additional custom Nunjucks filters

0 commit comments

Comments
 (0)