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

Remove GOVUKFrontend prefix from GOVUKFrontendComponent #5515

Merged
merged 5 commits into from
Feb 12, 2025
Merged
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
25 changes: 25 additions & 0 deletions docs/contributing/managing-change.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,31 @@ If possible, update the mixin or function to maintain the existing functionality
}
```

### Deprecating a JavaScript file ahead of its removal

JavaScript files may be removed because the module is no longer needed or has been moved to another place in the project.

However, the file needs to remain included in the built package, marked as deprecated, until it is removed in the next breaking release.

1. To make sure the file remains in the package, add its path within `src/govuk` to the list of paths in `packages/tasks/config/deprecated-scripts.mjs`. For example:

```mjs
export const deprecatedFilesPaths = [
'govuk-frontend-component.mjs'
]
```

This will build the file individually when creating the package, as the file is no longer being discovered automatically by Rollup when building `all.mjs`.

2. To mark the file as deprecated, add the following JSDoc comment at the top of the file:

```js
/**
* @deprecated - Optionally describe where the file has been moved to or why it's been removed
* @module
*/
```

## Renaming things

When renaming things, keep the old name available as an alias and mark it as deprecated, following the steps above to [make sure we remember to remove the deprecated feature](#make-sure-we-remember-to-remove-the-deprecated-feature).
Expand Down
38 changes: 22 additions & 16 deletions packages/govuk-frontend/rollup.publish.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { babel } from '@rollup/plugin-babel'
import replace from '@rollup/plugin-replace'
import { defineConfig } from 'rollup'

import { isDeprecated } from './tasks/config/deprecated-scripts.mjs'

/**
* Rollup config for npm publish
*/
Expand All @@ -28,31 +30,35 @@ export default defineConfig(({ i: input }) => ({
* ECMAScript (ES) module bundles for browser <script type="module">
* or using `import` for modern browsers and Node.js scripts
*/
{
format: 'es',
isDeprecated(input)
? null
: {
format: 'es',

// Bundled modules
preserveModules: false
},
// Bundled modules
preserveModules: false
},

/**
* Universal Module Definition (UMD) bundle for browser <script>
* `window` globals and compatibility with CommonJS and AMD `require()`
*/
{
format: 'umd',
isDeprecated(input)
? null
: {
format: 'umd',

// Bundled modules
preserveModules: false,
// Bundled modules
preserveModules: false,

// Export via `window.GOVUKFrontend.${exportName}`
name: 'GOVUKFrontend',
// Export via `window.GOVUKFrontend.${exportName}`
name: 'GOVUKFrontend',

// Loading multiple files will add their export to the same
// `GOVUKFrontend` object rather than re-creating a new `GOVUKFrontend`
// for each and wiping the components previously loaded
extend: true
}
// Loading multiple files will add their export to the same
// `GOVUKFrontend` object rather than re-creating a new `GOVUKFrontend`
// for each and wiping the components previously loaded
extend: true
}
],

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/govuk-frontend/src/govuk/all.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export { SkipLink } from './components/skip-link/skip-link.mjs'
export { Tabs } from './components/tabs/tabs.mjs'
export { initAll, createAll } from './init.mjs'
export { isSupported } from './common/index.mjs'
export { GOVUKFrontendComponent as Component } from './govuk-frontend-component.mjs'
export { Component } from './component.mjs'
export { ConfigurableComponent } from './common/configuration.mjs'

/**
Expand Down
8 changes: 4 additions & 4 deletions packages/govuk-frontend/src/govuk/common/configuration.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component } from '../component.mjs'
import { ConfigError } from '../errors/index.mjs'
import { GOVUKFrontendComponent } from '../govuk-frontend-component.mjs'

import { isObject, formatErrorMessage } from './index.mjs'

Expand All @@ -13,9 +13,9 @@ export const configOverride = Symbol.for('configOverride')
* @virtual
* @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]
* @template {Element & { dataset: DOMStringMap }} [RootElementType=HTMLElement]
* @augments GOVUKFrontendComponent<RootElementType>
* @augments Component<RootElementType>
*/
export class ConfigurableComponent extends GOVUKFrontendComponent {
export class ConfigurableComponent extends Component {
/**
* configOverride
*
Expand Down Expand Up @@ -371,5 +371,5 @@ export function extractConfigByNamespace(schema, dataset, namespace) {

/**
* @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]
* @typedef {typeof GOVUKFrontendComponent & ChildClass<ConfigurationType>} ChildClassConstructor<ConfigurationType>
* @typedef {typeof Component & ChildClass<ConfigurationType>} ChildClassConstructor<ConfigurationType>
*/
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Component } from './component.mjs'
import { SupportError } from './errors/index.mjs'
import { GOVUKFrontendComponent } from './govuk-frontend-component.mjs'

describe('GOVUKFrontendComponent', () => {
describe('Component', () => {
describe('checkSupport()', () => {
beforeEach(() => {
// Jest does not tidy the JSDOM document between tests
Expand All @@ -10,7 +10,7 @@ describe('GOVUKFrontendComponent', () => {
})

describe('default implementation', () => {
class ServiceComponent extends GOVUKFrontendComponent {
class ServiceComponent extends Component {
static moduleName = 'app-service-component'
}

Expand All @@ -27,7 +27,7 @@ describe('GOVUKFrontendComponent', () => {

describe('when overriden', () => {
it('Allows child classes to define their own condition for support', () => {
class ServiceComponent extends GOVUKFrontendComponent {
class ServiceComponent extends Component {
static moduleName = 'app-service-component'

static checkSupport() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { ElementError, InitError, SupportError } from './errors/index.mjs'
* @virtual
* @template {Element} [RootElementType=HTMLElement]
*/
export class GOVUKFrontendComponent {
export class Component {
/**
* @type {typeof Element}
*/
Expand Down Expand Up @@ -109,5 +109,5 @@ export class GOVUKFrontendComponent {
*/

/**
* @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor
* @typedef {typeof Component & ChildClass} ChildClassConstructor
*/
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Component } from '../../component.mjs'
import { ElementError } from '../../errors/index.mjs'
import { GOVUKFrontendComponent } from '../../govuk-frontend-component.mjs'

/**
* Checkboxes component
*
* @preserve
*/
export class Checkboxes extends GOVUKFrontendComponent {
export class Checkboxes extends Component {
/** @private */
$inputs

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { getBreakpoint } from '../../common/index.mjs'
import { Component } from '../../component.mjs'
import { ElementError } from '../../errors/index.mjs'
import { GOVUKFrontendComponent } from '../../govuk-frontend-component.mjs'

/**
* Header component
*
* @preserve
*/
export class Header extends GOVUKFrontendComponent {
export class Header extends Component {
/** @private */
$menuButton

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Component } from '../../component.mjs'
import { ElementError } from '../../errors/index.mjs'
import { GOVUKFrontendComponent } from '../../govuk-frontend-component.mjs'

/**
* Radios component
*
* @preserve
*/
export class Radios extends GOVUKFrontendComponent {
export class Radios extends Component {
/** @private */
$inputs

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { getBreakpoint } from '../../common/index.mjs'
import { Component } from '../../component.mjs'
import { ElementError } from '../../errors/index.mjs'
import { GOVUKFrontendComponent } from '../../govuk-frontend-component.mjs'

/**
* Service Navigation component
*
* @preserve
*/
export class ServiceNavigation extends GOVUKFrontendComponent {
export class ServiceNavigation extends Component {
/** @private */
$menuButton

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { getFragmentFromUrl, setFocus } from '../../common/index.mjs'
import { Component } from '../../component.mjs'
import { ElementError } from '../../errors/index.mjs'
import { GOVUKFrontendComponent } from '../../govuk-frontend-component.mjs'

/**
* Skip link component
*
* @preserve
* @augments GOVUKFrontendComponent<HTMLAnchorElement>
* @augments Component<HTMLAnchorElement>
*/
export class SkipLink extends GOVUKFrontendComponent {
export class SkipLink extends Component {
static elementType = HTMLAnchorElement

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/govuk-frontend/src/govuk/components/tabs/tabs.mjs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { getBreakpoint, getFragmentFromUrl } from '../../common/index.mjs'
import { Component } from '../../component.mjs'
import { ElementError } from '../../errors/index.mjs'
import { GOVUKFrontendComponent } from '../../govuk-frontend-component.mjs'

/**
* Tabs component
*
* @preserve
*/
export class Tabs extends GOVUKFrontendComponent {
export class Tabs extends Component {
/** @private */
$tabs

Expand Down
6 changes: 3 additions & 3 deletions packages/govuk-frontend/src/govuk/init.jsdom.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
} from '@govuk-frontend/lib/names'

import * as GOVUKFrontend from './all.mjs'
import { GOVUKFrontendComponent } from './govuk-frontend-component.mjs'
import { Component } from './component.mjs'
import { initAll, createAll } from './init.mjs'

// Annoyingly these don't get hoisted if done in a loop
Expand Down Expand Up @@ -227,14 +227,14 @@ describe('createAll', () => {
document.body.outerHTML = '<body></body>'
})

class MockComponent extends GOVUKFrontendComponent {
class MockComponent extends Component {
constructor(...args) {
super(...args)
this.args = args
}

static checkSupport() {
GOVUKFrontendComponent.checkSupport()
Component.checkSupport()
}

static moduleName = 'mock-component'
Expand Down
45 changes: 45 additions & 0 deletions packages/govuk-frontend/tasks/config/deprecated-scripts.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Logistics for handling files that get renamed and are no longer part of modules imported by `all.mjs`
* but need to remain in the published package to support deprecations before they get removed
*/
import { join } from 'node:path'

/**
* Paths to the deprecated files within `src/govuk`
* (excluding the `src/govuk` part)
*/
export const deprecatedFilesPaths = []

/**
* Checks if given Rollup input is a deprecated file
*
* This helps us decide whether to create bundled version of that input,
* which we don't want for deprecated files (we just want to include them in the package)
*
* @param {string} rollupInput - The path to the input Rollup is compiling
* @returns {boolean} - Whether the path corresponds to a deprecated file
*/
export function isDeprecated(rollupInput) {
return deprecatedFilesPaths.some((deprecatedFilePath) =>
rollupInput.endsWith(join('govuk', deprecatedFilePath))
)
}

/**
* Creates a glob matching the list of paths
*
* @param {string[]} paths - The list of paths to create a glob for
* @returns {string} - A glob matching the deprecated files
*/
export function createGlobFromPaths(paths) {
// Curly brace syntax in glob only works
// when there's more than one pattern to match
// so we need to distinguish between the two.
if (paths.length > 1) {
const joinedGlobs = paths.join(',')

return `{${joinedGlobs}}`
}

return paths[0]
}
32 changes: 29 additions & 3 deletions packages/govuk-frontend/tasks/scripts.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@ import { pkg } from '@govuk-frontend/config'
import { configs, scripts, task } from '@govuk-frontend/tasks'
import gulp from 'gulp'

import {
createGlobFromPaths,
deprecatedFilesPaths
} from './config/deprecated-scripts.mjs'

/**
* JavaScripts task (for watch)
*
* @type {import('@govuk-frontend/tasks').TaskFunction}
*/
export const compile = (options) =>
gulp.series(
export const compile = (options) => {
const args = [
/**
* Compile GOV.UK Frontend JavaScript for component entry points
*/
Expand All @@ -24,6 +29,24 @@ export const compile = (options) =>
})
),

...(deprecatedFilesPaths?.length
? [
/**
* Compile deprecated files no longer imported by `all.mjs`
* but that need to be kept in the package
*/
task.name("compile:js 'deprecations'", () =>
scripts.compile(createGlobFromPaths(deprecatedFilesPaths), {
...options,

srcPath: join(options.srcPath, 'govuk'),
destPath: join(options.destPath, 'govuk'),
configPath: join(options.basePath, 'rollup.publish.config.mjs')
})
)
]
: []),

/**
* Compile GOV.UK Frontend JavaScript for main entry point only
*/
Expand Down Expand Up @@ -65,4 +88,7 @@ export const compile = (options) =>
destPath: resolve(options.destPath, '../') // Top level (not dist) for compatibility
})
)
)
]

return gulp.series(...args)
}