@nx/react 21.7.0-canary.20250929-405d91d → 22.0.0-beta.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/migrations.json CHANGED
@@ -47,12 +47,6 @@
47
47
  "version": "21.0.0-beta.11",
48
48
  "description": "Replaces `classProperties.loose` option with `loose`.",
49
49
  "factory": "./src/migrations/update-21-0-0/update-babel-loose"
50
- },
51
- "update-22-0-0-add-svgr-to-webpack-config": {
52
- "cli": "nx",
53
- "version": "22.0.0-beta.0",
54
- "description": "Updates webpack configs using React to use the new withSvgr composable function instead of the svgr option in withReact or NxReactWebpackPlugin.",
55
- "factory": "./src/migrations/update-22-0-0/add-svgr-to-webpack-config"
56
50
  }
57
51
  },
58
52
  "packageJsonUpdates": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/react",
3
- "version": "21.7.0-canary.20250929-405d91d",
3
+ "version": "22.0.0-beta.0",
4
4
  "private": false,
5
5
  "description": "The React plugin for Nx contains executors and generators for managing React applications and libraries within an Nx workspace. It provides:\n\n\n- Integration with libraries such as Jest, Vitest, Playwright, Cypress, and Storybook.\n\n- Generators for applications, libraries, components, hooks, and more.\n\n- Library build support for publishing packages to npm or other registries.\n\n- Utilities for automatic workspace refactoring.",
6
6
  "repository": {
@@ -38,19 +38,19 @@
38
38
  "minimatch": "9.0.3",
39
39
  "picocolors": "^1.1.0",
40
40
  "tslib": "^2.3.0",
41
- "@nx/devkit": "21.7.0-canary.20250929-405d91d",
42
- "@nx/js": "21.7.0-canary.20250929-405d91d",
43
- "@nx/eslint": "21.7.0-canary.20250929-405d91d",
44
- "@nx/web": "21.7.0-canary.20250929-405d91d",
45
- "@nx/vite": "21.7.0-canary.20250929-405d91d",
46
- "@nx/module-federation": "21.7.0-canary.20250929-405d91d",
47
- "@nx/rollup": "21.7.0-canary.20250929-405d91d",
41
+ "@nx/devkit": "22.0.0-beta.0",
42
+ "@nx/js": "22.0.0-beta.0",
43
+ "@nx/eslint": "22.0.0-beta.0",
44
+ "@nx/web": "22.0.0-beta.0",
45
+ "@nx/vite": "22.0.0-beta.0",
46
+ "@nx/module-federation": "22.0.0-beta.0",
47
+ "@nx/rollup": "22.0.0-beta.0",
48
48
  "express": "^4.21.2",
49
49
  "http-proxy-middleware": "^3.0.5",
50
50
  "semver": "^7.6.3"
51
51
  },
52
52
  "devDependencies": {
53
- "nx": "21.7.0-canary.20250929-405d91d"
53
+ "nx": "22.0.0-beta.0"
54
54
  },
