/
module-federation-ssr-dev-server.impl.ts
117 lines (107 loc) · 3.26 KB
/
module-federation-ssr-dev-server.impl.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import {
ExecutorContext,
logger,
runExecutor,
workspaceRoot,
} from '@nrwl/devkit';
import ssrDevServerExecutor from '@nrwl/webpack/src/executors/ssr-dev-server/ssr-dev-server.impl';
import { WebSsrDevServerOptions } from '@nrwl/webpack/src/executors/ssr-dev-server/schema';
import { join } from 'path';
import * as chalk from 'chalk';
import {
combineAsyncIterableIterators,
tapAsyncIterable,
} from '@nrwl/devkit/src/utils/async-iterable';
import { execSync, fork } from 'child_process';
type ModuleFederationDevServerOptions = WebSsrDevServerOptions & {
devRemotes?: string | string[];
skipRemotes?: string[];
host: string;
};
export default async function* moduleFederationSsrDevServer(
options: ModuleFederationDevServerOptions,
context: ExecutorContext
) {
let iter: AsyncGenerator<any, any, any> = ssrDevServerExecutor(
options,
context
);
const p = context.workspace.projects[context.projectName];
const moduleFederationConfigPath = join(
context.root,
p.root,
'module-federation.config.js'
);
let moduleFederationConfig: any;
try {
moduleFederationConfig = require(moduleFederationConfigPath);
} catch {
// TODO(jack): Add a link to guide
throw new Error(
`Could not load ${moduleFederationConfigPath}. Was this project generated with "@nrwl/react:host"?`
);
}
const remotesToSkip = new Set(options.skipRemotes ?? []);
const knownRemotes = (moduleFederationConfig.remotes ?? []).filter(
(r) => !remotesToSkip.has(r)
);
const devServeApps = !options.devRemotes
? []
: Array.isArray(options.devRemotes)
? options.devRemotes
: [options.devRemotes];
for (const app of knownRemotes) {
const [appName] = Array.isArray(app) ? app : [app];
const isDev = devServeApps.includes(appName);
const remoteServeIter = (async function* () {
if (isDev) {
yield await runExecutor(
{
project: appName,
target: 'serve',
configuration: context.configurationName,
},
{
watch: isDev,
},
context
);
} else {
yield await new Promise((res) => {
const remoteProject = context.workspace.projects[appName];
const remoteServerOutput = join(
workspaceRoot,
remoteProject.targets.server.options.outputPath,
'main.js'
);
execSync(
`npx nx run ${appName}:server${
context.configurationName ? `:${context.configurationName}` : ''
}`,
{ stdio: 'inherit' }
);
const child = fork(remoteServerOutput, {
env: { port: remoteProject.targets['serve-browser'].options.port },
});
child.on('message', (msg) => {
if (msg === 'nx.server.ready') {
res(true);
}
});
});
}
})();
iter = combineAsyncIterableIterators(iter, remoteServeIter);
}
let numAwaiting = knownRemotes.length + 1; // remotes + host
return yield* tapAsyncIterable(iter, (x) => {
numAwaiting--;
if (numAwaiting === 0) {
logger.info(
`[ ${chalk.green('ready')} ] http://${options.host ?? 'localhost'}:${
options.port ?? 4200
}`
);
}
});
}