@nx/react 17.0.3 → 17.0.5

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 (154) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +9 -4
  3. package/generators.json +1 -1
  4. package/index.d.ts +1 -0
  5. package/index.js +3 -1
  6. package/mf/dynamic-federation.d.ts +4 -0
  7. package/mf/dynamic-federation.js +75 -0
  8. package/mf/index.d.ts +1 -0
  9. package/mf/index.js +7 -0
  10. package/migrations.json +21 -0
  11. package/package.json +7 -7
  12. package/plugins/component-testing/index.js +52 -24
  13. package/plugins/component-testing/webpack-fallback.js +1 -1
  14. package/plugins/nx-react-webpack-plugin/lib/apply-react-config.d.ts +4 -0
  15. package/plugins/nx-react-webpack-plugin/lib/apply-react-config.js +86 -0
  16. package/plugins/nx-react-webpack-plugin/nx-react-webpack-plugin.d.ts +8 -0
  17. package/plugins/nx-react-webpack-plugin/nx-react-webpack-plugin.js +13 -0
  18. package/plugins/storybook/index.js +6 -2
  19. package/plugins/storybook/merge-plugins.d.ts +1 -1
  20. package/plugins/webpack.d.ts +1 -3
  21. package/plugins/webpack.js +3 -11
  22. package/plugins/with-react.d.ts +2 -4
  23. package/plugins/with-react.js +2 -58
  24. package/src/executors/module-federation-dev-server/module-federation-dev-server.impl.d.ts +13 -0
  25. package/src/executors/module-federation-dev-server/module-federation-dev-server.impl.js +173 -58
  26. package/src/executors/module-federation-dev-server/schema.json +13 -1
  27. package/src/generators/application/application.js +41 -18
  28. package/src/generators/application/files/base-vite/index.html__tmpl__ +1 -1
  29. package/src/generators/application/files/base-webpack/src/index.html +0 -2
  30. package/src/generators/application/files/base-webpack/webpack.config.js__tmpl__ +46 -5
  31. package/src/generators/application/files/nx-welcome/src/app/nx-welcome.tsx +54 -13
  32. package/src/generators/application/files/style-tailwind/src/app/__fileName__.tsx__tmpl__ +33 -0
  33. package/src/generators/application/files/style-tailwind/src/styles.css +1 -0
  34. package/src/generators/application/lib/add-e2e.js +25 -7
  35. package/src/generators/application/lib/add-jest.js +2 -2
  36. package/src/generators/application/lib/add-project.d.ts +2 -2
  37. package/src/generators/application/lib/add-project.js +12 -15
  38. package/src/generators/application/lib/add-routing.d.ts +1 -1
  39. package/src/generators/application/lib/add-routing.js +4 -8
  40. package/src/generators/application/lib/create-application-files.js +30 -1
  41. package/src/generators/application/lib/install-common-dependencies.js +15 -1
  42. package/src/generators/application/lib/normalize-options.js +35 -1
  43. package/src/generators/application/lib/set-defaults.js +1 -0
  44. package/src/generators/application/lib/update-jest-config.js +8 -8
  45. package/src/generators/application/schema.d.ts +5 -0
  46. package/src/generators/application/schema.json +7 -3
  47. package/src/generators/component/files/__fileName__.tsx__tmpl__ +39 -22
  48. package/src/generators/component/lib/normalize-options.js +4 -2
  49. package/src/generators/component/schema.d.ts +6 -4
  50. package/src/generators/component/schema.json +7 -7
  51. package/src/generators/component-cypress-spec/schema.json +1 -1
  52. package/src/generators/component-story/schema.json +1 -1
  53. package/src/generators/component-test/schema.json +1 -1
  54. package/src/generators/cypress-component-configuration/cypress-component-configuration.d.ts +2 -1
  55. package/src/generators/cypress-component-configuration/cypress-component-configuration.js +18 -7
  56. package/src/generators/cypress-component-configuration/lib/add-files.js +1 -6
  57. package/src/generators/cypress-component-configuration/schema.d.ts +1 -0
  58. package/src/generators/federate-module/federate-module.js +2 -2
  59. package/src/generators/federate-module/schema.d.ts +1 -1
  60. package/src/generators/federate-module/schema.json +4 -3
  61. package/src/generators/hook/files/__fileName__.ts__tmpl__ +15 -15
  62. package/src/generators/hook/schema.d.ts +4 -4
  63. package/src/generators/hook/schema.json +5 -5
  64. package/src/generators/host/files/common/src/main.js__tmpl__ +10 -0
  65. package/src/generators/host/files/common/tsconfig.lint.json__tmpl__ +19 -0
  66. package/src/generators/host/files/common-ts/src/app/__fileName__.tsx__tmpl__ +41 -0
  67. package/src/generators/host/files/common-ts/src/main.ts__tmpl__ +10 -0
  68. package/src/generators/host/files/module-federation/module-federation.config.js__tmpl__ +17 -2
  69. package/src/generators/host/files/module-federation-ssr/module-federation.server.config.js__tmpl__ +5 -2
  70. package/src/generators/host/files/module-federation-ssr-ts/module-federation.server.config.ts__tmpl__ +5 -2
  71. package/src/generators/host/files/module-federation-ts/module-federation.config.ts__tmpl__ +17 -2
  72. package/src/generators/host/files/module-federation-ts/webpack.config.prod.ts__tmpl__ +2 -1
  73. package/src/generators/host/files/module-federation-ts/webpack.config.ts__tmpl__ +2 -2
  74. package/src/generators/host/host.js +15 -1
  75. package/src/generators/host/lib/add-module-federation-files.d.ts +2 -1
  76. package/src/generators/host/lib/add-module-federation-files.js +24 -11
  77. package/src/generators/host/lib/setup-ssr-for-host.js +1 -0
  78. package/src/generators/host/lib/update-module-federation-e2e-project.js +7 -5
  79. package/src/generators/host/schema.d.ts +5 -2
  80. package/src/generators/host/schema.json +16 -6
  81. package/src/generators/init/init.d.ts +1 -1
  82. package/src/generators/init/init.js +10 -49
  83. package/src/generators/init/schema.d.ts +1 -6
  84. package/src/generators/init/schema.json +5 -22
  85. package/src/generators/library/lib/add-linting.js +2 -2
  86. package/src/generators/library/lib/add-rollup-build-target.d.ts +2 -1
  87. package/src/generators/library/lib/add-rollup-build-target.js +16 -8
  88. package/src/generators/library/lib/install-common-dependencies.js +13 -5
  89. package/src/generators/library/lib/normalize-options.js +34 -5
  90. package/src/generators/library/lib/update-app-routes.js +1 -1
  91. package/src/generators/library/library.js +17 -6
  92. package/src/generators/library/schema.d.ts +1 -0
  93. package/src/generators/library/schema.json +3 -3
  94. package/src/generators/redux/schema.d.ts +1 -1
  95. package/src/generators/redux/schema.json +2 -2
  96. package/src/generators/remote/files/module-federation/module-federation.config.js__tmpl__ +4 -1
  97. package/src/generators/remote/files/module-federation-ssr/module-federation.server.config.js__tmpl__ +1 -1
  98. package/src/generators/remote/files/module-federation-ssr-ts/module-federation.server.config.ts__tmpl__ +1 -1
  99. package/src/generators/remote/files/module-federation-ssr-ts/tsconfig.lint.json__tmpl__ +19 -0
  100. package/src/generators/remote/files/module-federation-ts/module-federation.config.ts__tmpl__ +4 -1
  101. package/src/generators/remote/files/module-federation-ts/tsconfig.lint.json__tmpl__ +19 -0
  102. package/src/generators/remote/lib/add-remote-to-dynamic-host.d.ts +2 -0
  103. package/src/generators/remote/lib/add-remote-to-dynamic-host.js +11 -0
  104. package/src/generators/remote/lib/setup-ssr-for-remote.js +5 -1
  105. package/src/generators/remote/lib/setup-tspath-for-remote.js +2 -1
  106. package/src/generators/remote/lib/update-host-with-remote.js +10 -1
  107. package/src/generators/remote/remote.js +22 -2
  108. package/src/generators/remote/schema.d.ts +3 -2
  109. package/src/generators/remote/schema.json +17 -6
  110. package/src/generators/setup-ssr/schema.json +1 -1
  111. package/src/generators/setup-ssr/setup-ssr.js +23 -7
  112. package/src/generators/setup-tailwind/schema.json +1 -1
  113. package/src/generators/stories/schema.json +1 -1
  114. package/src/generators/stories/stories.js +17 -5
  115. package/src/generators/storybook-configuration/configuration.d.ts +2 -0
  116. package/src/generators/storybook-configuration/configuration.js +37 -15
  117. package/src/generators/storybook-configuration/schema.d.ts +2 -1
  118. package/src/generators/storybook-configuration/schema.json +7 -7
  119. package/src/migrations/update-18-0-0/add-mf-env-var-to-target-defaults.d.ts +2 -0
  120. package/src/migrations/update-18-0-0/add-mf-env-var-to-target-defaults.js +26 -0
  121. package/src/migrations/update-18-1-1/fix-target-defaults-inputs.d.ts +2 -0
  122. package/src/migrations/update-18-1-1/fix-target-defaults-inputs.js +53 -0
  123. package/src/module-federation/ast-utils.js +1 -1
  124. package/src/module-federation/utils.js +8 -1
  125. package/src/module-federation/with-module-federation-ssr.js +3 -0
  126. package/src/module-federation/with-module-federation.d.ts +3 -3
  127. package/src/module-federation/with-module-federation.js +14 -4
  128. package/src/rules/update-module-federation-project.d.ts +2 -0
  129. package/src/rules/update-module-federation-project.js +12 -3
  130. package/src/utils/add-mf-env-to-inputs.d.ts +2 -0
  131. package/src/utils/add-mf-env-to-inputs.js +27 -0
  132. package/src/utils/assertion.js +1 -0
  133. package/src/utils/ct-utils.d.ts +6 -1
  134. package/src/utils/ct-utils.js +39 -9
  135. package/src/utils/get-in-source-vitest-tests-template.js +1 -1
  136. package/src/utils/has-vite-plugin.d.ts +2 -0
  137. package/src/utils/has-vite-plugin.js +11 -0
  138. package/src/utils/has-webpack-plugin.d.ts +2 -0
  139. package/src/utils/has-webpack-plugin.js +11 -0
  140. package/src/utils/maybe-js.d.ts +3 -0
  141. package/src/utils/versions.d.ts +1 -1
  142. package/src/utils/versions.js +1 -1
  143. package/typings/style.d.ts +1 -0
  144. package/src/generators/application/files/base-webpack/src/environments/environment.prod.ts__tmpl__ +0 -3
  145. package/src/generators/application/files/base-webpack/src/environments/environment.ts__tmpl__ +0 -6
  146. package/src/generators/host/files/module-federation/src/main.ts__tmpl__ +0 -1
  147. package/src/generators/host/files/module-federation-ts/src/main.ts__tmpl__ +0 -1
  148. package/src/generators/library/lib/maybe-js.d.ts +0 -2
  149. /package/src/generators/host/files/common/src/app/{__fileName__.tsx__tmpl__ → __fileName__.js__tmpl__} +0 -0
  150. /package/src/generators/remote/files/{module-federation/src/main.ts__tmpl__ → common/src/main.js__tmpl__} +0 -0
  151. /package/src/generators/remote/files/{module-federation/src/remote-entry.ts__tmpl__ → common/src/remote-entry.js__tmpl__} +0 -0
  152. /package/src/generators/remote/files/{module-federation-ts → common-ts}/src/main.ts__tmpl__ +0 -0
  153. /package/src/generators/remote/files/{module-federation-ts → common-ts}/src/remote-entry.ts__tmpl__ +0 -0
  154. /package/src/{generators/library/lib → utils}/maybe-js.js +0 -0