55
55
  "publishConfig": {
56
56
  "access": "public"
@@ -1,6 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- // TODO(v22): Remove this in Nx 22 and migrate to explicit rollup.config.cjs files.
4
3
  /**
5
4
  * @deprecated Use `withNx` function from `@nx/rollup/with-nx` in your rollup.config.cjs file instead. Use `nx g @nx/rollup:convert-to-inferred` to generate the rollup.config.cjs file if it does not exist.
6
5
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/react/plugins/component-testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,yBAAyB,EAC1B,MAAM,oCAAoC,CAAC;AAsB5C,KAAK,aAAa,GAAG;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,GAAG,CAAC;CAClB,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,SAAS,CAAC;IACnB,aAAa,CAAC,EAAE,GAAG,CAAC;CACrB,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,wBAAwB,CACtC,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,yBAAyB,GAClC;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,aAAa,GAAG,gBAAgB,CAAC;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,OAAO,CAAC;CAC5B,CA+HA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/react/plugins/component-testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,yBAAyB,EAC1B,MAAM,oCAAoC,CAAC;AAsB5C,KAAK,aAAa,GAAG;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,GAAG,CAAC;CAClB,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,SAAS,CAAC;IACnB,aAAa,CAAC,EAAE,GAAG,CAAC;CACrB,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,wBAAwB,CACtC,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,yBAAyB,GAClC;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,aAAa,GAAG,gBAAgB,CAAC;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,OAAO,CAAC;CAC5B,CAkIA"}
@@ -65,7 +65,7 @@ function nxComponentTestingPreset(pathToConfig, options) {
65
65
  },
66
66
  };
67
67
  }
68
- let webpackConfig;
68
+ let webpackConfig = null;
69
69
  try {
70
70
  const graph = (0, devkit_1.readCachedProjectGraph)();
71
71
  const { targets: ctTargets, name: ctProjectName } = (0, ct_helpers_1.getProjectConfigByPath)(graph, pathToConfig);
@@ -93,6 +93,9 @@ function nxComponentTestingPreset(pathToConfig, options) {
93
93
  devkit_1.logger.warn((0, devkit_1.stripIndents) `Unable to build a webpack config with the project graph.
94
94
  Falling back to default webpack config.`);
95
95
  devkit_1.logger.warn(e);
96
+ }
97
+ // Fallback config
98
+ if (!webpackConfig) {
96
99
  const { buildBaseWebpackConfig } = require('./webpack-fallback');
97
100
  webpackConfig = buildBaseWebpackConfig({
98
101
  tsConfigPath: findTsConfig(normalizedProjectRootPath),
@@ -170,32 +173,31 @@ function buildTargetWebpack(ctx, buildTarget, componentTestingProjectName) {
170
173
  }
171
174
  return async () => {
172
175
  customWebpack = await customWebpack;
173
- // TODO(v22): Component testing need to be agnostic of the underlying executor. With Crystal, we're not using `@nx/webpack:webpack` by default.
174
- // We need to decouple CT from the build target of the app, we just care about bundler config (e.g. webpack.config.js).
175
- // The generated setup should support both Webpack and Vite as documented here: https://docs.cypress.io/guides/component-testing/react/overview
176
- // Related issue: https://github.com/nrwl/nx/issues/21546
177
- const configure = composePluginsSync(withNx(), withWeb());
178
- const defaultWebpack = configure({}, {
179
- options: {
180
- ...options,
181
- // cypress will generate its own index.html from component-index.html
182
- generateIndexHtml: false,
183
- // causes issues with buildable libraries with ENOENT: no such file or directory, scandir error
184
- extractLicenses: false,
185
- root: devkit_1.workspaceRoot,
186
- projectRoot: ctProjectConfig.root,
187
- sourceRoot: (0, ts_solution_setup_1.getProjectSourceRoot)(ctProjectConfig),
188
- },
189
- context,
190
- });
191
- if (customWebpack) {
192
- return await customWebpack(defaultWebpack, {
193
- options,
176
+ // For legacy `composePlugins(...)` setup, we need change some options to make Cypress CT work properly.
177
+ if (customWebpack &&
178
+ require('@nx/webpack').isNxWebpackComposablePlugin(customWebpack) // using inline since @nx/webpack may not be installed when using vite so top-level import would error
179
+ ) {
180
+ return await customWebpack({}, {
181
+ options: {
182
+ ...options,
183
+ // cypress will generate its own index.html from component-index.html
184
+ generateIndexHtml: false,
185
+ // causes issues with buildable libraries with ENOENT: no such file or directory, scandir error
186
+ extractLicenses: false,
187
+ root: devkit_1.workspaceRoot,
188
+ projectRoot: ctProjectConfig.root,
189
+ sourceRoot: (0, ts_solution_setup_1.getProjectSourceRoot)(ctProjectConfig),
190
+ },
194
191
  context,
195
192
  configuration: parsed.configuration,
196
193
  });
197
194
  }
198
- return defaultWebpack;
195
+ else if (typeof customWebpack === 'object' ||
196
+ typeof customWebpack === 'function') {
197
+ // If this is a standard webpack config object or function, just return. it
198
+ return customWebpack;
199
+ }
200
+ return null; // return null to use fallback config
199
201
  };
200
202
  }
201
203
  function findViteConfig(projectRootFullPath) {
@@ -1,3 +1,6 @@
1
1
  import { Configuration, WebpackOptionsNormalized } from 'webpack';
2
- export declare function applyReactConfig(options?: Record<string, any>, config?: Partial<WebpackOptionsNormalized | Configuration>): void;
2
+ import { SvgrOptions } from '../../with-react';
3
+ export declare function applyReactConfig(options: {
4
+ svgr?: boolean | SvgrOptions;
5
+ }, config?: Partial<WebpackOptionsNormalized | Configuration>): void;
3
6
  //# sourceMappingURL=apply-react-config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"apply-react-config.d.ts","sourceRoot":"","sources":["../../../../../../packages/react/plugins/nx-react-webpack-plugin/lib/apply-react-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AAElE,wBAAgB,gBAAgB,CAC9B,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,EACjC,MAAM,GAAE,OAAO,CAAC,wBAAwB,GAAG,aAAa,CAAM,GAC7D,IAAI,CAUN"}
1
+ {"version":3,"file":"apply-react-config.d.ts","sourceRoot":"","sources":["../../../../../../packages/react/plugins/nx-react-webpack-plugin/lib/apply-react-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,GAAG,WAAW,CAAA;CAAE,EACzC,MAAM,GAAE,OAAO,CAAC,wBAAwB,GAAG,aAAa,CAAM,GAC7D,IAAI,CAwCN"}
@@ -1,10 +1,35 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.applyReactConfig = applyReactConfig;
4
- function applyReactConfig(options = {}, config = {}) {
4
+ function applyReactConfig(options, config = {}) {
5
5
  if (!process.env['NX_TASK_TARGET_PROJECT'])
6
6
  return;
7
7
  addHotReload(config);
8
+ if (options.svgr !== false || typeof options.svgr === 'object') {
9
+ removeSvgLoaderIfPresent(config);
10
+ const defaultSvgrOptions = {
11
+ svgo: false,
12
+ titleProp: true,
13
+ ref: true,
14
+ };
15
+ const svgrOptions = typeof options.svgr === 'object' ? options.svgr : defaultSvgrOptions;
16
+ config.module.rules.push({
17
+ test: /\.svg$/,
18
+ issuer: /\.(js|ts|md)x?$/,
19
+ use: [
20
+ {
21
+ loader: require.resolve('@svgr/webpack'),
22
+ options: svgrOptions,
23
+ },
24
+ {
25
+ loader: require.resolve('file-loader'),
26
+ options: {
27
+ name: '[name].[hash].[ext]',
28
+ },
29
+ },
30
+ ],
31
+ });
32
+ }
8
33
  // enable webpack node api
9
34
  config.node = {
10
35
  __dirname: true,
@@ -34,3 +59,13 @@ function addHotReload(config) {
34
59
  config.plugins.push(new ReactRefreshPlugin({ overlay: false }));
35
60
  }
36
61
  }
62
+ // We remove potentially conflicting rules that target SVGs because we use @svgr/webpack loader
63
+ // See https://github.com/nrwl/nx/issues/14383
64
+ function removeSvgLoaderIfPresent(config) {
65
+ const svgLoaderIdx = config.module.rules.findIndex((rule) => typeof rule === 'object' &&
66
+ typeof rule.test !== 'undefined' &&
67
+ rule.test.toString().includes('svg'));
68
+ if (svgLoaderIdx === -1)
69
+ return;
70
+ config.module.rules.splice(svgLoaderIdx, 1);
71
+ }
@@ -1,7 +1,9 @@
1
1
  import { Compiler } from 'webpack';
2
2
  export declare class NxReactWebpackPlugin {
3
3
  private options;
4
- constructor(options?: Record<string, any>);
4
+ constructor(options?: {
5
+ svgr?: boolean;
6
+ });
5
7
  apply(compiler: Compiler): void;
6
8
  }
7
9
  //# sourceMappingURL=nx-react-webpack-plugin.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"nx-react-webpack-plugin.d.ts","sourceRoot":"","sources":["../../../../../packages/react/plugins/nx-react-webpack-plugin/nx-react-webpack-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnC,qBAAa,oBAAoB;IACnB,OAAO,CAAC,OAAO;gBAAP,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM;IAErD,KAAK,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;CAGhC"}
1
+ {"version":3,"file":"nx-react-webpack-plugin.d.ts","sourceRoot":"","sources":["../../../../../packages/react/plugins/nx-react-webpack-plugin/nx-react-webpack-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnC,qBAAa,oBAAoB;IACnB,OAAO,CAAC,OAAO;gBAAP,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAA;KAAO;IAEpD,KAAK,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;CAGhC"}
@@ -1,6 +1,16 @@
1
1
  import type { Configuration } from 'webpack';
2
2
  import type { NxWebpackExecutionContext, WithWebOptions } from '@nx/webpack';
3
+ export interface SvgrOptions {
4
+ svgo?: boolean;
5
+ titleProp?: boolean;
6
+ ref?: boolean;
7
+ }
3
8
  export interface WithReactOptions extends WithWebOptions {
9
+ /**
10
+ * @deprecated Add SVGR support in your Webpack configuration without relying on Nx. See https://react-svgr.com/docs/webpack/
11
+ * TODO(v22): Remove this option and migrate userland webpack config to explicitly configure @svgr/webpack
12
+ * */
13
+ svgr?: boolean | SvgrOptions;
4
14
  }
