sku 12.3.3 → 12.4.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,63 @@
1
1
  # sku
2
2
 
3
+ ## 12.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Enable caching for ESLint and Prettier ([#881](https://github.com/seek-oss/sku/pull/881))
8
+
9
+ - Add `--packageManager` flag ([#884](https://github.com/seek-oss/sku/pull/884))
10
+
11
+ Sku detects package managers in the following order: `yarn` -> `pnpm` -> `npm`.
12
+ The `--packageManager` flag can be used to override the package manager used for the `sku init` script.
13
+ This affects what package manager is used to install dependencies, as well as the scripts present in the initialized app template.
14
+
15
+ ```sh
16
+ $ pnpm dlx sku init --packageManager pnpm my-app
17
+ ```
18
+
19
+ - Adds support for Storybook configuration via the `.storybook` directory ([#878](https://github.com/seek-oss/sku/pull/878))
20
+
21
+ sku now supports the standard `.storybook` configuration directory, as documented in [Storybook's configuration documentation].
22
+ Please read [sku's storybook documentation][sku storybook docs] for more info.
23
+
24
+ [Storybook's configuration documentation]: https://storybook.js.org/docs/react/configure/overview
25
+ [sku storybook docs]: https://seek-oss.github.io/sku/#/./docs/storybook
26
+
27
+ - Drop support for running `devServerMiddleware` alongside `sku storybook` ([#878](https://github.com/seek-oss/sku/pull/878))
28
+
29
+ Now that sku supports Storybook configuration via the `.storybook` directory, this feature is unnecessary.
30
+ Storybook middleware can be configured by creating a `middleware.js` file in the `.storybook` directory.
31
+ See [the sku docs][sku storybook middleware] for more info.
32
+
33
+ **NOTE**: While this is technically a breaking change, it does not affect app builds, therefore it has been downgraded to a `minor` release.
34
+
35
+ [sku storybook middleware]: https://seek-oss.github.io/sku/#/./docs/storybook?id=devserver-middleware
36
+
37
+ - Update TypeScript to 5.2 ([#886](https://github.com/seek-oss/sku/pull/886))
38
+
39
+ This release includes breaking changes. See the [TypeScript 5.2 announcement][ts52] for more information.
40
+
41
+ [ts52]: https://devblogs.microsoft.com/typescript/announcing-typescript-5-2/
42
+
43
+ ### Patch Changes
44
+
45
+ - Fixes a bug where sku would fail to suggest existing `package.json` scripts before suggesting its own commands ([#876](https://github.com/seek-oss/sku/pull/876))
46
+
47
+ - Remove `lodash` dependency ([#883](https://github.com/seek-oss/sku/pull/883))
48
+
49
+ - Propagate `--config` argument to Storybook process ([#879](https://github.com/seek-oss/sku/pull/879))
50
+
51
+ Fixes a bug where `sku storybook` and `sku build-storybook` would not honour a custom sku config specified via the `--config` flag
52
+
53
+ - Fixes a bug where `pnpm` was not detected correctly when detecting [compile packages](https://seek-oss.github.io/sku/#/./docs/extra-features?id=compile-packages) ([#876](https://github.com/seek-oss/sku/pull/876))
54
+
55
+ - Bump `@pmmmwh/react-refresh-webpack-plugin` and `webpack-dev-server` dependencies. Remove unused dependencies. ([#885](https://github.com/seek-oss/sku/pull/885))
56
+
57
+ - Adds support for `pnpm` when suggesting commands ([#876](https://github.com/seek-oss/sku/pull/876))
58
+
59
+ - Disable Storybook telemetry ([#878](https://github.com/seek-oss/sku/pull/878))
60
+
3
61
  ## 12.3.3
4
62
 
5
63
  ### Patch Changes
package/README.md CHANGED
@@ -23,13 +23,17 @@ Create a new project and start a local development environment:
23
23
  ```bash
24
24
  $ npx sku init my-app
25
25
  $ cd my-app
26
- $ npm start
26
+ $ yarn start
27
27
  ```
28
28
 
29
- Don't have [npx](https://www.npmjs.com/package/npx)?
29
+ By default, a new project's dependencies will be installed with the first supported package manager detected on your system.
30
+ Package managers are detected in the following order: `yarn` -> `pnpm` -> `npm`.
31
+ This can be overridden via the `--packageManager` flag:
30
32
 
31
33
  ```bash
32
- $ npm install -g npx
34
+ $ pnpm dlx sku init --packageManager pnpm my-app
35
+ $ cd my-app
36
+ $ pnpm start
33
37
  ```
34
38
 
35
39
  ## [Documentation](https://seek-oss.github.io/sku)
@@ -1,11 +1,14 @@
1
- const isYarn = require('../../lib/isYarn');
1
+ const { isYarn } = require('../../lib/packageManager');
2
2
  const { lintExtensions } = require('../../lib/lint');
3
+ const { getCommand } = require('@antfu/ni');
3
4
 
4
5
  const steps = {};
5
6
 
6
7
  // Yarn lock integrity check
7
8
  if (isYarn) {
8
- steps['+(package.json|yarn.lock)'] = [() => 'yarn install --check-files'];
9
+ steps['+(package.json|yarn.lock)'] = [
10
+ () => getCommand('yarn', 'install', ['--check-files']),
11
+ ];
9
12
  }
10
13
 
11
14
  // Format & lint
@@ -0,0 +1,75 @@
1
+ /**
2
+ * This file and all its dependencies must be CJS
3
+ * https://github.com/storybookjs/storybook/pull/23018
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+ const {
9
+ paths,
10
+ storybookAddons,
11
+ storybookStoryStore,
12
+ } = require('../../context');
13
+
14
+ const makeStorybookWebpackConfig = require('./storybookWebpackConfig');
15
+
16
+ /** @type {import("@storybook/react-webpack5").StorybookConfig} */
17
+ module.exports = {
18
+ stories: paths.src
19
+ .filter((srcPath) => fs.statSync(srcPath).isDirectory())
20
+ .map((srcPath) => path.join(srcPath, '**/*.stories.@(js|ts|tsx)')),
21
+ addons: storybookAddons,
22
+ framework: {
23
+ // Storybook looks for a `/preset` entrypoint on the framework package,
24
+ // so we give it the dirname of the resolved path to package.json
25
+ // https://github.com/storybookjs/storybook/blob/aecfa1791f982bef6a06b51d20df3e31dd82b5b4/code/lib/core-common/src/utils/validate-config.ts#L34
26
+ name: path.dirname(
27
+ require.resolve('@storybook/react-webpack5/package.json'),
28
+ ),
29
+ options: {},
30
+ },
31
+ core: {
32
+ builder: {
33
+ name: require.resolve('@storybook/builder-webpack5'),
34
+ options: {
35
+ fsCache: true,
36
+ },
37
+ },
38
+ disableTelemetry: true,
39
+ },
40
+ features: {
41
+ storyStoreV7: storybookStoryStore,
42
+ },
43
+ // sku storybook -> configType === 'DEVELOPMENT'
44
+ // sku build-storybook -> configType === 'PRODUCTION'
45
+ webpackFinal: (config, { configType }) =>
46
+ makeStorybookWebpackConfig(config, {
47
+ isDevServer: configType === 'DEVELOPMENT',
48
+ }),
49
+ babel: (config) => ({
50
+ ...config,
51
+ presets: [
52
+ // Includes `@babel/preset-react`
53
+ ...config.presets,
54
+
55
+ // Storybook as of 7.0 no longer handles babel stuff for you (other than react)
56
+ // We need to configure TypeScript support ourselves, if we want it
57
+ // https://github.com/storybookjs/storybook/issues/22357#issuecomment-1532548058
58
+ [
59
+ require.resolve('@babel/preset-env'),
60
+ {
61
+ targets: {
62
+ chrome: 100,
63
+ },
64
+ },
65
+ ],
66
+ [
67
+ require.resolve('@babel/preset-typescript'),
68
+ {
69
+ allExtensions: true,
70
+ isTSX: true,
71
+ },
72
+ ],
73
+ ],
74
+ }),
75
+ };
@@ -1,20 +1,20 @@
1
1
  const { paths } = require('../../context');
2
- const find = require('lodash/find');
3
2
  const { merge: webpackMerge } = require('webpack-merge');
4
3
  const makeWebpackConfig = require('../webpack/webpack.config');
5
4
  const { resolvePackage } = require('../webpack/utils/resolvePackage');
6
5
 
7
6
  const hot = process.env.SKU_HOT !== 'false';
8
7
 
9
- module.exports = ({ config }, { isDevServer }) => {
10
- const clientWebpackConfig = find(
11
- makeWebpackConfig({
12
- isIntegration: true,
13
- isDevServer,
14
- hot: isDevServer && hot,
15
- }),
16
- ({ name }) => name === 'client',
17
- );
8
+ /**
9
+ * @param {import("webpack").Configuration} config
10
+ * @param {{isDevServer: boolean}}
11
+ */
12
+ module.exports = (config, { isDevServer }) => {
13
+ const clientWebpackConfig = makeWebpackConfig({
14
+ isIntegration: true,
15
+ isDevServer,
16
+ hot: isDevServer && hot,
17
+ }).find(({ name }) => name === 'client');
18
18
 
19
19
  // Ensure Storybook's webpack loaders ignore our code :(
20
20
  if (config && config.module && Array.isArray(config.module.rules)) {
@@ -1,5 +1,4 @@
1
1
  const webpack = require('webpack');
2
- const uniq = require('lodash/uniq');
3
2
  const defaultSupportedBrowsers = require('browserslist-config-seek');
4
3
  const { VanillaExtractPlugin } = require('@vanilla-extract/webpack-plugin');
5
4
  const {
@@ -32,10 +31,9 @@ class SkuWebpackPlugin {
32
31
  rootResolution: false,
33
32
  ...options,
34
33
  };
35
- this.compilePackages = uniq([
36
- ...defaultCompilePackages,
37
- ...this.options.compilePackages,
38
- ]);
34
+ this.compilePackages = [
35
+ ...new Set([...defaultCompilePackages, ...this.options.compilePackages]),
36
+ ];
39
37
  this.include = [
40
38
  ...this.options.include,
41
39
  ...this.compilePackages.map(resolvePackage),
@@ -1,7 +1,6 @@
1
1
  const webpack = require('webpack');
2
2
  const MiniCssExtractPlugin = require('mini-css-extract-plugin');
3
3
  const nodeExternals = require('webpack-node-externals');
4
- const lodash = require('lodash');
5
4
  const path = require('path');
6
5
  const LoadablePlugin = require('@loadable/webpack-plugin');
7
6
  const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
@@ -16,6 +15,7 @@ const { VocabWebpackPlugin } = require('@vocab/webpack');
16
15
 
17
16
  const utils = require('./utils');
18
17
  const { cwd } = require('../../lib/cwd');
18
+ const { stringifyEnvarValues } = require('../../lib/env');
19
19
 
20
20
  const renderEntry = require.resolve('../../entry/render');
21
21
  const libraryRenderEntry = require.resolve('../../entry/libraryRender');
@@ -58,28 +58,11 @@ const makeWebpackConfig = ({
58
58
 
59
59
  const vocabOptions = getVocabConfig();
60
60
 
61
- const envVars = lodash
62
- .chain(env)
63
- .mapValues((value, key) => {
64
- if (typeof value !== 'object') {
65
- return JSON.stringify(value);
66
- }
67
-
68
- const valueForEnv = value[args.env];
69
-
70
- if (typeof valueForEnv === 'undefined') {
71
- console.log(
72
- `WARNING: Environment variable "${key}" is missing a value for the "${args.env}" environment`,
73
- );
74
- process.exit(1);
75
- }
76
-
77
- return JSON.stringify(valueForEnv);
78
- })
79
- .set('SKU_ENV', JSON.stringify(args.env))
80
- .set('PORT', JSON.stringify(port))
81
- .mapKeys((value, key) => `process.env.${key}`)
82
- .value();
61
+ const envars = stringifyEnvarValues({
62
+ ...env,
63
+ SKU_ENV: args.env,
64
+ PORT: port,
65
+ });
83
66
 
84
67
  const resolvedPolyfills = polyfills.map((polyfill) => {
85
68
  return require.resolve(polyfill, { paths: [cwd()] });
@@ -220,7 +203,7 @@ const makeWebpackConfig = ({
220
203
  ...(isDevServer || isIntegration
221
204
  ? []
222
205
  : [bundleAnalyzerPlugin({ name: 'client' })]),
223
- new webpack.DefinePlugin(envVars),
206
+ new webpack.DefinePlugin(envars),
224
207
  new webpack.DefinePlugin({
225
208
  __SKU_CLIENT_PATH__: JSON.stringify(
226
209
  path.relative(cwd(), paths.clientEntry),
@@ -309,7 +292,7 @@ const makeWebpackConfig = ({
309
292
  },
310
293
  plugins: [
311
294
  ...(htmlRenderPlugin ? [htmlRenderPlugin.rendererPlugin] : []),
312
- new webpack.DefinePlugin(envVars),
295
+ new webpack.DefinePlugin(envars),
313
296
  new webpack.DefinePlugin({
314
297
  __SKU_LIBRARY_NAME__: JSON.stringify(libraryName),
315
298
  __SKU_LIBRARY_FILE__: JSON.stringify(libraryFile),
@@ -1,7 +1,6 @@
1
1
  const path = require('path');
2
2
  const webpack = require('webpack');
3
3
  const MiniCssExtractPlugin = require('mini-css-extract-plugin');
4
- const lodash = require('lodash');
5
4
  const nodeExternals = require('webpack-node-externals');
6
5
  const findUp = require('find-up');
7
6
  const LoadablePlugin = require('@loadable/webpack-plugin');
@@ -16,6 +15,7 @@ const args = require('../args');
16
15
  const { bundleAnalyzerPlugin } = require('./plugins/bundleAnalyzer');
17
16
  const utils = require('./utils');
18
17
  const { cwd } = require('../../lib/cwd');
18
+ const { stringifyEnvarValues } = require('../../lib/env');
19
19
  const {
20
20
  paths,
21
21
  env,
@@ -48,27 +48,10 @@ const makeWebpackConfig = ({
48
48
 
49
49
  const vocabOptions = getVocabConfig();
50
50
 
51
- const envVars = lodash
52
- .chain(env)
53
- .mapValues((value, key) => {
54
- if (typeof value !== 'object') {
55
- return JSON.stringify(value);
56
- }
57
-
58
- const valueForEnv = value[args.env];
59
-
60
- if (typeof valueForEnv === 'undefined') {
61
- console.log(
62
- `WARNING: Environment variable "${key}" is missing a value for the "${args.env}" environment`,
63
- );
64
- process.exit(1);
65
- }
66
-
67
- return JSON.stringify(valueForEnv);
68
- })
69
- .set('SKU_ENV', JSON.stringify(args.env))
70
- .mapKeys((value, key) => `process.env.${key}`)
71
- .value();
51
+ const envars = stringifyEnvarValues({
52
+ ...env,
53
+ SKU_ENV: args.env,
54
+ });
72
55
 
73
56
  const internalInclude = [path.join(__dirname, '../../entry'), ...paths.src];
74
57
 
@@ -173,7 +156,7 @@ const makeWebpackConfig = ({
173
156
  ],
174
157
  },
175
158
  plugins: [
176
- new webpack.DefinePlugin(envVars),
159
+ new webpack.DefinePlugin(envars),
177
160
  new LoadablePlugin({
178
161
  filename: webpackStatsFilename,
179
162
  writeToDisk: true,
@@ -268,7 +251,7 @@ const makeWebpackConfig = ({
268
251
  rules: [{ test: /\.mjs$/, type: 'javascript/auto' }],
269
252
  },
270
253
  plugins: [
271
- new webpack.DefinePlugin(envVars),
254
+ new webpack.DefinePlugin(envars),
272
255
  new webpack.DefinePlugin({
273
256
  __SKU_DEFAULT_SERVER_PORT__: JSON.stringify(serverPort),
274
257
  __SKU_PUBLIC_PATH__: JSON.stringify(publicPath),
@@ -5,7 +5,7 @@ const glob = require('fast-glob');
5
5
  const { cwd: skuCwd } = require('../lib/cwd');
6
6
  const toPosixPath = require('../lib/toPosixPath');
7
7
 
8
- const { findRootSync } = require('@manypkg/find-root');
8
+ const { rootDir, isPnpm } = require('../lib/packageManager');
9
9
 
10
10
  /** @type {string[]} */
11
11
  let detectedCompilePackages = [];
@@ -14,9 +14,9 @@ try {
14
14
  const globs = ['node_modules/@seek/*/package.json'];
15
15
  const cwd = skuCwd();
16
16
 
17
- const { rootDir, tool } = findRootSync(cwd);
18
-
19
- if (tool === 'pnpm') {
17
+ // `rootDir` is nullable, but while we have `strict: false` in our TSConfig it won't appear nullable
18
+ // It will be null during sku init, but we don't really care about detecting compile packages at that point anyway
19
+ if (isPnpm && rootDir) {
20
20
  const pnpmVirtualStorePath = path.join(
21
21
  toPosixPath(rootDir),
22
22
  'node_modules/.pnpm',
package/context/index.js CHANGED
@@ -19,8 +19,10 @@ const getSkuConfig = () => {
19
19
  const tsPath = getPathFromCwd('sku.config.ts');
20
20
  const jsPath = getPathFromCwd('sku.config.js');
21
21
 
22
- if (args.config) {
23
- appSkuConfigPath = getPathFromCwd(args.config);
22
+ const customSkuConfig = args.config || process.env.SKU_CONFIG;
23
+
24
+ if (customSkuConfig) {
25
+ appSkuConfigPath = getPathFromCwd(customSkuConfig);
24
26
  } else if (fs.existsSync(tsPath)) {
25
27
  appSkuConfigPath = tsPath;
26
28
  } else if (fs.existsSync(jsPath)) {
@@ -65,6 +67,9 @@ if (isCompilePackage && skuConfig.rootResolution) {
65
67
  process.exit(1);
66
68
  }
67
69
 
70
+ /**
71
+ * @type {Record<string, unknown>}
72
+ */
68
73
  const env = {
69
74
  ...skuConfig.env,
70
75
  SKU_TENANT: args.tenant,
package/lib/configure.js CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+
2
3
  const { writeFile, rm } = require('fs/promises');
3
4
  const path = require('path');
4
5
 
@@ -13,12 +14,14 @@ const prettierConfig = require('../config/prettier/prettierConfig');
13
14
  const eslintConfig = require('../config/eslint/eslintConfig');
14
15
  const createTSConfig = require('../config/typescript/tsconfig.js');
15
16
  const getCertificate = require('./certificate');
17
+ const { storybookMainConfigPath } = require('./storybook');
18
+ const managedConfigBanner = require('./managedConfigBanner.js');
19
+
16
20
  const coverageFolder = 'coverage';
17
21
 
18
22
  const convertToForwardSlashPaths = (pathStr) => pathStr.replace(/\\/g, '/');
19
23
  const addSep = (p) => `${p}${path.sep}`;
20
- const prependBanner = (str) =>
21
- `/** THIS FILE IS GENERATED BY SKU, MANUAL CHANGES WILL BE DISCARDED **/\n${str}`;
24
+ const prependBanner = (str) => `${managedConfigBanner}\n${str}`;
22
25
 
23
26
  const writeFileToCWD = async (fileName, content, { banner = true } = {}) => {
24
27
  const outPath = getPathFromCwd(fileName);
@@ -33,11 +36,13 @@ module.exports = async () => {
33
36
  const gitIgnorePatterns = [
34
37
  addSep(bundleReportFolder),
35
38
  addSep(coverageFolder),
39
+ storybookMainConfigPath,
36
40
  ];
37
41
  const lintIgnorePatterns = [
38
42
  addSep(bundleReportFolder),
39
43
  addSep(coverageFolder),
40
44
  '*.less.d.ts',
45
+ storybookMainConfigPath,
41
46
  ];
42
47
 
43
48
  // Ignore webpack target directories
@@ -51,8 +56,9 @@ module.exports = async () => {
51
56
 
52
57
  // Generate ESLint configuration
53
58
  const eslintConfigFilename = '.eslintrc';
59
+ const eslintCacheFilename = '.eslintcache';
54
60
  await writeFileToCWD(eslintConfigFilename, eslintConfig);
55
- gitIgnorePatterns.push(eslintConfigFilename);
61
+ gitIgnorePatterns.push(eslintConfigFilename, eslintCacheFilename);
56
62
 
57
63
  // Generate Prettier configuration
58
64
  // NOTE: We are not generating a banner as prettier does not support the `JSON
package/lib/env.js ADDED
@@ -0,0 +1,31 @@
1
+ const args = require('../config/args');
2
+
3
+ /**
4
+ * Stringify the values of an object of environment variables, prepending keys with
5
+ * `process.env.` in the process
6
+ * @param {Record<string, unknown>} envars An object of environment variables and their values
7
+ */
8
+ const stringifyEnvarValues = (envars) => {
9
+ const entries = Object.entries(envars);
10
+
11
+ const stringifiedEntries = entries.map(([key, value]) => {
12
+ const newKey = `process.env.${key}`;
13
+
14
+ if (typeof value !== 'object') {
15
+ return [newKey, JSON.stringify(value)];
16
+ }
17
+
18
+ if (typeof value === 'undefined') {
19
+ console.log(
20
+ `WARNING: Environment variable "${key}" is missing a value for the "${args.env}" environment`,
21
+ );
22
+ process.exit(1);
23
+ }
24
+
25
+ return [newKey, JSON.stringify(value)];
26
+ });
27
+
28
+ return Object.fromEntries(stringifiedEntries);
29
+ };
30
+
31
+ module.exports = { stringifyEnvarValues };
package/lib/hosts.js CHANGED
@@ -57,7 +57,7 @@ const checkHosts = async () => {
57
57
  );
58
58
  });
59
59
 
60
- await suggestScript('setup-hosts', { sudo: true });
60
+ suggestScript('setup-hosts', { sudo: true });
61
61
  }
62
62
  } catch (e) {
63
63
  // swallow error as this just a warning check
package/lib/install.js CHANGED
@@ -1,29 +1,14 @@
1
+ const { getAddCommand } = require('./packageManager');
2
+
1
3
  const spawn = require('cross-spawn');
2
4
 
3
- module.exports = ({ deps, type, exact = true, verbose, useYarn }) =>
5
+ /**
6
+ * @param {import("../lib/packageManager").GetAddCommandOptions} options
7
+ */
8
+ module.exports = ({ deps, type, logLevel, exact = true }) =>
4
9
  new Promise((resolve, reject) => {
5
- const command = useYarn ? 'yarnpkg' : 'npm';
6
- const isDev = type === 'dev';
7
-
8
- const args = useYarn
9
- ? [
10
- 'add',
11
- isDev ? '--dev' : null,
12
- exact ? '--exact' : null,
13
- ...deps,
14
- ].filter((arg) => arg !== null)
15
- : [
16
- 'install',
17
- `--save${isDev ? '-dev' : ''}`,
18
- exact ? '--save-exact' : null,
19
- '--loglevel',
20
- 'error',
21
- ...deps,
22
- ].filter((arg) => arg !== null);
23
-
24
- if (verbose) {
25
- args.push('--verbose');
26
- }
10
+ const addCommand = getAddCommand({ deps, type, logLevel, exact });
11
+ const [command, ...args] = addCommand.split(' ');
27
12
 
28
13
  const child = spawn(command, args, { stdio: 'inherit' });
29
14
 
@@ -0,0 +1 @@
1
+ module.exports = `/** THIS FILE IS GENERATED BY SKU, MANUAL CHANGES WILL BE DISCARDED **/`;