@nx/react 21.0.0-beta.0 → 21.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/package.json +6 -6
  2. package/plugins/nx-react-webpack-plugin/lib/apply-react-config.js +3 -1
  3. package/router-plugin.d.ts +1 -0
  4. package/router-plugin.js +5 -0
  5. package/src/generators/application/application.js +52 -15
  6. package/src/generators/application/files/react-router-ssr/common/app/app-nav.tsx__tmpl__ +14 -0
  7. package/src/generators/application/files/react-router-ssr/common/app/entry.client.tsx__tmpl__ +18 -0
  8. package/src/generators/application/files/react-router-ssr/common/app/entry.server.tsx__tmpl__ +74 -0
  9. package/src/generators/application/files/react-router-ssr/common/app/root.tsx__tmpl__ +51 -0
  10. package/src/generators/application/files/react-router-ssr/common/app/routes/about.tsx__tmpl__ +7 -0
  11. package/src/generators/application/files/react-router-ssr/common/app/routes.tsx__tmpl__ +6 -0
  12. package/src/generators/application/files/react-router-ssr/common/public/favicon.ico +0 -0
  13. package/src/generators/application/files/react-router-ssr/common/react-router.config.ts__tmpl__ +5 -0
  14. package/src/generators/application/files/react-router-ssr/common/tests/routes/_index.spec.tsx__tmpl__ +16 -0
  15. package/src/generators/application/files/react-router-ssr/common/tsconfig.app.json__tmpl__ +23 -0
  16. package/src/generators/application/files/react-router-ssr/common/tsconfig.json__tmpl__ +27 -0
  17. package/src/generators/application/files/react-router-ssr/non-root/.gitignore__tmpl__ +5 -0
  18. package/src/generators/application/files/react-router-ssr/non-root/package.json__tmpl__ +24 -0
  19. package/src/generators/application/files/react-router-ssr/nx-welcome/claimed/app/nx-welcome.tsx__tmpl__ +866 -0
  20. package/src/generators/application/files/react-router-ssr/nx-welcome/not-configured/app/nx-welcome.tsx__tmpl__ +866 -0
  21. package/src/generators/application/files/react-router-ssr/nx-welcome/unclaimed/app/nx-welcome.tsx__tmpl__ +864 -0
  22. package/src/generators/application/files/react-router-ssr/ts-solution/package.json__tmpl__ +24 -0
  23. package/src/generators/application/files/react-router-ssr/ts-solution/tsconfig.app.json__tmpl__ +39 -0
  24. package/src/generators/application/lib/add-e2e.js +33 -24
  25. package/src/generators/application/lib/add-jest.js +26 -2
  26. package/src/generators/application/lib/add-linting.d.ts +1 -0
  27. package/src/generators/application/lib/add-linting.js +38 -0
  28. package/src/generators/application/lib/add-project.js +31 -15
  29. package/src/generators/application/lib/add-routing.js +1 -1
  30. package/src/generators/application/lib/bundlers/add-rspack.d.ts +0 -1
  31. package/src/generators/application/lib/bundlers/add-rspack.js +0 -18
  32. package/src/generators/application/lib/bundlers/add-vite.js +15 -6
  33. package/src/generators/application/lib/create-application-files.d.ts +61 -0
  34. package/src/generators/application/lib/create-application-files.js +81 -39
  35. package/src/generators/application/lib/get-app-tests.js +3 -3
  36. package/src/generators/application/lib/install-common-dependencies.js +13 -2
  37. package/src/generators/application/lib/normalize-options.d.ts +0 -2
  38. package/src/generators/application/lib/normalize-options.js +14 -20
  39. package/src/generators/application/schema.d.ts +5 -1
  40. package/src/generators/application/schema.json +10 -1
  41. package/src/generators/component-test/component-test.js +1 -1
  42. package/src/generators/cypress-component-configuration/lib/add-files.d.ts +1 -1
  43. package/src/generators/cypress-component-configuration/lib/add-files.js +7 -4
  44. package/src/generators/host/files/rspack-module-federation/rspack.config.js__tmpl__ +37 -13
  45. package/src/generators/host/files/rspack-module-federation/rspack.config.prod.js__tmpl__ +60 -32
  46. package/src/generators/host/files/rspack-module-federation-ssr/module-federation.server.config.js__tmpl__ +6 -0
  47. package/src/generators/host/files/rspack-module-federation-ssr/rspack.config.js__tmpl__ +66 -0
  48. package/src/generators/host/files/rspack-module-federation-ssr/server.ts__tmpl__ +1 -1
  49. package/src/generators/host/files/rspack-module-federation-ssr/src/main.server.tsx__tmpl__ +49 -0
  50. package/src/generators/host/files/rspack-module-federation-ssr-ts/module-federation.server.config.ts__tmpl__ +6 -0
  51. package/src/generators/host/files/rspack-module-federation-ssr-ts/rspack.config.ts__tmpl__ +66 -0
  52. package/src/generators/host/files/rspack-module-federation-ssr-ts/server.ts__tmpl__ +1 -1
  53. package/src/generators/host/files/rspack-module-federation-ssr-ts/src/main.server.tsx__tmpl__ +49 -0
  54. package/src/generators/host/files/rspack-module-federation-ts/rspack.config.prod.ts__tmpl__ +37 -9
  55. package/src/generators/host/files/rspack-module-federation-ts/rspack.config.ts__tmpl__ +37 -14
  56. package/src/generators/host/host.js +21 -18
  57. package/src/generators/host/lib/add-module-federation-files.js +28 -12
  58. package/src/generators/host/lib/normalize-host-name.d.ts +2 -0
  59. package/src/generators/host/lib/normalize-host-name.js +12 -0
  60. package/src/generators/host/lib/setup-ssr-for-host.d.ts +3 -3
  61. package/src/generators/host/lib/setup-ssr-for-host.js +46 -22
  62. package/src/generators/init/init.js +23 -0
  63. package/src/generators/init/schema.d.ts +2 -0
  64. package/src/generators/library/lib/add-rollup-build-target.d.ts +3 -1
  65. package/src/generators/library/lib/add-rollup-build-target.js +6 -7
  66. package/src/generators/library/lib/create-files.js +2 -1
  67. package/src/generators/library/lib/normalize-options.js +8 -5
  68. package/src/generators/library/library.js +44 -30
  69. package/src/generators/library/schema.d.ts +2 -0
  70. package/src/generators/library/schema.json +4 -0
  71. package/src/generators/remote/files/rspack-module-federation/rspack.config.js__tmpl__ +40 -13
  72. package/src/generators/remote/files/rspack-module-federation-ssr/module-federation.server.config.js__tmpl__ +6 -0
  73. package/src/generators/remote/files/rspack-module-federation-ssr/rspack.config.js__tmpl__ +69 -0
  74. package/src/generators/remote/files/rspack-module-federation-ssr/server.ts__tmpl__ +2 -2
  75. package/src/generators/remote/files/rspack-module-federation-ssr/src/main.server.tsx__tmpl__ +45 -0
  76. package/src/generators/remote/files/rspack-module-federation-ssr-ts/module-federation.server.config.ts__tmpl__ +6 -0
  77. package/src/generators/remote/files/rspack-module-federation-ssr-ts/rspack.config.ts__tmpl__ +69 -0
  78. package/src/generators/remote/files/rspack-module-federation-ssr-ts/server.ts__tmpl__ +2 -2
  79. package/src/generators/remote/files/rspack-module-federation-ssr-ts/src/main.server.tsx__tmpl__ +45 -0
  80. package/src/generators/remote/files/rspack-module-federation-ts/rspack.config.ts__tmpl__ +40 -13
  81. package/src/generators/remote/lib/setup-ssr-for-remote.d.ts +1 -1
  82. package/src/generators/remote/lib/setup-ssr-for-remote.js +37 -15
  83. package/src/generators/remote/remote.js +46 -30
  84. package/src/plugins/router-plugin.d.ts +10 -0
  85. package/src/plugins/router-plugin.js +219 -0
  86. package/src/rules/update-module-federation-project.d.ts +2 -1
  87. package/src/rules/update-module-federation-project.js +28 -47
  88. package/src/utils/assertion.d.ts +2 -0
  89. package/src/utils/assertion.js +6 -0
  90. package/src/utils/ast-utils.d.ts +1 -1
  91. package/src/utils/ast-utils.js +2 -2
  92. package/src/utils/ct-utils.d.ts +1 -1
  93. package/src/utils/versions.d.ts +6 -4
  94. package/src/utils/versions.js +9 -6
  95. package/src/generators/host/files/rspack-module-federation-ssr/rspack.server.config.js__tmpl__ +0 -16
  96. package/src/generators/host/files/rspack-module-federation-ssr-ts/rspack.server.config.ts__tmpl__ +0 -16
  97. package/src/generators/remote/files/rspack-module-federation-ssr/rspack.server.config.js__tmpl__ +0 -16
  98. package/src/generators/remote/files/rspack-module-federation-ssr-ts/rspack.server.config.ts__tmpl__ +0 -16
  99. package/src/utils/format-file.d.ts +0 -1
  100. package/src/utils/format-file.js +0 -11
