@nx/react 17.0.2 → 17.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) 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 +12 -0
  25. package/src/executors/module-federation-dev-server/module-federation-dev-server.impl.js +149 -51
  26. package/src/executors/module-federation-dev-server/schema.json +9 -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 +27 -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 +11 -10
  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/lib/add-tailwind-style-imports.js +3 -0
  113. package/src/generators/setup-tailwind/schema.json +1 -1
  114. package/src/generators/stories/schema.json +1 -1
  115. package/src/generators/stories/stories.js +17 -5
  116. package/src/generators/storybook-configuration/configuration.d.ts +2 -0
  117. package/src/generators/storybook-configuration/configuration.js +37 -15
  118. package/src/generators/storybook-configuration/schema.d.ts +2 -1
  119. package/src/generators/storybook-configuration/schema.json +7 -7
  120. package/src/migrations/update-18-0-0/add-mf-env-var-to-target-defaults.d.ts +2 -0
  121. package/src/migrations/update-18-0-0/add-mf-env-var-to-target-defaults.js +26 -0
  122. package/src/migrations/update-18-1-1/fix-target-defaults-inputs.d.ts +2 -0
  123. package/src/migrations/update-18-1-1/fix-target-defaults-inputs.js +53 -0
  124. package/src/module-federation/ast-utils.js +1 -1
  125. package/src/module-federation/utils.js +8 -1
  126. package/src/module-federation/with-module-federation-ssr.js +3 -0
  127. package/src/module-federation/with-module-federation.d.ts +3 -3
  128. package/src/module-federation/with-module-federation.js +14 -4
  129. package/src/rules/update-module-federation-project.d.ts +2 -0
  130. package/src/rules/update-module-federation-project.js +12 -3
  131. package/src/utils/add-mf-env-to-inputs.d.ts +2 -0
  132. package/src/utils/add-mf-env-to-inputs.js +27 -0
  133. package/src/utils/assertion.js +1 -0
  134. package/src/utils/ct-utils.d.ts +6 -1
  135. package/src/utils/ct-utils.js +39 -9
  136. package/src/utils/get-in-source-vitest-tests-template.js +1 -1
  137. package/src/utils/has-vite-plugin.d.ts +2 -0
  138. package/src/utils/has-vite-plugin.js +11 -0
  139. package/src/utils/has-webpack-plugin.d.ts +2 -0
  140. package/src/utils/has-webpack-plugin.js +11 -0
  141. package/src/utils/maybe-js.d.ts +3 -0
  142. package/src/utils/versions.d.ts +3 -3
  143. package/src/utils/versions.js +3 -3
  144. package/typings/style.d.ts +1 -0
  145. package/src/generators/application/files/base-webpack/src/environments/environment.prod.ts__tmpl__ +0 -3
  146. package/src/generators/application/files/base-webpack/src/environments/environment.ts__tmpl__ +0 -6
  147. package/src/generators/host/files/module-federation/src/main.ts__tmpl__ +0 -1
  148. package/src/generators/host/files/module-federation-ts/src/main.ts__tmpl__ +0 -1
  149. package/src/generators/library/lib/maybe-js.d.ts +0 -2
  150. /package/src/generators/host/files/common/src/app/{__fileName__.tsx__tmpl__ → __fileName__.js__tmpl__} +0 -0
  151. /package/src/generators/remote/files/{module-federation/src/main.ts__tmpl__ → common/src/main.js__tmpl__} +0 -0
  152. /package/src/generators/remote/files/{module-federation/src/remote-entry.ts__tmpl__ → common/src/remote-entry.js__tmpl__} +0 -0
  153. /package/src/generators/remote/files/{module-federation-ts → common-ts}/src/main.ts__tmpl__ +0 -0
  154. /package/src/generators/remote/files/{module-federation-ts → common-ts}/src/remote-entry.ts__tmpl__ +0 -0
  155. /package/src/{generators/library/lib → utils}/maybe-js.js +0 -0
@@ -5,7 +5,19 @@ type ModuleFederationDevServerOptions = WebDevServerOptions & {
5
5
  skipRemotes?: string[];
6
6
  static?: boolean;
7
7
  isInitialHost?: boolean;
8
+ parallel?: number;
9
+ staticRemotesPort?: number;
8
10
  };
