|
1 | | -// Core dependencies |
2 | | -const { |
3 | | - createReadStream, |
4 | | - createWriteStream, |
5 | | - existsSync, |
6 | | - mkdirSync |
7 | | -} = require('node:fs') |
8 | 1 | const { join } = require('node:path') |
9 | | -const { format: urlFormat } = require('node:url') |
10 | 2 |
|
11 | | -// External dependencies |
12 | | -const bodyParser = require('body-parser') |
13 | | -const sessionInCookie = require('client-sessions') |
14 | | -const cookieParser = require('cookie-parser') |
15 | | -const dotenv = require('dotenv') |
16 | | -const express = require('express') |
17 | | -const sessionInMemory = require('express-session') |
18 | | -const nunjucks = require('nunjucks') |
19 | | - |
20 | | -// Run before other code to make sure variables from .env are available |
21 | | -dotenv.config({ |
22 | | - quiet: true |
23 | | -}) |
| 3 | +const NHSPrototypeKit = require('nhsuk-prototype-kit') |
24 | 4 |
|
25 | 5 | // Local dependencies |
26 | 6 | const config = require('./app/config') |
| 7 | +const sessionDataDefaults = require('./app/data/session-data-defaults') |
| 8 | +const filters = require('./app/filters') |
27 | 9 | const locals = require('./app/locals') |
28 | 10 | const routes = require('./app/routes') |
29 | | -const exampleTemplatesRoutes = require('./lib/example_templates_routes') |
30 | | -const authentication = require('./lib/middleware/authentication') |
31 | | -const automaticRouting = require('./lib/middleware/auto-routing') |
32 | | -const production = require('./lib/middleware/production') |
33 | | -const prototypeAdminRoutes = require('./lib/middleware/prototype-admin-routes') |
34 | | -const utils = require('./lib/utils') |
35 | | -const packageInfo = require('./package.json') |
36 | | - |
37 | | -// Set configuration variables |
38 | | -const port = parseInt(process.env.PORT || config.port, 10) || 2000 |
39 | 11 |
|
40 | | -// Initialise applications |
41 | | -const app = express() |
42 | | -const exampleTemplatesApp = express() |
| 12 | +const SERVICE_NAME = config.serviceName |
43 | 13 |
|
44 | | -// Set up configuration variables |
45 | | -const useAutoStoreData = |
46 | | - process.env.USE_AUTO_STORE_DATA || config.useAutoStoreData |
47 | | -const useCookieSessionStore = |
48 | | - process.env.USE_COOKIE_SESSION_STORE || config.useCookieSessionStore |
49 | | - |
50 | | -// Add variables that are available in all views |
51 | | -app.locals.asset_path = '/public/' |
52 | | -app.locals.useAutoStoreData = useAutoStoreData === 'true' |
53 | | -app.locals.useCookieSessionStore = useCookieSessionStore === 'true' |
54 | | -app.locals.serviceName = config.serviceName |
55 | | - |
56 | | -// Use cookie middleware to parse cookies |
57 | | -app.use(cookieParser()) |
| 14 | +// Set configuration variables |
| 15 | +const port = parseInt(process.env.PORT, 10) || 2000 |
58 | 16 |
|
59 | | -// Nunjucks configuration for application |
60 | | -const appViews = [ |
| 17 | +const viewsPath = [ |
61 | 18 | join(__dirname, 'app/views/'), |
62 | | - join(__dirname, 'lib/example-templates/'), |
63 | | - join(__dirname, 'lib/prototype-admin/'), |
64 | | - join(__dirname, 'lib/templates/'), |
65 | | - join(__dirname, 'node_modules/nhsuk-frontend/dist/nhsuk/components'), |
66 | | - join(__dirname, 'node_modules/nhsuk-frontend/dist/nhsuk/macros'), |
67 | | - join(__dirname, 'node_modules/nhsuk-frontend/dist/nhsuk'), |
68 | | - join(__dirname, 'node_modules/nhsuk-frontend/dist'), |
69 | 19 | join(__dirname, 'app/components/') |
70 | 20 | ] |
71 | 21 |
|
72 | | -/** |
73 | | - * @type {ConfigureOptions} |
74 | | - */ |
75 | | -const nunjucksConfig = { |
76 | | - autoescape: true, |
77 | | - noCache: true |
78 | | -} |
79 | | - |
80 | | -nunjucksConfig.express = app |
81 | | - |
82 | | -let nunjucksAppEnv = nunjucks.configure(appViews, nunjucksConfig) |
83 | | -nunjucksAppEnv.addGlobal('version', packageInfo.version) |
84 | | - |
85 | | -// Add Nunjucks filters |
86 | | -utils.addNunjucksFilters(nunjucksAppEnv) |
87 | | - |
88 | | -// Session uses service name to avoid clashes with other prototypes |
89 | | -const sessionName = `nhsuk-prototype-kit-${Buffer.from(config.serviceName, 'utf8').toString('hex')}` |
90 | | -const sessionOptions = { |
91 | | - secret: sessionName, |
92 | | - cookie: { |
93 | | - maxAge: 1000 * 60 * 60 * 4 // 4 hours |
94 | | - } |
95 | | -} |
96 | | - |
97 | | -if (process.env.NODE_ENV === 'production') { |
98 | | - app.use(production) |
99 | | - app.use(authentication) |
100 | | -} |
101 | | - |
102 | | -// Support session data in cookie or memory |
103 | | -if (useCookieSessionStore === 'true') { |
104 | | - app.use( |
105 | | - sessionInCookie({ |
106 | | - ...sessionOptions, |
107 | | - cookieName: sessionName, |
108 | | - proxy: true, |
109 | | - requestKey: 'session' |
110 | | - }) |
111 | | - ) |
112 | | -} else { |
113 | | - app.use( |
114 | | - sessionInMemory({ |
115 | | - ...sessionOptions, |
116 | | - name: sessionName, |
117 | | - resave: false, |
118 | | - saveUninitialized: false |
119 | | - }) |
120 | | - ) |
121 | | -} |
122 | | - |
123 | | -// Support for parsing data in POSTs |
124 | | -app.use(bodyParser.json()) |
125 | | -app.use( |
126 | | - bodyParser.urlencoded({ |
127 | | - extended: true |
128 | | - }) |
129 | | -) |
130 | | - |
131 | | -// Automatically store all data users enter |
132 | | -if (useAutoStoreData === 'true') { |
133 | | - app.use(utils.autoStoreData) |
134 | | - utils.addCheckedFunction(nunjucksAppEnv) |
135 | | -} |
136 | | - |
137 | | -app.use(utils.setLocals) |
138 | | - |
139 | | -// Warn if node_modules folder doesn't exist |
140 | | -function checkFiles() { |
141 | | - const nodeModulesExists = existsSync(join(__dirname, '/node_modules')) |
142 | | - if (!nodeModulesExists) { |
143 | | - throw new Error( |
144 | | - 'ERROR: Node module folder missing. Try running `npm install`' |
145 | | - ) |
146 | | - } |
147 | | - |
148 | | - // Create template .env file if it doesn't exist |
149 | | - const envExists = existsSync(join(__dirname, '/.env')) |
150 | | - if (!envExists) { |
151 | | - createReadStream(join(__dirname, '/lib/template.env')).pipe( |
152 | | - createWriteStream(join(__dirname, '/.env')) |
153 | | - ) |
| 22 | +const prototype = NHSPrototypeKit.init({ |
| 23 | + serviceName: SERVICE_NAME, |
| 24 | + routes: routes, |
| 25 | + locals: locals, |
| 26 | + sessionDataDefaults: sessionDataDefaults, |
| 27 | + viewsPath: viewsPath, |
| 28 | + buildOptions: { |
| 29 | + entryPoints: ['app/assets/sass/main.scss'] |
154 | 30 | } |
155 | | -} |
156 | | - |
157 | | -// initial checks |
158 | | -checkFiles() |
159 | | - |
160 | | -// Create template session data defaults file if it doesn't exist |
161 | | -const dataDirectory = join(__dirname, '/app/data') |
162 | | -const sessionDataDefaultsFile = join(dataDirectory, '/session-data-defaults.js') |
163 | | -const sessionDataDefaultsFileExists = existsSync(sessionDataDefaultsFile) |
164 | | - |
165 | | -if (!sessionDataDefaultsFileExists) { |
166 | | - console.log('Creating session data defaults file') |
167 | | - if (!existsSync(dataDirectory)) { |
168 | | - mkdirSync(dataDirectory) |
169 | | - } |
170 | | - |
171 | | - createReadStream( |
172 | | - join(__dirname, '/lib/template.session-data-defaults.js') |
173 | | - ).pipe(createWriteStream(sessionDataDefaultsFile)) |
174 | | -} |
175 | | - |
176 | | -// Local variables |
177 | | -app.use(locals(config)) |
178 | | - |
179 | | -// View engine |
180 | | -app.set('view engine', 'html') |
181 | | -exampleTemplatesApp.set('view engine', 'html') |
182 | | - |
183 | | -// This setting trusts the X-Forwarded headers set by |
184 | | -// a proxy and uses them to set the standard header in |
185 | | -// req. This is needed for hosts like Heroku. |
186 | | -// See https://expressjs.com/en/guide/behind-proxies.html |
187 | | -app.set('trust proxy', 1) |
188 | | - |
189 | | -// Use public folder for static assets |
190 | | -app.use(express.static(join(__dirname, 'public'))) |
191 | | - |
192 | | -// Use assets from NHS frontend |
193 | | -app.use( |
194 | | - '/nhsuk-frontend', |
195 | | - express.static(join(__dirname, 'node_modules/nhsuk-frontend/dist/nhsuk')) |
196 | | -) |
197 | | - |
198 | | -// Use custom application routes |
199 | | -app.use('/', routes) |
200 | | - |
201 | | -// Automatically route pages |
202 | | -app.get(/^([^.]+)$/, (req, res, next) => { |
203 | | - automaticRouting.matchRoutes(req, res, next) |
204 | | -}) |
205 | | - |
206 | | -// Example template routes |
207 | | -app.use('/example-templates', exampleTemplatesApp) |
208 | | - |
209 | | -nunjucksAppEnv = nunjucks.configure(appViews, { |
210 | | - autoescape: true, |
211 | | - express: exampleTemplatesApp |
212 | 31 | }) |
213 | | -nunjucksAppEnv.addGlobal('version', packageInfo.version) |
214 | 32 |
|
215 | | -// Add Nunjucks filters |
216 | | -utils.addNunjucksFilters(nunjucksAppEnv) |
217 | | - |
218 | | -exampleTemplatesApp.use('/', exampleTemplatesRoutes) |
219 | | - |
220 | | -// Automatically route example template pages |
221 | | -exampleTemplatesApp.get(/^([^.]+)$/, (req, res, next) => { |
222 | | - automaticRouting.matchRoutes(req, res, next) |
223 | | -}) |
224 | | - |
225 | | -app.use('/prototype-admin', prototypeAdminRoutes) |
226 | | - |
227 | | -// Redirect all POSTs to GETs - this allows users to use POST for autoStoreData |
228 | | -app.post(/^\/([^.]+)$/, (req, res) => { |
229 | | - res.redirect( |
230 | | - urlFormat({ |
231 | | - pathname: `/${req.params[0]}`, |
232 | | - query: req.query |
233 | | - }) |
234 | | - ) |
235 | | -}) |
236 | | - |
237 | | -// Catch 404 and forward to error handler |
238 | | -app.use((req, res, next) => { |
239 | | - const err = new Error(`Page not found: ${req.path}`) |
240 | | - err.status = 404 |
241 | | - next(err) |
242 | | -}) |
243 | | - |
244 | | -// Display error |
245 | | -app.use((err, req, res) => { |
246 | | - console.error(err.message) |
247 | | - res.status(err.status || 500) |
248 | | - res.send(err.message) |
249 | | -}) |
250 | | - |
251 | | -// Run the application |
252 | | -app.listen(port) |
253 | | - |
254 | | -if ( |
255 | | - process.env.WATCH !== 'true' && // If the user isn’t running watch |
256 | | - process.env.NODE_ENV !== 'production' // and it’s not in production mode |
257 | | -) { |
258 | | - console.info(`Running at http://localhost:${port}/`) |
259 | | - console.info('') |
260 | | - console.warn( |
261 | | - 'Warning: It looks like you may have run the command `npm start` locally.' |
262 | | - ) |
263 | | - console.warn('Press `Ctrl+C` and then run `npm run watch` instead') |
| 33 | +for (const [name, filter] of Object.entries(filters())) { |
| 34 | + prototype.nunjucks.addFilter(name, filter) |
264 | 35 | } |
265 | 36 |
|
266 | | -module.exports = app |
267 | | - |
268 | | -/** |
269 | | - * @import { ConfigureOptions } from 'nunjucks' |
270 | | - */ |
| 37 | +prototype.start(port) |
0 commit comments