Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get scripts and assets from config #2319

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cypress/e2e/smoke/0-smoke-tests/index-page.cypress.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ describe('smoke test', () => {
it('GOV.UK Frontend fonts loaded', () => {
waitForApplication('/')

const fontUrl = '/plugin-assets/govuk-frontend/govuk/assets/fonts/bold-b542beb274-v2.woff2'
const fontUrl = `/plugin-assets/govuk-frontend${Cypress.env('frontendAssetsFolder')}/fonts/bold-b542beb274-v2.woff2`

cy.task('log', 'Requesting govuk-frontend font')
cy.request(`/${fontUrl}`, { retryOnStatusCodeFailure: true })
Expand Down
5 changes: 5 additions & 0 deletions cypress/events/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ module.exports = function setupNodeEvents (on, config) {
config.env.packageFolder = path.join(config.env.projectFolder, 'node_modules', 'govuk-prototype-kit')
}

if ('govuk-frontend' in dependencies) {
const frontEndConfigFile = path.join(config.env.projectFolder, 'node_modules', 'govuk-frontend', 'govuk-prototype-kit.config.json')
config.env.frontendAssetsFolder = fse.readJsonSync(frontEndConfigFile).assets.find(asset => !asset.split(path.sep).pop().includes('.'))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This closely targets the current implementation inside govuk-frontend - if they add another assets item to their config which doesn't have any dots then this may identify the wrong one.

}

const waitUntilAppRestarts = (timeout = 20000) => waitOn({
delay: 3000,
resources: [config.baseUrl],
Expand Down
23 changes: 20 additions & 3 deletions lib/manage-prototype-handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const { doubleCsrf } = require('csrf-csrf')
const config = require('./config')
const plugins = require('./plugins/plugins')
const { exec } = require('./exec')
const { prototypeAppScripts } = require('./utils')
const { prototypeAppScripts, getScriptsAndAssetsConfig, getInternalGovukFrontendDir } = require('./utils')
const { projectDir, packageDir, appViewsDir } = require('./utils/paths')
const nunjucksConfiguration = require('./nunjucks/nunjucksConfiguration')
const syncChanges = require('./sync-changes')
Expand Down Expand Up @@ -103,7 +103,7 @@ function postPasswordHandler (req, res) {
const password = config.getConfig().password
const submittedPassword = req.body.password
const providedUrl = req.body.returnURL
const processedRedirectUrl = (!providedUrl || providedUrl.startsWith('/manage-prototype/password')) ? '/' : providedUrl
const processedRedirectUrl = (!providedUrl || providedUrl.startsWith(`${contextPath}/password`)) ? '/' : providedUrl

if (submittedPassword === password) {
// see lib/middleware/authentication.js for explanation
Expand All @@ -115,10 +115,26 @@ function postPasswordHandler (req, res) {
})
res.redirect(processedRedirectUrl)
} else {
res.redirect('/manage-prototype/password?error=wrong-password&returnURL=' + encodeURIComponent(processedRedirectUrl))
res.redirect(`${contextPath}/password?error=wrong-password&returnURL=` + encodeURIComponent(processedRedirectUrl))
}
}

function managePrototypeMiddleware (req, res, next) {
const { scripts: frontEndScripts } = getScriptsAndAssetsConfig(getInternalGovukFrontendDir())
const { scripts: kitScripts } = getScriptsAndAssetsConfig(packageDir)
res.locals.managePlugins = {
scripts: [
...frontEndScripts.map((script) => {
return { src: `${contextPath}/dependencies/govuk-frontend${script.src || script}`, type: script.type }
}),
...kitScripts.map((script) => {
return { src: `${contextPath}/dependencies/govuk-prototype-kit${script.src || script}`, type: script.type }
})
]
}
next()
}

// Middleware to ensure the routes specified below will render the manage-prototype-not-available
// view when the prototype is not running in development
function developmentOnlyMiddleware (req, res, next) {
Expand Down Expand Up @@ -728,6 +744,7 @@ async function postPluginsModeHandler (req, res) {

module.exports = {
contextPath,
managePrototypeMiddleware,
setKitRestarted,
csrfProtection: [doubleCsrfProtection, csrfErrorHandler],
getPageLoadedHandler,
Expand Down
24 changes: 24 additions & 0 deletions lib/manage-prototype-routes.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
// core dependencies
const path = require('path')

// npm dependencies
const express = require('express')

const {
contextPath,
managePrototypeMiddleware,
setKitRestarted,
csrfProtection,
getPageLoadedHandler,
Expand All @@ -26,11 +30,31 @@ const {
pluginCacheMiddleware,
postPluginsHandler
} = require('./manage-prototype-handlers')
const { getScriptsAndAssetsConfig, getInternalGovukFrontendDir } = require('./utils')
const { packageDir, projectDir } = require('./utils/paths')
const { govukFrontendPaths } = require('./govukFrontendPaths')

const router = require('../index').requests.setupRouter(contextPath)

router.use(managePrototypeMiddleware)

function getAssetUrls (pluginDir) {
const { scripts, assets } = getScriptsAndAssetsConfig(pluginDir)

return [
...assets,
...scripts.map(script => script.src || script)
]
}

getAssetUrls(getInternalGovukFrontendDir()).forEach(url => {
router.use(`/dependencies/govuk-frontend${url}`, express.static(path.join(getInternalGovukFrontendDir(), url)))
})

getAssetUrls(packageDir).forEach(url => {
router.use(`/dependencies/govuk-prototype-kit${url}`, express.static(path.join(packageDir, url)))
})

router.get('/csrf-token', getCsrfTokenHandler)

// Indicates page has loaded
Expand Down
43 changes: 39 additions & 4 deletions lib/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const crypto = require('crypto')
const fs = require('fs')
const fsp = fs.promises
const path = require('path')
const { existsSync } = require('fs')

// npm dependencies
const inquirer = require('inquirer')
Expand All @@ -17,7 +16,7 @@ const filters = require('../filters/api')
const functions = require('../functions/api')
const plugins = require('../plugins/plugins')
const routes = require('../routes/api')
const { appDir, projectDir } = require('./paths')
const { appDir, projectDir, packageDir } = require('./paths')
const { asyncSeriesMap } = require('./asyncSeriesMap')

// Tweak the Markdown renderer
Expand All @@ -35,7 +34,7 @@ marked.use({
})

const scripts = []
if (existsSync(path.join(projectDir, 'app', 'assets', 'javascripts', 'application.js'))) {
if (fs.existsSync(path.join(projectDir, 'app', 'assets', 'javascripts', 'application.js'))) {
scripts.push('/public/javascripts/application.js')
}
if (plugins.legacyGovukFrontendFixesNeeded()) {
Expand Down Expand Up @@ -214,7 +213,7 @@ function sessionFileStoreQuietLogFn (message) {
function recursiveDirectoryContentsSync (baseDir) {
function goThroughDir (dir = '') {
const fullPath = path.join(baseDir, dir)
if (!existsSync(fullPath)) {
if (!fs.existsSync(fullPath)) {
return []
}
const dirContents = fs.readdirSync(fullPath)
Expand Down Expand Up @@ -253,6 +252,40 @@ async function searchAndReplaceFiles (dir, searchText, replaceText, extensions)
return modifiedFiles.flat().filter(Boolean)
}

const managePrototypeCache = {}

function getScriptsAndAssetsConfig (pluginDir) {
if (managePrototypeCache[pluginDir]) {
return managePrototypeCache[pluginDir]
}
let {
assets = [],
scripts = []
} = fs.readFileSync(path.join(pluginDir, 'govuk-prototype-kit.config.json')).toJSON()

if (!Array.isArray(assets)) {
assets = [assets]
}

if (!Array.isArray(scripts)) {
scripts = [scripts]
}

managePrototypeCache[pluginDir] = { assets, scripts }
return managePrototypeCache[pluginDir]
}

let internalGovukFrontendDir

function getInternalGovukFrontendDir () {
if (!internalGovukFrontendDir) {
const packageDirFrontend = path.join(packageDir, 'node_modules', 'govuk-frontend')
const projectDirFrontend = path.join(projectDir, 'node_modules', 'govuk-frontend')
internalGovukFrontendDir = fs.existsSync(packageDirFrontend) ? packageDirFrontend : projectDirFrontend
}
return internalGovukFrontendDir
}

function sortByObjectKey (key) {
return function (a, b) {
if (a[key] > b[key]) {
Expand All @@ -279,5 +312,7 @@ module.exports = {
sessionFileStoreQuietLogFn,
searchAndReplaceFiles,
recursiveDirectoryContentsSync,
getScriptsAndAssetsConfig,
getInternalGovukFrontendDir,
sortByObjectKey
}