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

Ensure shared task options are mandatory unless specified #3647

Merged
merged 9 commits into from
May 19, 2023

Conversation

colinrotherham
Copy link
Contributor

@colinrotherham colinrotherham commented May 18, 2023

This PR ensures all build task options are mandatory and type checked

I've also included some related changes:

  1. Configure the Review app to use govuk-frontend JSDoc types again
  2. Remove unnecessary options (like renaming *.scss to *.scss)
  3. Adding comments to explain why files are renamed or moved

This work was split out whilst adding postcss.config.mjs and rollup.config.mjs files to each workspace

Before

This will crash as no destPath has been provided

import { scripts } from 'govuk-frontend-tasks'

// Compile GOV.UK Frontend JavaScript
scripts.compile('!(*.test).mjs', {
  destPath: '/custom/build/path'
})

After

This works by extending the build options using ...options

import { scripts } from 'govuk-frontend-tasks'

// Default build options
import { options } from './build/options.mjs'

// Compile GOV.UK Frontend JavaScript
scripts.compile('!(*.test).mjs', {
  ...options,
  destPath: '/custom/build/path'
})

@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-pr-3647 May 18, 2023 14:19 Inactive
@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-pr-3647 May 18, 2023 14:26 Inactive
@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-pr-3647 May 18, 2023 14:39 Inactive
Base automatically changed from component-types to main May 18, 2023 16:42
@romaricpascal
Copy link
Member

Tidying up looks good, cheers! Can you explain the benefits of having task.options over doing the spread ourselves?

I'm expecting that with the types not being optional anymore, we'd catch situations like the one you mentioned in the first post. Would TypeScript warn OK on your first example (for lack of the necessary options)?

import { scripts } from 'govuk-frontend-tasks'

// Compile GOV.UK Frontend JavaScript
scripts.compile('!(*.test).mjs', {
  destPath: '/custom/build/path'
})

If that's the case, I'd like to understand why we need a custom function for the merging. If it's only for freezing objects, I'm not sure it's that risky to let the objects be extended (especially as we'll be merging in the paths anyways so have a separate object per task call), but open to be convinced otherwise 😊

@colinrotherham
Copy link
Contributor Author

colinrotherham commented May 19, 2023

Would you rather I used spread? Happy to change it

  1. Options are frozen to prevent accidental edits
  2. Options are typed with Required<TaskOptions> (not custom objects)
  3. Task option refactors automatically update across the project

Could have alternatively used structuredClone() to prevent changes to one object affecting another?

We'd get the type checking behaviour either way which was the aim:

Argument of type '{ srcPath: string; destPath: string; hello: string; }' is not assignable to parameter of type 'Partial<AssetOptions>'
Type safe options

@romaricpascal
Copy link
Member

As we get type checking in any case, I'd reather we have less code and just use spread to start, cheers 😊

@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-pr-3647 May 19, 2023 11:22 Inactive
@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-pr-3647 May 19, 2023 11:32 Inactive
@colinrotherham
Copy link
Contributor Author

Swapped to using object spread, ready for review again

@@ -45,7 +45,6 @@
"devDependencies": {
"@babel/core": "^7.21.8",
"@babel/preset-env": "^7.21.5",
"@types/node": "^20.1.5",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We'd accidentally put this in twice

srcPath: join(options.srcPath, 'govuk'),
destPath: options.destPath,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Don't need to repeat ourselves. The destination is already in options

srcPath: join(options.srcPath, 'govuk'),
destPath: options.destPath,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Don't need to repeat ourselves. The destination is already in options

@@ -84,7 +86,6 @@ export async function write (filePath, result) {
* @typedef {object} AssetFileOptions
* @property {(file: import('path').ParsedPath) => string} [filePath] - File path formatter
* @property {(contents?: string) => Promise<string>} [fileContents] - File contents formatter
* @property {string[]} [ignore] - File path patterns to ignore
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We had to carefully ignore the published package.json and README.md in the past

We haven't used this option since merging:

@@ -11,7 +11,7 @@ import { files } from './index.mjs'
* Generate fixtures.json from component data
*
* @param {AssetEntry[0]} pattern - Path to ${componentName}.yaml
* @param {AssetEntry[1]} options - Asset options
* @param {Pick<AssetEntry[1], "srcPath" | "destPath">} options - Asset options
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This task already provides its own filePath and fileContents

Here we're narrowing down the types to warn when passing in options that aren't picked

@@ -44,7 +43,7 @@ export async function generateFixtures (pattern, { srcPath, destPath }) {
* Generate macro-options.json from component data
*
* @param {AssetEntry[0]} pattern - Path to ${componentName}.yaml
* @param {AssetEntry[1]} options - Asset options
* @param {Pick<AssetEntry[1], "srcPath" | "destPath">} options - Asset options
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This task already provides its own filePath and fileContents

Here we're narrowing down the types to warn when passing in options that aren't picked

@@ -7,7 +7,7 @@ import { files } from './index.mjs'
* Write config to JSON
*
* @param {AssetEntry[0]} modulePath - File path to config
* @param {AssetEntry[1]} options - Asset options
* @param {Pick<AssetEntry[1], "srcPath" | "destPath">} options - Asset options
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This task already provides its own filePath and fileContents

Here we're narrowing down the types to warn when passing in options that aren't picked

@@ -11,25 +11,25 @@ import slash from 'slash'
* Delete path globs for a given destination
*
* @param {string} pattern - Pattern to remove
* @param {AssetEntry[1]} options - Asset options
* @param {Pick<AssetEntry[1], "destPath">} options - Asset options
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The clean task only needs a destPath so we're being quite strict here

Other properties can be passed in when not TypeScript "strict": true but they'll be ignored

Config files are already JSON formatted so we can configure the filename in the shared task
The source files are already Sass so don’t need renaming
We’re not running `tsc` in strict mode so can easily break tasks by not specifying the required properties
Our main export in package.json is `"dist/govuk/all.js"` so we need to remap this to our source code for internal use only, otherwise code autocomplete doesn’t work in the review app

This can be removed if we export type declarations in the package instead
@colinrotherham colinrotherham changed the base branch from main to skip-lib-types May 19, 2023 12:42
@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-pr-3647 May 19, 2023 12:42 Inactive
Base automatically changed from skip-lib-types to main May 19, 2023 13:36
Copy link
Member

@romaricpascal romaricpascal left a comment

Choose a reason for hiding this comment

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

Cheers for updating to using spread 🙌🏻 ⛵

@colinrotherham colinrotherham merged commit 2f63da6 into main May 19, 2023
@colinrotherham colinrotherham deleted the task-types branch May 19, 2023 13:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

Successfully merging this pull request may close these issues.

3 participants