@nx/react 0.0.0-pr-22179-271588f → 0.0.0-pr-26482-ebe2dba

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 (51) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +1 -1
  3. package/index.d.ts +3 -1
  4. package/index.js +5 -3
  5. package/migrations.json +57 -160
  6. package/package.json +11 -9
  7. package/plugins/bundle-rollup.js +1 -1
  8. package/plugins/component-testing/index.js +5 -2
  9. package/plugins/component-testing/webpack-fallback.js +1 -1
  10. package/plugins/nx-react-webpack-plugin/lib/apply-react-config.d.ts +2 -1
  11. package/plugins/nx-react-webpack-plugin/lib/apply-react-config.js +33 -5
  12. package/plugins/storybook/index.js +1 -1
  13. package/plugins/with-react.d.ts +6 -1
  14. package/src/executors/module-federation-dev-server/module-federation-dev-server.impl.d.ts +5 -1
  15. package/src/executors/module-federation-dev-server/module-federation-dev-server.impl.js +58 -28
  16. package/src/executors/module-federation-dev-server/schema.json +25 -3
  17. package/src/generators/application/application.js +17 -4
  18. package/src/generators/application/files/base-webpack/webpack.config.js__tmpl__ +3 -3
  19. package/src/generators/application/lib/add-e2e.js +7 -6
  20. package/src/generators/application/lib/normalize-options.js +31 -4
  21. package/src/generators/application/schema.d.ts +3 -0
  22. package/src/generators/application/schema.json +2 -2
  23. package/src/generators/component/files/__fileName__.tsx__tmpl__ +3 -7
  24. package/src/generators/component/schema.d.ts +1 -1
  25. package/src/generators/component/schema.json +1 -1
  26. package/src/generators/hook/schema.d.ts +1 -1
  27. package/src/generators/hook/schema.json +2 -2
  28. package/src/generators/host/host.js +11 -0
  29. package/src/generators/host/schema.json +2 -2
  30. package/src/generators/library/lib/add-rollup-build-target.js +65 -28
  31. package/src/generators/redux/schema.d.ts +1 -1
  32. package/src/generators/redux/schema.json +1 -1
  33. package/src/generators/remote/lib/update-host-with-remote.js +1 -10
  34. package/src/generators/remote/remote.js +9 -0
  35. package/src/generators/remote/schema.json +2 -2
  36. package/src/generators/setup-tailwind/lib/add-tailwind-style-imports.js +7 -15
  37. package/src/generators/storybook-configuration/schema.json +3 -3
  38. package/src/migrations/{update-15-6-3/webpack-config-setup.d.ts → update-18-1-1/fix-target-defaults-inputs.d.ts} +1 -1
  39. package/src/migrations/update-18-1-1/fix-target-defaults-inputs.js +53 -0
  40. package/src/module-federation/with-module-federation.js +5 -0
  41. package/src/utils/add-mf-env-to-inputs.js +4 -1
  42. package/src/utils/ct-utils.js +1 -1
  43. package/src/utils/versions.d.ts +11 -11
  44. package/src/utils/versions.js +11 -11
  45. package/webpack-plugin.d.ts +1 -0
  46. package/webpack-plugin.js +5 -0
  47. package/src/migrations/update-15-3-0/install-webpack-rollup-dependencies.d.ts +0 -3
  48. package/src/migrations/update-15-3-0/install-webpack-rollup-dependencies.js +0 -37
  49. package/src/migrations/update-15-3-0/update-rollup-executor.d.ts +0 -3
  50. package/src/migrations/update-15-3-0/update-rollup-executor.js +0 -15
  51. package/src/migrations/update-15-6-3/webpack-config-setup.js +0 -103
@@ -7,9 +7,12 @@ const file_server_impl_1 = require("@nx/web/src/executors/file-server/file-serve
7
7
  const module_federation_1 = require("@nx/webpack/src/utils/module-federation");
8
8
  const async_iterable_1 = require("@nx/devkit/src/utils/async-iterable");
9
9
  const wait_for_port_open_1 = require("@nx/web/src/utils/wait-for-port-open");
10
- const child_process_1 = require("child_process");
11
- const path_1 = require("path");
10
+ const cache_directory_1 = require("nx/src/utils/cache-directory");
11
+ const node_child_process_1 = require("node:child_process");
12
+ const node_path_1 = require("node:path");
13
+ const node_fs_1 = require("node:fs");
12
14
  const fs_1 = require("fs");
15
+ const path_1 = require("path");
13
16
  function getBuildOptions(buildTarget, context) {
14
17
  const target = (0, devkit_1.parseTargetString)(buildTarget, context);
15
18
  const buildOptions = (0, devkit_1.readTargetOptions)(target, context);
@@ -31,10 +34,10 @@ function startStaticRemotesFileServer(staticRemotesConfig, context, options) {
31
34
  }
32
35
  }
33
36
  if (shouldMoveToCommonLocation) {
34
- commonOutputDirectory = (0, path_1.join)(devkit_1.workspaceRoot, 'tmp/static-remotes');
37
+ commonOutputDirectory = (0, node_path_1.join)(devkit_1.workspaceRoot, 'tmp/static-remotes');
35
38
  for (const app of staticRemotesConfig.remotes) {
36
39
  const remoteConfig = staticRemotesConfig.config[app];
37
- (0, fs_1.cpSync)(remoteConfig.outputPath, (0, path_1.join)(commonOutputDirectory, remoteConfig.urlSegment), {
40
+ (0, node_fs_1.cpSync)(remoteConfig.outputPath, (0, node_path_1.join)(commonOutputDirectory, remoteConfig.urlSegment), {
38
41
  force: true,
39
42
  recursive: true,
40
43
  });
@@ -55,27 +58,34 @@ function startStaticRemotesFileServer(staticRemotesConfig, context, options) {
55
58
  }, context);
56
59
  return staticRemotesIter;
57
60
  }
58
- async function startDevRemotes(remotes, context, options) {
59
- const devRemoteIters = [];
60
- for (const app of remotes.devRemotes) {
61
- const remoteProjectServeTarget = context.projectGraph.nodes[app].data.targets['serve'];
61
+ async function startRemotes(remotes, context, options, target = 'serve') {
62
+ const remoteIters = [];
63
+ for (const app of remotes) {
64
+ const remoteProjectServeTarget = context.projectGraph.nodes[app].data.targets[target];
62
65
  const isUsingModuleFederationDevServerExecutor = remoteProjectServeTarget.executor.includes('module-federation-dev-server');
63
- devRemoteIters.push(await (0, devkit_1.runExecutor)({
64
- project: app,
65
- target: 'serve',
66
- configuration: context.configurationName,
67
- }, {
68
- watch: true,
66
+ const configurationOverride = options.devRemotes?.find((r) => typeof r !== 'string' && r.remoteName === app)?.configuration;
67
+ const defaultOverrides = {
69
68
  ...(options.host ? { host: options.host } : {}),
70
69
  ...(options.ssl ? { ssl: options.ssl } : {}),
71
70
  ...(options.sslCert ? { sslCert: options.sslCert } : {}),
72
71
  ...(options.sslKey ? { sslKey: options.sslKey } : {}),
73
- ...(isUsingModuleFederationDevServerExecutor
74
- ? { isInitialHost: false }
75
- : {}),
76
- }, context));
72
+ };
73
+ const overrides = target === 'serve'
74
+ ? {
75
+ watch: true,
76
+ ...(isUsingModuleFederationDevServerExecutor
77
+ ? { isInitialHost: false }
78
+ : {}),
79
+ ...defaultOverrides,
80
+ }
81
+ : { ...defaultOverrides };
82
+ remoteIters.push(await (0, devkit_1.runExecutor)({
83
+ project: app,
84
+ target,
85
+ configuration: configurationOverride ?? context.configurationName,
86
+ }, overrides, context));
77
87
  }
78
- return devRemoteIters;
88
+ return remoteIters;
79
89
  }
80
90
  async function buildStaticRemotes(staticRemotesConfig, nxBin, context, options) {
81
91
  if (!staticRemotesConfig.remotes.length) {
@@ -88,7 +98,7 @@ async function buildStaticRemotes(staticRemotesConfig, nxBin, context, options)
88
98
  }
89
99
  process.env.NX_MF_DEV_SERVER_STATIC_REMOTES = JSON.stringify(mappedLocationOfRemotes);
90
100
  await new Promise((res) => {
91
- const staticProcess = (0, child_process_1.fork)(nxBin, [
101
+ const staticProcess = (0, node_child_process_1.fork)(nxBin, [
92
102
  'run-many',
93
103
  `--target=build`,
94
104
  `--projects=${staticRemotesConfig.remotes.join(',')}`,
@@ -100,9 +110,13 @@ async function buildStaticRemotes(staticRemotesConfig, nxBin, context, options)
100
110
  cwd: context.root,
101
111
  stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
102
112
  });
113
+ // File to debug build failures e.g. 2024-01-01T00_00_0_0Z-build.log'
114
+ const remoteBuildLogFile = (0, node_path_1.join)(cache_directory_1.workspaceDataDirectory, `${new Date().toISOString().replace(/[:\.]/g, '_')}-build.log`);
115
+ const stdoutStream = (0, node_fs_1.createWriteStream)(remoteBuildLogFile);
103
116
  staticProcess.stdout.on('data', (data) => {
104
117
  const ANSII_CODE_REGEX = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
105
118
  const stdoutString = data.toString().replace(ANSII_CODE_REGEX, '');
119
+ stdoutStream.write(stdoutString);
106
120
  if (stdoutString.includes('Successfully ran target build')) {
107
121
  staticProcess.stdout.removeAllListeners('data');
108
122
  devkit_1.logger.info(`NX Built ${staticRemotesConfig.remotes.length} static remotes`);
@@ -111,8 +125,9 @@ async function buildStaticRemotes(staticRemotesConfig, nxBin, context, options)
111
125
  });
112
126
  staticProcess.stderr.on('data', (data) => devkit_1.logger.info(data.toString()));
113
127
  staticProcess.on('exit', (code) => {
128
+ stdoutStream.end();
114
129
  if (code !== 0) {
115
- throw new Error(`Remote failed to start. See above for errors.`);
130
+ throw new Error(`Remote failed to start. A complete log can be found in: ${remoteBuildLogFile}`);
116
131
  }
117
132
  });
118
133
  process.on('SIGTERM', () => staticProcess.kill('SIGTERM'));
@@ -126,8 +141,8 @@ function parseStaticRemotesConfig(staticRemotes, context) {
126
141
  const config = {};
127
142
  for (const app of staticRemotes) {
128
143
  const outputPath = context.projectGraph.nodes[app].data.targets['build'].options.outputPath;
129
- const basePath = (0, path_1.dirname)(outputPath);
130
- const urlSegment = (0, path_1.basename)(outputPath);
144
+ const basePath = (0, node_path_1.dirname)(outputPath);
145
+ const urlSegment = (0, node_path_1.basename)(outputPath);
131
146
  config[app] = { basePath, outputPath, urlSegment };
132
147
  }
133
148
  return { remotes: staticRemotes, config };
@@ -149,18 +164,32 @@ async function* moduleFederationDevServer(options, context) {
149
164
  : (0, dev_server_impl_1.default)(options, context);
150
165
  const p = context.projectsConfigurations.projects[context.projectName];
151
166
  const buildOptions = getBuildOptions(options.buildTarget, context);
167
+ let pathToManifestFile = (0, node_path_1.join)(context.root, p.sourceRoot, 'assets/module-federation.manifest.json');
168
+ if (options.pathToManifestFile) {
169
+ const userPathToManifestFile = (0, node_path_1.join)(context.root, options.pathToManifestFile);
170
+ if (!(0, fs_1.existsSync)(userPathToManifestFile)) {
171
+ throw new Error(`The provided Module Federation manifest file path does not exist. Please check the file exists at "${userPathToManifestFile}".`);
172
+ }
173
+ else if ((0, path_1.extname)(options.pathToManifestFile) !== '.json') {
174
+ throw new Error(`The Module Federation manifest file must be a JSON. Please ensure the file at ${userPathToManifestFile} is a JSON.`);
175
+ }
176
+ pathToManifestFile = userPathToManifestFile;
177
+ }
152
178
  if (!options.isInitialHost) {
153
179
  return yield* currIter;
154
180
  }
155
181
  const moduleFederationConfig = (0, module_federation_1.getModuleFederationConfig)(buildOptions.tsConfig, context.root, p.root, 'react');
156
- const remotes = (0, module_federation_1.getRemotes)(options.devRemotes, options.skipRemotes, moduleFederationConfig, {
182
+ const remoteNames = options.devRemotes?.map((r) => typeof r === 'string' ? r : r.remoteName);
183
+ const remotes = (0, module_federation_1.getRemotes)(remoteNames, options.skipRemotes, moduleFederationConfig, {
157
184
  projectName: context.projectName,
158
185
  projectGraph: context.projectGraph,
159
186
  root: context.root,
160
- });
187
+ }, pathToManifestFile);
161
188
  if (remotes.devRemotes.length > 0 && !initialStaticRemotesPorts) {
162
189
  options.staticRemotesPort = options.devRemotes.reduce((portToUse, r) => {
163
- const remotePort = context.projectGraph.nodes[r].data.targets['serve'].options.port;
190
+ const remoteName = typeof r === 'string' ? r : r.remoteName;
191
+ const remotePort = context.projectGraph.nodes[remoteName].data.targets['serve'].options
192
+ .port;
164
193
  if (remotePort >= portToUse) {
165
194
  return remotePort + 1;
166
195
  }
@@ -171,11 +200,12 @@ async function* moduleFederationDevServer(options, context) {
171
200
  }
172
201
  const staticRemotesConfig = parseStaticRemotesConfig(remotes.staticRemotes, context);
173
202
  await buildStaticRemotes(staticRemotesConfig, nxBin, context, options);
174
- const devRemoteIters = await startDevRemotes(remotes, context, options);
203
+ const devRemoteIters = await startRemotes(remotes.devRemotes, context, options, 'serve');
204
+ const dynamicRemotesIters = await startRemotes(remotes.dynamicRemotes, context, options, 'serve-static');
175
205
  const staticRemotesIter = remotes.staticRemotes.length > 0
176
206
  ? startStaticRemotesFileServer(staticRemotesConfig, context, options)
177
207
  : undefined;
178
- return yield* (0, async_iterable_1.combineAsyncIterables)(currIter, ...devRemoteIters, ...(staticRemotesIter ? [staticRemotesIter] : []), (0, async_iterable_1.createAsyncIterable)(async ({ next, done }) => {
208
+ return yield* (0, async_iterable_1.combineAsyncIterables)(currIter, ...devRemoteIters, ...dynamicRemotesIters, ...(staticRemotesIter ? [staticRemotesIter] : []), (0, async_iterable_1.createAsyncIterable)(async ({ next, done }) => {
179
209
  if (!options.isInitialHost) {
180
210
  done();
181
211
  return;
@@ -9,7 +9,24 @@
9
9
  "devRemotes": {
10
10
  "type": "array",
11
11
  "items": {
12
- "type": "string"
12
+ "oneOf": [
13
+ {
14
+ "type": "string"
15
+ },
16
+ {
17
+ "type": "object",
18
+ "properties": {
19
+ "remoteName": {
20
+ "type": "string"
21
+ },
22
+ "configuration": {
23
+ "type": "string"
24
+ }
25
+ },
26
+ "required": ["remoteName"],
27
+ "additionalProperties": false
28
+ }
29
+ ]
13
30
  },
14
31
  "description": "List of remote applications to run in development mode (i.e. using serve target).",
15
32
  "x-priority": "important"
@@ -19,7 +36,7 @@
19
36
  "items": {
20
37
  "type": "string"
21
38
  },
22
- "description": "List of remote applications to not automatically serve, either statically or in development mode. This will not remove the remotes from the `module-federation.config` file, and therefore the application may still try to fetch these remotes.\nThis option is useful for when the `host` application is using a `remote` that does not live in the same workspace as the `host`.",
39
+ "description": "List of remote applications to not automatically serve, either statically or in development mode. This will not remove the remotes from the `module-federation.config` file, and therefore the application may still try to fetch these remotes.\nThis option is useful if you have other means for serving the `remote` application(s).\n**NOTE:** Remotes that are not in the workspace will be skipped automatically.",
23
40
  "x-priority": "important"
24
41
  },
25
42
  "buildTarget": {
@@ -109,6 +126,11 @@
109
126
  "staticRemotesPort": {
110
127
  "type": "number",
111
128
  "description": "The port at which to serve the file-server for the static remotes."
129
+ },
130
+ "pathToManifestFile": {
131
+ "type": "string",
132
+ "description": "Path to a Module Federation manifest file (e.g. `my/path/to/module-federation.manifest.json`) containing the dynamic remote applications relative to the workspace root."
112
133
  }
113
- }
134
+ },
135
+ "examplesFile": "../../../docs/module-federation-dev-server-examples.md"
114
136
  }
@@ -62,7 +62,6 @@ async function applicationGenerator(host, schema) {
62
62
  exports.applicationGenerator = applicationGenerator;
63
63
  async function applicationGeneratorInternal(host, schema) {
64
64
  const tasks = [];
65
- console.log('Well hello Katerina!');
66
65
  const options = await (0, normalize_options_1.normalizeOptions)(host, schema);
67
66
  (0, show_possible_warnings_1.showPossibleWarnings)(host, options);
68
67
  const jsInitTask = await (0, js_1.initGenerator)(host, {
@@ -76,6 +75,20 @@ async function applicationGeneratorInternal(host, schema) {
76
75
  skipFormat: true,
77
76
  });
78
77
  tasks.push(initTask);
78
+ if (!options.addPlugin) {
79
+ const nxJson = (0, devkit_1.readNxJson)(host);
80
+ nxJson.targetDefaults ??= {};
81
+ if (!Object.keys(nxJson.targetDefaults).includes('build')) {
82
+ nxJson.targetDefaults.build = {
83
+ cache: true,
84
+ dependsOn: ['^build'],
85
+ };
86
+ }
87
+ else if (!nxJson.targetDefaults.build.dependsOn) {
88
+ nxJson.targetDefaults.build.dependsOn = ['^build'];
89
+ }
90
+ (0, devkit_1.updateNxJson)(host, nxJson);
91
+ }
79
92
  if (options.bundler === 'webpack') {
80
93
  const { webpackInitGenerator } = (0, devkit_1.ensurePackage)('@nx/webpack', versions_1.nxVersion);
81
94
  const webpackInitTask = await webpackInitGenerator(host, {
@@ -144,7 +157,7 @@ async function applicationGeneratorInternal(host, schema) {
144
157
  tsConfig: (0, devkit_1.joinPathFragments)(options.appProjectRoot, 'tsconfig.app.json'),
145
158
  target: 'web',
146
159
  newProject: true,
147
- uiFramework: 'react',
160
+ framework: 'react',
148
161
  });
149
162
  tasks.push(rspackTask);
150
163
  }
@@ -202,8 +215,8 @@ async function applicationGeneratorInternal(host, schema) {
202
215
  devkit_1.logger.warn(`${chalk.bold('styled-jsx')} is not supported by ${chalk.bold('Rspack')}. We've added ${chalk.bold('babel-loader')} to your project, but using babel will slow down your build.`);
203
216
  tasks.push((0, devkit_1.addDependenciesToPackageJson)(host, {}, { 'babel-loader': versions_1.babelLoaderVersion }));
204
217
  host.write((0, devkit_1.joinPathFragments)(options.appProjectRoot, 'rspack.config.js'), (0, devkit_1.stripIndents) `
205
- const { composePlugins, withNx, withWeb } = require('@nx/rspack');
206
- module.exports = composePlugins(withNx(), withWeb(), (config) => {
218
+ const { composePlugins, withNx, withReact } = require('@nx/rspack');
219
+ module.exports = composePlugins(withNx(), withReact(), (config) => {
207
220
  config.module.rules.push({
208
221
  test: /\\.[jt]sx$/i,
209
222
  use: [
@@ -1,6 +1,6 @@
1
1
  <% if (webpackPluginOptions) { %>
2
- const { NxWebpackPlugin } = require('@nx/webpack');
3
- const { NxReactWebpackPlugin } = require('@nx/react');
2
+ const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
3
+ const { NxReactWebpackPlugin } = require('@nx/react/webpack-plugin');
4
4
  const { join } = require('path');
5
5
 
6
6
  module.exports = {
@@ -11,7 +11,7 @@ module.exports = {
11
11
  port: 4200
12
12
  },
13
13
  plugins: [
14
- new NxWebpackPlugin({
14
+ new NxAppWebpackPlugin({
15
15
  tsConfig: '<%= webpackPluginOptions.tsConfig %>',
16
16
  compiler: '<%= webpackPluginOptions.compiler %>',
17
17
  main: '<%= webpackPluginOptions.main %>',
@@ -12,9 +12,10 @@ async function addE2e(tree, options) {
12
12
  const hasNxBuildPlugin = (options.bundler === 'webpack' && (0, has_webpack_plugin_1.hasWebpackPlugin)(tree)) ||
13
13
  (options.bundler === 'vite' && (0, has_vite_plugin_1.hasVitePlugin)(tree));
14
14
  if (!hasNxBuildPlugin) {
15
- (0, web_1.webStaticServeGenerator)(tree, {
15
+ await (0, web_1.webStaticServeGenerator)(tree, {
16
16
  buildTarget: `${options.projectName}:build`,
17
17
  targetName: 'serve-static',
18
+ spa: true,
18
19
  });
19
20
  }
20
21
  const { configurationGenerator } = (0, devkit_1.ensurePackage)('@nx/cypress', versions_1.nxVersion);
@@ -33,13 +34,13 @@ async function addE2e(tree, options) {
33
34
  // the name and root are already normalized, instruct the generator to use them as is
34
35
  bundler: options.bundler === 'rspack' ? 'webpack' : options.bundler,
35
36
  skipFormat: true,
36
- devServerTarget: `${options.projectName}:serve`,
37
- baseUrl: `http://localhost:${options.devServerPort ?? 4200}`,
37
+ devServerTarget: `${options.projectName}:${options.e2eWebServerTarget}`,
38
+ baseUrl: options.e2eWebServerAddress,
38
39
  jsx: true,
39
40
  rootProject: options.rootProject,
40
41
  webServerCommands: hasNxBuildPlugin
41
42
  ? {
42
- default: `nx run ${options.projectName}:serve`,
43
+ default: `nx run ${options.projectName}:${options.e2eWebServerTarget}`,
43
44
  production: `nx run ${options.projectName}:preview`,
44
45
  }
45
46
  : undefined,
@@ -65,8 +66,8 @@ async function addE2e(tree, options) {
65
66
  js: false,
66
67
  linter: options.linter,
67
68
  setParserOptionsProject: options.setParserOptionsProject,
68
- webServerCommand: `${(0, devkit_1.getPackageManagerCommand)().exec} nx serve ${options.name}`,
69
- webServerAddress: `http://localhost:${options.devServerPort ?? 4200}`,
69
+ webServerCommand: `${(0, devkit_1.getPackageManagerCommand)().exec} nx ${options.e2eWebServerTarget} ${options.name}`,
70
+ webServerAddress: options.e2eWebServerAddress,
70
71
  rootProject: options.rootProject,
71
72
  addPlugin: options.addPlugin,
72
73
  });
@@ -32,8 +32,35 @@ async function normalizeOptions(host, options, callingGenerator = '@nx/react:app
32
32
  options.addPlugin ??= addPlugin;
33
33
  options.rootProject = appProjectRoot === '.';
34
34
  options.projectNameAndRootFormat = projectNameAndRootFormat;
35
+ let e2eWebServerTarget = 'serve';
36
+ if (options.addPlugin) {
37
+ if (nxJson.plugins) {
38
+ for (const plugin of nxJson.plugins) {
39
+ if (options.bundler === 'vite' &&
40
+ typeof plugin === 'object' &&
41
+ plugin.plugin === '@nx/vite/plugin' &&
42
+ plugin.options.serveTargetName) {
43
+ e2eWebServerTarget = plugin.options
44
+ .serveTargetName;
45
+ }
46
+ else if (options.bundler === 'webpack' &&
47
+ typeof plugin === 'object' &&
48
+ plugin.plugin === '@nx/webpack/plugin' &&
49
+ plugin.options.serveTargetName) {
50
+ e2eWebServerTarget = plugin.options
51
+ .serveTargetName;
52
+ }
53
+ }
54
+ }
55
+ }
56
+ let e2ePort = options.devServerPort ?? 4200;
57
+ if (nxJson.targetDefaults?.[e2eWebServerTarget] &&
58
+ nxJson.targetDefaults?.[e2eWebServerTarget].options?.port) {
59
+ e2ePort = nxJson.targetDefaults?.[e2eWebServerTarget].options?.port;
60
+ }
35
61
  const e2eProjectName = options.rootProject ? 'e2e' : `${appProjectName}-e2e`;
36
62
  const e2eProjectRoot = options.rootProject ? 'e2e' : `${appProjectRoot}-e2e`;
63
+ const e2eWebServerAddress = `http://localhost:${e2ePort}`;
37
64
  const parsedTags = options.tags
38
65
  ? options.tags.split(',').map((s) => s.trim())
39
66
  : [];
@@ -42,9 +69,6 @@ async function normalizeOptions(host, options, callingGenerator = '@nx/react:app
42
69
  ? null
43
70
  : options.style;
44
71
  (0, assertion_1.assertValidStyle)(options.style);
45
- if (options.bundler === 'vite' && options.unitTestRunner !== 'none') {
46
- options.unitTestRunner = 'vitest';
47
- }
48
72
  const normalized = {
49
73
  ...options,
50
74
  name: (0, devkit_1.names)(options.name).fileName,
@@ -52,6 +76,9 @@ async function normalizeOptions(host, options, callingGenerator = '@nx/react:app
52
76
  appProjectRoot,
53
77
  e2eProjectName,
54
78
  e2eProjectRoot,
79
+ e2eWebServerAddress,
80
+ e2eWebServerTarget,
81
+ e2ePort,
55
82
  parsedTags,
56
83
  fileName,
57
84
  styledModule,
@@ -63,7 +90,7 @@ async function normalizeOptions(host, options, callingGenerator = '@nx/react:app
63
90
  normalized.compiler = normalized.compiler ?? 'babel';
64
91
  normalized.bundler = normalized.bundler ?? 'webpack';
65
92
  normalized.unitTestRunner = normalized.unitTestRunner ?? 'jest';
66
- normalized.e2eTestRunner = normalized.e2eTestRunner ?? 'cypress';
93
+ normalized.e2eTestRunner = normalized.e2eTestRunner ?? 'playwright';
67
94
  normalized.inSourceTests = normalized.minimal || normalized.inSourceTests;
68
95
  normalized.devServerPort ??= (0, find_free_port_1.findFreePort)(host);
69
96
  normalized.minimal = normalized.minimal ?? false;
@@ -36,6 +36,9 @@ export interface NormalizedSchema<T extends Schema = Schema> extends T {
36
36
  appProjectRoot: string;
37
37
  e2eProjectName: string;
38
38
  e2eProjectRoot: string;
39
+ e2eWebServerAddress: string;
40
+ e2eWebServerTarget: string;
41
+ e2ePort: number;
39
42
  parsedTags: string[];
40
43
  fileName: string;
41
44
  styledModule: null | SupportedStyles;
@@ -122,10 +122,10 @@
122
122
  },
123
123
  "e2eTestRunner": {
124
124
  "type": "string",
125
- "enum": ["cypress", "playwright", "none"],
125
+ "enum": ["playwright", "cypress", "none"],
126
126
  "description": "Test runner to use for end to end (E2E) tests.",
127
127
  "x-prompt": "Which E2E test runner would you like to use?",
128
- "default": "cypress"
128
+ "default": "playwright"
129
129
  },
130
130
  "tags": {
131
131
  "type": "string",
@@ -23,10 +23,6 @@ import { Route, Link } from 'react-router-dom';
23
23
  var extras = '';
24
24
  } %>
25
25
 
26
- /* eslint-disable-next-line */
27
- export interface <%= className %>Props {
28
- }
29
-
30
26
  <% if (styledModule && styledModule !== 'styled-jsx') { %>
31
27
  const Styled<%= className %> = styled.div`
32
28
  color: pink;
@@ -34,7 +30,7 @@ const Styled<%= className %> = styled.div`
34
30
  <% }%>
35
31
  <% if(!isNextPage) { %>
36
32
  <% if (classComponent) { %>
37
- export class <%= className %> extends Component<<%= className %>Props> {
33
+ export class <%= className %> extends Component<{}> {
38
34
  override render() {
39
35
  return (
40
36
  <<%= wrapper %><%- extras %>>
@@ -51,7 +47,7 @@ const Styled<%= className %> = styled.div`
51
47
  }
52
48
  }
53
49
  <% } else { %>
54
- export function <%= className %>(props: <%= className %>Props) {
50
+ export function <%= className %>() {
55
51
  return (
56
52
  <<%= wrapper %><%- extras %>>
57
53
  <% if (styledModule === 'styled-jsx') { %><style jsx>{`div { color: pink; }`}</style><% } %>
@@ -69,7 +65,7 @@ const Styled<%= className %> = styled.div`
69
65
 
70
66
  export default <%= className %>;
71
67
  <% } else { %>
72
- export default function <%= className %>(props: <%= className %>Props) {
68
+ export default function <%= className %>() {
73
69
  return (
74
70
  <<%= wrapper %><%- extras %>>
75
71
  <% if (styledModule === 'styled-jsx') { %><style jsx>{`div { color: pink; }`}</style><% } %>
@@ -3,7 +3,7 @@ import { SupportedStyles } from '../../../typings/style';
3
3
  export interface Schema {
4
4
  name: string;
5
5
  /**
6
- * @deprecated Provide the `directory` option instead and use the `as-provided` format. The project will be determined from the directory provided. It will be removed in Nx v19.
6
+ * @deprecated Provide the `directory` option instead and use the `as-provided` format. The project will be determined from the directory provided. It will be removed in Nx v20.
7
7
  */
8
8
  project?: string;
9
9
  style: SupportedStyles;
@@ -13,7 +13,7 @@
13
13
  "$default": {
14
14
  "$source": "projectName"
15
15
  },
16
- "x-deprecated": "Provide the `directory` option instead and use the `as-provided` format. The project will be determined from the directory provided. It will be removed in Nx v19."
16
+ "x-deprecated": "Provide the `directory` option instead and use the `as-provided` format. The project will be determined from the directory provided. It will be removed in Nx v20."
17
17
  },
18
18
  "name": {
19
19
  "type": "string",
@@ -1,7 +1,7 @@
1
1
  export interface Schema {
2
2
  name: string;
3
3
  /**
4
- * @deprecated Provide the `directory` option instead and use the `as-provided` format. The project will be determined from the directory provided. It will be removed in Nx v19.
4
+ * @deprecated Provide the `directory` option instead and use the `as-provided` format. The project will be determined from the directory provided. It will be removed in Nx v20.
5
5
  */
6
6
  project: string;
7
7
  skipTests?: boolean;
@@ -19,7 +19,7 @@
19
19
  "$default": {
20
20
  "$source": "projectName"
21
21
  },
22
- "x-deprecated": "Provide the `directory` option instead and use the `as-provided` format. The project will be determined from the directory provided. It will be removed in Nx v19."
22
+ "x-deprecated": "Provide the `directory` option instead and use the `as-provided` format. The project will be determined from the directory provided. It will be removed in Nx v20."
23
23
  },
24
24
  "name": {
25
25
  "type": "string",
@@ -56,7 +56,7 @@
56
56
  "type": "boolean",
57
57
  "description": "Create hook at the source root rather than its own directory.",
58
58
  "default": false,
59
- "x-deprecated": "Provide the `directory` option instead and use the `as-provided` format. It will be removed in Nx v19."
59
+ "x-deprecated": "Provide the `directory` option instead and use the `as-provided` format. It will be removed in Nx v20."
60
60
  },
61
61
  "export": {
62
62
  "type": "boolean",
@@ -12,6 +12,7 @@ const normalize_remote_1 = require("./lib/normalize-remote");
12
12
  const setup_ssr_for_host_1 = require("./lib/setup-ssr-for-host");
13
13
  const update_module_federation_e2e_project_1 = require("./lib/update-module-federation-e2e-project");
14
14
  const add_mf_env_to_inputs_1 = require("../../utils/add-mf-env-to-inputs");
15
+ const js_1 = require("@nx/js");
15
16
  async function hostGenerator(host, schema) {
16
17
  return hostGeneratorInternal(host, {
17
18
  projectNameAndRootFormat: 'derived',
@@ -31,6 +32,16 @@ async function hostGeneratorInternal(host, schema) {
31
32
  // TODO(colum): remove when MF works with Crystal
32
33
  addPlugin: false,
33
34
  };
35
+ // Check to see if remotes are provided and also check if --dynamic is provided
36
+ // if both are check that the remotes are valid names else throw an error.
37
+ if (options.dynamic && options.remotes?.length > 0) {
38
+ options.remotes.forEach((remote) => {
39
+ const isValidRemote = (0, js_1.isValidVariable)(remote);
40
+ if (!isValidRemote.isValid) {
41
+ throw new Error(`Invalid remote name provided: ${remote}. ${isValidRemote.message}`);
42
+ }
43
+ });
44
+ }
34
45
  const initTask = await (0, application_1.default)(host, {
35
46
  ...options,
36
47
  // The target use-case is loading remotes as child routes, thus always enable routing.
@@ -103,10 +103,10 @@
103
103
  },
104
104
  "e2eTestRunner": {
105
105
  "type": "string",
106
- "enum": ["cypress", "playwright", "none"],
106
+ "enum": ["playwright", "cypress", "none"],
107
107
  "description": "Test runner to use for end to end (E2E) tests.",
108
108
  "x-prompt": "Which E2E test runner would you like to use?",
109
- "default": "cypress"
109
+ "default": "playwright"
110
110
  },
111
111
  "tags": {
112
112
  "type": "string",