@nx/webpack 24.0.0-beta.2 → 24.0.0-beta.4

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.
Files changed (61) hide show
  1. package/dist/index.d.ts +0 -1
  2. package/dist/index.js +0 -1
  3. package/dist/internal.d.ts +3 -0
  4. package/dist/internal.js +7 -1
  5. package/dist/ready-check.d.ts +1 -0
  6. package/dist/ready-check.js +9 -0
  7. package/dist/ready-signal.d.ts +1 -0
  8. package/dist/ready-signal.js +5 -0
  9. package/dist/src/executors/dev-server/dev-server.impl.js +38 -30
  10. package/dist/src/generators/configuration/configuration.js +14 -132
  11. package/dist/src/generators/configuration/schema.d.ts +0 -1
  12. package/dist/src/generators/convert-config-to-webpack-plugin/convert-config-to-webpack-plugin.js +82 -49
  13. package/dist/src/generators/convert-config-to-webpack-plugin/lib/extract-webpack-options.d.ts +1 -0
  14. package/dist/src/generators/convert-config-to-webpack-plugin/lib/extract-webpack-options.js +31 -2
  15. package/dist/src/generators/convert-config-to-webpack-plugin/schema.json +2 -2
  16. package/dist/src/generators/convert-to-inferred/convert-to-inferred.js +5 -4
  17. package/dist/src/generators/convert-to-inferred/utils/build-post-target-transformer.js +13 -5
  18. package/dist/src/generators/convert-to-inferred/utils/serve-post-target-transformer.js +8 -14
  19. package/dist/src/generators/init/init.js +45 -54
  20. package/dist/src/generators/init/schema.d.ts +0 -1
  21. package/dist/src/migrations/update-24-0-0/finish-inferred-conversion.md +11 -0
  22. package/dist/src/migrations/update-24-0-0/inventory.d.ts +9 -0
  23. package/dist/src/migrations/update-24-0-0/inventory.js +53 -0
  24. package/dist/src/migrations/update-24-0-0/migrate-compose-plugins.d.ts +10 -0
  25. package/dist/src/migrations/update-24-0-0/migrate-compose-plugins.js +60 -0
  26. package/dist/src/migrations/update-24-0-0/migrate-compose-plugins.md +98 -0
  27. package/dist/src/migrations/update-24-0-0/remove-deprecated-executors.d.ts +6 -0
  28. package/dist/src/migrations/update-24-0-0/remove-deprecated-executors.js +36 -0
  29. package/dist/src/migrations/update-24-0-0/remove-deprecated-executors.md +92 -0
  30. package/dist/src/plugins/nx-webpack-plugin/lib/normalize-options.d.ts +6 -0
  31. package/dist/src/plugins/nx-webpack-plugin/lib/normalize-options.js +29 -24
  32. package/dist/src/plugins/nx-webpack-plugin/nx-app-webpack-plugin.d.ts +2 -0
  33. package/dist/src/plugins/nx-webpack-plugin/nx-app-webpack-plugin.js +18 -1
  34. package/dist/src/plugins/plugin.js +24 -0
  35. package/dist/src/plugins/use-legacy-nx-plugin/use-legacy-nx-plugin.js +3 -0
  36. package/dist/src/utils/config.d.ts +8 -12
  37. package/dist/src/utils/config.js +15 -68
  38. package/dist/src/utils/deprecation.d.ts +1 -6
  39. package/dist/src/utils/deprecation.js +4 -27
  40. package/dist/src/utils/dev-server-ready-check.d.ts +48 -0
  41. package/dist/src/utils/dev-server-ready-check.js +325 -0
  42. package/dist/src/utils/dev-server-ready-signal.d.ts +29 -0
  43. package/dist/src/utils/dev-server-ready-signal.js +60 -0
  44. package/dist/src/utils/e2e-web-server-info-utils.d.ts +1 -1
  45. package/dist/src/utils/e2e-web-server-info-utils.js +2 -2
  46. package/dist/src/utils/webpack/read-webpack-options.d.ts +1 -1
  47. package/dist/src/utils/webpack/read-webpack-options.js +4 -4
  48. package/dist/src/utils/with-nx.d.ts +5 -9
  49. package/dist/src/utils/with-nx.js +5 -32
  50. package/dist/src/utils/with-web.d.ts +5 -9
  51. package/dist/src/utils/with-web.js +5 -24
  52. package/executors.json +0 -10
  53. package/migrations.json +13 -0
  54. package/package.json +20 -4
  55. package/dist/src/executors/webpack/lib/run-webpack.d.ts +0 -3
  56. package/dist/src/executors/webpack/lib/run-webpack.js +0 -36
  57. package/dist/src/executors/webpack/schema.json +0 -459
  58. package/dist/src/executors/webpack/webpack.impl.d.ts +0 -13
  59. package/dist/src/executors/webpack/webpack.impl.js +0 -117
  60. package/dist/src/utils/has-plugin.d.ts +0 -2
  61. package/dist/src/utils/has-plugin.js +0 -10
package/dist/index.d.ts CHANGED
@@ -14,7 +14,6 @@ export type { WebDevServerOptions } from './src/executors/dev-server/schema';
14
14
  export * from './src/executors/dev-server/dev-server.impl';
15
15
  export * from './src/executors/webpack/lib/normalize-options';