@@ -5,7 +5,20 @@ type ModuleFederationDevServerOptions = WebDevServerOptions & {
5
5
  skipRemotes?: string[];
6
6
  static?: boolean;
7
7
  isInitialHost?: boolean;
8
+ parallel?: number;
9
+ staticRemotesPort?: number;
10
+ pathToManifestFile?: string;
8
11
  };
12
+ type StaticRemoteConfig = {
13
+ basePath: string;
14
+ outputPath: string;
15
+ urlSegment: string;
16
+ };
17
+ type StaticRemotesConfig = {
18
+ remotes: string[];
19
+ config: Record<string, StaticRemoteConfig> | undefined;
20
+ };
21
+ export declare function parseStaticRemotesConfig(staticRemotes: string[] | undefined, context: ExecutorContext): StaticRemotesConfig;
9
22
  export default function moduleFederationDevServer(options: ModuleFederationDevServerOptions, context: ExecutorContext): AsyncIterableIterator<{
10
23
  success: boolean;
11
24
  baseUrl?: string;
@@ -1,12 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseStaticRemotesConfig = void 0;
3
4
  const devkit_1 = require("@nx/devkit");
4
5
  const dev_server_impl_1 = require("@nx/webpack/src/executors/dev-server/dev-server.impl");
5
6
  const file_server_impl_1 = require("@nx/web/src/executors/file-server/file-server.impl");
6
7
  const module_federation_1 = require("@nx/webpack/src/utils/module-federation");
7
8
  const async_iterable_1 = require("@nx/devkit/src/utils/async-iterable");
8
9
  const wait_for_port_open_1 = require("@nx/web/src/utils/wait-for-port-open");
9
- const child_process_1 = require("child_process");
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");
14
+ const fs_1 = require("fs");
15
+ const path_1 = require("path");
10
16
  function getBuildOptions(buildTarget, context) {
11
17
  const target = (0, devkit_1.parseTargetString)(buildTarget, context);
12
18
  const buildOptions = (0, devkit_1.readTargetOptions)(target, context);
@@ -14,7 +20,133 @@ function getBuildOptions(buildTarget, context) {
14
20
  ...buildOptions,
15
21
  };
16
22
  }
23
+ function startStaticRemotesFileServer(staticRemotesConfig, context, options) {
24
+ let shouldMoveToCommonLocation = false;
25
+ let commonOutputDirectory;
26
+ for (const app of staticRemotesConfig.remotes) {
27
+ const remoteBasePath = staticRemotesConfig.config[app].basePath;
28
+ if (!commonOutputDirectory) {
29
+ commonOutputDirectory = remoteBasePath;
30
+ }
31
+ else if (commonOutputDirectory !== remoteBasePath) {
32
+ shouldMoveToCommonLocation = true;
33
+ break;
34
+ }
35
+ }
36
+ if (shouldMoveToCommonLocation) {
37
+ commonOutputDirectory = (0, node_path_1.join)(devkit_1.workspaceRoot, 'tmp/static-remotes');
38
+ for (const app of staticRemotesConfig.remotes) {
39
+ const remoteConfig = staticRemotesConfig.config[app];
40
+ (0, node_fs_1.cpSync)(remoteConfig.outputPath, (0, node_path_1.join)(commonOutputDirectory, remoteConfig.urlSegment), {
41
+ force: true,
42
+ recursive: true,
43
+ });
44
+ }
45
+ }
46
+ const staticRemotesIter = (0, file_server_impl_1.default)({
47
+ cors: true,
48
+ watch: false,
49
+ staticFilePath: commonOutputDirectory,
50
+ parallel: false,
51
+ spa: false,
52
+ withDeps: false,
53
+ host: options.host,
54
+ port: options.staticRemotesPort,
55
+ ssl: options.ssl,
56
+ sslCert: options.sslCert,
57
+ sslKey: options.sslKey,
58
+ }, context);
59
+ return staticRemotesIter;
60
+ }
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];
65
+ const isUsingModuleFederationDevServerExecutor = remoteProjectServeTarget.executor.includes('module-federation-dev-server');
66
+ const overrides = target === 'serve'
67
+ ? {
68
+ watch: true,
69
+ ...(options.host ? { host: options.host } : {}),
70
+ ...(options.ssl ? { ssl: options.ssl } : {}),
71
+ ...(options.sslCert ? { sslCert: options.sslCert } : {}),
72
+ ...(options.sslKey ? { sslKey: options.sslKey } : {}),
73
+ ...(isUsingModuleFederationDevServerExecutor
74
+ ? { isInitialHost: false }
75
+ : {}),
76
+ }
77
+ : {};
78
+ remoteIters.push(await (0, devkit_1.runExecutor)({
79
+ project: app,
80
+ target,
81
+ configuration: context.configurationName,
82
+ }, overrides, context));
83
+ }
84
+ return remoteIters;
85
+ }
86
+ async function buildStaticRemotes(staticRemotesConfig, nxBin, context, options) {
87
+ if (!staticRemotesConfig.remotes.length) {
88
+ return;
89
+ }
90
+ devkit_1.logger.info(`NX Building ${staticRemotesConfig.remotes.length} static remotes...`);
91
+ const mappedLocationOfRemotes = {};
92
+ for (const app of staticRemotesConfig.remotes) {
93
+ mappedLocationOfRemotes[app] = `http${options.ssl ? 's' : ''}://${options.host}:${options.staticRemotesPort}/${staticRemotesConfig.config[app].urlSegment}`;
94
+ }
95
+ process.env.NX_MF_DEV_SERVER_STATIC_REMOTES = JSON.stringify(mappedLocationOfRemotes);
96
+ await new Promise((res) => {
97
+ const staticProcess = (0, node_child_process_1.fork)(nxBin, [
98
+ 'run-many',
99
+ `--target=build`,
100
+ `--projects=${staticRemotesConfig.remotes.join(',')}`,
101
+ ...(context.configurationName
102
+ ? [`--configuration=${context.configurationName}`]
103
+ : []),
104
+ ...(options.parallel ? [`--parallel=${options.parallel}`] : []),
105
+ ], {
106
+ cwd: context.root,
107
+ stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
108
+ });
109
+ // File to debug build failures e.g. 2024-01-01T00_00_0_0Z-build.log'
110
+ const remoteBuildLogFile = (0, node_path_1.join)(cache_directory_1.projectGraphCacheDirectory, `${new Date().toISOString().replace(/[:\.]/g, '_')}-build.log`);
111
+ const stdoutStream = (0, node_fs_1.createWriteStream)(remoteBuildLogFile);
112
+ staticProcess.stdout.on('data', (data) => {
113
+ const ANSII_CODE_REGEX = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
114
+ const stdoutString = data.toString().replace(ANSII_CODE_REGEX, '');
115
+ stdoutStream.write(stdoutString);
116
+ if (stdoutString.includes('Successfully ran target build')) {
117
+ staticProcess.stdout.removeAllListeners('data');
118
+ devkit_1.logger.info(`NX Built ${staticRemotesConfig.remotes.length} static remotes`);
119
+ res();
120
+ }
121
+ });
122
+ staticProcess.stderr.on('data', (data) => devkit_1.logger.info(data.toString()));
123
+ staticProcess.on('exit', (code) => {
124
+ stdoutStream.end();
125
+ if (code !== 0) {
126
+ throw new Error(`Remote failed to start. A complete log can be found in: ${remoteBuildLogFile}`);
127
+ }
128
+ });
129
+ process.on('SIGTERM', () => staticProcess.kill('SIGTERM'));
130
+ process.on('exit', () => staticProcess.kill('SIGTERM'));
131
+ });
132
+ }
133
+ function parseStaticRemotesConfig(staticRemotes, context) {
134
+ if (!staticRemotes?.length) {
135
+ return { remotes: [], config: undefined };
136
+ }
137
+ const config = {};
138
+ for (const app of staticRemotes) {
139
+ const outputPath = context.projectGraph.nodes[app].data.targets['build'].options.outputPath;
140
+ const basePath = (0, node_path_1.dirname)(outputPath);
141
+ const urlSegment = (0, node_path_1.basename)(outputPath);
142
+ config[app] = { basePath, outputPath, urlSegment };
143
+ }
144
+ return { remotes: staticRemotes, config };
145
+ }
146
+ exports.parseStaticRemotesConfig = parseStaticRemotesConfig;
17
147
  async function* moduleFederationDevServer(options, context) {
148
+ const initialStaticRemotesPorts = options.staticRemotesPort;
149
+ options.staticRemotesPort ??= options.port + 1;
18
150
  // Force Node to resolve to look for the nx binary that is inside node_modules
19
151
  const nxBin = require.resolve('nx/bin/nx');
20
152
  const currIter = options.static
@@ -28,6 +160,17 @@ async function* moduleFederationDevServer(options, context) {
28
160
  : (0, dev_server_impl_1.default)(options, context);
29
161
  const p = context.projectsConfigurations.projects[context.projectName];
30
162
  const buildOptions = getBuildOptions(options.buildTarget, context);
163
+ let pathToManifestFile = (0, node_path_1.join)(context.root, p.sourceRoot, 'assets/module-federation.manifest.json');
164
+ if (options.pathToManifestFile) {
165
+ const userPathToManifestFile = (0, node_path_1.join)(context.root, options.pathToManifestFile);
166
+ if (!(0, fs_1.existsSync)(userPathToManifestFile)) {
167
+ throw new Error(`The provided Module Federation manifest file path does not exist. Please check the file exists at "${userPathToManifestFile}".`);
168
+ }
169
+ else if ((0, path_1.extname)(options.pathToManifestFile) !== '.json') {
170
+ throw new Error(`The Module Federation manifest file must be a JSON. Please ensure the file at ${userPathToManifestFile} is a JSON.`);
171
+ }
172
+ pathToManifestFile = userPathToManifestFile;
173
+ }
31
174
  if (!options.isInitialHost) {
32
175
  return yield* currIter;
33
176
  }
@@ -36,57 +179,26 @@ async function* moduleFederationDevServer(options, context) {
36
179
  projectName: context.projectName,
37
180
  projectGraph: context.projectGraph,
38
181
  root: context.root,
39
- });
40
- let isCollectingStaticRemoteOutput = true;
41
- const devRemoteIters = [];
42
- for (const app of remotes.devRemotes) {
43
- const remoteProjectServeTarget = context.projectGraph.nodes[app].data.targets['serve'];
44
- const isUsingModuleFederationDevServerExecutor = remoteProjectServeTarget.executor.includes('module-federation-dev-server');
45
- devRemoteIters.push(await (0, devkit_1.runExecutor)({
46
- project: app,
47
- target: 'serve',
48
- configuration: context.configurationName,
49
- }, {
50
- watch: true,
51
- ...(isUsingModuleFederationDevServerExecutor
52
- ? { isInitialHost: false }
53
- : {}),
54
- }, context));
55
- }
56
- for (const app of remotes.staticRemotes) {
57
- const remoteProjectServeTarget = context.projectGraph.nodes[app].data.targets['serve-static'];
58
- const isUsingModuleFederationDevServerExecutor = remoteProjectServeTarget.executor.includes('module-federation-dev-server');
59
- let outWithErr = [];
60
- const staticProcess = (0, child_process_1.fork)(nxBin, [
61
- 'run',
62
- `${app}:serve-static${context.configurationName ? `:${context.configurationName}` : ''}`,
63
- ...(isUsingModuleFederationDevServerExecutor
64
- ? [`--isInitialHost=false`]
65
- : []),
66
- ], {
67
- cwd: context.root,
68
- stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
69
- });
70
- staticProcess.stdout.on('data', (data) => {
71
- if (isCollectingStaticRemoteOutput) {
72
- outWithErr.push(data.toString());
182
+ }, pathToManifestFile);
183
+ if (remotes.devRemotes.length > 0 && !initialStaticRemotesPorts) {
184
+ options.staticRemotesPort = options.devRemotes.reduce((portToUse, r) => {
185
+ const remotePort = context.projectGraph.nodes[r].data.targets['serve'].options.port;
186
+ if (remotePort >= portToUse) {
187
+ return remotePort + 1;
73
188
  }
74
189
  else {
75
- outWithErr = null;
76
- staticProcess.stdout.removeAllListeners('data');
77
- }
78
- });
79
- staticProcess.stderr.on('data', (data) => devkit_1.logger.info(data.toString()));
80
- staticProcess.on('exit', (code) => {
81
- if (code !== 0) {
82
- devkit_1.logger.info(outWithErr.join(''));
83
- throw new Error(`Remote failed to start. See above for errors.`);
190
+ return portToUse;
84
191
  }
85
- });
86
- process.on('SIGTERM', () => staticProcess.kill('SIGTERM'));
87
- process.on('exit', () => staticProcess.kill('SIGTERM'));
192
+ }, options.staticRemotesPort);
88
193
  }
89
- return yield* (0, async_iterable_1.combineAsyncIterables)(currIter, ...devRemoteIters, (0, async_iterable_1.createAsyncIterable)(async ({ next, done }) => {
194
+ const staticRemotesConfig = parseStaticRemotesConfig(remotes.staticRemotes, context);
195
+ await buildStaticRemotes(staticRemotesConfig, nxBin, context, options);
196
+ const devRemoteIters = await startRemotes(remotes.devRemotes, context, options, 'serve');
197
+ const dynamicRemotesIters = await startRemotes(remotes.dynamicRemotes, context, options, 'serve-static');
198
+ const staticRemotesIter = remotes.staticRemotes.length > 0
199
+ ? startStaticRemotesFileServer(staticRemotesConfig, context, options)
200
+ : undefined;
201
+ return yield* (0, async_iterable_1.combineAsyncIterables)(currIter, ...devRemoteIters, ...dynamicRemotesIters, ...(staticRemotesIter ? [staticRemotesIter] : []), (0, async_iterable_1.createAsyncIterable)(async ({ next, done }) => {
90
202
  if (!options.isInitialHost) {
91
203
  done();
92
204
  return;
@@ -96,20 +208,23 @@ async function* moduleFederationDevServer(options, context) {
96
208
  return;
97
209
  }
98
210
  try {
99
- await Promise.all(remotes.remotePorts.map((port) =>
100
- // Allow 20 minutes for each remote to start, which is plenty of time but we can tweak it later if needed.
101
- // Most remotes should start in under 1 minute.
102
- (0, wait_for_port_open_1.waitForPortOpen)(port, {
211
+ const host = options.host ?? 'localhost';
212
+ const baseUrl = `http${options.ssl ? 's' : ''}://${host}:${options.port}`;
213
+ const portsToWaitFor = staticRemotesIter
214
+ ? [options.staticRemotesPort, ...remotes.remotePorts]
215
+ : [...remotes.remotePorts];
216
+ await Promise.all(portsToWaitFor.map((port) => (0, wait_for_port_open_1.waitForPortOpen)(port, {
103
217
  retries: 480,
104
218
  retryDelay: 2500,
105
- host: 'localhost',
219
+ host: host,
106
220
  })));
107
- isCollectingStaticRemoteOutput = false;
108
- devkit_1.logger.info(`NX All remotes started, server ready at http://localhost:${options.port}`);
109
- next({ success: true, baseUrl: `http://localhost:${options.port}` });
221
+ devkit_1.logger.info(`NX All remotes started, server ready at ${baseUrl}`);
222
+ next({ success: true, baseUrl: baseUrl });
110
223
  }
111
- catch {
112
- throw new Error(`Timed out waiting for remote to start. Check above for any errors.`);
224
+ catch (err) {
225
+ throw new Error(`Failed to start remotes. Check above for any errors.`, {
226
+ cause: err,
227
+ });
113
228
  }
114
229
  finally {
115
230
  done();
@@ -19,7 +19,7 @@
19
19
  "items": {
20
20
  "type": "string"
21
21
  },
22
- "description": "List of remote applications to not automatically serve, either statically or in development mode.",
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`.",
23
23
  "x-priority": "important"
24
24
  },
25
25
  "buildTarget": {
@@ -101,6 +101,18 @@
101
101
  "description": "Whether the host that is running this executor is the first in the project tree to do so.",
102
102
  "default": true,
103
103
  "x-priority": "internal"
104
+ },
105
+ "parallel": {
106
+ "type": "number",
107
+ "description": "Max number of parallel processes for building static remotes"
108
+ },
109
+ "staticRemotesPort": {
110
+ "type": "number",
111
+ "description": "The port at which to serve the file-server for the static remotes."
112
+ },
113
+ "pathToManifestFile": {
114
+ "type": "string",
115
+ "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."
104
116
  }
105
117
  }
106
118
  }
@@ -13,8 +13,8 @@ const add_styled_dependencies_1 = require("../../rules/add-styled-dependencies")
13
13
  const devkit_1 = require("@nx/devkit");
14
14
  const init_1 = require("../init/init");
15
15
  const eslint_1 = require("@nx/eslint");
16
- const lint_project_1 = require("@nx/eslint/src/generators/lint-project/lint-project");
17
16
  const versions_1 = require("../../utils/versions");
17
+ const maybe_js_1 = require("../../utils/maybe-js");
18
18
  const install_common_dependencies_1 = require("./lib/install-common-dependencies");
19
19
  const create_ts_config_1 = require("../../utils/create-ts-config");
20
20
  const add_swc_dependencies_1 = require("@nx/js/src/utils/swc/add-swc-dependencies");
@@ -22,6 +22,9 @@ const chalk = require("chalk");
22
22
  const show_possible_warnings_1 = require("./lib/show-possible-warnings");
23
23
  const add_e2e_1 = require("./lib/add-e2e");
24
24
  const eslint_file_1 = require("@nx/eslint/src/generators/utils/eslint-file");
25
+ const js_1 = require("@nx/js");
26
+ const log_show_project_command_1 = require("@nx/devkit/src/utils/log-show-project-command");
27
+ const setup_tailwind_1 = require("../setup-tailwind/setup-tailwind");
25
28
  async function addLinting(host, options) {
26
29
  const tasks = [];
27
30
  if (options.linter === eslint_1.Linter.EsLint) {
@@ -32,12 +35,10 @@ async function addLinting(host, options) {
32
35
  (0, devkit_1.joinPathFragments)(options.appProjectRoot, 'tsconfig.app.json'),
33
36
  ],
34
37
  unitTestRunner: options.unitTestRunner,
35
- eslintFilePatterns: [
36
- (0, lint_project_1.mapLintPattern)(options.appProjectRoot, '{ts,tsx,js,jsx}', options.rootProject),
37
- ],
38
38
  skipFormat: true,
39
39
  rootProject: options.rootProject,
40
40
  skipPackageJson: options.skipPackageJson,
41
+ addPlugin: options.addPlugin,
41
42
  });
42
43
  tasks.push(lintTask);
43
44
  if ((0, eslint_file_1.isEslintConfigSupported)(host)) {
@@ -53,6 +54,7 @@ async function addLinting(host, options) {
53
54
  }
54
55
  async function applicationGenerator(host, schema) {
55
56
  return await applicationGeneratorInternal(host, {
57
+ addPlugin: false,
56
58
  projectNameAndRootFormat: 'derived',
57
59
  ...schema,
58
60
  });
@@ -62,17 +64,41 @@ async function applicationGeneratorInternal(host, schema) {
62
64
  const tasks = [];
63
65
  const options = await (0, normalize_options_1.normalizeOptions)(host, schema);
64
66
  (0, show_possible_warnings_1.showPossibleWarnings)(host, options);
67
+ const jsInitTask = await (0, js_1.initGenerator)(host, {
68
+ ...schema,
69
+ tsConfigName: schema.rootProject ? 'tsconfig.json' : 'tsconfig.base.json',
70
+ skipFormat: true,
71
+ });
72
+ tasks.push(jsInitTask);
65
73
  const initTask = await (0, init_1.default)(host, {
66
74
  ...options,
67
75
  skipFormat: true,
68
- skipHelperLibs: options.bundler === 'vite',
69
76
  });
70
77
  tasks.push(initTask);
78
+ if (options.bundler === 'webpack') {
79
+ const { webpackInitGenerator } = (0, devkit_1.ensurePackage)('@nx/webpack', versions_1.nxVersion);
80
+ const webpackInitTask = await webpackInitGenerator(host, {
81
+ skipPackageJson: options.skipPackageJson,
82
+ skipFormat: true,
83
+ addPlugin: options.addPlugin,
84
+ });
85
+ tasks.push(webpackInitTask);
86
+ if (!options.skipPackageJson) {
87
+ const { ensureDependencies } = await Promise.resolve().then(() => require('@nx/webpack/src/utils/ensure-dependencies'));
88
+ tasks.push(ensureDependencies(host, { uiFramework: 'react' }));
89
+ }
90
+ }
71
91
  if (!options.rootProject) {
72
92
  (0, create_ts_config_1.extractTsConfigBase)(host);
73
93
  }
74
94
  (0, create_application_files_1.createApplicationFiles)(host, options);
75
95
  (0, add_project_1.addProject)(host, options);
96
+ if (options.style === 'tailwind') {
97
+ const twTask = await (0, setup_tailwind_1.setupTailwindGenerator)(host, {
98
+ project: options.projectName,
99
+ });
100
+ tasks.push(twTask);
101
+ }
76
102
  if (options.bundler === 'vite') {
77
103
  const { createOrEditViteConfig, viteConfigurationGenerator } = (0, devkit_1.ensurePackage)('@nx/vite', versions_1.nxVersion);
78
104
  // We recommend users use `import.meta.env.MODE` and other variables in their code to differentiate between production and development.
@@ -88,6 +114,7 @@ async function applicationGeneratorInternal(host, schema) {
88
114
  inSourceTests: options.inSourceTests,
89
115
  compiler: options.compiler,
90
116
  skipFormat: true,
117
+ addPlugin: options.addPlugin,
91
118
  });
92
119
  tasks.push(viteTask);
93
120
  createOrEditViteConfig(host, {
@@ -108,23 +135,15 @@ async function applicationGeneratorInternal(host, schema) {
108
135
  plugins: ['react()'],
109
136
  }, false);
110
137
  }
111
- else if (options.bundler === 'webpack') {
112
- const { webpackInitGenerator } = (0, devkit_1.ensurePackage)('@nx/webpack', versions_1.nxVersion);
113
- const webpackInitTask = await webpackInitGenerator(host, {
114
- uiFramework: 'react',
115
- skipFormat: true,
116
- });
117
- tasks.push(webpackInitTask);
118
- }
119
138
  else if (options.bundler === 'rspack') {
120
139
  const { configurationGenerator } = (0, devkit_1.ensurePackage)('@nx/rspack', versions_1.nxRspackVersion);
121
140
  const rspackTask = await configurationGenerator(host, {
122
141
  project: options.projectName,
123
- main: (0, devkit_1.joinPathFragments)(options.appProjectRoot, (0, add_project_1.maybeJs)(options, `src/main.tsx`)),
142
+ main: (0, devkit_1.joinPathFragments)(options.appProjectRoot, (0, maybe_js_1.maybeJs)(options, `src/main.tsx`)),
124
143
  tsConfig: (0, devkit_1.joinPathFragments)(options.appProjectRoot, 'tsconfig.app.json'),
125
144
  target: 'web',
126
145
  newProject: true,
127
- uiFramework: 'react',
146
+ framework: 'react',
128
147
  });
129
148
  tasks.push(rspackTask);
130
149
  }
@@ -132,10 +151,11 @@ async function applicationGeneratorInternal(host, schema) {
132
151
  const { createOrEditViteConfig, vitestGenerator } = (0, devkit_1.ensurePackage)('@nx/vite', versions_1.nxVersion);
133
152
  const vitestTask = await vitestGenerator(host, {
134
153
  uiFramework: 'react',
135
- coverageProvider: 'c8',
154
+ coverageProvider: 'v8',
136
155
  project: options.projectName,
137
156
  inSourceTests: options.inSourceTests,
138
157
  skipFormat: true,
158
+ addPlugin: options.addPlugin,
139
159
  });
140
160
  tasks.push(vitestTask);
141
161
  createOrEditViteConfig(host, {
@@ -181,8 +201,8 @@ async function applicationGeneratorInternal(host, schema) {
181
201
  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.`);
182
202
  tasks.push((0, devkit_1.addDependenciesToPackageJson)(host, {}, { 'babel-loader': versions_1.babelLoaderVersion }));
183
203
  host.write((0, devkit_1.joinPathFragments)(options.appProjectRoot, 'rspack.config.js'), (0, devkit_1.stripIndents) `
184
- const { composePlugins, withNx, withWeb } = require('@nx/rspack');
185
- module.exports = composePlugins(withNx(), withWeb(), (config) => {
204
+ const { composePlugins, withNx, withReact } = require('@nx/rspack');
205
+ module.exports = composePlugins(withNx(), withReact(), (config) => {
186
206
  config.module.rules.push({
187
207
  test: /\\.[jt]sx$/i,
188
208
  use: [
@@ -202,6 +222,9 @@ async function applicationGeneratorInternal(host, schema) {
202
222
  if (!options.skipFormat) {
203
223
  await (0, devkit_1.formatFiles)(host);
204
224
  }
225
+ tasks.push(() => {
226
+ (0, log_show_project_command_1.logShowProjectCommand)(options.projectName);
227
+ });
205
228
  return (0, devkit_1.runTasksInSerial)(...tasks);
206
229
  }
207
230
  exports.applicationGeneratorInternal = applicationGeneratorInternal;
@@ -7,7 +7,7 @@
7
7
 
8
8
  <meta name="viewport" content="width=device-width, initial-scale=1" />
9
9
  <link rel="icon" type="image/x-icon" href="/favicon.ico" />
10
- <% if (!styledModule && style !== 'none') { %><link rel="stylesheet" href="/src/styles.<%= style %>" /><% } %>
10
+ <% if (!styledModule && style !== 'none') { %><link rel="stylesheet" href="/src/styles.<%= style === 'tailwind' ? 'css' : style %>" /><% } %>
11
11
  </head>
12
12
  <body>
13
13
  <div id="root"></div>
@@ -3,8 +3,6 @@
3
3
  <head>
4
4
  <meta charset="utf-8" />
5
5
  <title><%= className %></title>
6
- <base href="/" />
7
-
8
6
  <meta name="viewport" content="width=device-width, initial-scale=1" />
9
7
  <link rel="icon" type="image/x-icon" href="favicon.ico" />
10
8
  </head>
@@ -1,9 +1,50 @@
1
+ <% if (webpackPluginOptions) { %>
2
+ const { NxWebpackPlugin } = require('@nx/webpack');
3
+ const { NxReactWebpackPlugin } = require('@nx/react');
4
+ const { join } = require('path');
5
+
6
+ module.exports = {
7
+ output: {
8
+ path: join(__dirname, '<%= offsetFromRoot %><%= webpackPluginOptions.outputPath %>'),
9
+ },
10
+ devServer: {
11
+ port: 4200
12
+ },
13
+ plugins: [
14
+ new NxWebpackPlugin({
15
+ tsConfig: '<%= webpackPluginOptions.tsConfig %>',
16
+ compiler: '<%= webpackPluginOptions.compiler %>',
17
+ main: '<%= webpackPluginOptions.main %>',
18
+ index: '<%= webpackPluginOptions.index %>',
19
+ baseHref: '<%= webpackPluginOptions.baseHref %>',
20
+ assets: <%- JSON.stringify(webpackPluginOptions.assets) %>,
21
+ styles: <%- JSON.stringify(webpackPluginOptions.styles) %>,
22
+ outputHashing: process.env['NODE_ENV'] === 'production' ? 'all' : 'none',
23
+ optimization: process.env['NODE_ENV'] === 'production',
24
+ }),
25
+ new NxReactWebpackPlugin({
26
+ // Uncomment this line if you don't want to use SVGR
27
+ // See: https://react-svgr.com/
28
+ // svgr: false
29
+ }),
30
+ ],
31
+ };
32
+ <% } else { %>
1
33
  const { composePlugins, withNx } = require('@nx/webpack');
2
34
  const { withReact } = require('@nx/react');
3
35
 
4
36
  // Nx plugins for webpack.
5
- module.exports = composePlugins(withNx(), withReact(), (config) => {
6
- // Update the webpack config as needed here.
7
- // e.g. `config.plugins.push(new MyPlugin())`
8
- return config;
9
- });
37
+ module.exports = composePlugins(
38
+ withNx(),
39
+ withReact({
40
+ // Uncomment this line if you don't want to use SVGR
41
+ // See: https://react-svgr.com/
42
+ // svgr: false
43
+ }),
44
+ (config) => {
45
+ // Update the webpack config as needed here.
46
+ // e.g. `config.plugins.push(new MyPlugin())`
47
+ return config;
48
+ }
49
+ );
50
+ <% } %>