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

Include the govuk-frontend version number in CSS and JS files #3318

Merged
merged 5 commits into from
Apr 3, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
73 changes: 73 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
"postcss-unrgba": "^1.1.1",
"puppeteer": "^19.8.2",
"rollup": "0.59.4",
"rollup-plugin-replace": "^2.2.0",
"sass-embedded": "^1.60.0",
"sassdoc": "^2.7.4",
"slash": "^5.0.0",
Expand Down
18 changes: 18 additions & 0 deletions postcss.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import unmq from 'postcss-unmq'
import unopacity from 'postcss-unopacity'
import unrgba from 'postcss-unrgba'

import { pkg } from './config/index.js'
import { isDev } from './tasks/helpers/task-arguments.mjs'

/**
* PostCSS config
*
Expand Down Expand Up @@ -58,6 +61,21 @@ export default ({ from = '', to = '', env = 'production' }) => {
)
}

// Add GOV.UK Frontend release version
if (!isDev) {
config.plugins.push({
postcssPlugin: 'govuk-frontend-version',
Declaration: {
// Find CSS declaration for version, update value
// https://github.com/postcss/postcss/blob/main/docs/writing-a-plugin.md
// https://postcss.org/api/#declaration
'--govuk-frontend-version': (decl) => {
decl.value = `"${pkg.version}"`
}
}
})
}

// Always minify CSS
if (config.syntax !== scss) {
config.plugins.push(cssnano({
Expand Down
7 changes: 6 additions & 1 deletion postcss.config.unit.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ describe('PostCSS config', () => {
expect(getPluginNames(config))
.toEqual([
'autoprefixer',
'govuk-frontend-version',
'postcss-discard-comments',
'postcss-minify-gradients',
'postcss-reduce-initial',
Expand Down Expand Up @@ -127,6 +128,7 @@ describe('PostCSS config', () => {
'postcss-unmq',
'postcss-unopacity',
'postcss-color-rgba-fallback',
'govuk-frontend-version',
'postcss-discard-comments',
'postcss-minify-gradients',
'postcss-reduce-initial',
Expand Down Expand Up @@ -170,7 +172,8 @@ describe('PostCSS config', () => {

expect(getPluginNames(config))
.toEqual([
'autoprefixer'
'autoprefixer',
'govuk-frontend-version'
])
})
})
Expand All @@ -188,6 +191,7 @@ describe('PostCSS config', () => {
.toEqual([
'autoprefixer',
'postcss-pseudo-classes',
'govuk-frontend-version',
'postcss-discard-comments',
'postcss-minify-gradients',
'postcss-reduce-initial',
Expand Down Expand Up @@ -256,6 +260,7 @@ describe('PostCSS config', () => {
'postcss-unmq',
'postcss-unopacity',
'postcss-color-rgba-fallback',
'govuk-frontend-version',
'postcss-discard-comments',
'postcss-minify-gradients',
'postcss-reduce-initial',
Expand Down
4 changes: 4 additions & 0 deletions src/govuk/all.mjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { version } from './common/govuk-frontend-version.mjs'
import { nodeListForEach } from './common/index.mjs'
import Accordion from './components/accordion/accordion.mjs'
import Button from './components/button/button.mjs'
Expand Down Expand Up @@ -87,6 +88,9 @@ function initAll (config) {

export {
initAll,
version,

// Components
Accordion,
Button,
Details,
Expand Down
1 change: 1 addition & 0 deletions src/govuk/common/govuk-frontend-version.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export var version = 'development'
querkmachine marked this conversation as resolved.
Show resolved Hide resolved
4 changes: 2 additions & 2 deletions src/govuk/components/globals.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ describe('GOV.UK Frontend', () => {
const GOVUKFrontendGlobal = await page.evaluate(() => window.GOVUKFrontend)

const components = Object.keys(GOVUKFrontendGlobal)
.filter(method => !['initAll'].includes(method))
.filter(method => !['initAll', 'version'].includes(method))

// Ensure GOV.UK Frontend exports the expected components
expect(components).toEqual([
Expand All @@ -47,7 +47,7 @@ describe('GOV.UK Frontend', () => {

const componentsWithoutInitFunctions = await page.evaluate(() => {
const components = Object.keys(window.GOVUKFrontend)
.filter(method => !['initAll'].includes(method))
.filter(method => !['initAll', 'version'].includes(method))

return components.filter(component => {
const prototype = window.GOVUKFrontend[component].prototype
Expand Down
1 change: 1 addition & 0 deletions src/govuk/core/_all.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@import "govuk-frontend-version";
@import "links";
@import "lists";
@import "typography";
Expand Down
3 changes: 3 additions & 0 deletions src/govuk/core/_govuk-frontend-version.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:root {
--govuk-frontend-version: "development";
}
8 changes: 8 additions & 0 deletions tasks/build/dist.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ describe('dist/', () => {
it('should contain source mapping URL', () => {
expect(stylesheet).toMatch(new RegExp(`/\\*# sourceMappingURL=${filename}.map \\*/$`))
})

it('should contain version number custom property', () => {
expect(stylesheet).toContain(`--govuk-frontend-version:"${pkg.version}"`)
})
})

describe('govuk-frontend-ie8-[version].min.css', () => {
Expand Down Expand Up @@ -73,6 +77,10 @@ describe('dist/', () => {
expect(javascript).toBeTruthy()
})

it('should contain correct version number', () => {
expect(javascript).toContain(`.version="${pkg.version}",`)
})

it('should contain source mapping URL', () => {
expect(javascript).toMatch(new RegExp(`//# sourceMappingURL=${filename}.map$`))
})
Expand Down
10 changes: 9 additions & 1 deletion tasks/build/package.test.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { readFile } from 'fs/promises'
import { join } from 'path'

