@module-federation/sdk 0.0.0-next-20231219090402 → 0.0.0-next-20231219093556

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 (55) hide show
  1. package/CHANGELOG.md +2189 -2
  2. package/README.md +99 -0
  3. package/__tests__/decodeName.spec.ts +11 -0
  4. package/__tests__/encodeName.spec.ts +10 -0
  5. package/__tests__/generateSnapshotFromManifest.spec.ts +147 -0
  6. package/__tests__/parseEntry.spec.ts +36 -0
  7. package/__tests__/resources/constant.ts +6 -0
  8. package/__tests__/resources/getId.ts +5 -0
  9. package/__tests__/resources/manifestSnapshotMap.ts +1541 -0
  10. package/__tests__/simpleJoinRemoteEntry.spec.ts +53 -0
  11. package/dist/LICENSE +21 -0
  12. package/dist/package.json +40 -0
  13. package/jest.config.js +27 -0
  14. package/package.json +10 -11
  15. package/project.json +65 -0
  16. package/rollup.config.js +11 -0
  17. package/src/constant.ts +24 -0
  18. package/src/dom.ts +115 -0
  19. package/src/env.ts +25 -0
  20. package/src/generateSnapshotFromManifest.ts +176 -0
  21. package/src/index.ts +10 -0
  22. package/src/logger.ts +59 -0
  23. package/src/normalize-webpack-path.ts +33 -0
  24. package/src/types/common.ts +18 -0
  25. package/src/types/index.ts +4 -0
  26. package/src/types/manifest.ts +44 -0
  27. package/src/types/snapshot.ts +87 -0
  28. package/src/types/stats.ts +101 -0
  29. package/src/utils.ts +213 -0
  30. package/tsconfig.json +29 -0
  31. package/tsconfig.lib.json +10 -0
  32. package/tsconfig.spec.json +14 -0
  33. package/index.cjs.default.js +0 -1
  34. package/index.cjs.mjs +0 -2
  35. package/normalize-webpack-path.cjs.default.js +0 -1
  36. package/normalize-webpack-path.cjs.mjs +0 -2
  37. /package/{index.cjs.d.ts → dist/index.cjs.d.ts} +0 -0
  38. /package/{index.cjs.js → dist/index.cjs.js} +0 -0
  39. /package/{index.esm.js → dist/index.esm.js} +0 -0
  40. /package/{normalize-webpack-path.cjs.d.ts → dist/normalize-webpack-path.cjs.d.ts} +0 -0
  41. /package/{normalize-webpack-path.cjs.js → dist/normalize-webpack-path.cjs.js} +0 -0
  42. /package/{normalize-webpack-path.esm.js → dist/normalize-webpack-path.esm.js} +0 -0
  43. /package/{src → dist/src}/constant.d.ts +0 -0
  44. /package/{src → dist/src}/dom.d.ts +0 -0
  45. /package/{src → dist/src}/env.d.ts +0 -0
  46. /package/{src → dist/src}/generateSnapshotFromManifest.d.ts +0 -0
  47. /package/{src → dist/src}/index.d.ts +0 -0
  48. /package/{src → dist/src}/logger.d.ts +0 -0
  49. /package/{src → dist/src}/normalize-webpack-path.d.ts +0 -0
  50. /package/{src → dist/src}/types/common.d.ts +0 -0
  51. /package/{src → dist/src}/types/index.d.ts +0 -0
  52. /package/{src → dist/src}/types/manifest.d.ts +0 -0
  53. /package/{src → dist/src}/types/snapshot.d.ts +0 -0
  54. /package/{src → dist/src}/types/stats.d.ts +0 -0
  55. /package/{src → dist/src}/utils.d.ts +0 -0