@@ -2,30 +2,33 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.libraryGenerator = libraryGenerator;
4
4
  exports.libraryGeneratorInternal = libraryGeneratorInternal;
5
- const path_1 = require("path");
6
5
  const devkit_1 = require("@nx/devkit");
7
6
  const artifact_name_and_directory_utils_1 = require("@nx/devkit/src/generators/artifact-name-and-directory-utils");
8
7
  const log_show_project_command_1 = require("@nx/devkit/src/utils/log-show-project-command");
9
8
  const js_1 = require("@nx/js");
10
- const versions_1 = require("../../utils/versions");
9
+ const path_1 = require("path");
10
+ const add_release_config_1 = require("@nx/js/src/generators/library/utils/add-release-config");
11
+ const sort_fields_1 = require("@nx/js/src/utils/package-json/sort-fields");
12
+ const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup");
13
+ const use_legacy_versioning_1 = require("nx/src/command-line/release/config/use-legacy-versioning");
14
+ const create_ts_config_1 = require("../../utils/create-ts-config");
15
+ const jest_utils_1 = require("../../utils/jest-utils");
11
16
  const maybe_js_1 = require("../../utils/maybe-js");
17
+ const versions_1 = require("../../utils/versions");
12
18
  const component_1 = require("../component/component");
13
19
  const init_1 = require("../init/init");
14
- const jest_utils_1 = require("../../utils/jest-utils");
15
- const normalize_options_1 = require("./lib/normalize-options");
16
- const add_rollup_build_target_1 = require("./lib/add-rollup-build-target");
17
20
  const add_linting_1 = require("./lib/add-linting");
18
- const update_app_routes_1 = require("./lib/update-app-routes");
21
+ const add_rollup_build_target_1 = require("./lib/add-rollup-build-target");
19
22
  const create_files_1 = require("./lib/create-files");
20
- const create_ts_config_1 = require("../../utils/create-ts-config");
23
+ const determine_entry_fields_1 = require("./lib/determine-entry-fields");
21
24
  const install_common_dependencies_1 = require("./lib/install-common-dependencies");
25
+ const normalize_options_1 = require("./lib/normalize-options");
22
26
  const set_defaults_1 = require("./lib/set-defaults");
23
- const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup");
24
- const determine_entry_fields_1 = require("./lib/determine-entry-fields");
25
- const sort_fields_1 = require("@nx/js/src/utils/package-json/sort-fields");
27
+ const update_app_routes_1 = require("./lib/update-app-routes");
26
28
  async function libraryGenerator(host, schema) {
27
29
  return await libraryGeneratorInternal(host, {
28
30
  addPlugin: false,
31
+ useProjectJson: true,
29
32
  ...schema,
30
33
  });
31
34
  }
@@ -37,9 +40,6 @@ async function libraryGeneratorInternal(host, schema) {
37
40
  });
38
41
  tasks.push(jsInitTask);
39
42
  const options = await (0, normalize_options_1.normalizeOptions)(host, schema);
40
- if (options.isUsingTsSolutionConfig) {
41
- (0, ts_solution_setup_1.addProjectToTsSolutionWorkspace)(host, options.projectRoot);
42
- }
43
43
  if (options.publishable === true && !schema.importPath) {
44
44
  throw new Error(`For publishable libs you have to provide a proper "--importPath" which needs to be a valid npm package name (e.g. my-awesome-lib or @myorg/my-lib)`);
45
45
  }
@@ -51,18 +51,20 @@ async function libraryGeneratorInternal(host, schema) {
51
51
  skipFormat: true,
52
52
  });
53
53
  tasks.push(initTask);
54
- if (options.isUsingTsSolutionConfig) {
55
- (0, devkit_1.writeJson)(host, `${options.projectRoot}/package.json`, {
56
- name: options.importPath,
57
- version: '0.0.1',
58
- ...(0, determine_entry_fields_1.determineEntryFields)(options),
59
- nx: options.parsedTags?.length
60
- ? {
61
- tags: options.parsedTags,
62
- }
63
- : undefined,
64
- files: options.publishable ? ['dist', '!**/*.tsbuildinfo'] : undefined,
65
- });
54
+ const packageJson = {
55
+ name: options.importPath,
56
+ version: '0.0.1',
57
+ ...(0, determine_entry_fields_1.determineEntryFields)(options),
58
+ files: options.publishable ? ['dist', '!**/*.tsbuildinfo'] : undefined,
59
+ };
60
+ if (!options.useProjectJson) {
61
+ if (options.name !== options.importPath) {
62
+ packageJson.nx = { name: options.name };
63
+ }
64
+ if (options.parsedTags?.length) {
65
+ packageJson.nx ??= {};
66
+ packageJson.nx.tags = options.parsedTags;
67
+ }
66
68
  }
67
69
  else {
68
70
  (0, devkit_1.addProjectConfiguration)(host, options.name, {
@@ -73,7 +75,13 @@ async function libraryGeneratorInternal(host, schema) {
73
75
  targets: {},
74
76
  });
75
77
  }
78
+ if (!options.useProjectJson || options.isUsingTsSolutionConfig) {
79
+ (0, devkit_1.writeJson)(host, `${options.projectRoot}/package.json`, packageJson);
80
+ }
76
81
  (0, create_files_1.createFiles)(host, options);
82
+ if (options.isUsingTsSolutionConfig) {
83
+ await (0, ts_solution_setup_1.addProjectToTsSolutionWorkspace)(host, options.projectRoot);
84
+ }
77
85
  const lintTask = await (0, add_linting_1.addLinting)(host, options);
78
86
  tasks.push(lintTask);
79
87
  // Set up build target
@@ -183,11 +191,17 @@ async function libraryGeneratorInternal(host, schema) {
183
191
  });
184
192
  tasks.push(componentTask);
185
193
  }
