-
Notifications
You must be signed in to change notification settings - Fork 2.2k
/
index.ts
139 lines (117 loc) · 3.71 KB
/
index.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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import { readCachedProjectGraph } from '@nrwl/workspace/src/core/project-graph';
import { readWorkspaceJson } from '@nrwl/workspace/src/core/file-utils';
import {
ProjectGraph,
ProjectGraphDependency,
} from '@nrwl/tao/src/shared/project-graph';
import { WorkspaceJsonConfiguration } from '@nrwl/tao/src/shared/workspace';
const { ModuleFederationPlugin } = require('webpack').container;
const reactWebpackConfig = require('../webpack');
export type MFERemotes = string[] | [remoteName: string, remoteUrl: string][];
export type MFELibrary = { type: string; name: string };
export interface SharedLibraryConfig {
singleton?: boolean;
strictVersion?: boolean;
requiredVersion?: string;
eager?: boolean;
}
export interface MfeOptions {
name: string;
filename: string;
remotes?: string[];
library?: MFELibrary;
exposes?: Record<string, string>;
shared?: (
library: string,
config: SharedLibraryConfig
) => undefined | false | SharedLibraryConfig;
}
function getSharedDependencies(graph: ProjectGraph<any>, options: MfeOptions) {
const dependencies = graph.dependencies[options.name];
const sharedDependencies = dependencies.reduce((acc, dep) => {
//npm libs
if (graph.externalNodes[dep.target]) {
const externalNode = graph.externalNodes[dep.target];
acc[externalNode.data.packageName] = {
singleton: true,
requiredVersion: externalNode.data.version,
};
}
// workspace libs
if (graph.nodes[dep.target]) {
const node = graph.nodes[dep.target];
if (node.data.projectType !== 'application') {
acc[node.name] = {
requiredVersion: false,
};
}
}
return acc;
}, {});
if (options.shared) {
for (const [library, config] of Object.entries(sharedDependencies)) {
const shouldKeepDependency = options.shared(library, config);
if (shouldKeepDependency == false) {
delete sharedDependencies[library];
continue;
}
sharedDependencies[library] = shouldKeepDependency ?? config;
}
}
return sharedDependencies;
}
function getRemotes(options: MfeOptions, ws: WorkspaceJsonConfiguration) {
return options.remotes.reduce((acc, name) => {
const project = ws.projects[name];
if (!project) {
throw Error(
`Cannot find remote project "${options.name}". Check that the name is correct in mfe.config.js`
);
}
const serveOptions = project?.targets?.serve.options;
if (serveOptions) {
acc[name] = `${name}@//${serveOptions.host ?? 'localhost'}:${
serveOptions.port ?? 4200
}/remoteEntry.js`;
}
return acc;
}, {});
}
// This is probably something linked to a Schema
function withModuleFederation(options: MfeOptions) {
const ws = readWorkspaceJson();
const graph = readCachedProjectGraph();
const project = ws.projects[options.name];
if (!project) {
throw Error(
`Cannot find project "${options.name}". Check that the name is correct in mfe.config.js`
);
}
const mfeOptions = {
name: options.name,
filename: 'remoteEntry.js',
exposes: {},
} as any;
if (options.library) {
mfeOptions.library = options.library;
}
mfeOptions.shared = getSharedDependencies(graph, options);
if (options.remotes) {
mfeOptions.remotes = getRemotes(options, ws);
}
if (options.exposes) {
mfeOptions.exposes = options.exposes;
}
return (config, options) => {
config = reactWebpackConfig(config);
config.output.uniqueName = options.name;
config.output.publicPath = 'auto';
config.optimization = {
runtimeChunk: false,
minimize: false,
};
config.plugins.push(new ModuleFederationPlugin(mfeOptions));
return config;
};
}
module.exports = withModuleFederation;