@nx/react 16.9.0-beta.1 → 16.9.0-beta.3
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.
- package/babel.d.ts +4 -3
- package/babel.js +2 -2
- package/package.json +7 -7
- package/plugins/component-testing/index.js +3 -2
- package/src/executors/module-federation-dev-server/module-federation-dev-server.impl.js +1 -1
- package/src/generators/application/application.js +38 -2
- package/src/generators/host/files/module-federation-ssr-ts/module-federation.server.config.ts__tmpl__ +10 -0
- package/src/generators/host/files/module-federation-ssr-ts/server.ts__tmpl__ +28 -0
- package/src/generators/host/files/module-federation-ssr-ts/tsconfig.server.json__tmpl__ +15 -0
- package/src/generators/host/files/module-federation-ssr-ts/webpack.server.config.ts__tmpl__ +12 -0
- package/src/generators/host/files/module-federation-ts/module-federation.config.ts__tmpl__ +10 -0
- package/src/generators/host/files/module-federation-ts/src/main.ts__tmpl__ +1 -0
- package/src/generators/host/files/module-federation-ts/src/remotes.d.ts__tmpl__ +4 -0
- package/src/generators/host/files/module-federation-ts/webpack.config.prod.ts__tmpl__ +32 -0
- package/src/generators/host/files/module-federation-ts/webpack.config.ts__tmpl__ +12 -0
- package/src/generators/host/host.js +6 -2
- package/src/generators/host/lib/add-module-federation-files.js +14 -1
- package/src/generators/host/lib/setup-ssr-for-host.js +4 -1
- package/src/generators/host/schema.d.ts +1 -0
- package/src/generators/host/schema.json +5 -0
- package/src/generators/library/library.js +34 -2
- package/src/generators/remote/files/module-federation-ssr-ts/module-federation.server.config.ts__tmpl__ +10 -0
- package/src/generators/remote/files/module-federation-ssr-ts/server.ts__tmpl__ +45 -0
- package/src/generators/remote/files/module-federation-ssr-ts/webpack.server.config.ts__tmpl__ +12 -0
- package/src/generators/remote/files/module-federation-ts/module-federation.config.ts__tmpl__ +10 -0
- package/src/generators/remote/files/module-federation-ts/src/main.ts__tmpl__ +1 -0
- package/src/generators/remote/files/module-federation-ts/src/remote-entry.ts__tmpl__ +1 -0
- package/src/generators/remote/files/module-federation-ts/webpack.config.prod.ts__tmpl__ +1 -0
- package/src/generators/remote/files/module-federation-ts/webpack.config.ts__tmpl__ +12 -0
- package/src/generators/remote/lib/setup-ssr-for-remote.js +4 -1
- package/src/generators/remote/lib/update-host-with-remote.js +4 -1
- package/src/generators/remote/remote.d.ts +1 -1
- package/src/generators/remote/remote.js +19 -3
- package/src/generators/remote/schema.d.ts +6 -0
- package/src/generators/remote/schema.json +5 -0
- package/src/module-federation/utils.d.ts +1 -1
- package/src/module-federation/utils.js +12 -6
- package/src/module-federation/with-module-federation.js +11 -0
- package/src/rules/update-module-federation-project.d.ts +1 -0
- package/src/rules/update-module-federation-project.js +2 -2
package/babel.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
interface NxReactBabelOptions {
|
|
2
|
+
development?: boolean;
|
|
2
3
|
runtime?: string;
|
|
3
4
|
importSource?: string;
|
|
4
5
|
useBuiltIns?: boolean | string;
|
|
@@ -10,7 +11,7 @@ interface NxReactBabelOptions {
|
|
|
10
11
|
loose?: boolean;
|
|
11
12
|
};
|
|
12
13
|
}
|
|
13
|
-
declare function getReactPresetOptions({ presetOptions, env }: {
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
declare function getReactPresetOptions({ presetOptions, env, }: {
|
|
15
|
+
env: string;
|
|
16
|
+
presetOptions: NxReactBabelOptions;
|
|
16
17
|
}): Record<string, string | boolean>;
|
package/babel.js
CHANGED
|
@@ -33,10 +33,10 @@ module.exports = function (api, options) {
|
|
|
33
33
|
presets,
|
|
34
34
|
};
|
|
35
35
|
};
|
|
36
|
-
function getReactPresetOptions({ presetOptions, env }) {
|
|
36
|
+
function getReactPresetOptions({ presetOptions, env, }) {
|
|
37
37
|
const reactPresetOptions = {
|
|
38
38
|
runtime: presetOptions.runtime ?? 'automatic',
|
|
39
|
-
development: env !== 'production',
|
|
39
|
+
development: presetOptions.development ?? env !== 'production',
|
|
40
40
|
};
|
|
41
41
|
// JSX spread is transformed into object spread in `@babel/plugin-transform-react-jsx`
|
|
42
42
|
// `useBuiltIns` will be removed in Babel 8.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nx/react",
|
|
3
|
-
"version": "16.9.0-beta.
|
|
3
|
+
"version": "16.9.0-beta.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "The React plugin for Nx contains executors and generators for managing React applications and libraries within an Nx workspace. It provides:\n\n\n- Integration with libraries such as Jest, Cypress, and Storybook.\n\n- Generators for applications, libraries, components, hooks, and more.\n\n- Library build support for publishing packages to npm or other registries.\n\n- Utilities for automatic workspace refactoring.",
|
|
6
6
|
"repository": {
|
|
@@ -31,11 +31,11 @@
|
|
|
31
31
|
"migrations": "./migrations.json"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@nrwl/react": "16.9.0-beta.
|
|
35
|
-
"@nx/devkit": "16.9.0-beta.
|
|
36
|
-
"@nx/js": "16.9.0-beta.
|
|
37
|
-
"@nx/linter": "16.9.0-beta.
|
|
38
|
-
"@nx/web": "16.9.0-beta.
|
|
34
|
+
"@nrwl/react": "16.9.0-beta.3",
|
|
35
|
+
"@nx/devkit": "16.9.0-beta.3",
|
|
36
|
+
"@nx/js": "16.9.0-beta.3",
|
|
37
|
+
"@nx/linter": "16.9.0-beta.3",
|
|
38
|
+
"@nx/web": "16.9.0-beta.3",
|
|
39
39
|
"@phenomnomnominal/tsquery": "~5.0.1",
|
|
40
40
|
"@svgr/webpack": "^8.0.1",
|
|
41
41
|
"chalk": "^4.1.0",
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
"access": "public"
|
|
48
48
|
},
|
|
49
49
|
"type": "commonjs",
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "d5692528c089a75c76b21d2d1235d8cc5dbb1d26"
|
|
51
51
|
}
|
|
@@ -75,7 +75,7 @@ function nxComponentTestingPreset(pathToConfig, options) {
|
|
|
75
75
|
if (!buildTarget) {
|
|
76
76
|
throw new Error(`Unable to find the 'devServerTarget' executor option in the '${ctTargetName}' target of the '${ctProjectName}' project`);
|
|
77
77
|
}
|
|
78
|
-
webpackConfig = buildTargetWebpack(
|
|
78
|
+
webpackConfig = buildTargetWebpack(ctExecutorContext, buildTarget, ctProjectName);
|
|
79
79
|
}
|
|
80
80
|
catch (e) {
|
|
81
81
|
devkit_1.logger.warn((0, devkit_1.stripIndents) `Unable to build a webpack config with the project graph.
|
|
@@ -126,7 +126,8 @@ function withSchemaDefaults(target, context) {
|
|
|
126
126
|
options.generateIndexHtml ??= true;
|
|
127
127
|
return options;
|
|
128
128
|
}
|
|
129
|
-
function buildTargetWebpack(
|
|
129
|
+
function buildTargetWebpack(ctx, buildTarget, componentTestingProjectName) {
|
|
130
|
+
const graph = ctx.projectGraph;
|
|
130
131
|
const parsed = (0, devkit_1.parseTargetString)(buildTarget, graph);
|
|
131
132
|
const buildableProjectConfig = graph.nodes[parsed.project]?.data;
|
|
132
133
|
const ctProjectConfig = graph.nodes[componentTestingProjectName]?.data;
|
|
@@ -11,7 +11,7 @@ const child_process_1 = require("child_process");
|
|
|
11
11
|
const fs_1 = require("fs");
|
|
12
12
|
const tsnode_register_1 = require("@nx/js/src/utils/typescript/tsnode-register");
|
|
13
13
|
function getBuildOptions(buildTarget, context) {
|
|
14
|
-
const target = (0, devkit_1.parseTargetString)(buildTarget, context
|
|
14
|
+
const target = (0, devkit_1.parseTargetString)(buildTarget, context);
|
|
15
15
|
const buildOptions = (0, devkit_1.readTargetOptions)(target, context);
|
|
16
16
|
return {
|
|
17
17
|
...buildOptions,
|
|
@@ -74,7 +74,7 @@ async function applicationGeneratorInternal(host, schema) {
|
|
|
74
74
|
(0, create_application_files_1.createApplicationFiles)(host, options);
|
|
75
75
|
(0, add_project_1.addProject)(host, options);
|
|
76
76
|
if (options.bundler === 'vite') {
|
|
77
|
-
const { viteConfigurationGenerator } = (0, devkit_1.ensurePackage)('@nx/vite', versions_1.nxVersion);
|
|
77
|
+
const { createOrEditViteConfig, viteConfigurationGenerator } = (0, devkit_1.ensurePackage)('@nx/vite', versions_1.nxVersion);
|
|
78
78
|
// We recommend users use `import.meta.env.MODE` and other variables in their code to differentiate between production and development.
|
|
79
79
|
// See: https://vitejs.dev/guide/env-and-mode.html
|
|
80
80
|
if (host.exists((0, devkit_1.joinPathFragments)(options.appProjectRoot, 'src/environments'))) {
|
|
@@ -90,6 +90,24 @@ async function applicationGeneratorInternal(host, schema) {
|
|
|
90
90
|
skipFormat: true,
|
|
91
91
|
});
|
|
92
92
|
tasks.push(viteTask);
|
|
93
|
+
createOrEditViteConfig(host, {
|
|
94
|
+
project: options.projectName,
|
|
95
|
+
includeLib: false,
|
|
96
|
+
includeVitest: options.unitTestRunner === 'vitest',
|
|
97
|
+
inSourceTests: options.inSourceTests,
|
|
98
|
+
rollupOptionsExternal: [
|
|
99
|
+
`'react'`,
|
|
100
|
+
`'react-dom'`,
|
|
101
|
+
`'react/jsx-runtime'`,
|
|
102
|
+
],
|
|
103
|
+
rollupOptionsExternalString: `"'react', 'react-dom', 'react/jsx-runtime'"`,
|
|
104
|
+
imports: [
|
|
105
|
+
options.compiler === 'swc'
|
|
106
|
+
? `import react from '@vitejs/plugin-react-swc'`
|
|
107
|
+
: `import react from '@vitejs/plugin-react'`,
|
|
108
|
+
],
|
|
109
|
+
plugins: ['react()'],
|
|
110
|
+
}, false);
|
|
93
111
|
}
|
|
94
112
|
else if (options.bundler === 'webpack') {
|
|
95
113
|
const { webpackInitGenerator } = (0, devkit_1.ensurePackage)('@nx/webpack', versions_1.nxVersion);
|
|
@@ -112,7 +130,7 @@ async function applicationGeneratorInternal(host, schema) {
|
|
|
112
130
|
tasks.push(rspackTask);
|
|
113
131
|
}
|
|
114
132
|
if (options.bundler !== 'vite' && options.unitTestRunner === 'vitest') {
|
|
115
|
-
const { vitestGenerator } = (0, devkit_1.ensurePackage)('@nx/vite', versions_1.nxVersion);
|
|
133
|
+
const { createOrEditViteConfig, vitestGenerator } = (0, devkit_1.ensurePackage)('@nx/vite', versions_1.nxVersion);
|
|
116
134
|
const vitestTask = await vitestGenerator(host, {
|
|
117
135
|
uiFramework: 'react',
|
|
118
136
|
coverageProvider: 'c8',
|
|
@@ -121,6 +139,24 @@ async function applicationGeneratorInternal(host, schema) {
|
|
|
121
139
|
skipFormat: true,
|
|
122
140
|
});
|
|
123
141
|
tasks.push(vitestTask);
|
|
142
|
+
createOrEditViteConfig(host, {
|
|
143
|
+
project: options.projectName,
|
|
144
|
+
includeLib: false,
|
|
145
|
+
includeVitest: true,
|
|
146
|
+
inSourceTests: options.inSourceTests,
|
|
147
|
+
rollupOptionsExternal: [
|
|
148
|
+
`'react'`,
|
|
149
|
+
`'react-dom'`,
|
|
150
|
+
`'react/jsx-runtime'`,
|
|
151
|
+
],
|
|
152
|
+
rollupOptionsExternalString: `"'react', 'react-dom', 'react/jsx-runtime'"`,
|
|
153
|
+
imports: [
|
|
154
|
+
options.compiler === 'swc'
|
|
155
|
+
? `import react from '@vitejs/plugin-react-swc'`
|
|
156
|
+
: `import react from '@vitejs/plugin-react'`,
|
|
157
|
+
],
|
|
158
|
+
plugins: ['react()'],
|
|
159
|
+
}, true);
|
|
124
160
|
}
|
|
125
161
|
if ((options.bundler === 'vite' || options.unitTestRunner === 'vitest') &&
|
|
126
162
|
options.inSourceTests) {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import cors from 'cors';
|
|
4
|
+
|
|
5
|
+
import { handleRequest } from './src/main.server';
|
|
6
|
+
|
|
7
|
+
const port = process.env['PORT'] || 4200;
|
|
8
|
+
const app = express();
|
|
9
|
+
|
|
10
|
+
const browserDist = path.join(process.cwd(), '<%= browserBuildOutputPath %>');
|
|
11
|
+
const indexPath = path.join(browserDist, 'index.html');
|
|
12
|
+
|
|
13
|
+
app.use(cors());
|
|
14
|
+
|
|
15
|
+
app.get(
|
|
16
|
+
'*.*',
|
|
17
|
+
express.static(browserDist, {
|
|
18
|
+
maxAge: '1y',
|
|
19
|
+
})
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
app.use('*', handleRequest(indexPath));
|
|
23
|
+
|
|
24
|
+
const server = app.listen(port, () => {
|
|
25
|
+
console.log(`Express server listening on http://localhost:${port}`);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
server.on('error', console.error);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {composePlugins, withNx} from '@nx/webpack';
|
|
2
|
+
import {withReact} from '@nx/react';
|
|
3
|
+
import {withModuleFederationForSSR} from '@nx/react/module-federation';
|
|
4
|
+
|
|
5
|
+
import baseConfig from './module-federation.config';
|
|
6
|
+
|
|
7
|
+
const defaultConfig = {
|
|
8
|
+
...baseConfig
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// Nx plugins for webpack to build config object from Nx options and context.
|
|
12
|
+
export default composePlugins(withNx(), withReact({ssr: true}), withModuleFederationForSSR(defaultConfig));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import('./bootstrap');
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { composePlugins, withNx } from '@nx/webpack';
|
|
2
|
+
import { withReact } from '@nx/react';
|
|
3
|
+
import { withModuleFederation } from '@nx/react/module-federation';
|
|
4
|
+
|
|
5
|
+
import baseConfig from './module-federation.config';
|
|
6
|
+
|
|
7
|
+
const prodConfig = {
|
|
8
|
+
...baseConfig,
|
|
9
|
+
/*
|
|
10
|
+
* Remote overrides for production.
|
|
11
|
+
* Each entry is a pair of a unique name and the URL where it is deployed.
|
|
12
|
+
*
|
|
13
|
+
* e.g.
|
|
14
|
+
* remotes: [
|
|
15
|
+
* ['app1', 'http://app1.example.com'],
|
|
16
|
+
* ['app2', 'http://app2.example.com'],
|
|
17
|
+
* ]
|
|
18
|
+
*
|
|
19
|
+
* You can also use a full path to the remoteEntry.js file if desired.
|
|
20
|
+
*
|
|
21
|
+
* remotes: [
|
|
22
|
+
* ['app1', 'http://example.com/path/to/app1/remoteEntry.js'],
|
|
23
|
+
* ['app2', 'http://example.com/path/to/app2/remoteEntry.js'],
|
|
24
|
+
* ]
|
|
25
|
+
*/
|
|
26
|
+
remotes: [
|
|
27
|
+
<% remotes.forEach(function(r) {%>['<%= r.fileName %>', 'http://localhost:<%= r.port %>/'],<% }); %>
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Nx plugins for webpack to build config object from Nx options and context.
|
|
32
|
+
export default composePlugins(withNx(), withReact(), withModuleFederation(prodConfig));
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {composePlugins, withNx} from '@nx/webpack';
|
|
2
|
+
import {withReact} from '@nx/react';
|
|
3
|
+
import {withModuleFederation} from '@nx/react/module-federation';
|
|
4
|
+
|
|
5
|
+
import baseConfig from './module-federation.config';
|
|
6
|
+
|
|
7
|
+
const config = {
|
|
8
|
+
...baseConfig,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// Nx plugins for webpack to build config object from Nx options and context.
|
|
12
|
+
export default composePlugins(withNx(), withReact(), withModuleFederation(config));
|
|
@@ -20,7 +20,10 @@ async function hostGenerator(host, schema) {
|
|
|
20
20
|
exports.hostGenerator = hostGenerator;
|
|
21
21
|
async function hostGeneratorInternal(host, schema) {
|
|
22
22
|
const tasks = [];
|
|
23
|
-
const options =
|
|
23
|
+
const options = {
|
|
24
|
+
...(await (0, normalize_options_1.normalizeOptions)(host, schema, '@nx/react:host')),
|
|
25
|
+
typescriptConfiguration: schema.typescriptConfiguration ?? true,
|
|
26
|
+
};
|
|
24
27
|
const initTask = await (0, application_1.default)(host, {
|
|
25
28
|
...options,
|
|
26
29
|
// The target use-case is loading remotes as child routes, thus always enable routing.
|
|
@@ -47,6 +50,7 @@ async function hostGeneratorInternal(host, schema) {
|
|
|
47
50
|
ssr: options.ssr,
|
|
48
51
|
skipFormat: true,
|
|
49
52
|
projectNameAndRootFormat: options.projectNameAndRootFormat,
|
|
53
|
+
typescriptConfiguration: options.typescriptConfiguration,
|
|
50
54
|
});
|
|
51
55
|
remotePort++;
|
|
52
56
|
}
|
|
@@ -64,7 +68,7 @@ async function hostGeneratorInternal(host, schema) {
|
|
|
64
68
|
const setupSsrForHostTask = await (0, setup_ssr_for_host_1.setupSsrForHost)(host, options, options.projectName, remotesWithPorts);
|
|
65
69
|
tasks.push(setupSsrForHostTask);
|
|
66
70
|
const projectConfig = (0, devkit_1.readProjectConfiguration)(host, options.projectName);
|
|
67
|
-
projectConfig.targets.server.options.webpackConfig = (0, devkit_1.joinPathFragments)(projectConfig.root,
|
|
71
|
+
projectConfig.targets.server.options.webpackConfig = (0, devkit_1.joinPathFragments)(projectConfig.root, `webpack.server.config.${options.typescriptConfiguration ? 'ts' : 'js'}`);
|
|
68
72
|
(0, devkit_1.updateProjectConfiguration)(host, options.projectName, projectConfig);
|
|
69
73
|
}
|
|
70
74
|
if (!options.skipFormat) {
|
|
@@ -20,7 +20,20 @@ function addModuleFederationFiles(host, options, defaultRemoteManifest) {
|
|
|
20
20
|
// new entry file.
|
|
21
21
|
host.rename((0, path_1.join)(options.appProjectRoot, 'src/main.tsx'), (0, path_1.join)(options.appProjectRoot, 'src/bootstrap.tsx'));
|
|
22
22
|
(0, devkit_1.generateFiles)(host, (0, path_1.join)(__dirname, `../files/common`), options.appProjectRoot, templateVariables);
|
|
23
|
+
const pathToModuleFederationFiles = options.typescriptConfiguration
|
|
24
|
+
? 'module-federation-ts'
|
|
25
|
+
: 'module-federation';
|
|
23
26
|
// New entry file is created here.
|
|
24
|
-
(0, devkit_1.generateFiles)(host, (0, path_1.join)(__dirname, `../files
|
|
27
|
+
(0, devkit_1.generateFiles)(host, (0, path_1.join)(__dirname, `../files/${pathToModuleFederationFiles}`), options.appProjectRoot, templateVariables);
|
|
28
|
+
if (options.typescriptConfiguration) {
|
|
29
|
+
const pathToWebpackConfig = (0, devkit_1.joinPathFragments)(options.appProjectRoot, 'webpack.config.js');
|
|
30
|
+
const pathToWebpackProdConfig = (0, devkit_1.joinPathFragments)(options.appProjectRoot, 'webpack.config.prod.js');
|
|
31
|
+
if (host.exists(pathToWebpackConfig)) {
|
|
32
|
+
host.delete(pathToWebpackConfig);
|
|
33
|
+
}
|
|
34
|
+
if (host.exists(pathToWebpackProdConfig)) {
|
|
35
|
+
host.delete(pathToWebpackProdConfig);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
25
38
|
}
|
|
26
39
|
exports.addModuleFederationFiles = addModuleFederationFiles;
|
|
@@ -8,7 +8,10 @@ async function setupSsrForHost(tree, options, appName, defaultRemoteManifest) {
|
|
|
8
8
|
let project = (0, devkit_1.readProjectConfiguration)(tree, appName);
|
|
9
9
|
project.targets.serve.executor = '@nx/react:module-federation-ssr-dev-server';
|
|
10
10
|
(0, devkit_1.updateProjectConfiguration)(tree, appName, project);
|
|
11
|
-
|
|
11
|
+
const pathToModuleFederationSsrFiles = options.typescriptConfiguration
|
|
12
|
+
? 'module-federation-ssr-ts'
|
|
13
|
+
: 'module-federation-ssr';
|
|
14
|
+
(0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, `../files/${pathToModuleFederationSsrFiles}`), project.root, {
|
|
12
15
|
...options,
|
|
13
16
|
remotes: defaultRemoteManifest.map(({ name, port }) => {
|
|
14
17
|
return {
|
|
@@ -166,6 +166,11 @@
|
|
|
166
166
|
"description": "Generate a React app with a minimal setup. No nx starter template.",
|
|
167
167
|
"type": "boolean",
|
|
168
168
|
"default": false
|
|
169
|
+
},
|
|
170
|
+
"typescriptConfiguration": {
|
|
171
|
+
"type": "boolean",
|
|
172
|
+
"description": "Whether the module federation configuration and webpack configuration files should use TS.",
|
|
173
|
+
"default": true
|
|
169
174
|
}
|
|
170
175
|
},
|
|
171
176
|
"required": ["name"],
|
|
@@ -50,7 +50,7 @@ async function libraryGeneratorInternal(host, schema) {
|
|
|
50
50
|
(0, create_files_1.createFiles)(host, options);
|
|
51
51
|
// Set up build target
|
|
52
52
|
if (options.buildable && options.bundler === 'vite') {
|
|
53
|
-
const { viteConfigurationGenerator } = (0, devkit_1.ensurePackage)('@nx/vite', versions_1.nxVersion);
|
|
53
|
+
const { viteConfigurationGenerator, createOrEditViteConfig } = (0, devkit_1.ensurePackage)('@nx/vite', versions_1.nxVersion);
|
|
54
54
|
const viteTask = await viteConfigurationGenerator(host, {
|
|
55
55
|
uiFramework: 'react',
|
|
56
56
|
project: options.name,
|
|
@@ -63,6 +63,24 @@ async function libraryGeneratorInternal(host, schema) {
|
|
|
63
63
|
testEnvironment: 'jsdom',
|
|
64
64
|
});
|
|
65
65
|
tasks.push(viteTask);
|
|
66
|
+
createOrEditViteConfig(host, {
|
|
67
|
+
project: options.name,
|
|
68
|
+
includeLib: true,
|
|
69
|
+
includeVitest: options.unitTestRunner === 'vitest',
|
|
70
|
+
inSourceTests: options.inSourceTests,
|
|
71
|
+
rollupOptionsExternal: [
|
|
72
|
+
`'react'`,
|
|
73
|
+
`'react-dom'`,
|
|
74
|
+
`'react/jsx-runtime'`,
|
|
75
|
+
],
|
|
76
|
+
rollupOptionsExternalString: `"'react', 'react-dom', 'react/jsx-runtime'"`,
|
|
77
|
+
imports: [
|
|
78
|
+
options.compiler === 'swc'
|
|
79
|
+
? `import react from '@vitejs/plugin-react-swc'`
|
|
80
|
+
: `import react from '@vitejs/plugin-react'`,
|
|
81
|
+
],
|
|
82
|
+
plugins: ['react()'],
|
|
83
|
+
}, false);
|
|
66
84
|
}
|
|
67
85
|
else if (options.buildable && options.bundler === 'rollup') {
|
|
68
86
|
const rollupTask = await (0, add_rollup_build_target_1.addRollupBuildTarget)(host, options);
|
|
@@ -90,7 +108,7 @@ async function libraryGeneratorInternal(host, schema) {
|
|
|
90
108
|
else if (options.unitTestRunner === 'vitest' &&
|
|
91
109
|
options.bundler !== 'vite' // tests are already configured if bundler is vite
|
|
92
110
|
) {
|
|
93
|
-
const { vitestGenerator } = (0, devkit_1.ensurePackage)('@nx/vite', versions_1.nxVersion);
|
|
111
|
+
const { vitestGenerator, createOrEditViteConfig } = (0, devkit_1.ensurePackage)('@nx/vite', versions_1.nxVersion);
|
|
94
112
|
const vitestTask = await vitestGenerator(host, {
|
|
95
113
|
uiFramework: 'react',
|
|
96
114
|
project: options.name,
|
|
@@ -100,6 +118,20 @@ async function libraryGeneratorInternal(host, schema) {
|
|
|
100
118
|
testEnvironment: 'jsdom',
|
|
101
119
|
});
|
|
102
120
|
tasks.push(vitestTask);
|
|
121
|
+
createOrEditViteConfig(host, {
|
|
122
|
+
project: options.name,
|
|
123
|
+
includeLib: true,
|
|
124
|
+
includeVitest: true,
|
|
125
|
+
inSourceTests: options.inSourceTests,
|
|
126
|
+
rollupOptionsExternal: [
|
|
127
|
+
`'react'`,
|
|
128
|
+
`'react-dom'`,
|
|
129
|
+
`'react/jsx-runtime'`,
|
|
130
|
+
],
|
|
131
|
+
rollupOptionsExternalString: `"'react', 'react-dom', 'react/jsx-runtime'"`,
|
|
132
|
+
imports: [`import react from '@vitejs/plugin-react'`],
|
|
133
|
+
plugins: ['react()'],
|
|
134
|
+
}, true);
|
|
103
135
|
}
|
|
104
136
|
if (options.component) {
|
|
105
137
|
const componentTask = await (0, component_1.default)(host, {
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import cors from 'cors';
|
|
4
|
+
|
|
5
|
+
import { handleRequest } from './src/main.server';
|
|
6
|
+
|
|
7
|
+
const port = process.env['PORT'] || 4200;
|
|
8
|
+
const app = express();
|
|
9
|
+
|
|
10
|
+
const browserDist = path.join(process.cwd(), '<%= browserBuildOutputPath %>');
|
|
11
|
+
const serverDist = path.join(process.cwd(), '<%= serverBuildOutputPath %>');
|
|
12
|
+
const indexPath = path.join(browserDist, 'index.html');
|
|
13
|
+
|
|
14
|
+
app.use(cors());
|
|
15
|
+
|
|
16
|
+
// Client-side static bundles
|
|
17
|
+
app.get(
|
|
18
|
+
'*.*',
|
|
19
|
+
express.static(browserDist, {
|
|
20
|
+
maxAge: '1y',
|
|
21
|
+
})
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
// Static bundles for server-side module federation
|
|
25
|
+
app.use('/server',
|
|
26
|
+
express.static(serverDist, {
|
|
27
|
+
maxAge: '1y'
|
|
28
|
+
})
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
app.use('*', handleRequest(indexPath));
|
|
32
|
+
|
|
33
|
+
const server = app.listen(port, () => {
|
|
34
|
+
console.log(`Express server listening on http://localhost:${port}`);
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* DO NOT REMOVE IF USING @nx/react:module-federation-dev-ssr executor
|
|
38
|
+
* to serve your Host application with this Remote application.
|
|
39
|
+
* This message allows Nx to determine when the Remote is ready to be
|
|
40
|
+
* consumed by the Host.
|
|
41
|
+
*/
|
|
42
|
+
process.send?.('nx.server.ready');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
server.on('error', console.error);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {composePlugins, withNx} from '@nx/webpack';
|
|
2
|
+
import {withReact} from '@nx/react';
|
|
3
|
+
import {withModuleFederationForSSR} from '@nx/react/module-federation';
|
|
4
|
+
|
|
5
|
+
import baseConfig from "./module-federation.server.config";
|
|
6
|
+
|
|
7
|
+
const defaultConfig = {
|
|
8
|
+
...baseConfig,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// Nx plugins for webpack to build config object from Nx options and context.
|
|
12
|
+
export default composePlugins(withNx(), withReact({ssr: true}), withModuleFederationForSSR(defaultConfig));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import('./bootstrap');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './app/app';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default require('./webpack.config');
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {composePlugins, withNx} from '@nx/webpack';
|
|
2
|
+
import {withReact} from '@nx/react';
|
|
3
|
+
import {withModuleFederation} from '@nx/react/module-federation';
|
|
4
|
+
|
|
5
|
+
import baseConfig from './module-federation.config';
|
|
6
|
+
|
|
7
|
+
const config = {
|
|
8
|
+
...baseConfig,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// Nx plugins for webpack to build config object from Nx options and context.
|
|
12
|
+
export default composePlugins(withNx(), withReact(), withModuleFederation(config));
|
|
@@ -6,7 +6,10 @@ const versions_1 = require("../../../utils/versions");
|
|
|
6
6
|
async function setupSsrForRemote(tree, options, appName) {
|
|
7
7
|
const tasks = [];
|
|
8
8
|
const project = (0, devkit_1.readProjectConfiguration)(tree, appName);
|
|
9
|
-
|
|
9
|
+
const pathToModuleFederationSsrFiles = options.typescriptConfiguration
|
|
10
|
+
? 'module-federation-ssr-ts'
|
|
11
|
+
: 'module-federation-ssr';
|
|
12
|
+
(0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, `../files/${pathToModuleFederationSsrFiles}`), project.root, {
|
|
10
13
|
...options,
|
|
11
14
|
appName,
|
|
12
15
|
tmpl: '',
|
|
@@ -10,7 +10,10 @@ function updateHostWithRemote(host, hostName, remoteName) {
|
|
|
10
10
|
tsModule = (0, ensure_typescript_1.ensureTypescript)();
|
|
11
11
|
}
|
|
12
12
|
const hostConfig = (0, devkit_1.readProjectConfiguration)(host, hostName);
|
|
13
|
-
|
|
13
|
+
let moduleFederationConfigPath = (0, devkit_1.joinPathFragments)(hostConfig.root, 'module-federation.config.js');
|
|
14
|
+
if (!host.exists(moduleFederationConfigPath)) {
|
|
15
|
+
moduleFederationConfigPath = (0, devkit_1.joinPathFragments)(hostConfig.root, 'module-federation.config.ts');
|
|
16
|
+
}
|
|
14
17
|
const remoteDefsPath = (0, devkit_1.joinPathFragments)(hostConfig.sourceRoot, 'remotes.d.ts');
|
|
15
18
|
const appComponentPath = findAppComponentPath(host, hostConfig.sourceRoot);
|
|
16
19
|
if (host.exists(moduleFederationConfigPath)) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { GeneratorCallback, Tree } from '@nx/devkit';
|
|
2
2
|
import { NormalizedSchema } from '../application/schema';
|
|
3
3
|
import { Schema } from './schema';
|
|
4
|
-
export declare function addModuleFederationFiles(host: Tree, options: NormalizedSchema): void;
|
|
4
|
+
export declare function addModuleFederationFiles(host: Tree, options: NormalizedSchema<Schema>): void;
|
|
5
5
|
export declare function remoteGenerator(host: Tree, schema: Schema): Promise<GeneratorCallback>;
|
|
6
6
|
export declare function remoteGeneratorInternal(host: Tree, schema: Schema): Promise<GeneratorCallback>;
|
|
7
7
|
export default remoteGenerator;
|
|
@@ -15,7 +15,20 @@ function addModuleFederationFiles(host, options) {
|
|
|
15
15
|
...options,
|
|
16
16
|
tmpl: '',
|
|
17
17
|
};
|
|
18
|
-
|
|
18
|
+
const pathToModuleFederationFiles = options.typescriptConfiguration
|
|
19
|
+
? 'module-federation-ts'
|
|
20
|
+
: 'module-federation';
|
|
21
|
+
(0, devkit_1.generateFiles)(host, (0, path_1.join)(__dirname, `./files/${pathToModuleFederationFiles}`), options.appProjectRoot, templateVariables);
|
|
22
|
+
if (options.typescriptConfiguration) {
|
|
23
|
+
const pathToWebpackConfig = (0, devkit_1.joinPathFragments)(options.appProjectRoot, 'webpack.config.js');
|
|
24
|
+
const pathToWebpackProdConfig = (0, devkit_1.joinPathFragments)(options.appProjectRoot, 'webpack.config.prod.js');
|
|
25
|
+
if (host.exists(pathToWebpackConfig)) {
|
|
26
|
+
host.delete(pathToWebpackConfig);
|
|
27
|
+
}
|
|
28
|
+
if (host.exists(pathToWebpackProdConfig)) {
|
|
29
|
+
host.delete(pathToWebpackProdConfig);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
19
32
|
}
|
|
20
33
|
exports.addModuleFederationFiles = addModuleFederationFiles;
|
|
21
34
|
async function remoteGenerator(host, schema) {
|
|
@@ -27,7 +40,10 @@ async function remoteGenerator(host, schema) {
|
|
|
27
40
|
exports.remoteGenerator = remoteGenerator;
|
|
28
41
|
async function remoteGeneratorInternal(host, schema) {
|
|
29
42
|
const tasks = [];
|
|
30
|
-
const options =
|
|
43
|
+
const options = {
|
|
44
|
+
...(await (0, normalize_options_1.normalizeOptions)(host, schema, '@nx/react:remote')),
|
|
45
|
+
typescriptConfiguration: schema.typescriptConfiguration ?? true,
|
|
46
|
+
};
|
|
31
47
|
const initAppTask = await (0, application_1.default)(host, {
|
|
32
48
|
...options,
|
|
33
49
|
// Only webpack works with module federation for now.
|
|
@@ -54,7 +70,7 @@ async function remoteGeneratorInternal(host, schema) {
|
|
|
54
70
|
const setupSsrForRemoteTask = await (0, setup_ssr_for_remote_1.setupSsrForRemote)(host, options, options.projectName);
|
|
55
71
|
tasks.push(setupSsrForRemoteTask);
|
|
56
72
|
const projectConfig = (0, devkit_1.readProjectConfiguration)(host, options.projectName);
|
|
57
|
-
projectConfig.targets.server.options.webpackConfig = (0, devkit_1.joinPathFragments)(projectConfig.root,
|
|
73
|
+
projectConfig.targets.server.options.webpackConfig = (0, devkit_1.joinPathFragments)(projectConfig.root, `webpack.server.config.${options.typescriptConfiguration ? 'ts' : 'js'}`);
|
|
58
74
|
(0, devkit_1.updateProjectConfiguration)(host, options.projectName, projectConfig);
|
|
59
75
|
}
|
|
60
76
|
if (!options.skipFormat) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ProjectNameAndRootFormat } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
|
2
2
|
import type { Linter } from '@nx/linter';
|
|
3
3
|
import type { SupportedStyles } from '../../../typings';
|
|
4
|
+
import type { NormalizedSchema as ApplicationNormalizedSchema } from '../application/schema';
|
|
4
5
|
|
|
5
6
|
export interface Schema {
|
|
6
7
|
classComponent?: boolean;
|
|
@@ -24,4 +25,9 @@ export interface Schema {
|
|
|
24
25
|
style: SupportedStyles;
|
|
25
26
|
tags?: string;
|
|
26
27
|
unitTestRunner: 'jest' | 'vitest' | 'none';
|
|
28
|
+
typescriptConfiguration?: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface NormalizedSchema extends ApplicationNormalizedSchema {
|
|
32
|
+
typescriptConfiguration: boolean;
|
|
27
33
|
}
|
|
@@ -164,6 +164,11 @@
|
|
|
164
164
|
"description": "Whether to configure SSR for the host application",
|
|
165
165
|
"type": "boolean",
|
|
166
166
|
"default": false
|
|
167
|
+
},
|
|
168
|
+
"typescriptConfiguration": {
|
|
169
|
+
"type": "boolean",
|
|
170
|
+
"description": "Whether the module federation configuration and webpack configuration files should use TS.",
|
|
171
|
+
"default": true
|
|
167
172
|
}
|
|
168
173
|
},
|
|
169
174
|
"required": ["name"],
|
|
@@ -41,17 +41,23 @@ async function getModuleFederationConfig(mfConfig, options = { isServer: false }
|
|
|
41
41
|
const sharedLibraries = (0, module_federation_1.shareWorkspaceLibraries)(dependencies.workspaceLibraries);
|
|
42
42
|
const npmPackages = (0, module_federation_1.sharePackages)(dependencies.npmPackages);
|
|
43
43
|
const sharedDependencies = {
|
|
44
|
-
...sharedLibraries.getLibraries(),
|
|
44
|
+
...sharedLibraries.getLibraries(project.root),
|
|
45
45
|
...npmPackages,
|
|
46
46
|
};
|
|
47
47
|
(0, module_federation_1.applySharedFunction)(sharedDependencies, mfConfig.shared);
|
|
48
48
|
(0, module_federation_1.applyAdditionalShared)(sharedDependencies, mfConfig.additionalShared, projectGraph);
|
|
49
|
+
// Choose the correct mapRemotes function based on the server state.
|
|
49
50
|
const mapRemotesFunction = options.isServer ? module_federation_1.mapRemotesForSSR : module_federation_1.mapRemotes;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
// Determine the URL function, either from provided options or by using a default.
|
|
52
|
+
const determineRemoteUrlFunction = options.determineRemoteUrl
|
|
53
|
+
? options.determineRemoteUrl
|
|
54
|
+
: getFunctionDeterminateRemoteUrl(options.isServer);
|
|
55
|
+
// Map the remotes if they exist, otherwise default to an empty object.
|
|
56
|
+
let mappedRemotes = {};
|
|
57
|
+
if (mfConfig.remotes && mfConfig.remotes.length > 0) {
|
|
58
|
+
const isLibraryTypeVar = mfConfig.library?.type === 'var';
|
|
59
|
+
mappedRemotes = mapRemotesFunction(mfConfig.remotes, 'js', determineRemoteUrlFunction, isLibraryTypeVar);
|
|
60
|
+
}
|
|
55
61
|
return { sharedLibraries, sharedDependencies, mappedRemotes };
|
|
56
62
|
}
|
|
57
63
|
exports.getModuleFederationConfig = getModuleFederationConfig;
|
|
@@ -12,6 +12,10 @@ async function withModuleFederation(options) {
|
|
|
12
12
|
return (config, ctx) => {
|
|
13
13
|
config.output.uniqueName = options.name;
|
|
14
14
|
config.output.publicPath = 'auto';
|
|
15
|
+
if (options.library?.type === 'var') {
|
|
16
|
+
config.output.scriptType = 'text/javascript';
|
|
17
|
+
config.experiments.outputModule = false;
|
|
18
|
+
}
|
|
15
19
|
config.optimization = {
|
|
16
20
|
runtimeChunk: false,
|
|
17
21
|
};
|
|
@@ -28,6 +32,13 @@ async function withModuleFederation(options) {
|
|
|
28
32
|
shared: {
|
|
29
33
|
...sharedDependencies,
|
|
30
34
|
},
|
|
35
|
+
/**
|
|
36
|
+
* remoteType: 'script' is required for the remote to be loaded as a script tag.
|
|
37
|
+
* remotes will need to be defined as:
|
|
38
|
+
* { appX: 'appX@http://localhost:3001/remoteEntry.js' }
|
|
39
|
+
* { appY: 'appY@http://localhost:3002/remoteEntry.js' }
|
|
40
|
+
*/
|
|
41
|
+
...(options.library?.type === 'var' ? { remoteType: 'script' } : {}),
|
|
31
42
|
}), sharedLibraries.getReplacementPlugin());
|
|
32
43
|
return config;
|
|
33
44
|
};
|
|
@@ -8,11 +8,11 @@ function updateModuleFederationProject(host, options) {
|
|
|
8
8
|
projectConfig.targets.build.options = {
|
|
9
9
|
...projectConfig.targets.build.options,
|
|
10
10
|
main: `${options.appProjectRoot}/src/main.ts`,
|
|
11
|
-
webpackConfig: `${options.appProjectRoot}/webpack.config.js`,
|
|
11
|
+
webpackConfig: `${options.appProjectRoot}/webpack.config.${options.typescriptConfiguration ? 'ts' : 'js'}`,
|
|
12
12
|
};
|
|
13
13
|
projectConfig.targets.build.configurations.production = {
|
|
14
14
|
...projectConfig.targets.build.configurations.production,
|
|
15
|
-
webpackConfig: `${options.appProjectRoot}/webpack.config.prod.js`,
|
|
15
|
+
webpackConfig: `${options.appProjectRoot}/webpack.config.prod.${options.typescriptConfiguration ? 'ts' : 'js'}`,
|
|
16
16
|
};
|
|
17
17
|
projectConfig.targets.serve.executor =
|
|
18
18
|
'@nx/react:module-federation-dev-server';
|