16
16
  export type { WebpackExecutorOptions, NormalizedWebpackExecutorOptions, AssetGlobPattern, FileReplacement, } from './src/executors/webpack/schema';
17
- export * from './src/executors/webpack/webpack.impl';
18
17
  export * from './src/utils/get-css-module-local-ident';
19
18
  export * from './src/utils/with-nx';
20
19
  export * from './src/utils/with-web';
package/dist/index.js CHANGED
@@ -26,7 +26,6 @@ var init_1 = require("./src/generators/init/init");
26
26
  Object.defineProperty(exports, "webpackInitGenerator", { enumerable: true, get: function () { return init_1.webpackInitGenerator; } });
27
27
  tslib_1.__exportStar(require("./src/executors/dev-server/dev-server.impl"), exports);
28
28
  tslib_1.__exportStar(require("./src/executors/webpack/lib/normalize-options"), exports);
29
- tslib_1.__exportStar(require("./src/executors/webpack/webpack.impl"), exports);
30
29
  tslib_1.__exportStar(require("./src/utils/get-css-module-local-ident"), exports);
31
30
  tslib_1.__exportStar(require("./src/utils/with-nx"), exports);
32
31
  tslib_1.__exportStar(require("./src/utils/with-web"), exports);
@@ -6,3 +6,6 @@ export { suppressWebpackComposeHelperWarnings } from './src/utils/deprecation';
6
6
  export { WebpackNxBuildCoordinationPlugin } from './src/plugins/webpack-nx-build-coordination-plugin';
7
7
  export type { WebSsrDevServerOptions } from './src/executors/ssr-dev-server/schema';
8
8
  export { default as ssrDevServerExecutor } from './src/executors/ssr-dev-server/ssr-dev-server.impl';
9
+ export { applyBaseConfig } from './src/plugins/nx-webpack-plugin/lib/apply-base-config';
10
+ export { applyWebConfig } from './src/plugins/nx-webpack-plugin/lib/apply-web-config';
11
+ export { webpackExecutorContext } from './src/plugins/nx-webpack-plugin/lib/normalize-options';
package/dist/internal.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ssrDevServerExecutor = exports.WebpackNxBuildCoordinationPlugin = exports.suppressWebpackComposeHelperWarnings = exports.resolveUserDefinedWebpackConfig = exports.ensureDependencies = exports.deleteOutputDir = exports.findAllNodeModules = exports.findUp = void 0;
3
+ exports.webpackExecutorContext = exports.applyWebConfig = exports.applyBaseConfig = exports.ssrDevServerExecutor = exports.WebpackNxBuildCoordinationPlugin = exports.suppressWebpackComposeHelperWarnings = exports.resolveUserDefinedWebpackConfig = exports.ensureDependencies = exports.deleteOutputDir = exports.findAllNodeModules = exports.findUp = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  // Curated internal API surface for other first-party Nx plugins (e.g. @nx/react,
6
6
  // @nx/angular, @nx/web, @nx/node, @nx/next, @nx/react-native). Prefer this over