@@ -0,0 +1,33 @@
1
+ import type webpack from 'webpack';
2
+ import path from 'path';
3
+ export function getWebpackPath(compiler: webpack.Compiler): string {
4
+ try {
5
+ // @ts-ignore just throw err
6
+ compiler.webpack();
7
+ return '';
8
+ } catch (err) {
9
+ const trace = (err as Error).stack?.split('\n') || [];
10
+ const webpackErrLocation =
11
+ trace.find((item) => item.includes('at webpack')) || '';
12
+ const webpackLocationWithDetail = webpackErrLocation
13
+ .replace(/[^\(\)]+/, '')
14
+ .slice(1, -1);
15
+ const webpackPath = webpackLocationWithDetail.split(':').slice(0, -2)[0];
16
+ return require.resolve('webpack', { paths: [webpackPath] });
17
+ }
18
+ }
19
+
20
+ export const normalizeWebpackPath = (fullPath: string): string => {
21
+ if (fullPath === 'webpack') {
22
+ return process.env['FEDERATION_WEBPACK_PATH'] || fullPath;
23
+ }
24
+
25
+ if (process.env['FEDERATION_WEBPACK_PATH']) {
26
+ return path.resolve(
27
+ process.env['FEDERATION_WEBPACK_PATH'],
28
+ fullPath.replace('webpack', '../../'),
29
+ );
30
+ }
31
+
32
+ return fullPath;
33
+ };
@@ -0,0 +1,18 @@
1
+ export interface RemoteWithEntry {
2
+ name: string;
3
+ entry: string;
4
+ }
5
+
6
+ export interface RemoteWithVersion {
7
+ name: string;
8
+ version: string;
9
+ }
10
+
11
+ export type RemoteEntryInfo = RemoteWithEntry | RemoteWithVersion;
12
+ export type Module = any;
13
+
14
+ declare namespace NodeJS {
15
+ interface ProcessEnv {
16
+ FEDERATION_WEBPACK_PATH?: string;
17
+ }
18
+ }
@@ -0,0 +1,4 @@
1
+ export * from './common';
2
+ export * from './manifest';
3
+ export * from './stats';
4
+ export * from './snapshot';
@@ -0,0 +1,44 @@
1
+ import {
2
+ StatsMetaData,
3
+ StatsAssets,
4
+ StatsExpose,
5
+ BasicStatsMetaData,
6
+ } from './stats';
7
+ import { RemoteWithEntry, RemoteWithVersion } from './common';
8
+
9
+ export interface ManifestShared {
10
+ id: string;
11
+ name: string;
12
+ version: string;
13
+ singleton: boolean;
14
+ requiredVersion: string;
15
+ hash: string;
16
+ assets: StatsAssets;
17
+ }
18
+
19
+ export interface ManifestRemoteCommonInfo {
20
+ federationContainerName: string;
21
+ moduleName: string;
22
+ alias: string;
23
+ }
24
+
25
+ export type ManifestRemote<T = ManifestRemoteCommonInfo> =
26
+ | (Omit<RemoteWithEntry, 'name'> & T)
27
+ | (Omit<RemoteWithVersion, 'name'> & T);
28
+
29
+ export type ManifestExpose = Pick<
30
+ StatsExpose,
31
+ 'assets' | 'id' | 'name' | 'path'
32
+ >;
33
+
34
+ export interface Manifest<
35
+ T = BasicStatsMetaData,
36
+ K = ManifestRemoteCommonInfo,
37
+ > {
38
+ id: string;
39
+ name: string;
40
+ metaData: StatsMetaData<T>;
41
+ shared: ManifestShared[];
42
+ remotes: ManifestRemote<K>[];
43
+ exposes: ManifestExpose[];
44
+ }
@@ -0,0 +1,87 @@
1
+ import { RemoteEntryType, StatsAssets } from './stats';
2
+
3
+ interface BasicModuleInfo {
4
+ dev?: {
5
+ version?: string;
6
+ remotes?: { [nameWithType: string]: string };
7
+ };
8
+ version: string;
9
+ buildVersion: string;
10
+ remoteTypes: string;
11
+ remotesInfo: Record<string, { matchedVersion: string }>;
12
+ shared: Array<{
13
+ sharedName: string;
14
+ assets: StatsAssets;
15
+ }>;
16
+ }
17
+
18
+ export interface BasicProviderModuleInfo extends BasicModuleInfo {
19
+ remoteEntry: string;
20
+ remoteEntryType: RemoteEntryType;
21
+ remoteManifest?: string;
22
+ globalName: string;
23
+ modules: Array<{
24
+ moduleName: string;
25
+ modulePath?: string;
26
+ assets: StatsAssets;
27
+ }>;
28
+ prefetchEntry?: string;
29
+ prefetchEntryType?: RemoteEntryType;
30
+ }
31
+
32
+ interface BasicProviderModuleInfoWithPublicPath
33
+ extends BasicProviderModuleInfo {
34
+ publicPath: string;
35
+ }
36
+
37
+ interface BasicProviderModuleInfoWithGetPublicPath
38
+ extends BasicProviderModuleInfo {
39
+ getPublicPath: string;
40
+ }
41
+
42
+ export interface ManifestProvider {
43
+ remoteEntry: string;
44
+ version?: string;
45
+ }
46
+
47
+ export interface PureEntryProvider extends ManifestProvider {
48
+ globalName: string;
49
+ }
50
+
51
+ interface BasicConsumerModuleInfo extends BasicModuleInfo {
52
+ consumerList: Array<string>;
53
+ }
54
+
55
+ export interface ConsumerModuleInfoWithPublicPath
56
+ extends BasicConsumerModuleInfo,
57
+ BasicProviderModuleInfo {
58
+ publicPath: string;
59
+ }
60
+
61
+ interface ConsumerModuleInfoWithGetPublicPath
62
+ extends BasicConsumerModuleInfo,
63
+ BasicProviderModuleInfo {
64
+ getPublicPath: string;
65
+ }
66
+
67
+ export type PureConsumerModuleInfo = Omit<
68
+ BasicConsumerModuleInfo,
69
+ 'remoteTypes'
70
+ >;
71
+
72
+ export type ConsumerModuleInfo =
73
+ | ConsumerModuleInfoWithPublicPath
74
+ | ConsumerModuleInfoWithGetPublicPath;
75
+
76
+ export type ProviderModuleInfo =
77
+ | BasicProviderModuleInfoWithPublicPath
78
+ | BasicProviderModuleInfoWithGetPublicPath;
79
+
80
+ export type ModuleInfo =
81
+ | ConsumerModuleInfo
82
+ | PureConsumerModuleInfo
83
+ | ProviderModuleInfo;
84
+
85
+ export type GlobalModuleInfo = {
86
+ [key: string]: ModuleInfo | ManifestProvider | PureEntryProvider | undefined;
87
+ };
@@ -0,0 +1,101 @@
1
+ import type { RemoteWithEntry, RemoteWithVersion } from './common';
2
+
3
+ export type RemoteEntryType = 'esm' | 'global';
4
+
5
+ interface ResourceInfo {
6
+ path: string;
7
+ name: string;
8
+ type: RemoteEntryType;
9
+ }
10
+
11
+ export interface StatsBuildInfo {
12
+ buildVersion: string;
13
+ buildName: string;
14
+ }
15
+
16
+ export interface BasicStatsMetaData {
17
+ name: string;
18
+ globalName: string;
19
+ buildInfo: StatsBuildInfo;
20
+ remoteEntry: ResourceInfo;
21
+ prefetchEntry: ResourceInfo;
22
+ types: Omit<ResourceInfo, 'type'>;
23
+ }
24
+
25
+ type StatsMetaDataWithGetPublicPath<T = BasicStatsMetaData> = T & {
26
+ getPublicPath: string;
27
+ };
28
+
29
+ type StatsMetaDataWithPublicPath<T = BasicStatsMetaData> = T & {
30
+ publicPath: string;
31
+ };
32
+
33
+ export type StatsMetaData<T = BasicStatsMetaData> =
34
+ | StatsMetaDataWithGetPublicPath<T>
35
+ | StatsMetaDataWithPublicPath<T>;
36
+
37
+ export interface StatsAssets {
38
+ js: StatsAssetsInfo;
39
+ css: StatsAssetsInfo;
40
+ }
41
+
42
+ interface StatsAssetsInfo {
43
+ sync: string[];
44
+ async: string[];
45
+ }
46
+
47
+ export interface StatsShared {
48
+ id: string;
49
+ name: string;
50
+ version: string;
51
+ singleton: boolean;
52
+ requiredVersion: string;
53
+ hash: string;
54
+ assets: StatsAssets;
55
+ deps: string[];
56
+ usedIn: string[];
57
+ }
58
+ // extends Omit<RemoteEntryInfo, 'name'>
59
+ export interface StatsRemoteVal {
60
+ moduleName: string;
61
+ federationContainerName: string;
62
+ consumingFederationContainerName: string;
63
+ alias: string;
64
+ usedIn: string[];
65
+ }
66
+
67
+ export type StatsRemoteWithEntry<T = StatsRemoteVal> = T &
68
+ Omit<RemoteWithEntry, 'name'>;
69
+ export type StatsRemoteWithVersion<T = StatsRemoteVal> = T &
70
+ Omit<RemoteWithVersion, 'name'>;
71
+
72
+ export type StatsRemote<T = StatsRemoteVal> =
73
+ | StatsRemoteWithEntry<T>
74
+ | StatsRemoteWithVersion<T>;
75
+
76
+ export interface StatsModuleInfo {
77
+ name: string;
78
+ file: string;
79
+ }
80
+
81
+ export interface ManifestModuleInfos {
82
+ [exposeModuleName: string]: StatsModuleInfo;
83
+ }
84
+
85
+ export interface StatsExpose {
86
+ id: string;
87
+ name: string;
88
+ path?: string; // 对线上已有数据兼容过渡至 2023-05-26
89
+ file: string;
90
+ requires: string[];
91
+ assets: StatsAssets;
92
+ }
93
+
94
+ export interface Stats<T = BasicStatsMetaData, K = StatsRemoteVal> {
95
+ id: string;
96
+ name: string;
97
+ metaData: StatsMetaData<T>;
98
+ shared: StatsShared[];
99
+ remotes: StatsRemote<K>[];
100
+ exposes: StatsExpose[];
101
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,213 @@
1
+ import { RemoteEntryInfo, ModuleInfo } from './types';
2
+ import {
3
+ NameTransformMap,
4
+ NameTransformSymbol,
5
+ EncodedNameTransformMap,
6
+ SEPARATOR,
7
+ MANIFEST_EXT,
8
+ } from './constant';
9
+ import { Logger } from './logger';
10
+ import { getProcessEnv } from './env';
11
+
12
+ const LOG_CATEGORY = '[ Federation Runtime ]';
13
+
14
+ // entry: name:version version : 1.0.0 | ^1.2.3
15
+ // entry: name:entry entry: https://localhost:9000/federation-manifest.json
16
+ const parseEntry = (str: string, devVerOrUrl?: string): RemoteEntryInfo => {
17
+ const strSplit = str.split(SEPARATOR);
18
+ const devVersionOrUrl =
19
+ getProcessEnv()['NODE_ENV'] === 'development' && devVerOrUrl;
20
+ const defaultVersion = '*';
21
+ const isEntry = (s: string) =>
22
+ s.startsWith('http') || s.endsWith(MANIFEST_EXT);
23
+
24
+ // Check if the string starts with a type
25
+ if (strSplit.length >= 2) {
26
+ const [name, ...versionOrEntryArr] = strSplit;
27
+ const versionOrEntry = devVersionOrUrl || versionOrEntryArr.join(SEPARATOR);
28
+ if (isEntry(versionOrEntry)) {
29
+ return {
30
+ name,
31
+ entry: versionOrEntry,
32
+ };
33
+ } else {
34
+ // Apply version rule
35
+ // devVersionOrUrl => inputVersion => defaultVersion
36
+ return {
37
+ name,
38
+ version: versionOrEntry || defaultVersion,
39
+ };
40
+ }
41
+ } else if (strSplit.length === 1) {
42
+ const [name] = strSplit;
43
+ if (devVersionOrUrl && isEntry(devVersionOrUrl)) {
44
+ return {
45
+ name,
46
+ entry: devVersionOrUrl,
47
+ };
48
+ }
49
+ return {
50
+ name,
51
+ version: devVersionOrUrl || defaultVersion,
52
+ };
53
+ } else {
54
+ throw `Invalid entry value: ${str}`;
55
+ }
56
+ };
57
+
58
+ declare global {
59
+ // eslint-disable-next-line no-var
60
+ var FEDERATION_DEBUG: string | undefined;
61
+ }
62
+
63
+ const logger = new Logger();
64
+
65
+ const composeKeyWithSeparator = /* @__PURE__ */ function (
66
+ ...args: (string | undefined)[]
67
+ ): string {
68
+ if (!args.length) {
69
+ return '';
70
+ }
71
+
72
+ return args.reduce((sum, cur) => {
73
+ if (!cur) {
74
+ return sum;
75
+ }
76
+ if (!sum) {
77
+ return cur;
78
+ }
79
+
80
+ return `${sum}${SEPARATOR}${cur}`;
81
+ }, '') as string;
82
+ };
83
+
84
+ const encodeName = /* @__PURE__ */ function (
85
+ name: string,
86
+ prefix = '',
87
+ withExt = false,
88
+ ): string {
89
+ try {
90
+ const ext = withExt ? '.js' : '';
91
+ return `${prefix}${name
92
+ .replace(
93
+ new RegExp(`${NameTransformSymbol.AT}`, 'g'),
94
+ NameTransformMap[NameTransformSymbol.AT],
95
+ )
96
+ .replace(
97
+ new RegExp(`${NameTransformSymbol.HYPHEN}`, 'g'),
98
+ NameTransformMap[NameTransformSymbol.HYPHEN],
99
+ )
100
+ .replace(
101
+ new RegExp(`${NameTransformSymbol.SLASH}`, 'g'),
102
+ NameTransformMap[NameTransformSymbol.SLASH],
103
+ )}${ext}`;
104
+ } catch (err) {
105
+ throw err;
106
+ }
107
+ };
108
+
109
+ const decodeName = /* @__PURE__ */ function (
110
+ name: string,
111
+ prefix?: string,
112
+ withExt?: boolean,
113
+ ): string {
114
+ try {
115
+ let decodedName = name;
116
+ if (prefix) {
117
+ decodedName = decodedName.replace(new RegExp(prefix, 'g'), '');
118
+ }
119
+ decodedName = decodedName
120
+ .replace(
121
+ new RegExp(`${NameTransformMap[NameTransformSymbol.AT]}`, 'g'),
122
+ EncodedNameTransformMap[NameTransformMap[NameTransformSymbol.AT]],
123
+ )
124
+ .replace(
125
+ new RegExp(`${NameTransformMap[NameTransformSymbol.SLASH]}`, 'g'),
126
+ EncodedNameTransformMap[NameTransformMap[NameTransformSymbol.SLASH]],
127
+ )
128
+ .replace(
129
+ new RegExp(`${NameTransformMap[NameTransformSymbol.HYPHEN]}`, 'g'),
130
+ EncodedNameTransformMap[NameTransformMap[NameTransformSymbol.HYPHEN]],
131
+ );
132
+ if (withExt) {
133
+ decodedName = decodedName.replace('.js', '');
134
+ }
135
+ return decodedName;
136
+ } catch (err) {
137
+ throw err;
138
+ }
139
+ };
140
+
141
+ const generateExposeFilename = /* @__PURE__ */ (
142
+ exposeName: string,
143
+ withExt: boolean,
144
+ ): string => {
145
+ if (!exposeName) {
146
+ return '';
147
+ }
148
+
149
+ let expose = exposeName;
150
+ if (expose === '.') {
151
+ expose = 'default_export';
152
+ }
153
+ if (expose.startsWith('./')) {
154
+ expose = expose.replace('./', '');
155
+ }
156
+
157
+ return encodeName(expose, '__federation_expose_', withExt);
158
+ };
159
+
160
+ const generateShareFilename = /* @__PURE__ */ (
161
+ pkgName: string,
162
+ withExt: boolean,
163
+ ): string => {
164
+ if (!pkgName) {
165
+ return '';
166
+ }
167
+ return encodeName(pkgName, '__federation_shared_', withExt);
168
+ };
169
+
170
+ const getResourceUrl = (module: ModuleInfo, sourceUrl: string): string => {
171
+ if ('getPublicPath' in module) {
172
+ const publicPath = new Function(module.getPublicPath)();
173
+ return `${publicPath}${sourceUrl}`;
174
+ } else if ('publicPath' in module) {
175
+ return `${module.publicPath}${sourceUrl}`;
176
+ } else {
177
+ console.warn(
178
+ 'Can not get resource url, if in debug mode, please ignore',
179
+ module,
180
+ sourceUrl,
181
+ );
182
+ return '';
183
+ }
184
+ };
185
+
186
+ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
187
+ const assert = (condition: any, msg: string): asserts condition => {
188
+ if (!condition) {
189
+ error(msg);
190
+ }
191
+ };
192
+
193
+ const error = (msg: string | Error | unknown): never => {
194
+ throw new Error(`${LOG_CATEGORY}: ${msg}`);
195
+ };
196
+
197
+ const warn = (msg: Parameters<typeof console.warn>[0]): void => {
198
+ console.warn(`${LOG_CATEGORY}: ${msg}`);
199
+ };
200
+
201
+ export {
202
+ parseEntry,
203
+ logger,
204
+ decodeName,
205
+ encodeName,
206
+ composeKeyWithSeparator,
207
+ generateExposeFilename,
208
+ generateShareFilename,
209
+ getResourceUrl,
210
+ assert,
211
+ error,
212
+ warn,
213
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "module": "commonjs",
5
+ "forceConsistentCasingInFileNames": true,
6
+ "strict": true,
7
+ "noImplicitOverride": true,
8
+ "noPropertyAccessFromIndexSignature": true,
9
+ "noImplicitReturns": true,
10
+ "noFallthroughCasesInSwitch": true,
11
+ "moduleResolution": "node",
12
+ "resolveJsonModule": true,
13
+ "esModuleInterop": true,
14
+ "skipLibCheck": true,
15
+ "skipDefaultLibCheck": true,
16
+ "declaration": true
17
+ },
18
+ "files": [],
19
+ "include": [],
20
+ "exclude": ["node_modules"],
21
+ "references": [
22
+ {
23
+ "path": "./tsconfig.lib.json"
24
+ },
25
+ {
26
+ "path": "./tsconfig.spec.json"
27
+ }
28
+ ]
29
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "../../dist/out-tsc",
5
+ "declaration": true,
6
+ "types": ["node"]
7
+ },
8
+ "include": ["src/**/*.ts"],
9
+ "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
10
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "../../dist/out-tsc",
5
+ "module": "commonjs",
6
+ "types": ["jest", "node"]
7
+ },
8
+ "include": [
9
+ "jest.config.ts",
10
+ "src/**/*.test.ts",
11
+ "src/**/*.spec.ts",
12
+ "src/**/*.d.ts"
13
+ ]
14
+ }
@@ -1 +0,0 @@
1
- exports._default = require('./index.cjs.js').default;
package/index.cjs.mjs DELETED
@@ -1,2 +0,0 @@
1
- export * from './index.cjs.js';
2
- export { _default as default } from './index.cjs.default.js';
@@ -1 +0,0 @@
1
- exports._default = require('./normalize-webpack-path.cjs.js').default;
@@ -1,2 +0,0 @@
1
- export * from './normalize-webpack-path.cjs.js';
2
- export { _default as default } from './normalize-webpack-path.cjs.default.js';
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes