@nx/webpack 19.4.0-beta.1 → 19.4.0-beta.2

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 (39) hide show
  1. package/generators.json +11 -1
  2. package/index.d.ts +3 -1
  3. package/index.js +5 -1
  4. package/package.json +5 -4
  5. package/plugin.d.ts +1 -1
  6. package/plugin.js +2 -1
  7. package/src/executors/dev-server/dev-server.impl.js +7 -1
  8. package/src/executors/webpack/webpack.impl.js +5 -0
  9. package/src/generators/convert-config-to-webpack-plugin/convert-config-to-webpack-plugin.d.ts +7 -0
  10. package/src/generators/convert-config-to-webpack-plugin/convert-config-to-webpack-plugin.js +93 -0
  11. package/src/generators/convert-config-to-webpack-plugin/lib/extract-webpack-options.d.ts +6 -0
  12. package/src/generators/convert-config-to-webpack-plugin/lib/extract-webpack-options.js +106 -0
  13. package/src/generators/convert-config-to-webpack-plugin/lib/normalize-path-options.d.ts +2 -0
  14. package/src/generators/convert-config-to-webpack-plugin/lib/normalize-path-options.js +75 -0
  15. package/src/generators/convert-config-to-webpack-plugin/lib/utils.d.ts +1 -0
  16. package/src/generators/convert-config-to-webpack-plugin/lib/utils.js +14 -0
  17. package/src/generators/convert-config-to-webpack-plugin/lib/validate-project.d.ts +9 -0
  18. package/src/generators/convert-config-to-webpack-plugin/lib/validate-project.js +44 -0
  19. package/src/generators/convert-config-to-webpack-plugin/schema.json +19 -0
  20. package/src/generators/convert-to-inferred/convert-to-inferred.d.ts +7 -0
  21. package/src/generators/convert-to-inferred/convert-to-inferred.js +71 -0
  22. package/src/generators/convert-to-inferred/schema.json +19 -0
  23. package/src/generators/convert-to-inferred/utils/ast.d.ts +3 -0
  24. package/src/generators/convert-to-inferred/utils/ast.js +40 -0
  25. package/src/generators/convert-to-inferred/utils/build-post-target-transformer.d.ts +6 -0
  26. package/src/generators/convert-to-inferred/utils/build-post-target-transformer.js +219 -0
  27. package/src/generators/convert-to-inferred/utils/index.d.ts +3 -0
  28. package/src/generators/convert-to-inferred/utils/index.js +6 -0
  29. package/src/generators/convert-to-inferred/utils/serve-post-target-transformer.d.ts +6 -0
  30. package/src/generators/convert-to-inferred/utils/serve-post-target-transformer.js +250 -0
  31. package/src/generators/convert-to-inferred/utils/types.d.ts +11 -0
  32. package/src/generators/convert-to-inferred/utils/types.js +2 -0
  33. package/src/plugins/nx-webpack-plugin/lib/apply-base-config.js +5 -1
  34. package/src/plugins/nx-webpack-plugin/lib/normalize-options.js +1 -1
  35. package/src/plugins/plugin.d.ts +5 -1
  36. package/src/plugins/plugin.js +62 -41
  37. package/src/plugins/use-legacy-nx-plugin/use-legacy-nx-plugin.d.ts +29 -0
  38. package/src/plugins/use-legacy-nx-plugin/use-legacy-nx-plugin.js +59 -0
  39. package/src/utils/module-federation/get-remotes-for-host.js +1 -1
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toExpression = exports.toPropertyAssignment = void 0;
4
+ const ts = require("typescript");
5
+ function toPropertyAssignment(key, value) {
6
+ if (typeof value === 'string') {
7
+ return ts.factory.createPropertyAssignment(ts.factory.createStringLiteral(key), ts.factory.createStringLiteral(value));
8
+ }
9
+ else if (typeof value === 'number') {
10
+ return ts.factory.createPropertyAssignment(ts.factory.createStringLiteral(key), ts.factory.createNumericLiteral(value));
11
+ }
12
+ else if (typeof value === 'boolean') {
13
+ return ts.factory.createPropertyAssignment(ts.factory.createStringLiteral(key), value ? ts.factory.createTrue() : ts.factory.createFalse());
14
+ }
15
+ else if (Array.isArray(value)) {
16
+ return ts.factory.createPropertyAssignment(ts.factory.createStringLiteral(key), ts.factory.createArrayLiteralExpression(value.map((item) => toExpression(item))));
17
+ }
18
+ else {
19
+ return ts.factory.createPropertyAssignment(ts.factory.createStringLiteral(key), ts.factory.createObjectLiteralExpression(Object.entries(value).map(([key, value]) => toPropertyAssignment(key, value))));
20
+ }
21
+ }
22
+ exports.toPropertyAssignment = toPropertyAssignment;
23
+ function toExpression(value) {
24
+ if (typeof value === 'string') {
25
+ return ts.factory.createStringLiteral(value);
26
+ }
27
+ else if (typeof value === 'number') {
28
+ return ts.factory.createNumericLiteral(value);
29
+ }
30
+ else if (typeof value === 'boolean') {
31
+ return value ? ts.factory.createTrue() : ts.factory.createFalse();
32
+ }
33
+ else if (Array.isArray(value)) {
34
+ return ts.factory.createArrayLiteralExpression(value.map((item) => toExpression(item)));
35
+ }
36
+ else {
37
+ return ts.factory.createObjectLiteralExpression(Object.entries(value).map(([key, value]) => toPropertyAssignment(key, value)));
38
+ }
39
+ }
40
+ exports.toExpression = toExpression;
@@ -0,0 +1,6 @@
1
+ import type { TargetConfiguration, Tree } from '@nx/devkit';
2
+ import type { MigrationContext } from './types';
3
+ export declare function buildPostTargetTransformerFactory(migrationContext: MigrationContext): (target: TargetConfiguration, tree: Tree, projectDetails: {
4
+ projectName: string;
5
+ root: string;
6
+ }, inferredTarget: TargetConfiguration) => TargetConfiguration;
@@ -0,0 +1,219 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildPostTargetTransformerFactory = void 0;
4
+ const plugin_migration_utils_1 = require("@nx/devkit/src/generators/plugin-migrations/plugin-migration-utils");
5
+ const tsquery_1 = require("@phenomnomnominal/tsquery");
6
+ const ts = require("typescript");
7
+ const ast_1 = require("./ast");
8
+ function buildPostTargetTransformerFactory(migrationContext) {
9
+ return function buildPostTargetTransformer(target, tree, projectDetails, inferredTarget) {
10
+ const context = {
11
+ ...migrationContext,
12
+ projectName: projectDetails.projectName,
13
+ projectRoot: projectDetails.root,
14
+ };
15
+ const { pluginOptions, webpackConfigPath } = processOptions(target, context);
16
+ updateWebpackConfig(tree, webpackConfigPath, pluginOptions);
17
+ if (target.outputs) {
18
+ (0, plugin_migration_utils_1.processTargetOutputs)(target, [], inferredTarget, {
19
+ projectName: projectDetails.projectName,
20
+ projectRoot: projectDetails.root,
21
+ });
22
+ }
23
+ return target;
24
+ };
25
+ }
26
+ exports.buildPostTargetTransformerFactory = buildPostTargetTransformerFactory;
27
+ function processOptions(target, context) {
28
+ const webpackConfigPath = target.options.webpackConfig;
29
+ delete target.options.webpackConfig;
30
+ const pluginOptions = {
31
+ default: extractPluginOptions(target.options, context),
32
+ };
33
+ if (target.configurations && Object.keys(target.configurations).length) {
34
+ for (const [configName, config] of Object.entries(target.configurations)) {
35
+ pluginOptions[configName] = extractPluginOptions(config, context, configName);
36
+ }
37
+ }
38
+ return { pluginOptions, webpackConfigPath };
39
+ }
40
+ const pathOptions = new Set([
41
+ 'babelConfig',
42
+ 'index',
43
+ 'main',
44
+ 'outputPath',
45
+ 'polyfills',
46
+ 'postcssConfig',
47
+ 'tsConfig',
48
+ ]);
49
+ const assetsOptions = new Set(['assets', 'scripts', 'styles']);
50
+ function extractPluginOptions(options, context, configName) {
51
+ const pluginOptions = {};
52
+ for (const [key, value] of Object.entries(options)) {
53
+ if (pathOptions.has(key)) {
54
+ pluginOptions[key] = (0, plugin_migration_utils_1.toProjectRelativePath)(value, context.projectRoot);
55
+ delete options[key];
56
+ }
57
+ else if (assetsOptions.has(key)) {
58
+ pluginOptions[key] = value.map((asset) => {
59
+ if (typeof asset === 'string') {
60
+ return (0, plugin_migration_utils_1.toProjectRelativePath)(asset, context.projectRoot);
61
+ }
62
+ asset.input = (0, plugin_migration_utils_1.toProjectRelativePath)(asset.input, context.projectRoot);
63
+ return asset;
64
+ });
65
+ delete options[key];
66
+ }
67
+ else if (key === 'fileReplacements') {
68
+ pluginOptions.fileReplacements = value.map((replacement) => ({
69
+ replace: (0, plugin_migration_utils_1.toProjectRelativePath)(replacement.replace, context.projectRoot),
70
+ with: (0, plugin_migration_utils_1.toProjectRelativePath)(replacement.with, context.projectRoot),
71
+ }));
72
+ delete options.fileReplacements;
73
+ }
74
+ else if (key === 'additionalEntryPoints') {
75
+ pluginOptions.additionalEntryPoints = value.map((entryPoint) => {
76
+ entryPoint.entryPath = (0, plugin_migration_utils_1.toProjectRelativePath)(entryPoint.entryPath, context.projectRoot);
77
+ return entryPoint;
78
+ });
79
+ delete options.additionalEntryPoints;
80
+ }
81
+ else if (key === 'memoryLimit') {
82
+ pluginOptions.memoryLimit = value;
83
+ const serveMemoryLimit = getMemoryLimitFromServeTarget(context, configName);
84
+ if (serveMemoryLimit) {
85
+ pluginOptions.memoryLimit = Math.max(serveMemoryLimit, value);
86
+ context.logger.addLog({
87
+ executorName: '@nx/webpack:webpack',
88
+ log: `The "memoryLimit" option was set in both the serve and build configurations. The migration set the higher value to the build configuration and removed the option from the serve configuration.`,
89
+ project: context.projectName,
90
+ });
91
+ }
92
+ delete options.memoryLimit;
93
+ }
94
+ else if (key === 'isolatedConfig') {
95
+ context.logger.addLog({
96
+ executorName: '@nx/webpack:webpack',
97
+ log: `The 'isolatedConfig' option is deprecated and not supported by the NxAppWebpackPlugin. It was removed from your project configuration.`,
98
+ project: context.projectName,
99
+ });
100
+ delete options.isolatedConfig;
101
+ }
102
+ else if (key === 'standardWebpackConfigFunction') {
103
+ delete options.standardWebpackConfigFunction;
104
+ }
105
+ else {
106
+ pluginOptions[key] = value;
107
+ delete options[key];
108
+ }
109
+ }
110
+ return pluginOptions;
111
+ }
112
+ function updateWebpackConfig(tree, webpackConfig, pluginOptions) {
113
+ let sourceFile;
114
+ let webpackConfigText;
115
+ const updateSources = () => {
116
+ webpackConfigText = tree.read(webpackConfig, 'utf-8');
117
+ sourceFile = tsquery_1.tsquery.ast(webpackConfigText);
118
+ };
119
+ updateSources();
120
+ setOptionsInWebpackConfig(tree, webpackConfigText, sourceFile, webpackConfig, pluginOptions);
121
+ updateSources();
122
+ setOptionsInNxWebpackPlugin(tree, webpackConfigText, sourceFile, webpackConfig);
123
+ updateSources();
124
+ setOptionsInLegacyNxPlugin(tree, webpackConfigText, sourceFile, webpackConfig);
125
+ }
126
+ function setOptionsInWebpackConfig(tree, text, sourceFile, webpackConfig, pluginOptions) {
127
+ const { default: defaultOptions, ...configurationOptions } = pluginOptions;
128
+ const optionsSelector = 'VariableStatement:has(VariableDeclaration:has(Identifier[name=options]))';
129
+ const optionsVariable = (0, tsquery_1.tsquery)(sourceFile, optionsSelector)[0];
130
+ // This is assuming the `options` variable will be available since it's what the
131
+ // `convert-config-to-webpack-plugin` generates
132
+ let defaultOptionsObject;
133
+ const optionsObject = (0, tsquery_1.tsquery)(optionsVariable, 'ObjectLiteralExpression')[0];
134
+ if (optionsObject.properties.length === 0) {
135
+ defaultOptionsObject = ts.factory.createObjectLiteralExpression(Object.entries(defaultOptions).map(([key, value]) => (0, ast_1.toPropertyAssignment)(key, value)));
136
+ }
137
+ else {
138
+ // filter out the default options that are already in the options object
139
+ // the existing options override the options from the project.json file
140
+ const filteredDefaultOptions = Object.entries(defaultOptions).filter(([key]) => !optionsObject.properties.some((property) => ts.isPropertyAssignment(property) &&
141
+ ts.isIdentifier(property.name) &&
142
+ property.name.text === key));
143
+ defaultOptionsObject = ts.factory.createObjectLiteralExpression([
144
+ ...optionsObject.properties,
145
+ ...filteredDefaultOptions.map(([key, value]) => (0, ast_1.toPropertyAssignment)(key, value)),
146
+ ]);
147
+ }
148
+ /**
149
+ * const configValues = {
150
+ * build: {
151
+ * default: { ... },
152
+ * configuration1: { ... },
153
+ * configuration2: { ... },
154
+ * }
155
+ */
156
+ const configValuesVariable = ts.factory.createVariableStatement(undefined, ts.factory.createVariableDeclarationList([
157
+ ts.factory.createVariableDeclaration('configValues', undefined, undefined, ts.factory.createObjectLiteralExpression([
158
+ ts.factory.createPropertyAssignment('build', ts.factory.createObjectLiteralExpression([
159
+ ts.factory.createPropertyAssignment('default', defaultOptionsObject),
160
+ ...(configurationOptions
161
+ ? Object.entries(configurationOptions).map(([key, value]) => ts.factory.createPropertyAssignment(key, ts.factory.createObjectLiteralExpression(Object.entries(value).map(([key, value]) => (0, ast_1.toPropertyAssignment)(key, value)))))
162
+ : []),
163
+ ])),
164
+ ], true)),
165
+ ], ts.NodeFlags.Const));
166
+ text = `${text.slice(0, optionsVariable.getStart())}
167
+ // These options were migrated by @nx/webpack:convert-to-inferred from
168
+ // the project.json file and merged with the options in this file
169
+ ${ts
170
+ .createPrinter()
171
+ .printNode(ts.EmitHint.Unspecified, configValuesVariable, sourceFile)}
172
+
173
+ // Determine the correct configValue to use based on the configuration
174
+ const configuration = process.env.NX_TASK_TARGET_CONFIGURATION || 'default';
175
+
176
+ const buildOptions = {
177
+ ...configValues.build.default,
178
+ ...configValues.build[configuration],
179
+ };${text.slice(optionsVariable.getEnd())}`;
180
+ // These are comments written by the `convert-config-to-webpack-plugin` that are no longer needed
181
+ text = text
182
+ .replace(`// This file was migrated using @nx/webpack:convert-config-to-webpack-plugin from your './webpack.config.old.js'`, '')
183
+ .replace('// Please check that the options here are correct as they were moved from the old webpack.config.js to this file.', '');
184
+ tree.write(webpackConfig, text);
185
+ }
186
+ function setOptionsInNxWebpackPlugin(tree, text, sourceFile, webpackConfig) {
187
+ const nxAppWebpackPluginSelector = 'PropertyAssignment:has(Identifier[name=plugins]) NewExpression:has(Identifier[name=NxAppWebpackPlugin])';
188
+ const nxAppWebpackPlugin = (0, tsquery_1.tsquery)(sourceFile, nxAppWebpackPluginSelector)[0];
189
+ // the NxAppWebpackPlugin must exists, otherwise, the migration doesn't run and we wouldn't reach this point
190
+ const updatedNxAppWebpackPlugin = ts.factory.updateNewExpression(nxAppWebpackPlugin, nxAppWebpackPlugin.expression, undefined, [ts.factory.createIdentifier('buildOptions')]);
191
+ text = `${text.slice(0, nxAppWebpackPlugin.getStart())}${ts
192
+ .createPrinter()
193
+ .printNode(ts.EmitHint.Unspecified, updatedNxAppWebpackPlugin, sourceFile)}${text.slice(nxAppWebpackPlugin.getEnd())}`;
194
+ tree.write(webpackConfig, text);
195
+ }
196
+ function setOptionsInLegacyNxPlugin(tree, text, sourceFile, webpackConfig) {
197
+ const legacyNxPluginSelector = 'AwaitExpression CallExpression:has(Identifier[name=useLegacyNxPlugin])';
198
+ const legacyNxPlugin = (0, tsquery_1.tsquery)(sourceFile, legacyNxPluginSelector)[0];
199
+ // we're assuming the `useLegacyNxPlugin` function is being called since it's what the `convert-config-to-webpack-plugin` generates
200
+ // we've already "ensured" that the `convert-config-to-webpack-plugin` was run by checking for the `NxAppWebpackPlugin` in the project validation
201
+ const updatedLegacyNxPlugin = ts.factory.updateCallExpression(legacyNxPlugin, legacyNxPlugin.expression, undefined, [legacyNxPlugin.arguments[0], ts.factory.createIdentifier('buildOptions')]);
202
+ text = `${text.slice(0, legacyNxPlugin.getStart())}${ts
203
+ .createPrinter()
204
+ .printNode(ts.EmitHint.Unspecified, updatedLegacyNxPlugin, sourceFile)}${text.slice(legacyNxPlugin.getEnd())}`;
205
+ tree.write(webpackConfig, text);
206
+ }
207
+ function getMemoryLimitFromServeTarget(context, configName) {
208
+ const { targets } = context.projectGraph.nodes[context.projectName].data;
209
+ const serveTarget = Object.values(targets).find((target) => target.executor === '@nx/webpack:dev-server' ||
210
+ target.executor === '@nrwl/web:dev-server');
211
+ if (!serveTarget) {
212
+ return undefined;
213
+ }
214
+ if (configName && serveTarget.configurations?.[configName]) {
215
+ return (serveTarget.configurations[configName].options?.memoryLimit ??
216
+ serveTarget.options?.memoryLimit);
217
+ }
218
+ return serveTarget.options?.memoryLimit;
219
+ }
@@ -0,0 +1,3 @@
1
+ export * from './build-post-target-transformer';
2
+ export * from './serve-post-target-transformer';
3
+ export * from './types';
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./build-post-target-transformer"), exports);
5
+ tslib_1.__exportStar(require("./serve-post-target-transformer"), exports);
6
+ tslib_1.__exportStar(require("./types"), exports);
@@ -0,0 +1,6 @@
1
+ import { type TargetConfiguration, type Tree } from '@nx/devkit';
2
+ import type { MigrationContext } from './types';
3
+ export declare function servePostTargetTransformerFactory(migrationContext: MigrationContext): (target: TargetConfiguration, tree: Tree, projectDetails: {
4
+ projectName: string;
5
+ root: string;
6
+ }, inferredTarget: TargetConfiguration) => Promise<TargetConfiguration>;
@@ -0,0 +1,250 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.servePostTargetTransformerFactory = void 0;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const plugin_migration_utils_1 = require("@nx/devkit/src/generators/plugin-migrations/plugin-migration-utils");
6
+ const tsquery_1 = require("@phenomnomnominal/tsquery");
7
+ const path_1 = require("path");
8
+ const ts = require("typescript");
9
+ const serve_path_1 = require("../../../executors/dev-server/lib/serve-path");
10
+ const ast_1 = require("./ast");
11
+ function servePostTargetTransformerFactory(migrationContext) {
12
+ return async function servePostTargetTransformer(target, tree, projectDetails, inferredTarget) {
13
+ const context = {
14
+ ...migrationContext,
15
+ projectName: projectDetails.projectName,
16
+ projectRoot: projectDetails.root,
17
+ };
18
+ const { devServerOptions, webpackConfigPath } = await processOptions(tree, target, context);
19
+ updateWebpackConfig(tree, webpackConfigPath, devServerOptions, context);
20
+ if (target.outputs) {
21
+ (0, plugin_migration_utils_1.processTargetOutputs)(target, [], inferredTarget, {
22
+ projectName: projectDetails.projectName,
23
+ projectRoot: projectDetails.root,
24
+ });
25
+ }
26
+ return target;
27
+ };
28
+ }
29
+ exports.servePostTargetTransformerFactory = servePostTargetTransformerFactory;
30
+ async function processOptions(tree, target, context) {
31
+ const executorContext = {
32
+ cwd: process.cwd(),
33
+ nxJsonConfiguration: (0, devkit_1.readJson)(tree, 'nx.json'),
34
+ projectGraph: context.projectGraph,
35
+ projectName: context.projectName,
36
+ projectsConfigurations: Object.entries(context.projectGraph.nodes).reduce((acc, [projectName, project]) => {
37
+ acc.projects[projectName] = project.data;
38
+ return acc;
39
+ }, { version: 1, projects: {} }),
40
+ root: context.workspaceRoot,
41
+ };
42
+ const buildTarget = (0, devkit_1.parseTargetString)(target.options.buildTarget, executorContext);
43
+ const buildOptions = (0, devkit_1.readTargetOptions)(buildTarget, executorContext);
44
+ // it must exist, we validated it in the project filter
45
+ const webpackConfigPath = buildOptions.webpackConfig;
46
+ const defaultOptions = extractDevServerOptions(target.options, context);
47
+ applyDefaults(defaultOptions, buildOptions);
48
+ const devServerOptions = {
49
+ default: defaultOptions,
50
+ };
51
+ if (target.configurations && Object.keys(target.configurations).length) {
52
+ for (const [configName, config] of Object.entries(target.configurations)) {
53
+ devServerOptions[configName] = extractDevServerOptions(config, context);
54
+ }
55
+ }
56
+ return { devServerOptions, webpackConfigPath };
57
+ }
58
+ function extractDevServerOptions(options, context) {
59
+ const devServerOptions = {};
60
+ for (const [key, value] of Object.entries(options)) {
61
+ if (key === 'hmr') {
62
+ devServerOptions.hot = value;
63
+ if (value) {
64
+ // the executor disables liveReload when hmr is enabled
65
+ devServerOptions.liveReload = false;
66
+ delete options.liveReload;
67
+ }
68
+ delete options.hmr;
69
+ }
70
+ else if (key === 'allowedHosts') {
71
+ devServerOptions.allowedHosts = value.split(',');
72
+ delete options.allowedHosts;
73
+ }
74
+ else if (key === 'publicHost') {
75
+ devServerOptions.client = {
76
+ webSocketURL: value,
77
+ };
78
+ delete options.publicHost;
79
+ }
80
+ else if (key === 'proxyConfig') {
81
+ devServerOptions.proxy = getProxyConfig(context.workspaceRoot, value);
82
+ delete options.proxyConfig;
83
+ }
84
+ else if (key === 'ssl' || key === 'sslCert' || key === 'sslKey') {
85
+ if (key === 'ssl' || 'ssl' in options) {
86
+ if (options.ssl) {
87
+ devServerOptions.server = { type: 'https' };
88
+ if (options.sslCert && options.sslKey) {
89
+ devServerOptions.server.options = {};
90
+ devServerOptions.server.options.cert = (0, plugin_migration_utils_1.toProjectRelativePath)(options.sslCert, context.projectRoot);
91
+ devServerOptions.server.options.key = (0, plugin_migration_utils_1.toProjectRelativePath)(options.sslKey, context.projectRoot);
92
+ }
93
+ else if (options.sslCert) {
94
+ context.logger.addLog({
95
+ executorName: '@nx/webpack:dev-server',
96
+ log: 'The "sslCert" option was set but "sslKey" was missing and "ssl" was set to "true". This means that "sslCert" was ignored by the executor. It has been removed from the options.',
97
+ project: context.projectName,
98
+ });
99
+ }
100
+ else if (options.sslKey) {
101
+ context.logger.addLog({
102
+ executorName: '@nx/webpack:dev-server',
103
+ log: 'The "sslKey" option was set but "sslCert" was missing and "ssl" was set to "true". This means that "sslKey" was ignored by the executor. It has been removed from the options.',
104
+ project: context.projectName,
105
+ });
106
+ }
107
+ }
108
+ else if (options.sslCert || options.sslKey) {
109
+ context.logger.addLog({
110
+ executorName: '@nx/webpack:dev-server',
111
+ log: 'The "sslCert" and/or "sslKey" were set with "ssl" set to "false". This means they were ignored by the executor. They have been removed from the options.',
112
+ project: context.projectName,
113
+ });
114
+ }
115
+ delete options.ssl;
116
+ delete options.sslCert;
117
+ delete options.sslKey;
118
+ }
119
+ else if (options.sslCert || options.sslKey) {
120
+ context.logger.addLog({
121
+ executorName: '@nx/webpack:dev-server',
122
+ log: 'The "sslCert" and/or "sslKey" were set but the "ssl" was not set. This means they were ignored by the executor. They have been removed from the options.',
123
+ project: context.projectName,
124
+ });
125
+ delete options.sslCert;
126
+ delete options.sslKey;
127
+ }
128
+ }
129
+ else if (key === 'buildTarget') {
130
+ delete options.buildTarget;
131
+ }
132
+ else if (key === 'watch') {
133
+ context.logger.addLog({
134
+ executorName: '@nx/webpack:dev-server',
135
+ log: 'The "watch" option was removed from the serve configuration since it is not needed. The dev server always watches the files.',
136
+ project: context.projectName,
137
+ });
138
+ delete options.watch;
139
+ }
140
+ else if (key === 'baseHref') {
141
+ context.logger.addLog({
142
+ executorName: '@nx/webpack:dev-server',
143
+ log: 'The "baseHref" option was removed from the serve configuration. If you need different base hrefs for the build and the dev server, please update the final webpack config manually to achieve that.',
144
+ project: context.projectName,
145
+ });
146
+ delete options.baseHref;
147
+ }
148
+ else if (key === 'memoryLimit') {
149
+ // we already log a message for this one when processing the build options
150
+ delete options.memoryLimit;
151
+ }
152
+ else {
153
+ devServerOptions[key] = value;
154
+ delete options[key];
155
+ }
156
+ }
157
+ return devServerOptions;
158
+ }
159
+ function applyDefaults(options, buildOptions) {
160
+ if (options.port === undefined) {
161
+ options.port = 4200;
162
+ }
163
+ options.headers = { 'Access-Control-Allow-Origin': '*' };
164
+ const servePath = (0, serve_path_1.buildServePath)(buildOptions);
165
+ options.historyApiFallback = {
166
+ index: buildOptions.index && `${servePath}${(0, path_1.basename)(buildOptions.index)}`,
167
+ disableDotRule: true,
168
+ htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'],
169
+ };
170
+ }
171
+ function getProxyConfig(root, proxyConfig) {
172
+ const proxyPath = (0, path_1.resolve)(root, proxyConfig);
173
+ return require(proxyPath);
174
+ }
175
+ function updateWebpackConfig(tree, webpackConfigPath, devServerOptions, context) {
176
+ let sourceFile;
177
+ let webpackConfigText;
178
+ const updateSources = () => {
179
+ webpackConfigText = tree.read(webpackConfigPath, 'utf-8');
180
+ sourceFile = tsquery_1.tsquery.ast(webpackConfigText);
181
+ };
182
+ updateSources();
183
+ setOptionsInWebpackConfig(tree, webpackConfigText, sourceFile, webpackConfigPath, devServerOptions);
184
+ updateSources();
185
+ setDevServerOptionsInWebpackConfig(tree, webpackConfigText, sourceFile, webpackConfigPath, context);
186
+ }
187
+ function setOptionsInWebpackConfig(tree, text, sourceFile, webpackConfigPath, devServerOptions) {
188
+ const { default: defaultOptions, ...configurationOptions } = devServerOptions;
189
+ const configValuesSelector = 'VariableDeclaration:has(Identifier[name=configValues]) ObjectLiteralExpression';
190
+ const configValuesObject = (0, tsquery_1.tsquery)(sourceFile, configValuesSelector)[0];
191
+ // configValues must exist at this point, we added it when processing the build target
192
+ /**
193
+ * const configValues = {
194
+ * ...
195
+ * serve: {
196
+ * default: { ... },
197
+ * configuration1: { ... },
198
+ * ...
199
+ * },
200
+ */
201
+ const updatedConfigValuesObject = ts.factory.updateObjectLiteralExpression(configValuesObject, [
202
+ ...configValuesObject.properties,
203
+ ts.factory.createPropertyAssignment('serve', ts.factory.createObjectLiteralExpression([
204
+ ts.factory.createPropertyAssignment('default', ts.factory.createObjectLiteralExpression(Object.entries(defaultOptions).map(([key, value]) => (0, ast_1.toPropertyAssignment)(key, value)))),
205
+ ...(configurationOptions
206
+ ? Object.entries(configurationOptions).map(([key, value]) => ts.factory.createPropertyAssignment(key, ts.factory.createObjectLiteralExpression(Object.entries(value).map(([key, value]) => (0, ast_1.toPropertyAssignment)(key, value)))))
207
+ : []),
208
+ ])),
209
+ ]);
210
+ text = `${text.slice(0, configValuesObject.getStart())}${ts
211
+ .createPrinter()
212
+ .printNode(ts.EmitHint.Unspecified, updatedConfigValuesObject, sourceFile)}${text.slice(configValuesObject.getEnd())}`;
213
+ tree.write(webpackConfigPath, text);
214
+ sourceFile = tsquery_1.tsquery.ast(text);
215
+ const buildOptionsSelector = 'VariableStatement:has(VariableDeclaration:has(Identifier[name=buildOptions]))';
216
+ const buildOptionsStatement = (0, tsquery_1.tsquery)(sourceFile, buildOptionsSelector)[0];
217
+ text = `${text.slice(0, buildOptionsStatement.getEnd())}
218
+ const devServerOptions = {
219
+ ...configValues.serve.default,
220
+ ...configValues.serve[configuration],
221
+ };${text.slice(buildOptionsStatement.getEnd())}`;
222
+ tree.write(webpackConfigPath, text);
223
+ }
224
+ function setDevServerOptionsInWebpackConfig(tree, text, sourceFile, webpackConfigPath, context) {
225
+ const webpackConfigDevServerSelector = 'ObjectLiteralExpression > PropertyAssignment:has(Identifier[name=devServer])';
226
+ const webpackConfigDevServer = (0, tsquery_1.tsquery)(sourceFile, webpackConfigDevServerSelector)[0];
227
+ if (webpackConfigDevServer) {
228
+ context.logger.addLog({
229
+ executorName: '@nx/webpack:dev-server',
230
+ log: `The "devServer" option is already set in the webpack config. The migration doesn't support updating it. Please review it and make any necessary changes manually.`,
231
+ project: context.projectName,
232
+ });
233
+ text = `${text.slice(0, webpackConfigDevServer.getStart())}// This is the untouched "devServer" option from the original webpack config. Please review it and make any necessary changes manually.
234
+ ${text.slice(webpackConfigDevServer.getStart())}`;
235
+ tree.write(webpackConfigPath, text);
236
+ // If the devServer property already exists, we don't know how to merge the
237
+ // options, so we leave it as is.
238
+ return;
239
+ }
240
+ const webpackConfigSelector = 'ObjectLiteralExpression:has(PropertyAssignment:has(Identifier[name=plugins]))';
241
+ const webpackConfig = (0, tsquery_1.tsquery)(sourceFile, webpackConfigSelector)[0];
242
+ const updatedWebpackConfig = ts.factory.updateObjectLiteralExpression(webpackConfig, [
243
+ ts.factory.createPropertyAssignment('devServer', ts.factory.createIdentifier('devServerOptions')),
244
+ ...webpackConfig.properties,
245
+ ]);
246
+ text = `${text.slice(0, webpackConfig.getStart())}${ts
247
+ .createPrinter()
248
+ .printNode(ts.EmitHint.Unspecified, updatedWebpackConfig, sourceFile)}${text.slice(webpackConfig.getEnd())}`;
249
+ tree.write(webpackConfigPath, text);
250
+ }
@@ -0,0 +1,11 @@
1
+ import type { ProjectGraph } from '@nx/devkit';
2
+ import type { AggregatedLog } from '@nx/devkit/src/generators/plugin-migrations/aggregate-log-util';
3
+ export type MigrationContext = {
4
+ logger: AggregatedLog;
5
+ projectGraph: ProjectGraph;
6
+ workspaceRoot: string;
7
+ };
8
+ export type TransformerContext = MigrationContext & {
9
+ projectName: string;
10
+ projectRoot: string;
11
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -72,7 +72,11 @@ function applyNxIndependentConfig(options, config) {
72
72
  (options.target === 'node' ? 'commonjs' : undefined),
73
73
  path: config.output?.path ??
74
74
  (options.outputPath
75
- ? path.join(options.root, options.outputPath)
75
+ ? // If path is relative, it is relative from project root (aka cwd).
76
+ // Otherwise, it is relative to workspace root (legacy behavior).
77
+ options.outputPath.startsWith('.')
78
+ ? path.join(options.root, options.projectRoot, options.outputPath)
79
+ : path.join(options.root, options.outputPath)
76
80
  : undefined),
77
81
  filename: config.output?.filename ??
78
82
  (options.outputHashing ? `[name]${hashFormat.script}.js` : '[name].js'),
@@ -47,7 +47,7 @@ function normalizeOptions(options) {
47
47
  originalTargetOptions);
48
48
  }
49
49
  const sourceRoot = projectNode.data.sourceRoot ?? projectNode.data.root;
50
- if (!options.main) {
50
+ if (!combinedPluginAndMaybeExecutorOptions.main) {
51
51
  throw new Error(`Missing "main" option for the entry file. Set this option in your Nx webpack plugin.`);
52
52
  }
53
53
  return {
@@ -1,9 +1,13 @@
1
- import { CreateDependencies, CreateNodes } from '@nx/devkit';
1
+ import { CreateDependencies, CreateNodes, CreateNodesV2 } from '@nx/devkit';
2
2
  export interface WebpackPluginOptions {
3
3
  buildTargetName?: string;
4
4
  serveTargetName?: string;
5
5
  serveStaticTargetName?: string;
6
6
  previewTargetName?: string;
7
7
  }
8
+ /**
9
+ * @deprecated The 'createDependencies' function is now a no-op. This functionality is included in 'createNodesV2'.
10
+ */
8
11
  export declare const createDependencies: CreateDependencies;
12
+ export declare const createNodesV2: CreateNodesV2<WebpackPluginOptions>;
9
13
  export declare const createNodes: CreateNodes<WebpackPluginOptions>;