@@ -24,3 +24,9 @@ var webpack_nx_build_coordination_plugin_1 = require("./src/plugins/webpack-nx-b
24
24
  Object.defineProperty(exports, "WebpackNxBuildCoordinationPlugin", { enumerable: true, get: function () { return webpack_nx_build_coordination_plugin_1.WebpackNxBuildCoordinationPlugin; } });
25
25
  var ssr_dev_server_impl_1 = require("./src/executors/ssr-dev-server/ssr-dev-server.impl");
26
26
  Object.defineProperty(exports, "ssrDevServerExecutor", { enumerable: true, get: function () { return tslib_1.__importDefault(ssr_dev_server_impl_1).default; } });
27
+ var apply_base_config_1 = require("./src/plugins/nx-webpack-plugin/lib/apply-base-config");
28
+ Object.defineProperty(exports, "applyBaseConfig", { enumerable: true, get: function () { return apply_base_config_1.applyBaseConfig; } });
29
+ var apply_web_config_1 = require("./src/plugins/nx-webpack-plugin/lib/apply-web-config");
30
+ Object.defineProperty(exports, "applyWebConfig", { enumerable: true, get: function () { return apply_web_config_1.applyWebConfig; } });
31
+ var normalize_options_1 = require("./src/plugins/nx-webpack-plugin/lib/normalize-options");
32
+ Object.defineProperty(exports, "webpackExecutorContext", { enumerable: true, get: function () { return normalize_options_1.webpackExecutorContext; } });
@@ -0,0 +1 @@
1
+ export declare function waitForDevServer(configPath: string): Promise<void>;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.waitForDevServer = waitForDevServer;
4
+ const dev_server_ready_check_1 = require("./src/utils/dev-server-ready-check");
5
+ // The config can leave handles open, such as a type checker's workers
6
+ async function waitForDevServer(configPath) {
7
+ await (0, dev_server_ready_check_1.waitForWebpackDevServer)(configPath);
8
+ process.exit(0);
9
+ }
@@ -0,0 +1 @@
1
+ export { NxReadySignalPlugin } from './src/utils/dev-server-ready-signal';
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NxReadySignalPlugin = void 0;
4
+ var dev_server_ready_signal_1 = require("./src/utils/dev-server-ready-signal");
5
+ Object.defineProperty(exports, "NxReadySignalPlugin", { enumerable: true, get: function () { return dev_server_ready_signal_1.NxReadySignalPlugin; } });
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.devServerExecutor = devServerExecutor;
4
+ const normalize_options_1 = require("../../plugins/nx-webpack-plugin/lib/normalize-options");
4
5
  const internal_1 = require("@nx/devkit/internal");
5
6
  const devkit_1 = require("@nx/devkit");
6
7
  const operators_1 = require("rxjs/operators");
@@ -8,16 +9,15 @@ const get_dev_server_config_1 = require("./lib/get-dev-server-config");
8
9
  const internal_2 = require("@nx/js/internal");
9
10
  const run_webpack_1 = require("../../utils/run-webpack");
10
11
  const resolve_user_defined_webpack_config_1 = require("../../utils/webpack/resolve-user-defined-webpack-config");
11
- const deprecation_1 = require("../../utils/deprecation");
12
- const normalize_options_1 = require("../webpack/lib/normalize-options");
12
+ const normalize_options_2 = require("../webpack/lib/normalize-options");
13
13
  const config_1 = require("../../utils/config");
14
14
  const js_1 = require("@nx/js");
15
15
  async function* devServerExecutor(serveOptions, context) {
16
- (0, deprecation_1.warnWebpackDevServerExecutorDeprecation)();
17
16
  // Default to dev mode so builds are faster and HMR mode works better.
18
17
  process.env.NODE_ENV ??= 'development';
19
18
  const { root: projectRoot, sourceRoot } = context.projectsConfigurations.projects[context.projectName];
20
- const buildOptions = (0, normalize_options_1.normalizeOptions)(getBuildOptions(serveOptions, context), context.root, projectRoot, sourceRoot);
19
+ const executorOptions = getBuildOptions(serveOptions, context);
20
+ const buildOptions = (0, normalize_options_2.normalizeOptions)(executorOptions, context.root, projectRoot, sourceRoot);
21
21
  process.env.NX_BUILD_LIBS_FROM_SOURCE = `${buildOptions.buildLibsFromSource}`;
22
22
  process.env.NX_BUILD_TARGET = serveOptions.buildTarget;
23
23
  // TODO(jack): Figure out a way to port this into NxWebpackPlugin
@@ -29,37 +29,45 @@ async function* devServerExecutor(serveOptions, context) {
29
29
  context.configurationName);
30
30
  buildOptions.tsConfig = (0, internal_2.createTmpTsConfig)(buildOptions.tsConfig, context.root, target.data.root, dependencies);
31
31
  process.env.NX_TSCONFIG_PATH = buildOptions.tsConfig;
32
+ executorOptions.tsConfig = buildOptions.tsConfig;
32
33
  }
33
- let config;
34
34
  const devServer = (0, get_dev_server_config_1.getDevServerOptions)(context.root, serveOptions, buildOptions);
35
- if (buildOptions.webpackConfig) {
36
- let userDefinedWebpackConfig = (0, resolve_user_defined_webpack_config_1.resolveUserDefinedWebpackConfig)(buildOptions.webpackConfig, (0, js_1.getRootTsConfigPath)());
37
- if (typeof userDefinedWebpackConfig.then === 'function') {
38
- userDefinedWebpackConfig = await userDefinedWebpackConfig;
39
- }
40
- // Only add the dev server option if user is composable plugin.
41
- // Otherwise, user should define `devServer` option directly in their webpack config.
42
- if (typeof userDefinedWebpackConfig === 'function' &&
43
- ((0, config_1.isNxWebpackComposablePlugin)(userDefinedWebpackConfig) ||
44
- !buildOptions.standardWebpackConfigFunction)) {
45
- config = await userDefinedWebpackConfig({ devServer }, {
46
- options: buildOptions,
47
- context,
48
- configuration: serveOptions.buildTarget.split(':')[2],
49
- });
50
- }
51
- else if (userDefinedWebpackConfig) {
52
- // New behavior, we want the webpack config to export object
53
- // If the config is a function, we assume it's a standard webpack config function and it's async
54
- if (typeof userDefinedWebpackConfig === 'function') {
55
- config = await userDefinedWebpackConfig(process.env.NODE_ENV, {});
35
+ const config = await normalize_options_1.webpackExecutorContext.run({
36
+ options: executorOptions,
37
+ target: (0, devkit_1.parseTargetString)(serveOptions.buildTarget, context.projectGraph),
38
+ }, async () => {
39
+ let config;
40
+ if (buildOptions.webpackConfig) {
41
+ let userDefinedWebpackConfig = (0, resolve_user_defined_webpack_config_1.resolveUserDefinedWebpackConfig)(buildOptions.webpackConfig, (0, js_1.getRootTsConfigPath)());
42
+ if (typeof userDefinedWebpackConfig.then === 'function') {
43
+ userDefinedWebpackConfig = await userDefinedWebpackConfig;
56
44
  }
57
- else {
58
- config = userDefinedWebpackConfig;
45
+ // Legacy config functions receive the dev server options as their input config.
46
+ if (typeof userDefinedWebpackConfig === 'function' &&
47
+ ((0, config_1.isNxWebpackComposablePlugin)(userDefinedWebpackConfig) ||
48
+ !buildOptions.standardWebpackConfigFunction)) {
49
+ config = await userDefinedWebpackConfig({ devServer }, {
50
+ options: buildOptions,
51
+ context,
52
+ configuration: serveOptions.buildTarget.split(':')[2],
53
+ });
59
54
  }
60
- config.devServer ??= devServer;
55
+ else if (userDefinedWebpackConfig) {
56
+ // New behavior, we want the webpack config to export object
57
+ // If the config is a function, we assume it's a standard webpack config function and it's async
58
+ if (typeof userDefinedWebpackConfig === 'function') {
59
+ config = await userDefinedWebpackConfig(process.env.NODE_ENV, {});
60
+ }
61
+ else {
62
+ config = userDefinedWebpackConfig;
63
+ }
64
+ }
65
+ // Configs that ignore their arguments still get the target's dev server options.
66
+ if (config)
67
+ config.devServer ??= devServer;
61
68
  }
62
- }
69
+ return config;
70
+ });
63
71
  // Lazy-loaded: optional peers absent during project-graph discovery.
64
72
  const webpack = require('webpack');
65
73
  const WebpackDevServer = require('webpack-dev-server');
@@ -2,24 +2,16 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.configurationGenerator = configurationGenerator;
4
4
  exports.configurationGeneratorInternal = configurationGeneratorInternal;
5
- const internal_1 = require("@nx/devkit/internal");
6
5
  const devkit_1 = require("@nx/devkit");
7
6
  const init_1 = require("../init/init");
8
- const has_plugin_1 = require("../../utils/has-plugin");
9
- const deprecation_1 = require("../../utils/deprecation");
10
- const internal_2 = require("@nx/js/internal");
11
7
  const ensure_dependencies_1 = require("../../utils/ensure-dependencies");
12
8
  const versions_1 = require("../../utils/versions");
13
9
  function configurationGenerator(tree, options) {
14
- return configurationGeneratorInternal(tree, { addPlugin: false, ...options });
10
+ return configurationGeneratorInternal(tree, options);
15
11
  }
16
12
  async function configurationGeneratorInternal(tree, options) {
17
13
  (0, versions_1.assertSupportedWebpackVersion)(tree);
18
14
  const tasks = [];
19
- const nxJson = (0, devkit_1.readNxJson)(tree);
20
- const addPluginDefault = process.env.NX_ADD_PLUGINS !== 'false' &&
21
- nxJson.useInferencePlugins !== false;
22
- options.addPlugin ??= addPluginDefault;
23
15
  const initTask = await (0, init_1.webpackInitGenerator)(tree, {
24
16
  ...options,
25
17
  skipFormat: true,
@@ -30,13 +22,6 @@ async function configurationGeneratorInternal(tree, options) {
30
22
  });
31
23
  tasks.push(depsTask);
32
24
  checkForTargetConflicts(tree, options);
33
- if (!(0, has_plugin_1.hasPlugin)(tree)) {
34
- (0, deprecation_1.warnWebpackExecutorGenerating)();
35
- addBuildTarget(tree, options);
36
- if (options.devServer) {
37
- addServeTarget(tree, options);
38
- }
39
- }
40
25
  createWebpackConfig(tree, options);
41
26
  if (!options.skipFormat) {
42
27
  await (0, devkit_1.formatFiles)(tree);
@@ -64,42 +49,16 @@ function createWebpackConfig(tree, options) {
64
49
  tsConfig: options.tsConfig ?? (0, devkit_1.joinPathFragments)(project.root, 'tsconfig.app.json'),
65
50
  webpackConfig: (0, devkit_1.joinPathFragments)(project.root, 'webpack.config.js'),
66
51
  };
67
- if (options.target === 'web') {
68
- tree.write((0, devkit_1.joinPathFragments)(project.root, 'webpack.config.js'), (0, has_plugin_1.hasPlugin)(tree)
69
- ? `
70
- const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
71
- const { join } = require('path');
72
-
73
- module.exports = {
74
- output: {
75
- path: join(__dirname, '${(0, devkit_1.offsetFromRoot)(project.root)}${buildOptions.outputPath}'),
76
- },
77
- plugins: [
78
- new NxAppWebpackPlugin({
79
- target: '${buildOptions.target}',
80
- tsConfig: '${buildOptions.tsConfig}',
81
- compiler: '${buildOptions.compiler}',
82
- main: '${buildOptions.main}',
83
- outputHashing: '${buildOptions.target !== 'web' ? 'none' : 'all'}',
84
- })
85
- ],
86
- }
87
- `
88
- : `
89
- const { composePlugins, withNx, withWeb } = require('@nx/webpack');
90
-
91
- // Nx plugins for webpack.
92
- module.exports = composePlugins(withNx(), withWeb(), (config) => {
93
- // Update the webpack config as needed here.
94
- // e.g. \`config.plugins.push(new MyPlugin())\`
95
- config.output.clean = true;
96
- return config;
97
- });
98
- `);
52
+ if (options.babelConfig) {
53
+ buildOptions.babelConfig = options.babelConfig;
54
+ }
55
+ else if (options.compiler === 'babel') {
56
+ // Without a config file babel-loader looks for <projectRoot>/.babelrc and the build fails.
57
+ (0, devkit_1.writeJson)(tree, (0, devkit_1.joinPathFragments)(project.root, '.babelrc'), {
58
+ presets: ['@nx/js/babel'],
59
+ });
99
60
  }
100
- else {
101
- tree.write((0, devkit_1.joinPathFragments)(project.root, 'webpack.config.js'), (0, has_plugin_1.hasPlugin)(tree)
102
- ? `
61
+ tree.write((0, devkit_1.joinPathFragments)(project.root, 'webpack.config.js'), `
103
62
  const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
104
63
  const { join } = require('path');
105
64
 
@@ -111,92 +70,15 @@ module.exports = {
111
70
  new NxAppWebpackPlugin({
112
71
  target: '${buildOptions.target}',
113
72
  tsConfig: '${buildOptions.tsConfig}',
114
- compiler: '${buildOptions.compiler}',
73
+ compiler: '${buildOptions.compiler}',${buildOptions.babelConfig
74
+ ? `
75
+ babelConfig: '${buildOptions.babelConfig}',`
76
+ : ''}
115
77
  main: '${buildOptions.main}',
116
78
  outputHashing: '${buildOptions.target !== 'web' ? 'none' : 'all'}',
117
79
  })
118
80
  ],
119
81
  }
120
- `
121
- : `
122
- const { composePlugins, withNx } = require('@nx/webpack');
123
-
124
- // Nx plugins for webpack.
125
- module.exports = composePlugins(withNx(), (config) => {
126
- // Update the webpack config as needed here.
127
- // e.g. \`config.plugins.push(new MyPlugin())\`
128
- config.output.clean = true;
129
- return config;
130
- });
131
82
  `);
132
- }
133
- }
134
- function addBuildTarget(tree, options) {
135
- (0, internal_1.addBuildTargetDefaults)(tree, '@nx/webpack:webpack', 'build', [
136
- internal_2.TS_SOLUTION_SETUP_TSCONFIG_INPUT,
137
- ]);
138
- const project = (0, devkit_1.readProjectConfiguration)(tree, options.project);
139
- const buildOptions = {
140
- target: options.target,
141
- outputPath: (0, devkit_1.joinPathFragments)('dist', project.root),
142
- compiler: options.compiler ?? 'swc',
143
- main: options.main ?? (0, devkit_1.joinPathFragments)(project.root, 'src/main.ts'),
144
- tsConfig: options.tsConfig ?? (0, devkit_1.joinPathFragments)(project.root, 'tsconfig.app.json'),
145
- webpackConfig: (0, devkit_1.joinPathFragments)(project.root, 'webpack.config.js'),
146
- };
147
- if (options.webpackConfig) {
148
- buildOptions.webpackConfig = options.webpackConfig;
149
- }
150
- if (options.babelConfig) {
151
- buildOptions.babelConfig = options.babelConfig;
152
- }
153
- else if (options.compiler === 'babel') {
154
- // If no babel config file is provided then write a default one, otherwise build will fail.
155
- (0, devkit_1.writeJson)(tree, (0, devkit_1.joinPathFragments)(project.root, '.babelrc'), {
156
- presets: ['@nx/js/babel'],
157
- });
158
- }
159
- (0, devkit_1.updateProjectConfiguration)(tree, options.project, {
160
- ...project,
161
- targets: {
162
- ...project.targets,
163
- build: {
164
- executor: '@nx/webpack:webpack',
165
- outputs: ['{options.outputPath}'],
166
- defaultConfiguration: 'production',
167
- options: buildOptions,
168
- configurations: {
169
- production: {
170
- optimization: true,
171
- outputHashing: options.target === 'web' ? 'all' : 'none',
172
- sourceMap: false,
173
- namedChunks: false,
174
- extractLicenses: true,
175
- vendorChunk: false,
176
- },
177
- },
178
- },
179
- },
180
- });
181
- }
182
- function addServeTarget(tree, options) {
183
- const project = (0, devkit_1.readProjectConfiguration)(tree, options.project);
184
- (0, devkit_1.updateProjectConfiguration)(tree, options.project, {
185
- ...project,
186
- targets: {
187
- ...project.targets,
188
- serve: {
189
- executor: '@nx/webpack:dev-server',
190
- options: {
191
- buildTarget: `${options.project}:build`,
192
- },
193
- configurations: {
194
- production: {
195
- buildTarget: `${options.project}:build:production`,
196
- },
197
- },
198
- },
199
- },
200
- });
201
83
  }
202
84
  exports.default = configurationGenerator;
@@ -10,5 +10,4 @@ export interface ConfigurationGeneratorSchema {
10
10
  target?: 'node' | 'web' | 'webworker';
11
11
  webpackConfig?: string;
12
12
  babelConfig?: string;
13
- addPlugin?: boolean;
14
13
  }
@@ -32,58 +32,30 @@ async function convertConfigToWebpackPluginGenerator(tree, options) {
32
32
  throw new Error(hasError);
33
33
  }
34
34
  const webpackConfigPath = currentTargetOptions?.webpackConfig || '';
35
- if (webpackConfigPath && tree.exists(webpackConfigPath)) {
36
- let { withNxConfig: webpackOptions, withReactConfig } = (0, extract_webpack_options_1.extractWebpackOptions)(tree, webpackConfigPath);
37
- // if webpackOptions === undefined
38
- // withNx was not found in the webpack.config.js file so we should skip this project
39
- if (webpackOptions !== undefined) {
40
- let parsedOptions = {};
41
- if (webpackOptions) {
42
- parsedOptions = JSON.parse(preprocessText(webpackOptions.getText()));
43
- parsedOptions = (0, normalize_path_options_1.normalizePathOptions)(project.root, parsedOptions);
44
- }
45
- target.options.standardWebpackConfigFunction = true;
46
- (0, devkit_1.updateProjectConfiguration)(tree, projectName, project);
47
- const { dir, name, ext } = (0, path_1.parse)(webpackConfigPath);
48
- tree.rename(webpackConfigPath, `${(0, devkit_1.joinPathFragments)(dir, `${name}.old${ext}`)}`);
49
- tree.write(webpackConfigPath, (0, devkit_1.stripIndents) `
50
- const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
51
- const { NxReactWebpackPlugin } = require('@nx/react/webpack-plugin');
52
- const { useLegacyNxPlugin } = require('@nx/webpack');
53
-
54
- // This file was migrated using @nx/webpack:convert-config-to-webpack-plugin from your './webpack.config.old.js'
55
- // Please check that the options here are correct as they were moved from the old webpack.config.js to this file.
56
- const options = ${webpackOptions ? JSON.stringify(parsedOptions, null, 2) : '{}'};
57
-
58
- /**
59
- * @type{import('webpack').WebpackOptionsNormalized}
60
- */
61
- module.exports = async () => ({
62
- plugins: [
63
- ${webpackOptions
64
- ? 'new NxAppWebpackPlugin(options)'
65
- : 'new NxAppWebpackPlugin()'},
66
- ${withReactConfig
67
- ? `new NxReactWebpackPlugin(${withReactConfig.getText()})`
68
- : `new NxReactWebpackPlugin({
69
- // Uncomment this line if you don't want to use SVGR
70
- // See: https://react-svgr.com/
71
- // svgr: false
72
- })`},
73
- // NOTE: useLegacyNxPlugin ensures that the non-standard Webpack configuration file previously used still works.
74
- // To remove its usage, move options such as "plugins" into this file as standard Webpack configuration options.
75
- // To enhance configurations after Nx plugins have applied, you can add a new plugin with the \`apply\` method.
76
- // e.g. \`{ apply: (compiler) => { /* modify compiler.options */ }\`
77
- // eslint-disable-next-line react-hooks/rules-of-hooks
78
- await useLegacyNxPlugin(require('./webpack.config.old${ext}'), options),
79
- ],
80
- });
81
- `);
82
- migrated++;
83
- }
35
+ if (webpackConfigPath &&
36
+ tree.exists(webpackConfigPath) &&
37
+ convertConfigFile(tree, project.root, webpackConfigPath)) {
38
+ target.options.standardWebpackConfigFunction = true;
39
+ (0, devkit_1.updateProjectConfiguration)(tree, projectName, project);
40
+ migrated++;
84
41
  }
85
42
  }
86
43
  });
44
+ // Projects already on the inference plugin keep their options in the config,
45
+ // so only the config needs converting.
46
+ for (const [projectName, project] of projects) {
47
+ if (options.project && projectName !== options.project) {
48
+ continue;
49
+ }
50
+ if (Object.values(project.targets ?? {}).some((target) => target.executor === '@nx/webpack:webpack')) {
51
+ continue;
52
+ }
53
+ const webpackConfigPath = (0, devkit_1.joinPathFragments)(project.root, 'webpack.config.js');
54
+ if (tree.exists(webpackConfigPath) &&
55
+ convertConfigFile(tree, project.root, webpackConfigPath)) {
56
+ migrated++;
57
+ }
58
+ }
87
59
  if (migrated === 0) {
88
60
  throw new Error('Could not find any projects to migrate.');
89
61
  }
@@ -91,4 +63,65 @@ async function convertConfigToWebpackPluginGenerator(tree, options) {
91
63
  await (0, devkit_1.formatFiles)(tree);
92
64
  }
93
65
  }
66
+ /** Returns whether the config used `withNx` and was converted. */
67
+ function convertConfigFile(tree, projectRoot, webpackConfigPath) {
68
+ let { withNxConfig: webpackOptions, withReactConfig, strippedSource, } = (0, extract_webpack_options_1.extractWebpackOptions)(tree, webpackConfigPath);
69
+ // if webpackOptions === undefined
70
+ // withNx was not found in the webpack.config.js file so we should skip this project
71
+ if (webpackOptions !== undefined) {
72
+ let parsedOptions = {};
73
+ if (webpackOptions) {
74
+ // Parse before writing anything: a non-literal option value leaves the
75
+ // project untouched for the migration prompt instead of a config whose
76
+ // helper calls are gone and whose options never made it across.
77
+ try {
78
+ parsedOptions = JSON.parse(preprocessText(webpackOptions.getText()));
79
+ }
80
+ catch {
81
+ throw new Error(`Could not read the \`withNx\` options in ${webpackConfigPath}. They must be a plain object literal; spreads, variables and function calls are not supported.`);
82
+ }
83
+ parsedOptions = (0, normalize_path_options_1.normalizePathOptions)(projectRoot, parsedOptions);
84
+ }
85
+ if (strippedSource !== undefined) {
86
+ tree.write(webpackConfigPath, strippedSource);
87
+ }
88
+ const { dir, name, ext } = (0, path_1.parse)(webpackConfigPath);
89
+ tree.rename(webpackConfigPath, `${(0, devkit_1.joinPathFragments)(dir, `${name}.old${ext}`)}`);
90
+ // `@nx/webpack` does not depend on `@nx/react`, so only React configs may require it.
91
+ const usesReact = withReactConfig !== undefined;
92
+ const reactRequire = usesReact
93
+ ? `\nconst { NxReactWebpackPlugin } = require('@nx/react/webpack-plugin');`
94
+ : '';
95
+ const reactPlugin = usesReact
96
+ ? `\nnew NxReactWebpackPlugin(${withReactConfig ? withReactConfig.getText() : ''}),`
97
+ : '';
98
+ tree.write(webpackConfigPath, (0, devkit_1.stripIndents) `
99
+ const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');${reactRequire}
100
+ const { useLegacyNxPlugin } = require('@nx/webpack');
101
+
102
+ // This file was migrated using @nx/webpack:convert-config-to-webpack-plugin from your './webpack.config.old.js'
103
+ // Please check that the options here are correct as they were moved from the old webpack.config.js to this file.
104
+ const options = ${webpackOptions ? JSON.stringify(parsedOptions, null, 2) : '{}'};
105
+
106
+ /**
107
+ * @type{import('webpack').WebpackOptionsNormalized}
108
+ */
109
+ module.exports = async () => ({
110
+ plugins: [
111
+ ${webpackOptions
112
+ ? 'new NxAppWebpackPlugin(options)'
113
+ : 'new NxAppWebpackPlugin()'},${reactPlugin}
114
+ // NOTE: useLegacyNxPlugin ensures that the non-standard Webpack configuration file previously used still works.
115
+ // To remove its usage, move options such as "plugins" into this file as standard Webpack configuration options.
116
+ // To enhance configurations after Nx plugins have applied, you can add a new plugin with the \`apply\` method.
117
+ // e.g. \`{ apply: (compiler) => { /* modify compiler.options */ }\`
118
+ // eslint-disable-next-line react-hooks/rules-of-hooks
119
+ await useLegacyNxPlugin(require('./webpack.config.old${ext}'), options),
120
+ ],
121
+ });
122
+ `);
123
+ return true;
124
+ }
125
+ return false;
126
+ }
94
127
  exports.default = convertConfigToWebpackPluginGenerator;
@@ -3,4 +3,5 @@ import * as ts from 'typescript';
3
3
  export declare function extractWebpackOptions(tree: Tree, webpackConfigPath: string): {
4
4
  withNxConfig: "" | ts.Node;
5
5
  withReactConfig: "" | ts.Node;
6
+ strippedSource: string;
6
7
  };
@@ -15,6 +15,9 @@ function extractWebpackOptions(tree, webpackConfigPath) {
15
15
  const withWebCall = (0, tsquery_1.query)(sourceFile, withWebQuery);
16
16
  // If the config is empty set to empty string to avoid undefined. Undefined is used to check if the withNx exists inside of the config file.
17
17
  let withNxConfig, withReactConfig;
18
+ // Returned rather than written here so the caller can reject configs whose
19
+ // options are not a plain literal before touching the file.
20
+ let strippedSource;
18
21
  withWebCall.forEach((node) => {
19
22
  const argument = node.arguments[0] || '';
20
23
  withNxConfig = argument; // Since withWeb and withNx use the same config object and both should not exist in the same file, we can reuse the withNxConfig variable.
@@ -37,9 +40,35 @@ function extractWebpackOptions(tree, webpackConfigPath) {
37
40
  updatedSource = removeImportDeclarations(updatedSource, 'withNx', '@nx/webpack');
38
41
  updatedSource = removeImportDeclarations(updatedSource, 'withWeb', '@nx/webpack');
39
42
  updatedSource = removeImportDeclarations(updatedSource, 'withReact', '@nx/react');
40
- tree.write(webpackConfigPath, updatedSource);
43
+ updatedSource = inlineComposePlugins(updatedSource);
44
+ updatedSource = removeImportDeclarations(updatedSource, 'composePlugins', '@nx/webpack');
45
+ strippedSource = updatedSource;
41
46
  }
42
- return { withNxConfig, withReactConfig };
47
+ return { withNxConfig, withReactConfig, strippedSource };
48
+ }
49
+ // `composePlugins` is an inert stub since Nx v24, so the old config composes its
50
+ // remaining callbacks with a local copy.
51
+ function inlineComposePlugins(source) {
52
+ let found = false;
53
+ const updatedSource = (0, tsquery_1.replace)(source, 'CallExpression > Identifier[name="composePlugins"]', (node) => {
54
+ if (node.parent.expression !== node) {
55
+ return node.getText();
56
+ }
57
+ found = true;
58
+ return 'composeLegacyPlugins';
59
+ });
60
+ if (!found)
61
+ return source;
62
+ return `${updatedSource}
63
+ function composeLegacyPlugins(...plugins) {
64
+ return async (config, ctx) => {
65
+ for (const plugin of plugins) {
66
+ config = await (await plugin)(config, ctx);
67
+ }
68
+ return config;
69
+ };
70
+ }
71
+ `;
43
72
  }
44
73
  function removeCallExpressions(source, functionNames) {
45
74
  let modifiedSource = source;
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/schema",
3
3
  "$id": "NxWebpackConvertConfigToWebpackPlugin",
4
- "description": "Convert existing Webpack project(s) using `@nx/webpack:webpack` executor that uses `withNx` to use `NxAppWebpackPlugin`. Defaults to migrating all projects. Pass '--project' to migrate only one target.",
4
+ "description": "Convert existing Webpack config(s) that use `withNx` to use `NxAppWebpackPlugin`, for projects on the `@nx/webpack:webpack` executor or the `@nx/webpack/plugin` inference plugin. Defaults to migrating all projects. Pass '--project' to migrate only one target.",
5
5
  "title": "Convert Webpack project using withNx to NxAppWebpackPlugin",
6
6
  "type": "object",
7
7
  "properties": {
8
8
  "project": {
9
9
  "type": "string",
10
- "description": "The project to convert from using the `@nx/webpack:webpack` executor and `withNx` plugin to use `NxAppWebpackPlugin`.",
10
+ "description": "The project whose webpack config to convert from the `withNx` plugin to `NxAppWebpackPlugin`.",
11
11
  "x-priority": "important"
12
12
  },
13
13
  "skipFormat": {
@@ -40,7 +40,7 @@ async function convertToInferred(tree, options) {
40
40
  const convertMessage = [...logger.loggedMessages.values()]
41
41
  .flat()
42
42
  .find((v) => v.includes('@nx/webpack:convert-config-to-webpack-plugin'));
43
- if (convertMessage.length > 0) {
43
+ if (convertMessage?.length > 0) {
44
44
  logger.flushLogs((message) => !convertMessage.includes(message));
45
45
  throw new Error(convertMessage);
46
46
  }
@@ -56,9 +56,10 @@ async function convertToInferred(tree, options) {
56
56
  if (!options.skipFormat) {
57
57
  await (0, devkit_1.formatFiles)(tree);
58
58
  }
59
- return (0, devkit_1.runTasksInSerial)(installCallback, () => {
60
- migrationContext.logger.flushLogs();
61
- });
59
+ // Flushed now rather than in the callback so remove-deprecated-executors, which
60
+ // skips the install callback, still prints these.
61
+ migrationContext.logger.flushLogs();
62
+ return installCallback;
62
63
  }
63
64
  function skipProjectFilterFactory(tree) {
64
65
  return function skipProjectFilter(projectConfiguration) {
@@ -118,9 +118,17 @@ function updateWebpackConfig(tree, webpackConfig, pluginOptions) {
118
118
  function setOptionsInWebpackConfig(tree, text, sourceFile, webpackConfig, pluginOptions) {
119
119
  const { default: defaultOptions, ...configurationOptions } = pluginOptions;
120
120
  const optionsSelector = 'VariableStatement:has(VariableDeclaration:has(Identifier[name=options]))';
121
- const optionsVariable = (0, tsquery_1.query)(sourceFile, optionsSelector)[0];
122
- // This is assuming the `options` variable will be available since it's what the
123
- // `convert-config-to-webpack-plugin` generates
121
+ let optionsVariable = (0, tsquery_1.query)(sourceFile, optionsSelector)[0];
122
+ if (!optionsVariable) {
123
+ const plugin = (0, tsquery_1.query)(sourceFile, 'NewExpression:has(Identifier[name=NxAppWebpackPlugin])')[0];
124
+ const argument = plugin.arguments?.[0];
125
+ if (argument && !ts.isObjectLiteralExpression(argument)) {
126
+ throw new Error('Move NxAppWebpackPlugin options into an object literal before converting this config.');
127
+ }
128
+ text = `const options = ${argument?.getText(sourceFile) ?? '{}'};\n${text}`;
129
+ sourceFile = (0, tsquery_1.ast)(text);
130
+ optionsVariable = (0, tsquery_1.query)(sourceFile, optionsSelector)[0];
131
+ }
124
132
  let defaultOptionsObject;
125
133
  const optionsObject = (0, tsquery_1.query)(optionsVariable, 'ObjectLiteralExpression')[0];
126
134
  if (optionsObject.properties.length === 0) {
@@ -188,8 +196,8 @@ function setOptionsInNxWebpackPlugin(tree, text, sourceFile, webpackConfig) {
188
196
  function setOptionsInLegacyNxPlugin(tree, text, sourceFile, webpackConfig) {
189
197
  const legacyNxPluginSelector = 'AwaitExpression CallExpression:has(Identifier[name=useLegacyNxPlugin])';
190
198
  const legacyNxPlugin = (0, tsquery_1.query)(sourceFile, legacyNxPluginSelector)[0];
191
- // we're assuming the `useLegacyNxPlugin` function is being called since it's what the `convert-config-to-webpack-plugin` generates
192
- // we've already "ensured" that the `convert-config-to-webpack-plugin` was run by checking for the `NxAppWebpackPlugin` in the project validation
199
+ if (!legacyNxPlugin)
200
+ return;
193
201
  const updatedLegacyNxPlugin = ts.factory.updateCallExpression(legacyNxPlugin, legacyNxPlugin.expression, undefined, [legacyNxPlugin.arguments[0], ts.factory.createIdentifier('buildOptions')]);
194
202
  text = `${text.slice(0, legacyNxPlugin.getStart())}${ts
195
203
  .createPrinter()