186
- if (options.publishable || options.buildable) {
187
- (0, devkit_1.updateJson)(host, `${options.projectRoot}/package.json`, (json) => {
188
- json.name = options.importPath;
189
- return json;
190
- });
194
+ if (options.publishable) {
195
+ const projectConfiguration = (0, devkit_1.readProjectConfiguration)(host, options.name);
196
+ if (options.isUsingTsSolutionConfig) {
197
+ await (0, add_release_config_1.addReleaseConfigForTsSolution)(host, options.name, projectConfiguration);
198
+ }
199
+ else {
200
+ const nxJson = (0, devkit_1.readNxJson)(host);
201
+ await (0, add_release_config_1.addReleaseConfigForNonTsSolution)((0, use_legacy_versioning_1.shouldUseLegacyVersioning)(nxJson.release), host, options.name, projectConfiguration);
202
+ }
203
+ (0, devkit_1.updateProjectConfiguration)(host, options.name, projectConfiguration);
204
+ tasks.push(await (0, add_release_config_1.releaseTasks)(host));
191
205
  }
192
206
  if (!options.skipPackageJson) {
193
207
  const installReactTask = await (0, install_common_dependencies_1.installCommonDependencies)(host, options);
@@ -27,6 +27,7 @@ export interface Schema {
27
27
  minimal?: boolean;
28
28
  simpleName?: boolean;
29
29
  addPlugin?: boolean;
30
+ useProjectJson?: boolean;
30
31
  }
31
32
 
32
33
  export interface NormalizedSchema extends Schema {
@@ -36,6 +37,7 @@ export interface NormalizedSchema extends Schema {
36
37
  projectRoot: string;
37
38
  routePath: string;
38
39
  parsedTags: string[];
40
+ importPath: string;
39
41
  appMain?: string;
40
42
  appSourceRoot?: string;
41
43
  unitTestRunner: 'jest' | 'vitest' | 'none';
@@ -190,6 +190,10 @@
190
190
  "description": "Don't include the directory in the name of the module of the library.",
191
191
  "type": "boolean",
192
192
  "default": false
193
+ },
194
+ "useProjectJson": {
195
+ "type": "boolean",
196
+ "description": "Use a `project.json` configuration file instead of inlining the Nx configuration in the `package.json` file."
193
197
  }
194
198
  },
195
199
  "required": ["directory"]
@@ -1,16 +1,43 @@
1
- const { composePlugins, withNx, withReact } = require('@nx/rspack');
2
- const { withModuleFederation } = require('@nx/module-federation/rspack');
1
+ const { NxAppRspackPlugin } = require('@nx/rspack/app-plugin');
2
+ const { NxReactRspackPlugin } = require('@nx/rspack/react-plugin');
3
+ const { NxModuleFederationPlugin, NxModuleFederationDevServerPlugin } = require('@nx/module-federation/rspack');
4
+ const { join } = require('path');
3
5
 
4
- const baseConfig = require('./module-federation.config');
6
+ const config = require('./module-federation.config');
5
7
 
6
- const config = {
7
- ...baseConfig,
8
+ module.exports = {
9
+ output: {
10
+ path: join(__dirname, '<%= rspackPluginOptions.outputPath %>'),
11
+ publicPath: 'auto'
12
+ },
13
+ devServer: {
14
+ port: <%= devServerPort %>,
15
+ headers: {
16
+ "Access-Control-Allow-Origin": "*"
17
+ },
18
+ historyApiFallback: {
19
+ index: '/index.html',
20
+ disableDotRule: true,
21
+ htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'],
22
+ },
23
+ },
24
+ plugins: [
25
+ new NxAppRspackPlugin({
26
+ tsConfig: '<%= rspackPluginOptions.tsConfig %>',
27
+ main: '<%= rspackPluginOptions.main %>',
28
+ index: '<%= rspackPluginOptions.index %>',
29
+ baseHref: '<%= rspackPluginOptions.baseHref %>',
30
+ assets: <%- JSON.stringify(rspackPluginOptions.assets) %>,
31
+ styles: <%- JSON.stringify(rspackPluginOptions.styles) %>,
32
+ outputHashing: process.env['NODE_ENV'] === 'production' ? 'all' : 'none',
33
+ optimization: process.env['NODE_ENV'] === 'production',
34
+ }),
35
+ new NxReactRspackPlugin({
36
+ // Uncomment this line if you don't want to use SVGR
37
+ // See: https://react-svgr.com/
38
+ // svgr: false
39
+ }),
40
+ new NxModuleFederationPlugin({ config }, { dts: false }),
41
+ new NxModuleFederationDevServerPlugin({ config }),
42
+ ],
8
43
  };
9
-
10
- // Nx plugins for rspack to build config object from Nx options and context.
11
- /**
12
- * DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support Module Federation
13
- * The DTS Plugin can be enabled by setting dts: true
14
- * Learn more about the DTS Plugin here: https://module-federation.io/configure/dts.html
15
- */
16
- module.exports = composePlugins(withNx(), withReact(), withModuleFederation(config, { dts: false }));
@@ -6,4 +6,10 @@ module.exports = {
6
6
  exposes: {
7
7
  './Module': './src/remote-entry.<%= js ? 'js' : 'ts' %>',
8
8
  },
9
+ shared: (libraryName, libraryConfig) => {
10
+ return {
11
+ ...libraryConfig,
12
+ eager: true
13
+ }
14
+ },
9
15
  };
@@ -0,0 +1,69 @@
1
+ const { NxAppRspackPlugin } = require('@nx/rspack/app-plugin');
2
+ const { NxReactRspackPlugin } = require('@nx/rspack/react-plugin');
3
+ const { NxModuleFederationPlugin, NxModuleFederationSSRDevServerPlugin } = require('@nx/module-federation/rspack');
4
+ const { join } = require('path');
5
+
6
+ const browserMfConfig = require('./module-federation.config');
7
+ const serverMfConfig = require('./module-federation.server.config');
8
+
9
+ const browserRspackConfig = {
10
+ name: 'browser',
11
+ output: {
12
+ path: join(__dirname, '<%= rspackPluginOptions.outputPath %>', 'browser'),
13
+ publicPath: 'auto'
14
+ },
15
+ devServer: {
16
+ port: <%= devServerPort %>,
17
+ headers: {
18
+ "Access-Control-Allow-Origin": "*"
19
+ },
20
+ historyApiFallback: {
21
+ index: '/index.html',
22
+ disableDotRule: true,
23
+ htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'],
24
+ },
25
+ devMiddleware: {
26
+ writeToDisk: (file: string) => !file.includes('.hot-update.'),
27
+ },
28
+ },
29
+ plugins: [
30
+ new NxAppRspackPlugin({
31
+ tsConfig: '<%= rspackPluginOptions.tsConfig %>',
32
+ main: '<%= rspackPluginOptions.main %>',
33
+ index: '<%= rspackPluginOptions.index %>',
34
+ baseHref: '<%= rspackPluginOptions.baseHref %>',
35
+ assets: <%- JSON.stringify(rspackPluginOptions.assets) %>,
36
+ styles: <%- JSON.stringify(rspackPluginOptions.styles) %>,
37
+ outputHashing: process.env['NODE_ENV'] === 'production' ? 'all' : 'none',
38
+ optimization: process.env['NODE_ENV'] === 'production',
39
+ }),
40
+ new NxReactRspackPlugin({
41
+ // Uncomment this line if you don't want to use SVGR
42
+ // See: https://react-svgr.com/
43
+ // svgr: false
44
+ }),
45
+ new NxModuleFederationPlugin({ config: browserMfConfig }, { dts: false }),
46
+ ],
47
+ };
48
+
49
+ const serverRspackConfig = {
50
+ name: 'server',
51
+ target: 'async-node',
52
+ output: {
53
+ path: join(__dirname, '<%= rspackPluginOptions.outputPath %>', 'server'),
54
+ filename: 'server.js'
55
+ },
56
+ plugins: [
57
+ new NxAppRspackPlugin({
58
+ outputPath: join(__dirname, '<%= rspackPluginOptions.outputPath %>', 'server'),
59
+ outputFileName: 'server.js',
60
+ tsConfig: '<%= rspackPluginOptions.tsConfig %>',
61
+ main: '<%= rspackPluginOptions.mainServer %>',
62
+ baseHref: '<%= rspackPluginOptions.baseHref %>',
63
+ }),
64
+ new NxModuleFederationPlugin({ config: serverMfConfig, isServer: true }, { dts: false }),
65
+ new NxModuleFederationSSRDevServerPlugin({ config: serverMfConfig }),
66
+ ],
67
+ };
68
+
69
+ module.exports = [browserRspackConfig, serverRspackConfig];
@@ -7,8 +7,8 @@ import { handleRequest } from './src/main.server';
7
7
  const port = process.env['PORT'] || <%= port %>;
8
8
  const app = express();
9
9
 
10
- const browserDist = path.join(process.cwd(), '<%= browserBuildOutputPath %>');
11
- const serverDist = path.join(process.cwd(), '<%= serverBuildOutputPath %>');
10
+ const browserDist = path.join(process.cwd(), '<%= rspackPluginOptions.outputPath %>', 'browser');
11
+ const serverDist = path.join(process.cwd(), '<%= rspackPluginOptions.outputPath %>', 'server');
12
12
  const indexPath = path.join(browserDist, 'index.html');
13
13
 
14
14
  app.use(cors());
@@ -0,0 +1,45 @@
1
+ import type { Request, Response } from 'express';
2
+ import * as fs from 'fs';
3
+ import * as ReactDOMServer from 'react-dom/server';
4
+ import isbot from 'isbot';
5
+
6
+ import App from './app/app';
7
+
8
+ let indexHtml: null | string = null;
9
+
10
+ export function handleRequest(indexPath: string) {
11
+ return function render(req: Request, res: Response) {
12
+ let didError = false;
13
+
14
+ if (!indexHtml) {
15
+ indexHtml = fs.readFileSync(indexPath).toString();
16
+ }
17
+
18
+ const [htmlStart, htmlEnd] = indexHtml.split(`<div id="root"></div>`);
19
+
20
+ // For bots (e.g. search engines), the content will not be streamed but render all at once.
21
+ // For users, content should be streamed to the user as they are ready.
22
+ const callbackName = isbot(req.headers['user-agent'])
23
+ ? 'onAllReady'
24
+ : 'onShellReady';
25
+
26
+ const stream = ReactDOMServer.renderToPipeableStream(<App />, {
27
+ [callbackName]() {
28
+ res.statusCode = didError ? 500 : 200;
29
+ res.setHeader('Content-type', 'text/html; charset=utf-8');
30
+ res.write(`${htmlStart}<div id="root">`);
31
+ stream.pipe(res);
32
+ res.write(`</div>${htmlEnd}`);
33
+ },
34
+ onShellError(error) {
35
+ console.error(error);
36
+ res.statusCode = 500;
37
+ res.send('<!doctype html><h1>Server Error</h1>');
38
+ },
39
+ onError(error) {
40
+ didError = true;
41
+ console.error(error);
42
+ },
43
+ });
44
+ };
45
+ }
@@ -5,6 +5,12 @@ const config: ModuleFederationConfig = {
5
5
  exposes: {
6
6
  './Module': './src/remote-entry.<%= js ? 'js' : 'ts' %>',
7
7
  },
8
+ shared: (libraryName, libraryConfig) => {
9
+ return {
10
+ ...libraryConfig,
11
+ eager: true
12
+ }
13
+ },
8
14
  };
9
15
 
10
16
  /**
@@ -0,0 +1,69 @@
1
+ import { NxAppRspackPlugin } from '@nx/rspack/app-plugin';
2
+ import { NxReactRspackPlugin } from '@nx/rspack/react-plugin';
3
+ import { NxModuleFederationPlugin, NxModuleFederationSSRDevServerPlugin } from '@nx/module-federation/rspack';
4
+ import { join } from 'path';
5
+
6
+ import browserMfConfig from './module-federation.config';
7
+ import serverMfConfig from './module-federation.server.config';
8
+
9
+ const browserRspackConfig = {
10
+ name: 'browser',
11
+ output: {
12
+ path: join(__dirname, '<%= rspackPluginOptions.outputPath %>', 'browser'),
13
+ publicPath: 'auto'
14
+ },
15
+ devServer: {
16
+ port: <%= devServerPort %>,
17
+ headers: {
18
+ "Access-Control-Allow-Origin": "*"
19
+ },
20
+ historyApiFallback: {
21
+ index: '/index.html',
22
+ disableDotRule: true,
23
+ htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'],
24
+ },
25
+ devMiddleware: {
26
+ writeToDisk: (file: string) => !file.includes('.hot-update.'),
27
+ },
28
+ },
29
+ plugins: [
30
+ new NxAppRspackPlugin({
31
+ tsConfig: '<%= rspackPluginOptions.tsConfig %>',
32
+ main: '<%= rspackPluginOptions.main %>',
33
+ index: '<%= rspackPluginOptions.index %>',
34
+ baseHref: '<%= rspackPluginOptions.baseHref %>',
35
+ assets: <%- JSON.stringify(rspackPluginOptions.assets) %>,
36
+ styles: <%- JSON.stringify(rspackPluginOptions.styles) %>,
37
+ outputHashing: process.env['NODE_ENV'] === 'production' ? 'all' : 'none',
38
+ optimization: process.env['NODE_ENV'] === 'production',
39
+ }),
40
+ new NxReactRspackPlugin({
41
+ // Uncomment this line if you don't want to use SVGR
42
+ // See: https://react-svgr.com/
43
+ // svgr: false
44
+ }),
45
+ new NxModuleFederationPlugin({ config: browserMfConfig }, { dts: false }),
46
+ ],
47
+ };
48
+
49
+ const serverRspackConfig = {
50
+ name: 'server',
51
+ target: 'async-node',
52
+ output: {
53
+ path: join(__dirname, '<%= rspackPluginOptions.outputPath %>', 'server'),
54
+ filename: 'server.js'
55
+ },
56
+ plugins: [
57
+ new NxAppRspackPlugin({
58
+ outputPath: join(__dirname, '<%= rspackPluginOptions.outputPath %>', 'server'),
59
+ outputFileName: 'server.js',
60
+ tsConfig: '<%= rspackPluginOptions.tsConfig %>',
61
+ main: '<%= rspackPluginOptions.mainServer %>',
62
+ baseHref: '<%= rspackPluginOptions.baseHref %>',
63
+ }),
64
+ new NxModuleFederationPlugin({ config: serverMfConfig, isServer: true }, { dts: false }),
65
+ new NxModuleFederationSSRDevServerPlugin({ config: serverMfConfig }),
66
+ ],
67
+ };
68
+
69
+ export default [browserRspackConfig, serverRspackConfig];
@@ -7,8 +7,8 @@ import { handleRequest } from './src/main.server';
7
7
  const port = process.env['PORT'] || <%= port %>;
8
8
  const app = express();
9
9
 
10
- const browserDist = path.join(process.cwd(), '<%= browserBuildOutputPath %>');
11
- const serverDist = path.join(process.cwd(), '<%= serverBuildOutputPath %>');
10
+ const browserDist = path.join(process.cwd(), '<%= rspackPluginOptions.outputPath %>', 'browser');
11
+ const serverDist = path.join(process.cwd(), '<%= rspackPluginOptions.outputPath %>', 'server');
12
12
  const indexPath = path.join(browserDist, 'index.html');
13
13
 
14
14
  app.use(cors());
@@ -0,0 +1,45 @@
1
+ import type { Request, Response } from 'express';
2
+ import * as fs from 'fs';
3
+ import * as ReactDOMServer from 'react-dom/server';
4
+ import isbot from 'isbot';
5
+
6
+ import App from './app/app';
7
+
8
+ let indexHtml: null | string = null;
9
+
10
+ export function handleRequest(indexPath: string) {
11
+ return function render(req: Request, res: Response) {
12
+ let didError = false;
13
+
14
+ if (!indexHtml) {
15
+ indexHtml = fs.readFileSync(indexPath).toString();
16
+ }
17
+
18
+ const [htmlStart, htmlEnd] = indexHtml.split(`<div id="root"></div>`);
19
+
20
+ // For bots (e.g. search engines), the content will not be streamed but render all at once.
21
+ // For users, content should be streamed to the user as they are ready.
22
+ const callbackName = isbot(req.headers['user-agent'])
23
+ ? 'onAllReady'
24
+ : 'onShellReady';
25
+
26
+ const stream = ReactDOMServer.renderToPipeableStream(<App />, {
27
+ [callbackName]() {
28
+ res.statusCode = didError ? 500 : 200;
29
+ res.setHeader('Content-type', 'text/html; charset=utf-8');
30
+ res.write(`${htmlStart}<div id="root">`);
31
+ stream.pipe(res);
32
+ res.write(`</div>${htmlEnd}`);
33
+ },
34
+ onShellError(error) {
35
+ console.error(error);
36
+ res.statusCode = 500;
37
+ res.send('<!doctype html><h1>Server Error</h1>');
38
+ },
39
+ onError(error) {
40
+ didError = true;
41
+ console.error(error);
42
+ },
43
+ });
44
+ };
45
+ }
@@ -1,16 +1,43 @@
1
- import {composePlugins, withNx, withReact} from '@nx/rspack';
2
- import {withModuleFederation} from '@nx/module-federation/rspack';
1
+ import { NxAppRspackPlugin } from '@nx/rspack/app-plugin';
2
+ import { NxReactRspackPlugin } from '@nx/rspack/react-plugin';
3
+ import { NxModuleFederationPlugin, NxModuleFederationDevServerPlugin } from '@nx/module-federation/rspack';
4
+ import { join } from 'path';
3
5
 
4
- import baseConfig from './module-federation.config';
6
+ import config from './module-federation.config';
5
7
 
6
- const config = {
7
- ...baseConfig,
8
+ export default {
9
+ output: {
10
+ path: join(__dirname, '<%= rspackPluginOptions.outputPath %>'),
11
+ publicPath: 'auto'
12
+ },
13
+ devServer: {
14
+ port: <%= devServerPort %>,
15
+ headers: {
16
+ "Access-Control-Allow-Origin": "*"
17
+ },
18
+ historyApiFallback: {
19
+ index: '/index.html',
20
+ disableDotRule: true,
21
+ htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'],
22
+ },
23
+ },
24
+ plugins: [
25
+ new NxAppRspackPlugin({
26
+ tsConfig: '<%= rspackPluginOptions.tsConfig %>',
27
+ main: '<%= rspackPluginOptions.main %>',
28
+ index: '<%= rspackPluginOptions.index %>',
29
+ baseHref: '<%= rspackPluginOptions.baseHref %>',
30
+ assets: <%- JSON.stringify(rspackPluginOptions.assets) %>,
31
+ styles: <%- JSON.stringify(rspackPluginOptions.styles) %>,
32
+ outputHashing: process.env['NODE_ENV'] === 'production' ? 'all' : 'none',
33
+ optimization: process.env['NODE_ENV'] === 'production',
34
+ }),
35
+ new NxReactRspackPlugin({
36
+ // Uncomment this line if you don't want to use SVGR
37
+ // See: https://react-svgr.com/
38
+ // svgr: false
39
+ }),
40
+ new NxModuleFederationPlugin({ config }, { dts: false }),
41
+ new NxModuleFederationDevServerPlugin({ config }),
42
+ ],
8
43
  };
9
-
10
- // Nx plugins for rspack to build config object from Nx options and context.
11
- /**
12
- * DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support Module Federation
13
- * The DTS Plugin can be enabled by setting dts: true
14
- * Learn more about the DTS Plugin here: https://module-federation.io/configure/dts.html
15
- */
16
- export default composePlugins(withNx(), withReact(), withModuleFederation(config, { dts: false }));
@@ -1,4 +1,4 @@
1
- import type { GeneratorCallback, Tree } from '@nx/devkit';
1
+ import { GeneratorCallback, Tree } from '@nx/devkit';
2
2
  import { NormalizedSchema } from '../../application/schema';
3
3
  import type { Schema } from '../schema';
4
4
  export declare function setupSsrForRemote(tree: Tree, options: NormalizedSchema<Schema>, appName: string): Promise<GeneratorCallback>;
@@ -2,39 +2,61 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.setupSsrForRemote = setupSsrForRemote;
4
4
  const devkit_1 = require("@nx/devkit");
5
+ const devkit_2 = require("@nx/devkit");
5
6
  const versions_1 = require("../../../utils/versions");
7
+ const create_application_files_1 = require("../../application/lib/create-application-files");
6
8
  async function setupSsrForRemote(tree, options, appName) {
7
9
  const tasks = [];
8
- const project = (0, devkit_1.readProjectConfiguration)(tree, appName);
10
+ const project = (0, devkit_2.readProjectConfiguration)(tree, appName);
9
11
  const pathToModuleFederationSsrFiles = options.typescriptConfiguration
10
12
  ? `${options.bundler === 'rspack' ? 'rspack-' : 'webpack-'}module-federation-ssr-ts`
11
13
  : `${options.bundler === 'rspack' ? 'rspack-' : 'webpack-'}module-federation-ssr`;
12
- (0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, `../files/${pathToModuleFederationSsrFiles}`), project.root, {
13
- ...options,
14
- port: Number(options?.devServerPort) || 4200,
15
- appName,
16
- tmpl: '',
17
- browserBuildOutputPath: project.targets.build.options.outputPath,
18
- serverBuildOutputPath: project.targets.server.options.outputPath,
19
- });
14
+ const templateVariables = options.bundler === 'rspack'
15
+ ? {
16
+ ...(0, create_application_files_1.getDefaultTemplateVariables)(tree, options),
17
+ rspackPluginOptions: {
18
+ ...(0, create_application_files_1.createNxRspackPluginOptions)(options, (0, devkit_1.offsetFromRoot)(options.appProjectRoot), false),
19
+ mainServer: `./server.ts`,
20
+ },
21
+ port: Number(options?.devServerPort) || 4200,
22
+ appName,
23
+ }
24
+ : {
25
+ ...options,
26
+ port: Number(options?.devServerPort) || 4200,
27
+ appName,
28
+ tmpl: '',
29
+ browserBuildOutputPath: project.targets.build?.options?.outputPath,
30
+ serverBuildOutputPath: project.targets.server?.options?.outputPath,
31
+ };
32
+ (0, devkit_2.generateFiles)(tree, (0, devkit_2.joinPathFragments)(__dirname, `../files/${pathToModuleFederationSsrFiles}`), project.root, templateVariables);
20
33
  // For hosts to use when running remotes in static mode.
21
- const originalOutputPath = project.targets.build?.options?.outputPath;
34
+ const originalOutputPath = project.targets.build?.options?.outputPath ??
35
+ options.isUsingTsSolutionConfig
36
+ ? 'dist'
37
+ : (0, devkit_2.joinPathFragments)((0, devkit_1.offsetFromRoot)(options.appProjectRoot), 'dist', options.appProjectRoot != '.'
38
+ ? options.appProjectRoot
39
+ : options.projectName);
22
40
  const serverOptions = project.targets.server?.options;
23
41
  const serverOutputPath = serverOptions?.outputPath ??
24
- (0, devkit_1.joinPathFragments)(originalOutputPath, 'server');
42
+ (0, devkit_2.joinPathFragments)(originalOutputPath, 'server');
25
43
  const serverOutputName = serverOptions?.outputFileName ?? 'main.js';
26
44
  project.targets['serve-static'] = {
27
45
  dependsOn: ['build', 'server'],
28
46
  executor: 'nx:run-commands',
29
47
  defaultConfiguration: 'development',
30
48
  options: {
31
- command: `PORT=${options.devServerPort ?? 4200} node ${(0, devkit_1.joinPathFragments)(serverOutputPath, serverOutputName)}`,
49
+ command: `PORT=${options.devServerPort ?? 4200} node ${(0, devkit_2.joinPathFragments)(serverOutputPath, serverOutputName)}`,
32
50
  },
33
51
  };
34
- (0, devkit_1.updateProjectConfiguration)(tree, appName, project);
35
- const installTask = (0, devkit_1.addDependenciesToPackageJson)(tree, {
52
+ (0, devkit_2.updateProjectConfiguration)(tree, appName, project);
53
+ const installTask = (0, devkit_2.addDependenciesToPackageJson)(tree, {
36
54
  '@module-federation/node': versions_1.moduleFederationNodeVersion,
55
+ cors: versions_1.corsVersion,
56
+ isbot: versions_1.isbotVersion,
57
+ express: versions_1.expressVersion,
58
+ '@types/express': versions_1.typesExpressVersion,
37
59
  }, {});
38
60
  tasks.push(installTask);
39
- return (0, devkit_1.runTasksInSerial)(...tasks);
61
+ return (0, devkit_2.runTasksInSerial)(...tasks);
40
62
  }