5
15
  /**
6
16
  * @param {WithReactOptions} pluginOptions
@@ -1 +1 @@
1
- {"version":3,"file":"with-react.d.ts","sourceRoot":"","sources":["../../../../packages/react/plugins/with-react.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,KAAK,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAK7E,MAAM,WAAW,gBAAiB,SAAQ,cAAc;CAAG;AAE3D;;;GAGG;AACH,wBAAgB,SAAS,CAAC,aAAa,GAAE,gBAAqB,IAE1D,QAAQ,aAAa,EACrB,SAAS,yBAAyB,KACjC,aAAa,CAajB"}
1
+ {"version":3,"file":"with-react.d.ts","sourceRoot":"","sources":["../../../../packages/react/plugins/with-react.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,KAAK,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAK7E,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AACD,MAAM,WAAW,gBAAiB,SAAQ,cAAc;IACtD;;;SAGK;IACL,IAAI,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,aAAa,GAAE,gBAAqB,IAE1D,QAAQ,aAAa,EACrB,SAAS,yBAAyB,KACjC,aAAa,CAajB"}
@@ -14,7 +14,7 @@ function withReact(pluginOptions = {}) {
14
14
  return config;
15
15
  // Apply web config for CSS, JSX, index.html handling, etc.
16
16
  config = withWeb(pluginOptions)(config, context);
17
- (0, apply_react_config_1.applyReactConfig)({}, config);
17
+ (0, apply_react_config_1.applyReactConfig)(pluginOptions, config);
18
18
  processed.add(config);
19
19
  return config;
20
20
  };
@@ -6,6 +6,7 @@ const { join } = require('path');
6
6
  module.exports = {
7
7
  output: {
8
8
  path: join(__dirname, '<%= webpackPluginOptions.outputPath %>'),
9
+ clean: true,
9
10
  },
10
11
  devServer: {
11
12
  port: <%= port %>,
@@ -49,6 +50,7 @@ module.exports = composePlugins(
49
50
  (config) => {
50
51
  // Update the webpack config as needed here.
51
52
  // e.g. `config.plugins.push(new MyPlugin())`
53
+ config.output.clean = true;
52
54
  return config;
53
55
  }
54
56
  );
@@ -1 +1 @@
1
- {"version":3,"file":"normalize-options.d.ts","sourceRoot":"","sources":["../../../../../../../packages/react/src/generators/library/lib/normalize-options.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,IAAI,EACL,MAAM,YAAY,CAAC;AAMpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAOrD,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,gBAAgB,CAAC,CAqG3B"}
1
+ {"version":3,"file":"normalize-options.d.ts","sourceRoot":"","sources":["../../../../../../../packages/react/src/generators/library/lib/normalize-options.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,IAAI,EACL,MAAM,YAAY,CAAC;AAMpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAOrD,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,gBAAgB,CAAC,CAmG3B"}
@@ -18,9 +18,7 @@ async function normalizeOptions(host, options) {
18
18
  const addPlugin = process.env.NX_ADD_PLUGINS !== 'false' &&
19
19
  nxJson.useInferencePlugins !== false;
20
20
  options.addPlugin ??= addPlugin;
21
- const fileName = options.simpleName
22
- ? projectNames.projectSimpleName
23
- : projectNames.projectFileName;
21
+ const fileName = projectNames.projectFileName;
24
22
  const parsedTags = options.tags
25
23
  ? options.tags.split(',').map((s) => s.trim())
26
24
  : [];
@@ -1 +1 @@
1
- {"version":3,"file":"library.d.ts","sourceRoot":"","sources":["../../../../../../packages/react/src/generators/library/library.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,iBAAiB,EAOjB,IAAI,EAGL,MAAM,YAAY,CAAC;AAiCpB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,8BAMhE;AAED,wBAAsB,wBAAwB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,8BA6RxE;AAED,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"library.d.ts","sourceRoot":"","sources":["../../../../../../packages/react/src/generators/library/library.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,iBAAiB,EAOjB,IAAI,EAGL,MAAM,YAAY,CAAC;AAiCpB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,8BAMhE;AAED,wBAAsB,wBAAwB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,8BAsRxE;AAED,eAAe,gBAAgB,CAAC"}
@@ -47,10 +47,6 @@ async function libraryGeneratorInternal(host, schema) {
47
47
  !schema.importPath) {
48
48
  throw new Error(`For publishable libs you have to provide a proper "--importPath" which needs to be a valid npm package name (e.g. my-awesome-lib or @myorg/my-lib)`);
49
49
  }
50
- if (schema.simpleName !== undefined && schema.simpleName !== false) {
51
- // TODO(v22): Remove simpleName as user should be using name.
52
- devkit_1.logger.warn(`The "--simpleName" option is deprecated and will be removed in Nx 22. Please use the "--name" option to provide the exact name you want for the library.`);
53
- }
54
50
  if (!options.component) {
55
51
  options.style = 'none';
56
52
  }
@@ -25,7 +25,6 @@ export interface Schema {
25
25
  tags?: string;
26
26
  unitTestRunner?: 'jest' | 'vitest' | 'none';
27
27
  minimal?: boolean;
28
- simpleName?: boolean;
29
28
  addPlugin?: boolean;
30
29
  useProjectJson?: boolean;
31
30
  }
@@ -186,12 +186,6 @@
186
186
  "type": "boolean",
187
187
  "default": false
188
188
  },
189
- "simpleName": {
190
- "description": "Don't include the directory in the name of the module of the library.",
191
- "type": "boolean",
192
- "default": false,
193
- "x-deprecated": "Use the --name option to provide the exact name instead. This option will be removed in Nx 22."
194
- },
195
189
  "useProjectJson": {
196
190
  "type": "boolean",
197
191
  "description": "Use a `project.json` configuration file instead of inlining the Nx configuration in the `package.json` file."
@@ -1,3 +0,0 @@
1
- import { type Tree } from '@nx/devkit';
2
- export default function addSvgrToWebpackConfig(tree: Tree): Promise<import("@nx/devkit").GeneratorCallback>;
3
- //# sourceMappingURL=add-svgr-to-webpack-config.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"add-svgr-to-webpack-config.d.ts","sourceRoot":"","sources":["../../../../../../packages/react/src/migrations/update-22-0-0/add-svgr-to-webpack-config.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,IAAI,EAOV,MAAM,YAAY,CAAC;AAuGpB,wBAA8B,sBAAsB,CAAC,IAAI,EAAE,IAAI,mDA+X9D"}
@@ -1,403 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = addSvgrToWebpackConfig;
4
- const devkit_1 = require("@nx/devkit");
5
- const executor_options_utils_1 = require("@nx/devkit/src/generators/executor-options-utils");
6
- const tsquery_1 = require("@phenomnomnominal/tsquery");
7
- const ts = require("typescript");
8
- const withSvgrFunctionForWithReact = `
9
-
10
- // SVGR support function (migrated from svgr option in withReact/NxReactWebpackPlugin)
11
- function withSvgr(svgrOptions = {}) {
12
- const defaultOptions = {
13
- svgo: false,
14
- titleProp: true,
15
- ref: true,
16
- };
17
-
18
- const options = { ...defaultOptions, ...svgrOptions };
19
-
20
- return function configure(config) {
21
- // Remove existing SVG loader if present
22
- const svgLoaderIdx = config.module.rules.findIndex(
23
- (rule) =>
24
- typeof rule === 'object' &&
25
- typeof rule.test !== 'undefined' &&
26
- rule.test.toString().includes('svg')
27
- );
28
-
29
- if (svgLoaderIdx !== -1) {
30
- config.module.rules.splice(svgLoaderIdx, 1);
31
- }
32
-
33
- // Add SVGR loader
34
- config.module.rules.push({
35
- test: /\\.svg$/,
36
- issuer: /\\.(js|ts|md)x?$/,
37
- use: [
38
- {
39
- loader: require.resolve('@svgr/webpack'),
40
- options,
41
- },
42
- {
43
- loader: require.resolve('file-loader'),
44
- options: {
45
- name: '[name].[hash].[ext]',
46
- },
47
- },
48
- ],
49
- });
50
-
51
- return config;
52
- };
53
- }
54
- `;
55
- const withSvgrFunctionForNxReactWebpackPlugin = `
56
-
57
- // SVGR support function (migrated from svgr option in withReact/NxReactWebpackPlugin)
58
- function withSvgr(svgrOptions = {}) {
59
- const defaultOptions = {
60
- svgo: false,
61
- titleProp: true,
62
- ref: true,
63
- };
64
-
65
- const options = { ...defaultOptions, ...svgrOptions };
66
-
67
- return (config) => {
68
- config.plugins.push({
69
- apply: (compiler) => {
70
- // Remove ALL existing SVG loaders
71
- compiler.options.module.rules = compiler.options.module.rules.filter(
72
- (rule) =>
73
- !(
74
- rule &&
75
- typeof rule === 'object' &&
76
- rule.test &&
77
- rule.test.toString().includes('svg')
78
- )
79
- );
80
-
81
- // Add SVGR loader with both default and named exports
82
- compiler.options.module.rules.push({
83
- test: /\.svg$/,
84
- issuer: /\.[jt]sx?$/,
85
- use: [
86
- {
87
- loader: require.resolve('@svgr/webpack'),
88
- options,
89
- },
90
- {
91
- loader: require.resolve('file-loader'),
92
- options: {
93
- name: '[name].[hash].[ext]',
94
- },
95
- },
96
- ],
97
- });
98
- },
99
- });
100
- return config;
101
- };
102
- }
103
- `;
104
- async function addSvgrToWebpackConfig(tree) {
105
- const projects = new Map();
106
- // Find all React webpack projects using either withReact OR NxReactWebpackPlugin
107
- (0, executor_options_utils_1.forEachExecutorOptions)(tree, '@nx/webpack:webpack', (options, project, target) => {
108
- if (!options.webpackConfig)
109
- return;
110
- const webpackConfigPath = options.webpackConfig;
111
- if (!tree.exists(webpackConfigPath))
112
- return;
113
- const content = tree.read(webpackConfigPath, 'utf-8');
114
- const ast = tsquery_1.tsquery.ast(content);
115
- // Check if this is a withReact setup
116
- if (content.includes('withReact')) {
117
- const withReactCalls = (0, tsquery_1.tsquery)(ast, 'CallExpression[expression.name=withReact]');
118
- if (withReactCalls.length > 0) {
119
- const callExpr = withReactCalls[0];
120
- if (callExpr.arguments.length === 0)
121
- return;
122
- const arg = callExpr.arguments[0];
123
- if (!ts.isObjectLiteralExpression(arg))
124
- return;
125
- const svgrProp = arg.properties.find((prop) => ts.isPropertyAssignment(prop) &&
126
- ts.isIdentifier(prop.name) &&
127
- prop.name.text === 'svgr');
128
- if (svgrProp) {
129
- let svgrValue;
130
- if (ts.isObjectLiteralExpression(svgrProp.initializer)) {
131
- svgrValue = {};
132
- for (const prop of svgrProp.initializer.properties) {
133
- if (!ts.isPropertyAssignment(prop))
134
- continue;
135
- if (!ts.isIdentifier(prop.name))
136
- continue;
137
- const key = prop.name.text;
138
- if (prop.initializer.kind === ts.SyntaxKind.TrueKeyword) {
139
- svgrValue[key] = true;
140
- }
141
- else if (prop.initializer.kind === ts.SyntaxKind.FalseKeyword) {
142
- svgrValue[key] = false;
143
- }
144
- }
145
- }
146
- else {
147
- svgrValue =
148
- svgrProp.initializer.kind === ts.SyntaxKind.TrueKeyword;
149
- }
150
- projects.set(webpackConfigPath, {
151
- svgrOptions: svgrValue,
152
- isWithReact: true,
153
- });
154
- }
155
- }
156
- }
157
- // Otherwise check if this is NxReactWebpackPlugin setup
158
- else if (content.includes('NxReactWebpackPlugin')) {
159
- const pluginCalls = (0, tsquery_1.tsquery)(ast, 'NewExpression[expression.name=NxReactWebpackPlugin]');
160
- if (pluginCalls.length > 0) {
161
- const newExpr = pluginCalls[0];
162
- if (!newExpr.arguments || newExpr.arguments.length === 0)
163
- return;
164
- const arg = newExpr.arguments[0];
165
- if (!ts.isObjectLiteralExpression(arg))
166
- return;
167
- const svgrProp = arg.properties.find((prop) => ts.isPropertyAssignment(prop) &&
168
- ts.isIdentifier(prop.name) &&
169
- prop.name.text === 'svgr');
170
- if (svgrProp) {
171
- let svgrValue;
172
- if (ts.isObjectLiteralExpression(svgrProp.initializer)) {
173
- svgrValue = {};
174
- for (const prop of svgrProp.initializer.properties) {
175
- if (!ts.isPropertyAssignment(prop))
176
- continue;
177
- if (!ts.isIdentifier(prop.name))
178
- continue;
179
- const key = prop.name.text;
180
- if (prop.initializer.kind === ts.SyntaxKind.TrueKeyword) {
181
- svgrValue[key] = true;
182
- }
183
- else if (prop.initializer.kind === ts.SyntaxKind.FalseKeyword) {
184
- svgrValue[key] = false;
185
- }
186
- }
187
- }
188
- else if (svgrProp.initializer.kind === ts.SyntaxKind.TrueKeyword) {
189
- svgrValue = true;
190
- }
191
- else if (svgrProp.initializer.kind === ts.SyntaxKind.FalseKeyword) {
192
- svgrValue = false;
193
- }
194
- // Add to projects if svgr is explicitly set
195
- if (svgrValue !== undefined) {
196
- projects.set(webpackConfigPath, {
197
- svgrOptions: svgrValue,
198
- isWithReact: false,
199
- });
200
- }
201
- }
202
- }
203
- }
204
- });
205
- if (projects.size === 0)
206
- return;
207
- // Update webpack configs to add withSvgr function inline
208
- for (const [webpackConfigPath, config] of projects.entries()) {
209
- let content = tree.read(webpackConfigPath, 'utf-8');
210
- const ast = tsquery_1.tsquery.ast(content);
211
- const changes = [];
212
- // Build the svgr options for this specific config
213
- let svgrOptionsStr = '';
214
- if (config.svgrOptions) {
215
- const importStatements = (0, tsquery_1.tsquery)(ast, 'ImportDeclaration');
216
- const requireStatements = (0, tsquery_1.tsquery)(ast, 'VariableStatement:has(CallExpression[expression.name=require])');
217
- const allImportRequires = [
218
- ...importStatements,
219
- ...requireStatements,
220
- ].sort((a, b) => a.getEnd() - b.getEnd());
221
- const lastImportOrRequire = allImportRequires[allImportRequires.length - 1];
222
- if (config.svgrOptions === true || config.svgrOptions === undefined) {
223
- svgrOptionsStr = '';
224
- }
225
- else if (typeof config.svgrOptions === 'object') {
226
- const options = Object.entries(config.svgrOptions)
227
- .map(([key, value]) => ` ${key}: ${value}`)
228
- .join(',\n');
229
- svgrOptionsStr = `{\n${options}\n}`;
230
- }
231
- if (lastImportOrRequire) {
232
- changes.push({
233
- type: devkit_1.ChangeType.Insert,
234
- index: lastImportOrRequire.getEnd(),
235
- text: config.isWithReact
236
- ? withSvgrFunctionForWithReact
237
- : withSvgrFunctionForNxReactWebpackPlugin,
238
- });
239
- }
240
- else {
241
- changes.push({
242
- type: devkit_1.ChangeType.Insert,
243
- index: 0,
244
- text: (config.isWithReact
245
- ? withSvgrFunctionForWithReact
246
- : withSvgrFunctionForNxReactWebpackPlugin) + '\n',
247
- });
248
- }
249
- }
250
- // Remove svgr option based on the style (withReact OR NxReactWebpackPlugin)
251
- if (config.isWithReact) {
252
- // Remove svgr option from first withReact call (only one expected)
253
- const withReactCalls = (0, tsquery_1.tsquery)(ast, 'CallExpression[expression.name=withReact]');
254
- if (withReactCalls.length > 0) {
255
- const callExpr = withReactCalls[0];
256
- if (callExpr.arguments.length > 0) {
257
- const arg = callExpr.arguments[0];
258
- if (ts.isObjectLiteralExpression(arg)) {
259
- const svgrProp = arg.properties.find((prop) => ts.isPropertyAssignment(prop) &&
260
- ts.isIdentifier(prop.name) &&
261
- prop.name.text === 'svgr');
262
- if (svgrProp) {
263
- changes.push({
264
- type: devkit_1.ChangeType.Delete,
265
- start: arg.getStart(),
266
- length: arg.getEnd() - arg.getStart(),
267
- });
268
- if (config.svgrOptions) {
269
- const composePluginsCalls = (0, tsquery_1.tsquery)(ast, 'CallExpression[expression.name=composePlugins]');
270
- if (composePluginsCalls.length > 0) {
271
- const composeCall = composePluginsCalls[0];
272
- let svgrCallStr = '';
273
- if (config.svgrOptions === true ||
274
- config.svgrOptions === undefined) {
275
- svgrCallStr = 'withSvgr()';
276
- }
277
- else if (typeof config.svgrOptions === 'object') {
278
- svgrCallStr = `withSvgr(${svgrOptionsStr})`;
279
- }
280
- const withReactIdx = composeCall.arguments.findIndex((arg) => arg.getText().includes('withReact'));
281
- // Insert withSvgr as the last argument before the closing paren
282
- const argToInsertAfter = composeCall.arguments[withReactIdx];
283
- if (argToInsertAfter) {
284
- changes.push({
285
- type: devkit_1.ChangeType.Insert,
286
- index: argToInsertAfter.getEnd(),
287
- text: `, ${svgrCallStr}`,
288
- });
289
- }
290
- }
291
- }
292
- }
293
- }
294
- }
295
- }
296
- }
297
- else {
298
- // Remove svgr option from first NxReactWebpackPlugin call
299
- const pluginCalls = (0, tsquery_1.tsquery)(ast, 'NewExpression[expression.name=NxReactWebpackPlugin]');
300
- if (pluginCalls.length > 0) {
301
- const newExpr = pluginCalls[0];
302
- if (newExpr.arguments && newExpr.arguments.length > 0) {
303
- const arg = newExpr.arguments[0];
304
- if (ts.isObjectLiteralExpression(arg)) {
305
- const svgrProp = arg.properties.find((prop) => ts.isPropertyAssignment(prop) &&
306
- ts.isIdentifier(prop.name) &&
307
- prop.name.text === 'svgr');
308
- if (svgrProp) {
309
- const hasOnlySvgrProperty = arg.properties.length === 1;
310
- // Replace entire object argument with empty parentheses when only svgr property exists
311
- if (hasOnlySvgrProperty) {
312
- changes.push({
313
- type: devkit_1.ChangeType.Delete,
314
- start: arg.getStart(),
315
- length: arg.getEnd() - arg.getStart(),
316
- });
317
- }
318
- // If more properties exist, just remove the svgr property
319
- else {
320
- const propIndex = arg.properties.indexOf(svgrProp);
321
- const isLastProp = propIndex === arg.properties.length - 1;
322
- const isFirstProp = propIndex === 0;
323
- let removeStart = svgrProp.getFullStart();
324
- let removeEnd = svgrProp.getEnd();
325
- if (!isLastProp) {
326
- const nextProp = arg.properties[propIndex + 1];
327
- removeEnd = nextProp.getFullStart();
328
- }
329
- else if (!isFirstProp) {
330
- const prevProp = arg.properties[propIndex - 1];
331
- const textBetween = content.substring(prevProp.getEnd(), svgrProp.getFullStart());
332
- const commaIndex = textBetween.indexOf(',');
333
- if (commaIndex !== -1) {
334
- removeStart = prevProp.getEnd() + commaIndex;
335
- }
336
- }
337
- changes.push({
338
- type: devkit_1.ChangeType.Delete,
339
- start: removeStart,
340
- length: removeEnd - removeStart,
341
- });
342
- }
343
- }
344
- }
345
- }
346
- }
347
- // For NxReactWebpackPlugin style, wrap the entire module.exports or export default with withSvgr
348
- if (config.svgrOptions) {
349
- const allAssignments = (0, tsquery_1.tsquery)(ast, 'BinaryExpression');
350
- // Find the one that has module.exports on the left side
351
- const moduleExportsAssignment = allAssignments.find((node) => {
352
- const binaryExpr = node;
353
- const left = binaryExpr.left;
354
- return (ts.isPropertyAccessExpression(left) &&
355
- ts.isIdentifier(left.expression) &&
356
- left.expression.text === 'module' &&
357
- ts.isIdentifier(left.name) &&
358
- left.name.text === 'exports');
359
- });
360
- // Also check for export default
361
- const exportDefaultStatements = (0, tsquery_1.tsquery)(ast, 'ExportAssignment');
362
- const exportDefaultStatement = exportDefaultStatements[0];
363
- // Use whichever export style is found
364
- let exportValue;
365
- if (moduleExportsAssignment) {
366
- exportValue = moduleExportsAssignment.right;
367
- }
368
- else if (exportDefaultStatement) {
369
- exportValue = exportDefaultStatement.expression;
370
- }
371
- if (exportValue) {
372
- let svgrCallStr = '';
373
- if (config.svgrOptions === true || config.svgrOptions === undefined) {
374
- svgrCallStr = 'withSvgr()';
375
- }
376
- else if (typeof config.svgrOptions === 'object') {
377
- const options = Object.entries(config.svgrOptions)
378
- .map(([key, value]) => ` ${key}: ${value}`)
379
- .join(',\n');
380
- svgrCallStr = `withSvgr({\n${options}\n})`;
381
- }
382
- changes.push({
383
- type: devkit_1.ChangeType.Insert,
384
- index: exportValue.getStart(),
385
- text: `${svgrCallStr}(`,
386
- });
387
- changes.push({
388
- type: devkit_1.ChangeType.Insert,
389
- index: exportValue.getEnd(),
390
- text: ')',
391
- });
392
- }
393
- }
394
- }
395
- content = (0, devkit_1.applyChangesToString)(content, changes);
396
- tree.write(webpackConfigPath, content);
397
- }
398
- await (0, devkit_1.formatFiles)(tree);
399
- // Add file-loader as a dev dependency since it's now required for SVGR
400
- return (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
401
- 'file-loader': '^6.2.0',
402
- });
403
- }