sku 12.5.0 → 12.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,68 @@
1
1
  # sku
2
2
 
3
+ ## 12.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Add support for [removing assertion functions][assertion removal docs] named `invariant` and assertions from the `tiny-invariant` library, a lightweight alternative to `assert` ([#966](https://github.com/seek-oss/sku/pull/966))
8
+
9
+ **EXAMPLE USAGE**:
10
+
11
+ ```tsx
12
+ import React from 'react';
13
+ import invariant from 'tiny-invariant';
14
+
15
+ export const Rating = ({ rating }: { rating: number }) => {
16
+ invariant(rating >= 0 && rating <= 5, 'Rating must be between 0 and 5');
17
+
18
+ return <div>...</div>;
19
+ };
20
+ ```
21
+
22
+ [assertion removal docs]: https://seek-oss.github.io/sku/#/./docs/extra-features?id=assertion-removal
23
+
24
+ ## 12.5.1
25
+
26
+ ### Patch Changes
27
+
28
+ - Remove `rimraf` dependency in favour of Node.js's `rm` ([#961](https://github.com/seek-oss/sku/pull/961))
29
+
30
+ - Unpin and bump `@pmmmwh/react-refresh-webpack-plugin` ([#959](https://github.com/seek-oss/sku/pull/959))
31
+
32
+ - Ensure all sku-generated gitignored files are present in `.prettierignore` and `.eslintignore` too ([#957](https://github.com/seek-oss/sku/pull/957))
33
+
34
+ Consumers should notice a few new files being added to the sku-managed sections within `.prettierignore` and `.eslintignore` the next time a `sku` command is run:
35
+
36
+ ```diff
37
+ # managed by sku
38
+ *.less.d.ts
39
+ +.eslintcache
40
+ +.eslintrc
41
+ +.prettierrc
42
+ .storybook/main.js
43
+ coverage/
44
+ dist-storybook/
45
+ dist/
46
+ report/
47
+ # end managed by sku
48
+ ```
49
+
50
+ These changes should be committed to your repo.
51
+
52
+ - Disable peer dependency validation for PNPM ([#952](https://github.com/seek-oss/sku/pull/952))
53
+
54
+ The method we currently use to validate peer dependencies and warn users about duplicate package is not compatible with how PNPM organizes dependencies in `node_modules`. This feature has been disabled for PNPM repos until further notice.
55
+
56
+ - Replace `memoizee` dependency with `nano-memoize` ([#953](https://github.com/seek-oss/sku/pull/953))
57
+
58
+ - Replace `fast-glob` with `fdir` and `picomatch` ([#952](https://github.com/seek-oss/sku/pull/952))
59
+
60
+ - Replace `validate-npm-package-name` dependency with a regexp ([#954](https://github.com/seek-oss/sku/pull/954))
61
+
62
+ - Improve performance of peer dependency validation ([#952](https://github.com/seek-oss/sku/pull/952))
63
+
64
+ Peer dependency validation shoould now complete within a few seconds, rather than a few minutes.
65
+
3
66
  ## 12.5.0
4
67
 
5
68
  ### Minor Changes
package/README.md CHANGED
@@ -6,7 +6,8 @@
6
6
 
7
7
  Front-end development toolkit, powered by [Webpack](https://webpack.js.org/), [Babel](https://babeljs.io/), [Vanilla Extract](https://vanilla-extract.style/), [CSS Modules](https://github.com/css-modules/css-modules), [Less](http://lesscss.org/), [ESLint](http://eslint.org/), [Prettier](https://prettier.io/), [Jest](https://facebook.github.io/jest/) and [Storybook](https://storybook.js.org/).
8
8
 
9
- Quickly get up and running with a zero-config development environment, or optionally add minimal config when needed. Designed for usage with [braid-design-system](https://github.com/seek-oss/braid-design-system), although this isn't a requirement.
9
+ Quickly get up and running with a zero-config development environment, or optionally add minimal config when needed.
10
+ Designed for usage with [braid-design-system](https://github.com/seek-oss/braid-design-system), although this isn't a requirement.
10
11
 
11
12
  This tool is heavily inspired by other work, most notably:
12
13
 
@@ -14,13 +15,19 @@ This tool is heavily inspired by other work, most notably:
14
15
  - [insin/nwb](https://github.com/insin/nwb)
15
16
  - [NYTimes/kyt](https://github.com/NYTimes/kyt)
16
17
 
17
- **WARNING: While this software is open source, its primary purpose is to improve consistency, cross-team collaboration and code quality at SEEK. As a result, it’s likely that we will introduce more breaking API changes to this project than you’ll find in its alternatives.**
18
+ > [!WARNING]
19
+ > While this software is open source, its primary purpose is to improve consistency, cross-team collaboration and code quality at SEEK.
20
+ > As a result, it’s likely that this tool may not exactly suit your needs, or may be overkill for your use case.
21
+ > It may be worth considering alternatives such as [Vite] or [Parcel].
22
+
23
+ [Vite]: https://vitejs.dev/
24
+ [Parcel]: https://parceljs.org/
18
25
 
19
26
  ## Getting Started
20
27
 
21
28
  Create a new project and start a local development environment:
22
29
 
23
- ```bash
30
+ ```sh
24
31
  $ npx sku init my-app
25
32
  $ cd my-app
26
33
  $ yarn start
@@ -30,7 +37,7 @@ By default, a new project's dependencies will be installed with the first suppor
30
37
  Package managers are detected in the following order: `yarn` -> `pnpm` -> `npm`.
31
38
  This can be overridden via the `--packageManager` flag:
32
39
 
33
- ```bash
40
+ ```sh
34
41
  $ pnpm dlx sku init --packageManager pnpm my-app
35
42
  $ cd my-app
36
43
  $ pnpm start
@@ -40,7 +47,8 @@ $ pnpm start
40
47
 
41
48
  ## Contributing
42
49
 
43
- Refer to [CONTRIBUTING.md](/CONTRIBUTING.md). If you're planning to change the public API, please [open a new issue](https://github.com/seek-oss/sku/issues/new).
50
+ Refer to [CONTRIBUTING.md](/CONTRIBUTING.md).
51
+ If you're planning to change the public API, please [open a new issue](https://github.com/seek-oss/sku/issues/new).
44
52
 
45
53
  ## License
46
54
 
@@ -55,7 +55,13 @@ module.exports = ({
55
55
  }
56
56
 
57
57
  if (removeAssertionsInProduction) {
58
- plugins.push(require.resolve('babel-plugin-unassert'));
58
+ plugins.push([
59
+ require.resolve('babel-plugin-unassert'),
60
+ {
61
+ variables: ['assert', 'invariant'],
62
+ modules: ['assert', 'node:assert', 'tiny-invariant'],
63
+ },
64
+ ]);
59
65
  }
60
66
  }
61
67
 
@@ -1,5 +1,5 @@
1
1
  const { HtmlRenderPlugin } = require('html-render-webpack-plugin');
2
- const memoize = require('memoizee/weak');
2
+ const { default: memoize } = require('nano-memoize');
3
3
  const debug = require('debug');
4
4
 
5
5
  const {
@@ -1,5 +1,5 @@
1
1
  const path = require('node:path');
2
- const memoize = require('memoizee');
2
+ const { default: memoize } = require('nano-memoize');
3
3
  const debug = require('debug')('sku:resolvePackage');
4
4
  const { cwd } = require('../../../lib/cwd');
5
5
 
@@ -37,6 +37,7 @@ const createPackageResolver = (fs, resolve) => {
37
37
  *
38
38
  * Throws if a package is listed in the project's dependencies and cannot be resolved.
39
39
  */
40
+ /** @param {string} packageName */
40
41
  function resolvePackage(packageName) {
41
42
  try {
42
43
  // First, try to use require.resolve to find the package.
@@ -1,57 +1,83 @@
1
1
  const { posix: path } = require('node:path');
2
2
  const chalk = require('chalk');
3
- const glob = require('fast-glob');
3
+ const { fdir: Fdir } = require('fdir');
4
4
 
5
- const { cwd: skuCwd } = require('../lib/cwd');
5
+ const { cwd } = require('../lib/cwd');
6
6
  const toPosixPath = require('../lib/toPosixPath');
7
7
 
8
8
  const { rootDir, isPnpm } = require('../lib/packageManager');
9
+ const debug = require('debug')('sku:compilePackages');
9
10
 
10
11
  /** @type {string[]} */
11
12
  let detectedCompilePackages = [];
12
13
 
13
- try {
14
- const globs = ['node_modules/@seek/*/package.json'];
15
- const cwd = skuCwd();
14
+ // If there's no rootDir, we're either inside `sku init`, or we can't determine the user's
15
+ // package manager. In either case, we can't correctly detect compile packages.
16
+ if (rootDir) {
17
+ try {
18
+ let crawler = new Fdir();
16
19
 
17
- if (isPnpm && rootDir) {
18
- const pnpmVirtualStorePath = path.join(
19
- toPosixPath(rootDir),
20
- 'node_modules/.pnpm',
21
- );
22
- const pnpmVirtualStoreRelativePath = path.relative(
23
- '.',
24
- pnpmVirtualStorePath,
25
- );
26
- const pnpmVirtualStoreGlob = path.join(
27
- pnpmVirtualStoreRelativePath,
28
- '@seek*/node_modules/@seek/*/package.json',
29
- );
20
+ if (isPnpm) {
21
+ // Follow symlinks inside node_modules into the pnpm virtual store
22
+ crawler = crawler.withSymlinks().withRelativePaths();
23
+ } else {
24
+ crawler = crawler.withBasePath();
25
+ }
30
26
 
31
- globs.push(pnpmVirtualStoreGlob);
32
- }
27
+ const seekDependencyGlob = '**/@seek/*/package.json';
28
+
29
+ let results = crawler
30
+ .glob(seekDependencyGlob)
31
+ .crawl('./node_modules/@seek')
32
+ .sync();
33
+
34
+ if (isPnpm) {
35
+ const pnpmVirtualStorePath = path.join(
36
+ toPosixPath(rootDir),
37
+ 'node_modules/.pnpm',
38
+ );
39
+
40
+ const pnpmVirtualStoreRelativePath = path.relative(
41
+ '.',
42
+ pnpmVirtualStorePath,
43
+ );
33
44
 
34
- detectedCompilePackages = glob
35
- .sync(globs, {
36
- cwd,
37
- })
38
- .map((packagePath) => {
39
- const packageJson = require(path.join(cwd, packagePath));
40
-
41
- return {
42
- isCompilePackage: Boolean(packageJson.skuCompilePackage),
43
- packageName: packageJson.name,
44
- };
45
- })
46
- .filter(({ isCompilePackage }) => isCompilePackage)
47
- .map(({ packageName }) => packageName);
48
- } catch (e) {
49
- console.log(
50
- chalk.red`Warning: Failed to detect compile packages. Contact #sku-support.`,
51
- );
52
- console.error(e);
45
+ const pnpmVirtualStoreResults = new Fdir()
46
+ .withRelativePaths()
47
+ .glob(seekDependencyGlob)
48
+ .crawl(pnpmVirtualStoreRelativePath)
49
+ .sync();
50
+
51
+ results.push(...pnpmVirtualStoreResults);
52
+
53
+ // All results will be relative to the virtual store directory, so we need
54
+ // to prepend the relative path from the current directory to the virtual store
55
+ results = results.map((file) =>
56
+ path.join(pnpmVirtualStoreRelativePath, file),
57
+ );
58
+ }
59
+
60
+ detectedCompilePackages = results
61
+ .map((packagePath) => {
62
+ const packageJson = require(path.join(cwd(), packagePath));
63
+
64
+ return {
65
+ isCompilePackage: Boolean(packageJson.skuCompilePackage),
66
+ packageName: packageJson.name,
67
+ };
68
+ })
69
+ .filter(({ isCompilePackage }) => isCompilePackage)
70
+ .map(({ packageName }) => packageName);
71
+ } catch (e) {
72
+ console.log(
73
+ chalk.red`Warning: Failed to detect compile packages. Contact #sku-support.`,
74
+ );
75
+ console.error(e);
76
+ }
53
77
  }
54
78
 
79
+ debug(detectedCompilePackages);
80
+
55
81
  module.exports = [
56
82
  'sku',
57
83
  'braid-design-system',
@@ -1,9 +1,10 @@
1
+ // @ts-check
1
2
  const { yellow, bold } = require('chalk');
2
3
  const getPort = require('get-port');
3
4
  const debug = require('debug')('sku:allocatePort');
4
5
 
5
6
  /**
6
- * @param {{ port?: number, host?: string }}
7
+ * @param {{ port?: number, host?: string }} options
7
8
  */
8
9
  const allocatePort = async ({ port, host }) => {
9
10
  debug(`Finding available port with request for ${port}`);
@@ -1,12 +1,15 @@
1
+ // @ts-check
1
2
  const path = require('node:path');
2
3
  const fs = require('node:fs/promises');
3
- const { rimraf } = require('rimraf');
4
+ const { fdir: Fdir } = require('fdir');
4
5
 
5
6
  const { paths } = require('../context');
6
7
  const exists = require('./exists');
7
8
  const copyDirContents = require('./copyDirContents');
8
9
 
9
- const cleanTargetDirectory = () => rimraf(`${paths.target}/*`, { glob: true });
10
+ const cleanTargetDirectory = async () => {
11
+ fs.rm(paths.target, { recursive: true, force: true });
12
+ };
10
13
 
11
14
  const copyPublicFiles = async () => {
12
15
  if (await exists(paths.public)) {
@@ -18,14 +21,21 @@ const ensureTargetDirectory = async () => {
18
21
  await fs.mkdir(paths.target, { recursive: true });
19
22
  };
20
23
 
21
- const cleanRenderJs = async () => {
22
- const renderFileGlob = path.join(paths.target, '*render.js');
23
- await rimraf(renderFileGlob, { glob: true });
24
+ const cleanStaticRenderEntry = async () => {
25
+ const files = await new Fdir()
26
+ .withBasePath()
27
+ .filter((file) => file.endsWith('render.js'))
28
+ .crawl(paths.target)
29
+ .withPromise();
30
+
31
+ for (const file of files) {
32
+ await fs.rm(file);
33
+ }
24
34
  };
25
35
 
26
36
  module.exports = {
27
37
  cleanTargetDirectory,
28
38
  copyPublicFiles,
29
39
  ensureTargetDirectory,
30
- cleanRenderJs,
40
+ cleanStaticRenderEntry,
31
41
  };
package/lib/configure.js CHANGED
@@ -48,7 +48,6 @@ module.exports = async () => {
48
48
  storybookTargetDirectory,
49
49
  storybookMainConfigPath,
50
50
  ];
51
- const lintIgnorePatterns = [...gitIgnorePatterns, '*.less.d.ts'];
52
51
 
53
52
  // Generate ESLint configuration
54
53
  const eslintConfigFilename = '.eslintrc';
@@ -67,6 +66,8 @@ module.exports = async () => {
67
66
  });
68
67
  gitIgnorePatterns.push(prettierConfigFilename);
69
68
 
69
+ const lintIgnorePatterns = [...gitIgnorePatterns, '*.less.d.ts'];
70
+
70
71
  if (languages) {
71
72
  const generatedVocabFileGlob = '**/*.vocab/index.ts';
72
73
  gitIgnorePatterns.push(generatedVocabFileGlob);
@@ -1,3 +1,4 @@
1
+ // @ts-check
1
2
  const path = require('node:path');
2
3
  const fs = require('node:fs/promises');
3
4
  const exists = require('./exists');
@@ -1,3 +1,4 @@
1
+ // @ts-check
1
2
  const http = require('node:http');
2
3
  const https = require('node:https');
3
4
 
package/lib/cwd.js CHANGED
@@ -1,3 +1,4 @@
1
+ // @ts-check
1
2
  const path = require('node:path');
2
3
 
3
4
  let currentCwd = process.cwd();
package/lib/env.js CHANGED
@@ -1,3 +1,4 @@
1
+ // @ts-check
1
2
  const args = require('../config/args');
2
3
 
3
4
  /**
package/lib/exists.js CHANGED
@@ -1,3 +1,4 @@
1
+ // @ts-check
1
2
  const { access } = require('node:fs/promises');
2
3
 
3
4
  /**
@@ -1,3 +1,4 @@
1
+ // @ts-check
1
2
  const { sites } = require('../context');
2
3
 
3
4
  /**
package/lib/install.js CHANGED
@@ -1,9 +1,11 @@
1
+ // @ts-check
1
2
  const { getAddCommand } = require('./packageManager');
2
3
 
3
4
  const spawn = require('cross-spawn');
4
5
 
5
6
  /**
6
7
  * @param {import("../lib/packageManager").GetAddCommandOptions} options
8
+ * @returns {Promise<void>}
7
9
  */
8
10
  module.exports = ({ deps, type, logLevel, exact = true }) =>
9
11
  new Promise((resolve, reject) => {
package/lib/isCI.js CHANGED
@@ -1 +1,2 @@
1
+ // @ts-check
1
2
  module.exports = Boolean(process.env.CI || process.env.BUILDKITE_BUILD_ID);
@@ -1,3 +1,4 @@
1
+ // @ts-check
1
2
  const { getPathFromCwd } = require('./cwd');
2
3
 
3
4
  const isCompilePackage = () => {
package/lib/isEmptyDir.js CHANGED
@@ -1,3 +1,4 @@
1
+ // @ts-check
1
2
  const { statSync, readdirSync } = require('node:fs');
2
3
 
3
4
  /**
package/lib/parseArgs.js CHANGED
@@ -1,10 +1,11 @@
1
+ // @ts-check
1
2
  const minimist = require('minimist');
2
3
 
3
4
  /**
4
5
  * Supports parsing args that look like:
5
6
  * [/path/to/node/node, /path/to/sku, scriptName, arg1, arg2]
6
7
  *
7
- * @param {string[]} args - should look like process.argv
8
+ * @param {string[]} processArgv - should look like process.argv
8
9
  */
9
10
  module.exports = (processArgv) => {
10
11
  /**
@@ -48,6 +49,8 @@ module.exports = (processArgv) => {
48
49
  // need to track them ourselves
49
50
  unknown: (arg) => {
50
51
  unknown.push(arg);
52
+
53
+ return true;
51
54
  },
52
55
  },
53
56
  );
@@ -1,3 +1,4 @@
1
+ // @ts-check
1
2
  const { match } = require('path-to-regexp');
2
3
 
3
4
  /**
package/lib/runBin.js CHANGED
@@ -1,3 +1,4 @@
1
+ // @ts-check
1
2
  const path = require('node:path');
2
3
  const spawn = require('cross-spawn');
3
4
 
@@ -45,13 +46,13 @@ const spawnPromise = (commandPath, args, options) => {
45
46
  */
46
47
 
47
48
  /**
48
- * @param {Options}
49
+ * @param {Options} options
49
50
  */
50
51
  const runBin = ({ packageName, binName, args, options }) =>
51
52
  spawnPromise(resolveBin(packageName, binName), args, options);
52
53
 
53
54
  /**
54
- * @param {Options}
55
+ * @param {Options} options
55
56
  */
56
57
  const startBin = ({ packageName, binName, args, options }) => {
57
58
  const childProcess = spawn(resolveBin(packageName, binName), args, options);
package/lib/runTsc.js CHANGED
@@ -1,3 +1,4 @@
1
+ // @ts-check
1
2
  const chalk = require('chalk');
2
3
  const { runBin } = require('./runBin');
3
4
  const { cwd } = require('./cwd');
package/lib/runVocab.js CHANGED
@@ -1,3 +1,4 @@
1
+ // @ts-check
1
2
  const { compile } = require('@vocab/core');
2
3
  const { getVocabConfig } = require('../config/vocab/vocab');
3
4
 
package/lib/storybook.js CHANGED
@@ -1,3 +1,4 @@
1
+ // @ts-check
1
2
  const path = require('node:path');
2
3
  const fs = require('node:fs/promises');
3
4
  const debug = require('debug');
@@ -1,3 +1,4 @@
1
+ // @ts-check
1
2
  const { getRunCommand, getExecuteCommand } = require('./packageManager');
2
3
 
3
4
  const chalk = require('chalk');
@@ -1,7 +1,6 @@
1
1
  const fs = require('node:fs');
2
- const path = require('node:path');
3
- const glob = require('fast-glob');
4
2
  const chalk = require('chalk');
3
+ const { fdir: Fdir } = require('fdir');
5
4
 
6
5
  const printBanner = require('./banner');
7
6
  const exists = require('./exists');
@@ -14,11 +13,18 @@ module.exports = async () => {
14
13
  const lessFileGlobResults = await Promise.all(
15
14
  srcPathsExist
16
15
  .filter((srcPath) => srcPath && fs.statSync(srcPath).isDirectory())
17
- .map(async (srcPath) => await glob(path.join(srcPath, '**/*.less'))),
16
+ .map(async (srcPath) =>
17
+ new Fdir()
18
+ .filter((file) => file.endsWith('.less'))
19
+ .crawl(srcPath)
20
+ .withPromise(),
21
+ ),
18
22
  );
23
+
19
24
  const srcHasLessFiles = lessFileGlobResults.some(
20
25
  (fileArray) => fileArray.length > 0,
21
26
  );
27
+
22
28
  if (srcHasLessFiles) {
23
29
  printBanner('warning', 'LESS styles detected', [
24
30
  `Support for ${chalk.bold('LESS')} has been deprecated.`,
@@ -1,13 +1,13 @@
1
- const { getWhyCommand } = require('./packageManager');
1
+ const { getWhyCommand, isPnpm } = require('./packageManager');
2
2
 
3
3
  const { readFile } = require('node:fs/promises');
4
- const glob = require('fast-glob');
4
+ const { fdir: Fdir } = require('fdir');
5
5
  const semver = require('semver');
6
6
  const chalk = require('chalk');
7
7
 
8
8
  const banner = require('./banner');
9
9
  const track = require('../telemetry');
10
- const { cwd, getPathFromCwd } = require('../lib/cwd');
10
+ const { getPathFromCwd } = require('../lib/cwd');
11
11
  const { paths } = require('../context');
12
12
 
13
13
  /**
@@ -21,30 +21,42 @@ const asyncMap = (list, fn) => {
21
21
  const singletonPackages = ['@vanilla-extract/css'];
22
22
 
23
23
  module.exports = async () => {
24
+ if (isPnpm) {
25
+ // pnpm doesn't nest dependencies in the same way as yarn or npm, so the method used below won't
26
+ // work for detecting duplicate packages
27
+ return;
28
+ }
29
+
24
30
  try {
25
- const packages = [];
26
-
27
- for (const packageName of [
28
- ...paths.compilePackages,
29
- ...singletonPackages,
30
- ]) {
31
- const results = await glob(
32
- [
33
- `node_modules/${packageName}/package.json`,
34
- `node_modules/**/node_modules/${packageName}/package.json`,
35
- ],
36
- {
37
- cwd: cwd(),
38
- },
31
+ /** @type {string[]} */
32
+ const duplicatePackages = [];
33
+ const packagesToCheck = [...paths.compilePackages, ...singletonPackages];
34
+
35
+ const packagePatterns = packagesToCheck.map((packageName) => [
36
+ packageName,
37
+ `node_modules/${packageName}/package.json`,
38
+ ]);
39
+
40
+ const patterns = packagePatterns.map(([, pattern]) => pattern);
41
+
42
+ const results = await new Fdir()
43
+ .withBasePath()
44
+ .filter((file) => patterns.some((pattern) => file.endsWith(pattern)))
45
+ .crawl('./node_modules')
46
+ .withPromise();
47
+
48
+ for (const [packageName, pattern] of packagePatterns) {
49
+ const resultsForPackage = results.filter((result) =>
50
+ result.endsWith(pattern),
39
51
  );
40
52
 
41
- if (results.length > 1) {
53
+ if (resultsForPackage.length > 1) {
42
54
  const messages = [
43
55
  chalk`Multiple copies of {bold ${packageName}} are present in node_modules. This is likely to cause errors, but even if it works, it will probably result in an unnecessarily large bundle size.`,
44
56
  ];
45
57
 
46
58
  messages.push(
47
- results
59
+ resultsForPackage
48
60
  .map((depLocation) => {
49
61
  const { version } = require(getPathFromCwd(depLocation));
50
62
 
@@ -64,14 +76,14 @@ module.exports = async () => {
64
76
  compile_package: packageName,
65
77
  });
66
78
  banner('error', 'Error: Duplicate packages detected', messages);
67
- }
68
79
 
69
- packages.push(...results);
80
+ duplicatePackages.push(...resultsForPackage);
81
+ }
70
82
  }
71
83
 
72
84
  const compilePackages = new Map();
73
85
 
74
- await asyncMap(packages, async (p) => {
86
+ await asyncMap(duplicatePackages, async (p) => {
75
87
  const contents = await readFile(getPathFromCwd(p), {
76
88
  encoding: 'utf8',
77
89
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sku",
3
- "version": "12.5.0",
3
+ "version": "12.6.0",
4
4
  "description": "Front-end development toolkit, powered by Webpack, Babel, CSS Modules, Less and Jest",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -39,7 +39,7 @@
39
39
  "@loadable/server": "^5.14.0",
40
40
  "@loadable/webpack-plugin": "^5.14.0",
41
41
  "@manypkg/find-root": "^2.2.0",
42
- "@pmmmwh/react-refresh-webpack-plugin": "0.5.11",
42
+ "@pmmmwh/react-refresh-webpack-plugin": "^0.5.12",
43
43
  "@storybook/builder-webpack5": "^7.0.17",
44
44
  "@storybook/cli": "^7.0.17",
45
45
  "@storybook/react": "^7.0.17",
@@ -82,8 +82,8 @@
82
82
  "eslint-config-seek": "^12.0.1",
83
83
  "exception-formatter": "^2.1.2",
84
84
  "express": "^4.16.3",
85
- "fast-glob": "^3.2.5",
86
85
  "fastest-validator": "^1.9.0",
86
+ "fdir": "^6.1.1",
87
87
  "find-up": "^5.0.0",
88
88
  "get-port": "^5.0.0",
89
89
  "hostile": "^1.3.3",
@@ -95,18 +95,18 @@
95
95
  "less": "^4.1.0",
96
96
  "less-loader": "^12.0.0",
97
97
  "lint-staged": "^11.1.1",
98
- "memoizee": "^0.4.15",
99
98
  "mini-css-extract-plugin": "^2.6.1",
100
99
  "minimist": "^1.2.8",
100
+ "nano-memoize": "^3.0.16",
101
101
  "node-html-parser": "^6.1.1",
102
102
  "open": "^7.3.1",
103
103
  "path-to-regexp": "^6.2.0",
104
+ "picomatch": "^3.0.1",
104
105
  "postcss": "^8.4.0",
105
106
  "postcss-loader": "^8.0.0",
106
107
  "prettier": "^2.8.8",
107
108
  "pretty-ms": "^7.0.1",
108
109
  "react-refresh": "^0.14.0",
109
- "rimraf": "^5.0.0",
110
110
  "selfsigned": "^2.1.1",
111
111
  "semver": "^7.3.4",
112
112
  "serialize-javascript": "^6.0.0",
@@ -115,7 +115,6 @@
115
115
  "terser-webpack-plugin": "^5.1.4",
116
116
  "tree-kill": "^1.2.1",
117
117
  "typescript": "~5.3.0",
118
- "validate-npm-package-name": "^5.0.0",
119
118
  "webpack": "^5.52.0",
120
119
  "webpack-bundle-analyzer": "^4.6.1",
121
120
  "webpack-dev-server": "^5.0.2",
@@ -127,7 +126,10 @@
127
126
  },
128
127
  "devDependencies": {
129
128
  "@types/cross-spawn": "^6.0.3",
129
+ "@types/debug": "^4.1.12",
130
130
  "@types/express": "^4.17.11",
131
+ "@types/minimist": "^1.2.5",
132
+ "@types/picomatch": "^2.3.3",
131
133
  "@types/react": "^18.2.3",
132
134
  "@types/react-dom": "^18.2.3",
133
135
  "@types/which": "^3.0.0",
@@ -1,7 +1,7 @@
1
1
  // First, ensure the build is running in production mode
2
2
  process.env.NODE_ENV = 'production';
3
3
 
4
- const { rimraf } = require('rimraf');
4
+ const { rm } = require('node:fs/promises');
5
5
  const { argv, config } = require('../config/args');
6
6
  const gracefulSpawn = require('../lib/gracefulSpawn');
7
7
  const { storybookTarget } = require('../context');
@@ -11,7 +11,7 @@ const { setUpStorybookConfigDirectory } = require('../lib/storybook');
11
11
 
12
12
  (async () => {
13
13
  await runVocabCompile();
14
- await rimraf(storybookTarget);
14
+ await rm(storybookTarget, { recursive: true, force: true });
15
15
  await setUpStorybookConfigDirectory();
16
16
 
17
17
  argv.push('build');
package/scripts/build.js CHANGED
@@ -10,7 +10,7 @@ const {
10
10
  copyPublicFiles,
11
11
  cleanTargetDirectory,
12
12
  ensureTargetDirectory,
13
- cleanRenderJs,
13
+ cleanStaticRenderEntry,
14
14
  } = require('../lib/buildFileUtils');
15
15
  const { run } = require('../lib/runWebpack');
16
16
  const createHtmlRenderPlugin = require('../config/webpack/plugins/createHtmlRenderPlugin');
@@ -31,7 +31,7 @@ const { runVocabCompile } = require('../lib/runVocab');
31
31
  }),
32
32
  ),
33
33
  );
34
- await cleanRenderJs();
34
+ await cleanStaticRenderEntry();
35
35
  await copyPublicFiles();
36
36
 
37
37
  const timeTaken = performance.now();
package/scripts/init.js CHANGED
@@ -11,7 +11,6 @@ const chalk = require('chalk');
11
11
  const fs = require('node:fs/promises');
12
12
  const { posix: path } = require('node:path');
13
13
  const { isEmptyDir } = require('../lib/isEmptyDir');
14
- const validatePackageName = require('validate-npm-package-name');
15
14
  const dedent = require('dedent');
16
15
  const { setCwd } = require('../lib/cwd');
17
16
  const prettierWrite = require('../lib/runPrettier').write;
@@ -21,7 +20,7 @@ const install = require('../lib/install');
21
20
  const banner = require('../lib/banner');
22
21
  const toPosixPath = require('../lib/toPosixPath');
23
22
  const trace = require('debug')('sku:init');
24
- const glob = require('fast-glob');
23
+ const { fdir: Fdir } = require('fdir');
25
24
  const ejs = require('ejs');
26
25
 
27
26
  const args = require('../config/args');
@@ -48,6 +47,11 @@ const getTemplateFileDestinationFromRoot =
48
47
  return path.join(projectRoot, filePathRelativeToTemplate);
49
48
  };
50
49
 
50
+ // Copied from `package-name-regex@4.0.0`
51
+ // See https://github.com/dword-design/package-name-regex/blob/acae7d482b1d03379003899df4d484238625364d/src/index.js#L1-L2
52
+ const packageNameRegex =
53
+ /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
54
+
51
55
  (async () => {
52
56
  const projectName = args.argv[0];
53
57
 
@@ -89,21 +93,16 @@ const getTemplateFileDestinationFromRoot =
89
93
  'braid-design-system',
90
94
  ].sort();
91
95
 
92
- const {
93
- validForNewPackages,
94
- errors = [],
95
- warnings = [],
96
- } = validatePackageName(appName);
96
+ const isValidPackageName = packageNameRegex.test(appName);
97
97
 
98
- if (!validForNewPackages) {
98
+ if (!isValidPackageName) {
99
99
  console.error(dedent`
100
- Could not create a project called ${chalk.red(`"${appName}"`)} \
101
- because of npm naming restrictions:
100
+ Could not create a project called ${chalk.red(
101
+ `"${appName}"`,
102
+ )} because of npm naming restrictions. \
103
+ Please see https://docs.npmjs.com/cli/configuring-npm/package-json for package name rules.
102
104
  `);
103
105
 
104
- const results = [...errors, ...warnings];
105
- results.forEach((result) => console.error(chalk.red(` * ${result}`)));
106
-
107
106
  process.exit(1);
108
107
  }
109
108
 
@@ -152,9 +151,11 @@ const getTemplateFileDestinationFromRoot =
152
151
  process.chdir(root);
153
152
 
154
153
  const templateDirectory = path.join(toPosixPath(__dirname), '../template');
155
- const templateFiles = await glob(`${templateDirectory}/**/*`, {
156
- onlyFiles: true,
157
- });
154
+
155
+ const templateFiles = await new Fdir()
156
+ .withBasePath()
157
+ .crawl(templateDirectory)
158
+ .withPromise();
158
159
 
159
160
  const getTemplateFileDestination = getTemplateFileDestinationFromRoot(
160
161
  root,
package/tsconfig.json DELETED
@@ -1,4 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.json",
3
- "include": ["@loadable/**/*", "@storybook/**/*", "sku-types.d.ts"]
4
- }