11
+ type StaticRemoteConfig = {
12
+ basePath: string;
13
+ outputPath: string;
14
+ urlSegment: string;
15
+ };
16
+ type StaticRemotesConfig = {
17
+ remotes: string[];
18
+ config: Record<string, StaticRemoteConfig> | undefined;
19
+ };
20
+ export declare function parseStaticRemotesConfig(staticRemotes: string[] | undefined, context: ExecutorContext): StaticRemotesConfig;
9
21
  export default function moduleFederationDevServer(options: ModuleFederationDevServerOptions, context: ExecutorContext): AsyncIterableIterator<{
10
22
  success: boolean;
11
23
  baseUrl?: string;
@@ -1,12 +1,16 @@
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");
10
14
  function getBuildOptions(buildTarget, context) {
11
15
  const target = (0, devkit_1.parseTargetString)(buildTarget, context);
12
16
  const buildOptions = (0, devkit_1.readTargetOptions)(target, context);
@@ -14,30 +18,45 @@ function getBuildOptions(buildTarget, context) {
14
18
  ...buildOptions,
15
19
  };
16
20
  }
17
- async function* moduleFederationDevServer(options, context) {
18
- // Force Node to resolve to look for the nx binary that is inside node_modules
19
- const nxBin = require.resolve('nx/bin/nx');
20
- const currIter = options.static
21
- ? (0, file_server_impl_1.default)({
22
- ...options,
23
- parallel: false,
24
- withDeps: false,
25
- spa: false,
26
- cors: true,
27
- }, context)
28
- : (0, dev_server_impl_1.default)(options, context);
29
- const p = context.projectsConfigurations.projects[context.projectName];
30
- const buildOptions = getBuildOptions(options.buildTarget, context);
31
- if (!options.isInitialHost) {
32
- return yield* currIter;
21
+ function startStaticRemotesFileServer(staticRemotesConfig, context, options) {
22
+ let shouldMoveToCommonLocation = false;
23
+ let commonOutputDirectory;
24
+ for (const app of staticRemotesConfig.remotes) {
25
+ const remoteBasePath = staticRemotesConfig.config[app].basePath;
26
+ if (!commonOutputDirectory) {
27
+ commonOutputDirectory = remoteBasePath;
28
+ }
29
+ else if (commonOutputDirectory !== remoteBasePath) {
30
+ shouldMoveToCommonLocation = true;
31
+ break;
32
+ }
33
33
  }
34
- const moduleFederationConfig = (0, module_federation_1.getModuleFederationConfig)(buildOptions.tsConfig, context.root, p.root, 'react');
35
- const remotes = (0, module_federation_1.getRemotes)(options.devRemotes, options.skipRemotes, moduleFederationConfig, {
36
- projectName: context.projectName,
37
- projectGraph: context.projectGraph,
38
- root: context.root,
39
- });
40
- let isCollectingStaticRemoteOutput = true;
34
+ if (shouldMoveToCommonLocation) {
35
+ commonOutputDirectory = (0, node_path_1.join)(devkit_1.workspaceRoot, 'tmp/static-remotes');
36
+ for (const app of staticRemotesConfig.remotes) {
37
+ const remoteConfig = staticRemotesConfig.config[app];
38
+ (0, node_fs_1.cpSync)(remoteConfig.outputPath, (0, node_path_1.join)(commonOutputDirectory, remoteConfig.urlSegment), {
39
+ force: true,
40
+ recursive: true,
41
+ });
42
+ }
43
+ }
44
+ const staticRemotesIter = (0, file_server_impl_1.default)({
45
+ cors: true,
46
+ watch: false,
47
+ staticFilePath: commonOutputDirectory,
48
+ parallel: false,
49
+ spa: false,
50
+ withDeps: false,
51
+ host: options.host,
52
+ port: options.staticRemotesPort,
53
+ ssl: options.ssl,
54
+ sslCert: options.sslCert,
55
+ sslKey: options.sslKey,
56
+ }, context);
57
+ return staticRemotesIter;
58
+ }
59
+ async function startDevRemotes(remotes, context, options) {
41
60
  const devRemoteIters = [];
42
61
  for (const app of remotes.devRemotes) {
43
62
  const remoteProjectServeTarget = context.projectGraph.nodes[app].data.targets['serve'];
@@ -48,45 +67,121 @@ async function* moduleFederationDevServer(options, context) {
48
67
  configuration: context.configurationName,
49
68
  }, {
50
69
  watch: true,
70
+ ...(options.host ? { host: options.host } : {}),
71
+ ...(options.ssl ? { ssl: options.ssl } : {}),
72
+ ...(options.sslCert ? { sslCert: options.sslCert } : {}),
73
+ ...(options.sslKey ? { sslKey: options.sslKey } : {}),
51
74
  ...(isUsingModuleFederationDevServerExecutor
52
75
  ? { isInitialHost: false }
53
76
  : {}),
54
77
  }, context));
55
78
  }
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`]
79
+ return devRemoteIters;
80
+ }
81
+ async function buildStaticRemotes(staticRemotesConfig, nxBin, context, options) {
82
+ if (!staticRemotesConfig.remotes.length) {
83
+ return;
84
+ }
85
+ devkit_1.logger.info(`NX Building ${staticRemotesConfig.remotes.length} static remotes...`);
86
+ const mappedLocationOfRemotes = {};
87
+ for (const app of staticRemotesConfig.remotes) {
88
+ mappedLocationOfRemotes[app] = `http${options.ssl ? 's' : ''}://${options.host}:${options.staticRemotesPort}/${staticRemotesConfig.config[app].urlSegment}`;
89
+ }
90
+ process.env.NX_MF_DEV_SERVER_STATIC_REMOTES = JSON.stringify(mappedLocationOfRemotes);
91
+ await new Promise((res) => {
92
+ const staticProcess = (0, node_child_process_1.fork)(nxBin, [
93
+ 'run-many',
94
+ `--target=build`,
95
+ `--projects=${staticRemotesConfig.remotes.join(',')}`,
96
+ ...(context.configurationName
97
+ ? [`--configuration=${context.configurationName}`]
65
98
  : []),
99
+ ...(options.parallel ? [`--parallel=${options.parallel}`] : []),
66
100
  ], {
67
101
  cwd: context.root,
68
102
  stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
69
103
  });
104
+ // File to debug build failures e.g. 2024-01-01T00_00_0_0Z-build.log'
105
+ const remoteBuildLogFile = (0, node_path_1.join)(cache_directory_1.projectGraphCacheDirectory, `${new Date().toISOString().replace(/[:\.]/g, '_')}-build.log`);
106
+ const stdoutStream = (0, node_fs_1.createWriteStream)(remoteBuildLogFile);
70
107
  staticProcess.stdout.on('data', (data) => {
71
- if (isCollectingStaticRemoteOutput) {
72
- outWithErr.push(data.toString());
73
- }
74
- else {
75
- outWithErr = null;
108
+ const ANSII_CODE_REGEX = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
109
+ const stdoutString = data.toString().replace(ANSII_CODE_REGEX, '');
110
+ stdoutStream.write(stdoutString);
111
+ if (stdoutString.includes('Successfully ran target build')) {
76
112
  staticProcess.stdout.removeAllListeners('data');
113
+ devkit_1.logger.info(`NX Built ${staticRemotesConfig.remotes.length} static remotes`);
114
+ res();
77
115
  }
78
116
  });
79
117
  staticProcess.stderr.on('data', (data) => devkit_1.logger.info(data.toString()));
80
118
  staticProcess.on('exit', (code) => {
119
+ stdoutStream.end();
81
120
  if (code !== 0) {
82
- devkit_1.logger.info(outWithErr.join(''));
83
- throw new Error(`Remote failed to start. See above for errors.`);
121
+ throw new Error(`Remote failed to start. A complete log can be found in: ${remoteBuildLogFile}`);
84
122
  }
85
123
  });
86
124
  process.on('SIGTERM', () => staticProcess.kill('SIGTERM'));
87
125
  process.on('exit', () => staticProcess.kill('SIGTERM'));
126
+ });
127
+ }
128
+ function parseStaticRemotesConfig(staticRemotes, context) {
129
+ if (!staticRemotes?.length) {
130
+ return { remotes: [], config: undefined };
131
+ }
132
+ const config = {};
133
+ for (const app of staticRemotes) {
134
+ const outputPath = context.projectGraph.nodes[app].data.targets['build'].options.outputPath;
135
+ const basePath = (0, node_path_1.dirname)(outputPath);
136
+ const urlSegment = (0, node_path_1.basename)(outputPath);
137
+ config[app] = { basePath, outputPath, urlSegment };
138
+ }
139
+ return { remotes: staticRemotes, config };
140
+ }
141
+ exports.parseStaticRemotesConfig = parseStaticRemotesConfig;
142
+ async function* moduleFederationDevServer(options, context) {
143
+ const initialStaticRemotesPorts = options.staticRemotesPort;
144
+ options.staticRemotesPort ??= options.port + 1;
145
+ // Force Node to resolve to look for the nx binary that is inside node_modules
146
+ const nxBin = require.resolve('nx/bin/nx');
147
+ const currIter = options.static
148
+ ? (0, file_server_impl_1.default)({
149
+ ...options,
150
+ parallel: false,
151
+ withDeps: false,
152
+ spa: false,
153
+ cors: true,
154
+ }, context)
155
+ : (0, dev_server_impl_1.default)(options, context);
156
+ const p = context.projectsConfigurations.projects[context.projectName];
157
+ const buildOptions = getBuildOptions(options.buildTarget, context);
158
+ if (!options.isInitialHost) {
159
+ return yield* currIter;
160
+ }
161
+ const moduleFederationConfig = (0, module_federation_1.getModuleFederationConfig)(buildOptions.tsConfig, context.root, p.root, 'react');
162
+ const remotes = (0, module_federation_1.getRemotes)(options.devRemotes, options.skipRemotes, moduleFederationConfig, {
163
+ projectName: context.projectName,
164
+ projectGraph: context.projectGraph,
165
+ root: context.root,
166
+ });
167
+ if (remotes.devRemotes.length > 0 && !initialStaticRemotesPorts) {
168
+ options.staticRemotesPort = options.devRemotes.reduce((portToUse, r) => {
169
+ const remotePort = context.projectGraph.nodes[r].data.targets['serve'].options.port;
170
+ if (remotePort >= portToUse) {
171
+ return remotePort + 1;
172
+ }
173
+ else {
174
+ return portToUse;
175
+ }
176
+ }, options.staticRemotesPort);
88
177
  }
89
- return yield* (0, async_iterable_1.combineAsyncIterables)(currIter, ...devRemoteIters, (0, async_iterable_1.createAsyncIterable)(async ({ next, done }) => {
178
+ const staticRemotesConfig = parseStaticRemotesConfig(remotes.staticRemotes, context);
179
+ await buildStaticRemotes(staticRemotesConfig, nxBin, context, options);
180
+ const devRemoteIters = await startDevRemotes(remotes, context, options);
181
+ const staticRemotesIter = remotes.staticRemotes.length > 0
182
+ ? startStaticRemotesFileServer(staticRemotesConfig, context, options)
183
+ : undefined;
184
+ return yield* (0, async_iterable_1.combineAsyncIterables)(currIter, ...devRemoteIters, ...(staticRemotesIter ? [staticRemotesIter] : []), (0, async_iterable_1.createAsyncIterable)(async ({ next, done }) => {
90
185
  if (!options.isInitialHost) {
91
186
  done();
92
187
  return;
@@ -96,20 +191,23 @@ async function* moduleFederationDevServer(options, context) {
96
191
  return;
97
192
  }
98
193
  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, {
194
+ const host = options.host ?? 'localhost';
195
+ const baseUrl = `http${options.ssl ? 's' : ''}://${host}:${options.port}`;
196
+ const portsToWaitFor = staticRemotesIter
197
+ ? [options.staticRemotesPort, ...remotes.remotePorts]
198
+ : [...remotes.remotePorts];
199
+ await Promise.all(portsToWaitFor.map((port) => (0, wait_for_port_open_1.waitForPortOpen)(port, {
103
200
  retries: 480,
104
201
  retryDelay: 2500,
105
- host: 'localhost',
202
+ host: host,
106
203
  })));
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}` });
204
+ devkit_1.logger.info(`NX All remotes started, server ready at ${baseUrl}`);
205
+ next({ success: true, baseUrl: baseUrl });
110
206
  }
111
- catch {
112
- throw new Error(`Timed out waiting for remote to start. Check above for any errors.`);
207
+ catch (err) {
208
+ throw new Error(`Failed to start remotes. Check above for any errors.`, {
209
+ cause: err,
210
+ });
113
211
  }
114
212
  finally {
115
213
  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,14 @@
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."
104
112
  }
105
113
  }
106
114
  }
@@ -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
+ <% } %>
@@ -274,12 +274,21 @@ export function NxWelcome({ title }: { title: string }) {
274
274
  .button-pill:hover {
275
275
  color: rgba(255, 255, 255, 1) !important;
276
276
  }
277
- .nx-console:hover {
277
+ #nx-console:hover {
278
278
  background-color: rgba(0, 122, 204, 1);
279
279
  }
280
- .nx-console svg {
280
+ #nx-console svg {
281
281
  color: rgba(0, 122, 204, 1);
282
282
  }
283
+ #nx-console-jetbrains {
284
+ margin-top: 2rem;
285
+ }
286
+ #nx-console-jetbrains:hover {
287
+ background-color: rgba(255, 49, 140, 1);
288
+ }
289
+ #nx-console-jetbrains svg {
290
+ color: rgba(255, 49, 140, 1);
291
+ }
283
292
  #nx-repo:hover {
284
293
  background-color: rgba(24, 23, 23, 1);
285
294
  }
@@ -644,7 +653,8 @@ export function NxWelcome({ title }: { title: string }) {
644
653
  </div>
645
654
  <div id="other-links">
646
655
  <a
647
- className="button-pill nx-console rounded shadow"
656
+ id="nx-console"
657
+ className="button-pill rounded shadow"
648
658
  href="https://marketplace.visualstudio.com/items?itemName=nrwl.angular-console&utm_source=nx-project"
649
659
  target="_blank"
650
660
  rel="noreferrer"
@@ -660,23 +670,35 @@ export function NxWelcome({ title }: { title: string }) {
660
670
  </svg>
661
671
  <span>
662
672
  Install Nx Console for VSCode
663
- <span>The official VSCode plugin for Nx.</span>
673
+ <span>The official VSCode extension for Nx.</span>
664
674
  </span>
665
675
  </a>
666
676
  <a
667
- className="button-pill nx-console rounded shadow"
677
+ id="nx-console-jetbrains"
678
+ className="button-pill rounded shadow"
668
679
  href="https://plugins.jetbrains.com/plugin/21060-nx-console"
669
680
  target="_blank"
670
681
  rel="noreferrer"
671
682
  >
672
683
  <svg
673
- fill="currentColor"
674
- role="img"
675
- viewBox="0 0 24 24"
684
+ height="48"
685
+ width="48"
686
+ viewBox="20 20 60 60"
676
687
  xmlns="http://www.w3.org/2000/svg"
677
688
  >
678
- <title>IntelliJ</title>
679
- <path d="M0 0v24h24V0zm3.723 3.111h5v1.834h-1.39v6.277h1.39v1.834h-5v-1.834h1.444V4.945H3.723zm11.055 0H17v6.5c0 .612-.055 1.111-.222 1.556-.167.444-.39.777-.723 1.11-.277.279-.666.557-1.11.668a3.933 3.933 0 0 1-1.445.278c-.778 0-1.444-.167-1.944-.445a4.81 4.81 0 0 1-1.279-1.056l1.39-1.555c.277.334.555.555.833.722.277.167.611.278.945.278.389 0 .721-.111 1-.389.221-.278.333-.667.333-1.278zM2.222 19.5h9V21h-9z"></path>
689
+ <path d="m22.5 22.5h60v60h-60z" />
690
+ <g fill="#fff">
691
+ <path d="m29.03 71.25h22.5v3.75h-22.5z" />
692
+ <path d="m28.09 38 1.67-1.58a1.88 1.88 0 0 0 1.47.87c.64 0 1.06-.44 1.06-1.31v-5.98h2.58v6a3.48 3.48 0 0 1 -.87 2.6 3.56 3.56 0 0 1 -2.57.95 3.84 3.84 0 0 1 -3.34-1.55z" />
693
+ <path d="m36 30h7.53v2.19h-5v1.44h4.49v2h-4.42v1.49h5v2.21h-7.6z" />
694
+ <path d="m47.23 32.29h-2.8v-2.29h8.21v2.27h-2.81v7.1h-2.6z" />
695
+ <path d="m29.13 43.08h4.42a3.53 3.53 0 0 1 2.55.83 2.09 2.09 0 0 1 .6 1.53 2.16 2.16 0 0 1 -1.44 2.09 2.27 2.27 0 0 1 1.86 2.29c0 1.61-1.31 2.59-3.55 2.59h-4.44zm5 2.89c0-.52-.42-.8-1.18-.8h-1.29v1.64h1.24c.79 0 1.25-.26 1.25-.81zm-.9 2.66h-1.57v1.73h1.62c.8 0 1.24-.31 1.24-.86 0-.5-.4-.87-1.27-.87z" />
696
+ <path d="m38 43.08h4.1a4.19 4.19 0 0 1 3 1 2.93 2.93 0 0 1 .9 2.19 3 3 0 0 1 -1.93 2.89l2.24 3.27h-3l-1.88-2.84h-.87v2.84h-2.56zm4 4.5c.87 0 1.39-.43 1.39-1.11 0-.75-.54-1.12-1.4-1.12h-1.44v2.26z" />
697
+ <path d="m49.59 43h2.5l4 9.44h-2.79l-.67-1.69h-3.63l-.67 1.69h-2.71zm2.27 5.73-1-2.65-1.06 2.65z" />
698
+ <path d="m56.46 43.05h2.6v9.37h-2.6z" />
699
+ <path d="m60.06 43.05h2.42l3.37 5v-5h2.57v9.37h-2.26l-3.53-5.14v5.14h-2.57z" />
700
+ <path d="m68.86 51 1.45-1.73a4.84 4.84 0 0 0 3 1.13c.71 0 1.08-.24 1.08-.65 0-.4-.31-.6-1.59-.91-2-.46-3.53-1-3.53-2.93 0-1.74 1.37-3 3.62-3a5.89 5.89 0 0 1 3.86 1.25l-1.26 1.84a4.63 4.63 0 0 0 -2.62-.92c-.63 0-.94.25-.94.6 0 .42.32.61 1.63.91 2.14.46 3.44 1.16 3.44 2.91 0 1.91-1.51 3-3.79 3a6.58 6.58 0 0 1 -4.35-1.5z" />
701
+ </g>
680
702
  </svg>
681
703
  <span>
682
704
  Install Nx Console for JetBrains
@@ -705,7 +727,7 @@ export function NxWelcome({ title }: { title: string }) {
705
727
  />
706
728
  </svg>
707
729
  <h2>
708
- NxCloud
730
+ Nx Cloud
709
731
  <span>Enable faster CI & better DX</span>
710
732
  </h2>
711
733
  </div>
@@ -713,7 +735,7 @@ export function NxWelcome({ title }: { title: string }) {
713
735
  You can activate distributed tasks executions and caching by
714
736
  running:
715
737
  </p>
716
- <pre>nx connect-to-nx-cloud</pre>
738
+ <pre>nx connect</pre>
717
739
  <a
718
740
  href="https://nx.app/?utm_source=nx-project"
719
741
  target="_blank"
@@ -770,9 +792,28 @@ export function NxWelcome({ title }: { title: string }) {
770
792
  <span># Generate UI lib</span>
771
793
  nx g @nx/react:lib ui
772
794
  <span># Add a component</span>
773
- nx g @nx/react:component button --project ui
795
+ nx g @nx/react:component ui/src/lib/button
774
796
  </pre>
775
797
  </details>
798
+ <details>
799
+ <summary>
800
+ <svg
801
+ fill="none"
802
+ stroke="currentColor"
803
+ viewBox="0 0 24 24"
804
+ xmlns="http://www.w3.org/2000/svg"
805
+ >
806
+ <path
807
+ strokeLinecap="round"
808
+ strokeLinejoin="round"
809
+ strokeWidth="2"
810
+ d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
811
+ />
812
+ </svg>
813
+ View project details
814
+ </summary>
815
+ <pre>nx show project {title} --web</pre>
816
+ </details>
776
817
  <details>
777
818
  <summary>
778
819
  <svg