@squide/firefly-webpack-configs 4.2.1 → 4.2.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/CHANGELOG.md +12 -0
- package/dist/defineConfig.d.ts +59 -0
- package/dist/defineConfig.js +387 -0
- package/dist/defineConfig.js.map +1 -0
- package/dist/index.d.ts +2 -25
- package/dist/index.js +7 -45
- package/dist/index.js.map +1 -0
- package/dist/nonCacheableRemoteEntryPlugin.d.ts +3 -0
- package/dist/nonCacheableRemoteEntryPlugin.js +21 -0
- package/dist/nonCacheableRemoteEntryPlugin.js.map +1 -0
- package/dist/shared.d.ts +1 -0
- package/dist/shared.js +8 -0
- package/dist/shared.js.map +1 -0
- package/dist/sharedDependenciesResolutionPlugin.d.ts +9 -0
- package/dist/sharedDependenciesResolutionPlugin.js +137 -0
- package/dist/sharedDependenciesResolutionPlugin.js.map +1 -0
- package/package.json +30 -19
- package/src/defineConfig.ts +514 -0
- package/src/index.ts +3 -0
- package/src/nonCacheableRemoteEntryPlugin.ts +20 -0
- package/src/shared.ts +2 -0
- package/src/sharedDependenciesResolutionPlugin.ts +173 -0
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
import { ModuleFederationPlugin } from "@module-federation/enhanced/webpack";
|
|
2
|
+
import type { SwcConfig } from "@workleap/swc-configs";
|
|
3
|
+
import { defineBuildConfig, defineBuildHtmlWebpackPluginConfig, defineDevConfig, defineDevHtmlWebpackPluginConfig, type DefineBuildConfigOptions, type DefineDevConfigOptions, type WebpackConfig, type WebpackConfigTransformer } from "@workleap/webpack-configs";
|
|
4
|
+
import merge from "deepmerge";
|
|
5
|
+
import type HtmlWebpackPlugin from "html-webpack-plugin";
|
|
6
|
+
import fs from "node:fs";
|
|
7
|
+
import path, { dirname } from "node:path";
|
|
8
|
+
import url, { fileURLToPath } from "node:url";
|
|
9
|
+
import type webpack from "webpack";
|
|
10
|
+
import { HostApplicationName } from "./shared.ts";
|
|
11
|
+
|
|
12
|
+
// Using import.meta.url instead of import.meta.dirname because Jest is throwing the following error:
|
|
13
|
+
// SyntaxError: Cannot use 'import.meta' outside a module
|
|
14
|
+
const applicationDirectory = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const packageDirectory = url.fileURLToPath(new URL(".", import.meta.url));
|
|
16
|
+
|
|
17
|
+
// Must be similar to the module name defined in @workleap/module-federation.
|
|
18
|
+
const RemoteRegisterModuleName = "./register";
|
|
19
|
+
const RemoteEntryPoint = "remoteEntry.js";
|
|
20
|
+
|
|
21
|
+
// Webpack doesn't export ModuleFederationPlugin typings.
|
|
22
|
+
export type ModuleFederationPluginOptions = ConstructorParameters<typeof ModuleFederationPlugin>[0];
|
|
23
|
+
export type ModuleFederationRemotesOption = ModuleFederationPluginOptions["remotes"];
|
|
24
|
+
|
|
25
|
+
export type ModuleFederationRuntimePlugins = NonNullable<ModuleFederationPluginOptions["runtimePlugins"]>;
|
|
26
|
+
export type ModuleFederationShared = NonNullable<ModuleFederationPluginOptions["shared"]>;
|
|
27
|
+
|
|
28
|
+
// Generally, only the host application should have eager dependencies.
|
|
29
|
+
// For more informations about shared dependencies refer to: https://github.com/patricklafrance/wmf-versioning
|
|
30
|
+
function getDefaultSharedDependencies(features: Features, isHost: boolean): ModuleFederationShared {
|
|
31
|
+
return {
|
|
32
|
+
"react": {
|
|
33
|
+
singleton: true,
|
|
34
|
+
eager: isHost ? true : undefined,
|
|
35
|
+
// Fixed the warning when `react-i18next` is imported in any remote modules.
|
|
36
|
+
// For more information, refer to: https://github.com/i18next/react-i18next/issues/1697#issuecomment-1821748226.
|
|
37
|
+
requiredVersion: features.i18next ? false : undefined
|
|
38
|
+
},
|
|
39
|
+
"react-dom": {
|
|
40
|
+
singleton: true,
|
|
41
|
+
eager: isHost ? true : undefined
|
|
42
|
+
},
|
|
43
|
+
"@squide/core": {
|
|
44
|
+
singleton: true,
|
|
45
|
+
eager: isHost ? true : undefined
|
|
46
|
+
},
|
|
47
|
+
"@squide/module-federation": {
|
|
48
|
+
singleton: true,
|
|
49
|
+
eager: isHost ? true : undefined
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export type Router = "react-router";
|
|
55
|
+
|
|
56
|
+
export interface Features {
|
|
57
|
+
router?: Router;
|
|
58
|
+
msw?: boolean;
|
|
59
|
+
i18next?: boolean;
|
|
60
|
+
environmentVariables?: boolean;
|
|
61
|
+
honeycomb?: boolean;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Generally, only the host application should have eager dependencies.
|
|
65
|
+
// For more informations about shared dependencies refer to: https://github.com/patricklafrance/wmf-versioning
|
|
66
|
+
function getReactRouterSharedDependencies(isHost: boolean): ModuleFederationShared {
|
|
67
|
+
return {
|
|
68
|
+
"react-router-dom": {
|
|
69
|
+
singleton: true,
|
|
70
|
+
eager: isHost ? true : undefined
|
|
71
|
+
},
|
|
72
|
+
"@squide/react-router": {
|
|
73
|
+
singleton: true,
|
|
74
|
+
eager: isHost ? true : undefined
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function getMswSharedDependency(isHost: boolean): ModuleFederationShared {
|
|
80
|
+
return {
|
|
81
|
+
"@squide/msw": {
|
|
82
|
+
singleton: true,
|
|
83
|
+
eager: isHost ? true : undefined
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function getI18nextSharedDependency(isHost: boolean): ModuleFederationShared {
|
|
89
|
+
return {
|
|
90
|
+
"i18next": {
|
|
91
|
+
singleton: true,
|
|
92
|
+
eager: isHost ? true : undefined
|
|
93
|
+
},
|
|
94
|
+
// Not adding as a shared dependency for the moment because it causes the following error:
|
|
95
|
+
// Uncaught (in promise) TypeError: i18next_browser_languagedetector__WEBPACK_IMPORTED_MODULE_3__ is not a constructor
|
|
96
|
+
// "i18next-browser-languagedetector": {
|
|
97
|
+
// singleton: true,
|
|
98
|
+
// eager: isHost ? true : undefined
|
|
99
|
+
// },
|
|
100
|
+
"react-i18next": {
|
|
101
|
+
singleton: true,
|
|
102
|
+
eager: isHost ? true : undefined
|
|
103
|
+
},
|
|
104
|
+
"@squide/i18next": {
|
|
105
|
+
singleton: true,
|
|
106
|
+
eager: isHost ? true : undefined
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function getEnvironmentVariablesSharedDependencies(isHost: boolean): ModuleFederationShared {
|
|
112
|
+
return {
|
|
113
|
+
"@squide/env-vars": {
|
|
114
|
+
singleton: true,
|
|
115
|
+
eager: isHost ? true : undefined
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function getHoneycombSharedDependencies(isHost: boolean): ModuleFederationShared {
|
|
121
|
+
return {
|
|
122
|
+
"@honeycombio/opentelemetry-web": {
|
|
123
|
+
singleton: true,
|
|
124
|
+
eager: isHost ? true : undefined
|
|
125
|
+
},
|
|
126
|
+
"@opentelemetry/api": {
|
|
127
|
+
singleton: true,
|
|
128
|
+
eager: isHost ? true : undefined
|
|
129
|
+
},
|
|
130
|
+
"@opentelemetry/auto-instrumentations-web": {
|
|
131
|
+
singleton: true,
|
|
132
|
+
eager: isHost ? true : undefined
|
|
133
|
+
},
|
|
134
|
+
"@squide/firefly-honeycomb": {
|
|
135
|
+
singleton: true,
|
|
136
|
+
eager: isHost ? true : undefined
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function getFeaturesDependencies(features: Features, isHost: boolean) {
|
|
142
|
+
const {
|
|
143
|
+
router = "react-router",
|
|
144
|
+
msw = true,
|
|
145
|
+
i18next,
|
|
146
|
+
environmentVariables,
|
|
147
|
+
honeycomb
|
|
148
|
+
} = features;
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
...(router === "react-router" ? getReactRouterSharedDependencies(isHost) : {}),
|
|
152
|
+
...(msw ? getMswSharedDependency(isHost) : {}),
|
|
153
|
+
...(i18next ? getI18nextSharedDependency(isHost) : {}),
|
|
154
|
+
...(environmentVariables ? getEnvironmentVariablesSharedDependencies(isHost) : {}),
|
|
155
|
+
...(honeycomb ? getHoneycombSharedDependencies(isHost) : {})
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function resolveDefaultSharedDependencies(features: Features, isHost: boolean) {
|
|
160
|
+
return {
|
|
161
|
+
...getDefaultSharedDependencies(features, isHost),
|
|
162
|
+
...getFeaturesDependencies(features, isHost)
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const forceNamedChunkIdsTransformer: WebpackConfigTransformer = (config: WebpackConfig) => {
|
|
167
|
+
config.optimization = {
|
|
168
|
+
...(config.optimization ?? {}),
|
|
169
|
+
// Without named chunk ids, there are some Webpack features that do not work
|
|
170
|
+
// when used with Module Federation. One of these feature is using a dynamic import in
|
|
171
|
+
// a remote module.
|
|
172
|
+
chunkIds: "named"
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
return config;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
function createSetUniqueNameTransformer(uniqueName: string) {
|
|
179
|
+
const transformer: WebpackConfigTransformer = (config: WebpackConfig) => {
|
|
180
|
+
config.output = {
|
|
181
|
+
...(config.output ?? {}),
|
|
182
|
+
// Every host and remotes must have a "uniqueName" for React Refresh to work
|
|
183
|
+
// with Module Federation.
|
|
184
|
+
uniqueName
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
return config;
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
return transformer;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function resolveEntryFilePath(entryPaths: string[]) {
|
|
194
|
+
for (const entryPath in entryPaths) {
|
|
195
|
+
if (fs.existsSync(path.resolve(applicationDirectory, entryPath))) {
|
|
196
|
+
return entryPath;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return entryPaths[0];
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
//////////////////////////// Host /////////////////////////////
|
|
204
|
+
|
|
205
|
+
export interface RemoteDefinition {
|
|
206
|
+
// The name of the remote module.
|
|
207
|
+
name: string;
|
|
208
|
+
// The URL of the remote, ex: http://localhost:8081.
|
|
209
|
+
url: string;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const HostEntryFilePaths = [
|
|
213
|
+
"./src/index.ts",
|
|
214
|
+
"./src/index.tsx"
|
|
215
|
+
];
|
|
216
|
+
|
|
217
|
+
export interface DefineHostModuleFederationPluginOptions extends ModuleFederationPluginOptions {
|
|
218
|
+
features?: Features;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// The function return type is mandatory, otherwise we got an error TS4058.
|
|
222
|
+
export function defineHostModuleFederationPluginOptions(remotes: RemoteDefinition[], options: DefineHostModuleFederationPluginOptions): ModuleFederationPluginOptions {
|
|
223
|
+
const {
|
|
224
|
+
features = {},
|
|
225
|
+
shared = {},
|
|
226
|
+
runtimePlugins = [],
|
|
227
|
+
...rest
|
|
228
|
+
} = options;
|
|
229
|
+
|
|
230
|
+
const defaultSharedDependencies = resolveDefaultSharedDependencies(features, true);
|
|
231
|
+
|
|
232
|
+
return {
|
|
233
|
+
name: HostApplicationName,
|
|
234
|
+
// Since Squide modules are only exporting a register function with a standardized API
|
|
235
|
+
// it doesn't requires any typing.
|
|
236
|
+
dts: false,
|
|
237
|
+
// Currently only supporting .js remotes.
|
|
238
|
+
manifest: false,
|
|
239
|
+
remotes: remotes.reduce((acc, x) => {
|
|
240
|
+
// Object reduce are always a mess for typings.
|
|
241
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
242
|
+
// @ts-ignore
|
|
243
|
+
acc[x.name] = `${x.name}@${x.url}/${RemoteEntryPoint}`;
|
|
244
|
+
|
|
245
|
+
return acc;
|
|
246
|
+
}, {}) as ModuleFederationRemotesOption,
|
|
247
|
+
// Deep merging the default shared dependencies with the provided shared dependencies
|
|
248
|
+
// to allow the consumer to easily override a default option of a shared dependency
|
|
249
|
+
// without extending the whole default shared dependencies object.
|
|
250
|
+
shared: merge.all([
|
|
251
|
+
defaultSharedDependencies,
|
|
252
|
+
shared
|
|
253
|
+
]) as ModuleFederationShared,
|
|
254
|
+
runtimePlugins: [
|
|
255
|
+
path.resolve(packageDirectory, "./sharedDependenciesResolutionPlugin.js"),
|
|
256
|
+
path.resolve(packageDirectory, "./nonCacheableRemoteEntryPlugin.js"),
|
|
257
|
+
...runtimePlugins
|
|
258
|
+
],
|
|
259
|
+
// Commented because it doesn't seems to work, the runtime is still embedded into remotes.
|
|
260
|
+
// experiments: {
|
|
261
|
+
// // The runtime is 100kb minified.
|
|
262
|
+
// federationRuntime: "hoisted"
|
|
263
|
+
// },
|
|
264
|
+
...rest
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Fixing HMR and page reloads when using `publicPath: auto` either in the host or remotes webpack configuration.
|
|
269
|
+
// Otherwise, when a nested page that belongs to a remote module is reloaded, an "Unexpected token" error will be thrown.
|
|
270
|
+
function trySetHtmlWebpackPluginPublicPath(options: HtmlWebpackPlugin.Options) {
|
|
271
|
+
if (!options.publicPath) {
|
|
272
|
+
options.publicPath = "/";
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return options;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export interface DefineDevHostConfigOptions extends Omit<DefineDevConfigOptions, "htmlWebpackPlugin" | "port"> {
|
|
279
|
+
htmlWebpackPluginOptions?: HtmlWebpackPlugin.Options;
|
|
280
|
+
features?: Features;
|
|
281
|
+
sharedDependencies?: ModuleFederationShared;
|
|
282
|
+
runtimePlugins?: ModuleFederationRuntimePlugins;
|
|
283
|
+
moduleFederationPluginOptions?: ModuleFederationPluginOptions;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// The function return type is mandatory, otherwise we got an error TS4058.
|
|
287
|
+
export function defineDevHostConfig(swcConfig: SwcConfig, port: number, remotes: RemoteDefinition[], options: DefineDevHostConfigOptions = {}): webpack.Configuration {
|
|
288
|
+
const {
|
|
289
|
+
entry = resolveEntryFilePath(HostEntryFilePaths),
|
|
290
|
+
publicPath = "auto",
|
|
291
|
+
cache,
|
|
292
|
+
plugins = [],
|
|
293
|
+
htmlWebpackPluginOptions,
|
|
294
|
+
transformers = [],
|
|
295
|
+
features,
|
|
296
|
+
sharedDependencies,
|
|
297
|
+
runtimePlugins,
|
|
298
|
+
moduleFederationPluginOptions = defineHostModuleFederationPluginOptions(remotes, { features, shared: sharedDependencies, runtimePlugins }),
|
|
299
|
+
...webpackOptions
|
|
300
|
+
} = options;
|
|
301
|
+
|
|
302
|
+
return defineDevConfig(swcConfig, {
|
|
303
|
+
entry,
|
|
304
|
+
port,
|
|
305
|
+
publicPath,
|
|
306
|
+
cache,
|
|
307
|
+
htmlWebpackPlugin: trySetHtmlWebpackPluginPublicPath(htmlWebpackPluginOptions ?? defineBuildHtmlWebpackPluginConfig()),
|
|
308
|
+
plugins: [
|
|
309
|
+
...plugins,
|
|
310
|
+
new ModuleFederationPlugin(moduleFederationPluginOptions)
|
|
311
|
+
],
|
|
312
|
+
...webpackOptions,
|
|
313
|
+
transformers: [
|
|
314
|
+
createSetUniqueNameTransformer(HostApplicationName),
|
|
315
|
+
...transformers
|
|
316
|
+
]
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export interface DefineBuildHostConfigOptions extends Omit<DefineBuildConfigOptions, "htmlWebpackPlugin"> {
|
|
321
|
+
htmlWebpackPluginOptions?: HtmlWebpackPlugin.Options;
|
|
322
|
+
features?: Features;
|
|
323
|
+
sharedDependencies?: ModuleFederationShared;
|
|
324
|
+
runtimePlugins?: ModuleFederationRuntimePlugins;
|
|
325
|
+
moduleFederationPluginOptions?: ModuleFederationPluginOptions;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// The function return type is mandatory, otherwise we got an error TS4058.
|
|
329
|
+
export function defineBuildHostConfig(swcConfig: SwcConfig, remotes: RemoteDefinition[], options: DefineBuildHostConfigOptions = {}): webpack.Configuration {
|
|
330
|
+
const {
|
|
331
|
+
entry = resolveEntryFilePath(HostEntryFilePaths),
|
|
332
|
+
publicPath = "auto",
|
|
333
|
+
plugins = [],
|
|
334
|
+
htmlWebpackPluginOptions,
|
|
335
|
+
transformers = [],
|
|
336
|
+
features,
|
|
337
|
+
sharedDependencies,
|
|
338
|
+
runtimePlugins,
|
|
339
|
+
moduleFederationPluginOptions = defineHostModuleFederationPluginOptions(remotes, { features, shared: sharedDependencies, runtimePlugins }),
|
|
340
|
+
...webpackOptions
|
|
341
|
+
} = options;
|
|
342
|
+
|
|
343
|
+
return defineBuildConfig(swcConfig, {
|
|
344
|
+
entry,
|
|
345
|
+
publicPath,
|
|
346
|
+
htmlWebpackPlugin: trySetHtmlWebpackPluginPublicPath(htmlWebpackPluginOptions ?? defineDevHtmlWebpackPluginConfig()),
|
|
347
|
+
plugins: [
|
|
348
|
+
...plugins,
|
|
349
|
+
new ModuleFederationPlugin(moduleFederationPluginOptions)
|
|
350
|
+
],
|
|
351
|
+
transformers: [
|
|
352
|
+
forceNamedChunkIdsTransformer,
|
|
353
|
+
createSetUniqueNameTransformer(HostApplicationName),
|
|
354
|
+
...transformers
|
|
355
|
+
],
|
|
356
|
+
...webpackOptions
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
//////////////////////////// Remote /////////////////////////////
|
|
361
|
+
|
|
362
|
+
const RemoteEntryFilePaths = [
|
|
363
|
+
"./src/register.tsx",
|
|
364
|
+
"./src/register.ts"
|
|
365
|
+
];
|
|
366
|
+
|
|
367
|
+
export interface DefineRemoteModuleFederationPluginOptions extends ModuleFederationPluginOptions {
|
|
368
|
+
features?: Features;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// The function return type is mandatory, otherwise we got an error TS4058.
|
|
372
|
+
export function defineRemoteModuleFederationPluginOptions(applicationName: string, options: DefineRemoteModuleFederationPluginOptions): ModuleFederationPluginOptions {
|
|
373
|
+
const {
|
|
374
|
+
features = {},
|
|
375
|
+
exposes = {},
|
|
376
|
+
shared = {},
|
|
377
|
+
runtimePlugins = [],
|
|
378
|
+
...rest
|
|
379
|
+
} = options;
|
|
380
|
+
|
|
381
|
+
const defaultSharedDependencies = resolveDefaultSharedDependencies(features, false);
|
|
382
|
+
|
|
383
|
+
return {
|
|
384
|
+
name: applicationName,
|
|
385
|
+
// Since Squide modules are only exporting a register function with a standardized API
|
|
386
|
+
// it doesn't requires any typing.
|
|
387
|
+
dts: false,
|
|
388
|
+
// Currently only supporting .js remotes.
|
|
389
|
+
manifest: false,
|
|
390
|
+
filename: RemoteEntryPoint,
|
|
391
|
+
exposes: {
|
|
392
|
+
[RemoteRegisterModuleName]: "./src/register",
|
|
393
|
+
...exposes
|
|
394
|
+
},
|
|
395
|
+
// Deep merging the default shared dependencies with the provided shared dependencies
|
|
396
|
+
// to allow the consumer to easily override a default option of a shared dependency
|
|
397
|
+
// without extending the whole default shared dependencies object.
|
|
398
|
+
shared: merge.all([
|
|
399
|
+
defaultSharedDependencies,
|
|
400
|
+
shared
|
|
401
|
+
]) as ModuleFederationShared,
|
|
402
|
+
runtimePlugins: [
|
|
403
|
+
path.resolve(packageDirectory, "./sharedDependenciesResolutionPlugin.js"),
|
|
404
|
+
path.resolve(packageDirectory, "./nonCacheableRemoteEntryPlugin.js"),
|
|
405
|
+
...runtimePlugins
|
|
406
|
+
],
|
|
407
|
+
// Commented because it doesn't seems to work, the runtime is still embedded into remotes.
|
|
408
|
+
// experiments: {
|
|
409
|
+
// // The runtime is 100kb minified.
|
|
410
|
+
// federationRuntime: "hoisted"
|
|
411
|
+
// },
|
|
412
|
+
...rest
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const devRemoteModuleTransformer: WebpackConfigTransformer = (config: WebpackConfig) => {
|
|
417
|
+
// "config.devServer" does exist but webpack types are a messed. It could probably be solved by importing "webpack-dev-server"
|
|
418
|
+
// but I would prefer not adding it as a project dependency.
|
|
419
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
420
|
+
// @ts-ignore
|
|
421
|
+
config.devServer.headers = {
|
|
422
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
423
|
+
// @ts-ignore
|
|
424
|
+
...(config.devServer.headers ?? {}),
|
|
425
|
+
// Otherwise hot reload in the host failed with a CORS error.
|
|
426
|
+
"Access-Control-Allow-Origin": "*"
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
return config;
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
export interface DefineDevRemoteModuleConfigOptions extends Omit<DefineDevConfigOptions, "port" | "overlay"> {
|
|
433
|
+
features?: Features;
|
|
434
|
+
sharedDependencies?: ModuleFederationShared;
|
|
435
|
+
runtimePlugins?: ModuleFederationRuntimePlugins;
|
|
436
|
+
moduleFederationPluginOptions?: ModuleFederationPluginOptions;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// The function return type is mandatory, otherwise we got an error TS4058.
|
|
440
|
+
export function defineDevRemoteModuleConfig(swcConfig: SwcConfig, applicationName: string, port: number, options: DefineDevRemoteModuleConfigOptions = {}): webpack.Configuration {
|
|
441
|
+
const {
|
|
442
|
+
entry = resolveEntryFilePath(RemoteEntryFilePaths),
|
|
443
|
+
publicPath = "auto",
|
|
444
|
+
cache,
|
|
445
|
+
plugins = [],
|
|
446
|
+
htmlWebpackPlugin = false,
|
|
447
|
+
transformers = [],
|
|
448
|
+
features,
|
|
449
|
+
sharedDependencies,
|
|
450
|
+
runtimePlugins,
|
|
451
|
+
moduleFederationPluginOptions = defineRemoteModuleFederationPluginOptions(applicationName, { features, shared: sharedDependencies, runtimePlugins }),
|
|
452
|
+
...webpackOptions
|
|
453
|
+
} = options;
|
|
454
|
+
|
|
455
|
+
return defineDevConfig(swcConfig, {
|
|
456
|
+
entry,
|
|
457
|
+
port,
|
|
458
|
+
publicPath,
|
|
459
|
+
cache,
|
|
460
|
+
htmlWebpackPlugin,
|
|
461
|
+
// Disable the error overlay by default for remotes as otherwise every remote module's error overlay will be
|
|
462
|
+
// stack on top of the host application's error overlay.
|
|
463
|
+
overlay: false,
|
|
464
|
+
plugins: [
|
|
465
|
+
...plugins,
|
|
466
|
+
new ModuleFederationPlugin(moduleFederationPluginOptions)
|
|
467
|
+
],
|
|
468
|
+
transformers: [
|
|
469
|
+
devRemoteModuleTransformer,
|
|
470
|
+
createSetUniqueNameTransformer(applicationName),
|
|
471
|
+
...transformers
|
|
472
|
+
],
|
|
473
|
+
...webpackOptions
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
export interface DefineBuildRemoteModuleConfigOptions extends DefineBuildConfigOptions {
|
|
478
|
+
features?: Features;
|
|
479
|
+
sharedDependencies?: ModuleFederationShared;
|
|
480
|
+
runtimePlugins?: ModuleFederationRuntimePlugins;
|
|
481
|
+
moduleFederationPluginOptions?: ModuleFederationPluginOptions;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// The function return type is mandatory, otherwise we got an error TS4058.
|
|
485
|
+
export function defineBuildRemoteModuleConfig(swcConfig: SwcConfig, applicationName: string, options: DefineBuildRemoteModuleConfigOptions = {}): webpack.Configuration {
|
|
486
|
+
const {
|
|
487
|
+
entry = resolveEntryFilePath(RemoteEntryFilePaths),
|
|
488
|
+
publicPath = "auto",
|
|
489
|
+
plugins = [],
|
|
490
|
+
htmlWebpackPlugin = false,
|
|
491
|
+
transformers = [],
|
|
492
|
+
features,
|
|
493
|
+
sharedDependencies,
|
|
494
|
+
runtimePlugins,
|
|
495
|
+
moduleFederationPluginOptions = defineRemoteModuleFederationPluginOptions(applicationName, { features, shared: sharedDependencies, runtimePlugins }),
|
|
496
|
+
...webpackOptions
|
|
497
|
+
} = options;
|
|
498
|
+
|
|
499
|
+
return defineBuildConfig(swcConfig, {
|
|
500
|
+
entry,
|
|
501
|
+
publicPath,
|
|
502
|
+
htmlWebpackPlugin,
|
|
503
|
+
plugins: [
|
|
504
|
+
...plugins,
|
|
505
|
+
new ModuleFederationPlugin(moduleFederationPluginOptions)
|
|
506
|
+
],
|
|
507
|
+
transformers: [
|
|
508
|
+
forceNamedChunkIdsTransformer,
|
|
509
|
+
createSetUniqueNameTransformer(applicationName),
|
|
510
|
+
...transformers
|
|
511
|
+
],
|
|
512
|
+
...webpackOptions
|
|
513
|
+
});
|
|
514
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { FederationRuntimePlugin } from "@module-federation/enhanced/runtime";
|
|
2
|
+
|
|
3
|
+
const plugin: () => FederationRuntimePlugin = () => {
|
|
4
|
+
return {
|
|
5
|
+
name: "non-cacheable-remote-entry-plugin",
|
|
6
|
+
createScript: function({ url }) {
|
|
7
|
+
const element = document.createElement("script");
|
|
8
|
+
|
|
9
|
+
// Adding a timestamp to make sure the remote entry points are never cached.
|
|
10
|
+
// View: https://github.com/module-federation/module-federation-examples/issues/566.
|
|
11
|
+
element.src = `${url}?t=${Date.now()}`;
|
|
12
|
+
element.type = "text/javascript";
|
|
13
|
+
element.async = true;
|
|
14
|
+
|
|
15
|
+
return element;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default plugin;
|
package/src/shared.ts
ADDED