import { paths } from '../../config/index.js'
import { paths, pkg } from '../../config/index.js'
import { filterPath, getDirectories, getListing, mapPathTo } from '../../lib/file-helper.js'
import { componentNameToClassName, componentPathToModuleName } from '../../lib/helper-functions.js'
import { compileSassFile } from '../../lib/jest-helpers.js'
Expand Down Expand Up @@ -112,6 +112,14 @@ describe('package/', () => {
// Look for AMD module definition for 'GOVUKFrontend'
expect(contents).toContain("typeof define === 'function' && define.amd ? define('GOVUKFrontend', ['exports'], factory)")
})

it('should have correct version number', async () => {
const contents = await readFile(join(paths.package, 'govuk', 'all.js'), 'utf8')

// Look for AMD module export 'GOVUKFrontend.version'
expect(contents).toContain(`var version = '${pkg.version}';`)
expect(contents).toContain('exports.version = version;')
})
})

describe('component', () => {
Expand Down
19 changes: 17 additions & 2 deletions tasks/scripts.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ import { join, parse } from 'path'

import PluginError from 'plugin-error'
import { rollup } from 'rollup'
import replace from 'rollup-plugin-replace'
import { minify } from 'terser'

import { pkg } from '../config/index.js'
import { getListing } from '../lib/file-helper.js'
import { componentPathToModuleName } from '../lib/helper-functions.js'

import { isDev } from './helpers/task-arguments.mjs'
import { assets } from './index.mjs'

/**
Expand Down Expand Up @@ -38,10 +41,22 @@ export async function compileJavaScript ([modulePath, { srcPath, destPath, fileP
const moduleSrcPath = join(srcPath, modulePath)
const moduleDestPath = join(destPath, filePath ? filePath(parse(modulePath)) : modulePath)

// Rollup plugins
const plugins = []

if (!isDev) {
// Add GOV.UK Frontend release version
// @ts-expect-error "This expression is not callable" due to incorrect types
Copy link
Contributor

Choose a reason for hiding this comment

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

By using "moduleResolution": "Node" we can resolve this in another PR

Although it still works, not all packages are typed to say "I work as ESM-only"

plugins.push(replace({
include: join(srcPath, 'common/govuk-frontend-version.mjs'),
values: { development: pkg.version }
}))
}

// Option 1: Rollup bundle set (multiple files)
// - Module imports are preserved, not concatenated
if (moduleDestPath.endsWith('.mjs')) {
const bundle = await rollup({ input: [moduleSrcPath], experimentalPreserveModules: true })
const bundle = await rollup({ input: [moduleSrcPath], plugins, experimentalPreserveModules: true })

// Compile JavaScript to ES modules
await bundle.write({
Expand All @@ -55,7 +70,7 @@ export async function compileJavaScript ([modulePath, { srcPath, destPath, fileP

// Option 1: Rollup bundle (single file)
// - Universal Module Definition (UMD) bundle
const bundle = await rollup({ input: moduleSrcPath })
const bundle = await rollup({ input: moduleSrcPath, plugins })

// Compile JavaScript to output format
const bundled = await bundle[moduleDestPath.endsWith('.min.js') ? 'generate' : 'write']({
Expand Down