@tramvai/cli 2.111.0 → 2.112.0
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/lib/api/start/providers/application/shared.js +4 -4
- package/lib/api/start/providers/application/shared.js.map +1 -1
- package/lib/api/start/providers/child-app/shared.js +1 -4
- package/lib/api/start/providers/child-app/shared.js.map +1 -1
- package/lib/api/start/providers/module/shared.js +1 -4
- package/lib/api/start/providers/module/shared.js.map +1 -1
- package/lib/api/start-prod/providers/application.js +4 -4
- package/lib/api/start-prod/providers/application.js.map +1 -1
- package/lib/api/start-prod/providers/child-app.js +4 -4
- package/lib/api/start-prod/providers/child-app.js.map +1 -1
- package/lib/builder/webpack/tokens.d.ts +3 -0
- package/lib/commands/update/dependantLibs.d.ts +0 -1
- package/lib/commands/update/dependantLibs.js +3 -24
- package/lib/commands/update/dependantLibs.js.map +1 -1
- package/lib/commands/update/updatePackageJson.js +3 -5
- package/lib/commands/update/updatePackageJson.js.map +1 -1
- package/lib/di/tokens/config.d.ts +1 -0
- package/lib/library/typescript/index.d.ts +1 -1
- package/lib/library/webpack/application/client/common.js +7 -1
- package/lib/library/webpack/application/client/common.js.map +1 -1
- package/lib/library/webpack/child-app/client/common.js +7 -1
- package/lib/library/webpack/child-app/client/common.js.map +1 -1
- package/lib/library/webpack/child-app/moduleFederationShared.js +4 -4
- package/lib/library/webpack/plugins/ModuleFederationFixRange.d.ts +23 -0
- package/lib/library/webpack/plugins/ModuleFederationFixRange.js +125 -0
- package/lib/library/webpack/plugins/ModuleFederationFixRange.js.map +1 -0
- package/lib/schema/autogeneratedSchema.json +21 -3
- package/lib/typings/configEntry/cli.d.ts +7 -1
- package/lib/utils/detectPortSync.d.ts +13 -1
- package/lib/utils/detectPortSync.js +12 -2
- package/lib/utils/detectPortSync.js.map +1 -1
- package/lib/utils/tramvaiVersions.d.ts +3 -0
- package/lib/utils/tramvaiVersions.js +30 -0
- package/lib/utils/tramvaiVersions.js.map +1 -0
- package/package.json +6 -6
- package/schema.json +21 -3
- package/src/api/start/__integration__/start.test.ts +22 -3
- package/src/api/start/providers/application/shared.ts +5 -2
- package/src/api/start/providers/child-app/shared.ts +1 -1
- package/src/api/start/providers/module/shared.ts +1 -1
- package/src/api/start-prod/providers/application.ts +5 -2
- package/src/api/start-prod/providers/child-app.ts +4 -1
- package/src/commands/update/dependantLibs.ts +1 -23
- package/src/commands/update/updatePackageJson.ts +2 -5
- package/src/library/swc/__integration__/__snapshots__/swc.start.test.ts.snap +14 -14
- package/src/library/webpack/application/client/common.ts +9 -1
- package/src/library/webpack/child-app/client/common.ts +9 -1
- package/src/library/webpack/child-app/moduleFederationShared.ts +4 -4
- package/src/library/webpack/plugins/ModuleFederationFixRange.ts +174 -0
- package/src/models/config.spec.ts +4 -0
- package/src/schema/autogeneratedSchema.json +21 -3
- package/src/schema/tramvai.spec.ts +2 -0
- package/src/typings/configEntry/cli.ts +7 -1
- package/src/utils/detectPortSync.ts +18 -2
- package/src/utils/tramvaiVersions.ts +26 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import type webpack from 'webpack';
|
|
2
|
+
import type { Compiler, NormalModule } from 'webpack';
|
|
3
|
+
import { sync as resolve } from 'resolve';
|
|
4
|
+
import type packageJson from 'package-json';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
// eslint-disable-next-line no-restricted-imports
|
|
7
|
+
import { parseRange } from 'webpack/lib/util/semver';
|
|
8
|
+
import { isDependantLib, isUnifiedVersion } from '../../../utils/tramvaiVersions';
|
|
9
|
+
|
|
10
|
+
const PLUGIN_NAME = 'ModuleFederationValidateDuplicates';
|
|
11
|
+
|
|
12
|
+
type SemverRange = [number, number, number, number];
|
|
13
|
+
|
|
14
|
+
interface SharedModuleOptions {
|
|
15
|
+
shareKey: string;
|
|
16
|
+
requiredVersion?: SemverRange;
|
|
17
|
+
importResolved: string;
|
|
18
|
+
singleton?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface SharedModule extends NormalModule {
|
|
22
|
+
options?: SharedModuleOptions;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const resolvePackageVersion = (name: string, basedir: string) => {
|
|
26
|
+
try {
|
|
27
|
+
const packageJsonPath = resolve(`${name}/package.json`, {
|
|
28
|
+
basedir,
|
|
29
|
+
});
|
|
30
|
+
const packageJson: packageJson.FullMetadataOptions = require(packageJsonPath);
|
|
31
|
+
|
|
32
|
+
return packageJson.version;
|
|
33
|
+
} catch (error: any) {
|
|
34
|
+
console.warn(`ModuleFederation: could not infer version for package "${name}"`);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export interface ModuleFederationFixRangeOptions {
|
|
39
|
+
flexibleTramvaiVersions: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export class ModuleFederationFixRange implements webpack.WebpackPluginInstance {
|
|
43
|
+
private flexibleTramvaiVersions: boolean;
|
|
44
|
+
// { name: { importResolved: { number }} }
|
|
45
|
+
private sharedModules: Map<string, Map<string, Set<number>>> = new Map();
|
|
46
|
+
|
|
47
|
+
constructor({ flexibleTramvaiVersions }: ModuleFederationFixRangeOptions) {
|
|
48
|
+
this.flexibleTramvaiVersions = flexibleTramvaiVersions ?? false;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
apply(compiler: Compiler) {
|
|
52
|
+
compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (_, { normalModuleFactory }) => {
|
|
53
|
+
normalModuleFactory.hooks.factorize.intercept({
|
|
54
|
+
register: (tap) => {
|
|
55
|
+
if (tap.name === 'ConsumeSharedPlugin') {
|
|
56
|
+
const originalFn = tap.fn;
|
|
57
|
+
// eslint-disable-next-line no-param-reassign
|
|
58
|
+
tap.fn = async (...args) => {
|
|
59
|
+
const module: SharedModule | undefined = await originalFn(...args);
|
|
60
|
+
|
|
61
|
+
if (module?.options) {
|
|
62
|
+
this.fixVersionRange(module);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return module;
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return tap;
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
compiler.hooks.done.tap(PLUGIN_NAME, () => {
|
|
75
|
+
const duplicates: Array<{ name: string; paths: string[] }> = [];
|
|
76
|
+
const criticalDuplicates: Array<{ name: string; path: string }> = [];
|
|
77
|
+
|
|
78
|
+
for (const [name, shared] of this.sharedModules) {
|
|
79
|
+
if (shared.size > 1) {
|
|
80
|
+
duplicates.push({
|
|
81
|
+
name,
|
|
82
|
+
paths: [...shared.keys()],
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
for (const [path, versions] of shared) {
|
|
87
|
+
if (versions.size > 1) {
|
|
88
|
+
criticalDuplicates.push({ name, path });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// reset sharedModules info after compilation has ended
|
|
94
|
+
this.sharedModules = new Map();
|
|
95
|
+
|
|
96
|
+
if (duplicates.length) {
|
|
97
|
+
console.warn(`⚠️ ModuleFederation: Found duplicates for next shared modules:
|
|
98
|
+
${duplicates
|
|
99
|
+
.map(({ name, paths }) => {
|
|
100
|
+
return `\t${chalk.yellowBright(name)}: ${paths.join(', ')}`;
|
|
101
|
+
})
|
|
102
|
+
.join('\n')}
|
|
103
|
+
`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (criticalDuplicates.length) {
|
|
107
|
+
console.error(
|
|
108
|
+
`❗ ModuleFederation: Found duplicates for shared modules with different major versions that are resolved to the same path:
|
|
109
|
+
${criticalDuplicates
|
|
110
|
+
.map(({ name, path }) => {
|
|
111
|
+
return `\t${chalk.red(name)}: ${path}`;
|
|
112
|
+
})
|
|
113
|
+
.join('\n')}`
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
throw new Error(
|
|
117
|
+
'ModuleFederation: Different major versions have resolved to the same path for shared modules, please review errors above'
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
fixVersionRange(module: SharedModule) {
|
|
124
|
+
const {
|
|
125
|
+
options,
|
|
126
|
+
options: { shareKey: name, singleton, importResolved },
|
|
127
|
+
context,
|
|
128
|
+
} = module;
|
|
129
|
+
let { requiredVersion } = options;
|
|
130
|
+
|
|
131
|
+
// ignore singletons as the actual version won't change anything
|
|
132
|
+
// and usually it is just a react and co libraries
|
|
133
|
+
if (!requiredVersion && context && !singleton) {
|
|
134
|
+
const version = resolvePackageVersion(name, context);
|
|
135
|
+
if (version) {
|
|
136
|
+
requiredVersion = parseRange(version);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (!requiredVersion) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (requiredVersion && this.flexibleTramvaiVersions) {
|
|
145
|
+
const isTramvai = isUnifiedVersion(name) || isDependantLib(name);
|
|
146
|
+
|
|
147
|
+
if (isTramvai && requiredVersion[0] > 2) {
|
|
148
|
+
// 1 is used for `^` range modifier
|
|
149
|
+
// see https://github.com/webpack/webpack/blob/56363993156e06a1230c9759eba277a22e6b6604/lib/util/semver.js#LL235C20-L235C20
|
|
150
|
+
requiredVersion[0] = 1;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// change version in webpack module
|
|
155
|
+
options.requiredVersion = requiredVersion;
|
|
156
|
+
|
|
157
|
+
let shared = this.sharedModules.get(name);
|
|
158
|
+
|
|
159
|
+
if (!shared) {
|
|
160
|
+
shared = new Map();
|
|
161
|
+
this.sharedModules.set(name, shared);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
let versions = shared.get(importResolved);
|
|
165
|
+
|
|
166
|
+
if (!versions) {
|
|
167
|
+
versions = new Set();
|
|
168
|
+
shared.set(importResolved, versions);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// save major version of the semver array
|
|
172
|
+
versions.add(requiredVersion[1]);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -103,6 +103,7 @@ it('should populate defaults for config', () => {
|
|
|
103
103
|
"serverApiDir": "src/api",
|
|
104
104
|
"shared": {
|
|
105
105
|
"deps": [],
|
|
106
|
+
"flexibleTramvaiVersions": true,
|
|
106
107
|
},
|
|
107
108
|
"sourceMap": false,
|
|
108
109
|
"splitChunks": {
|
|
@@ -159,6 +160,7 @@ it('should populate defaults for config', () => {
|
|
|
159
160
|
"root": "packages/child-app",
|
|
160
161
|
"shared": {
|
|
161
162
|
"deps": [],
|
|
163
|
+
"flexibleTramvaiVersions": true,
|
|
162
164
|
},
|
|
163
165
|
"sourceMap": false,
|
|
164
166
|
"terser": {
|
|
@@ -336,6 +338,7 @@ it('should populate defaults for overridable options', () => {
|
|
|
336
338
|
"serverApiDir": "src/api",
|
|
337
339
|
"shared": {
|
|
338
340
|
"deps": [],
|
|
341
|
+
"flexibleTramvaiVersions": true,
|
|
339
342
|
},
|
|
340
343
|
"sourceMap": false,
|
|
341
344
|
"splitChunks": {
|
|
@@ -406,6 +409,7 @@ it('should populate defaults for overridable options', () => {
|
|
|
406
409
|
"root": "packages/child-app",
|
|
407
410
|
"shared": {
|
|
408
411
|
"deps": [],
|
|
412
|
+
"flexibleTramvaiVersions": true,
|
|
409
413
|
},
|
|
410
414
|
"sourceMap": {
|
|
411
415
|
"development": true,
|
|
@@ -1225,7 +1225,13 @@
|
|
|
1225
1225
|
"properties": {
|
|
1226
1226
|
"defaultTramvaiDependencies": {
|
|
1227
1227
|
"title": "Should default dependencies list be added to shared list",
|
|
1228
|
-
"description": "It includes the list of commonly used dependencies in the child-apps\nBy default, it is enabled in application in case of",
|
|
1228
|
+
"description": "It includes the list of commonly used dependencies in the child-apps\nBy default, it is enabled in application in case of tramvai/module-child-app is specified in package.json\nand for child-apps",
|
|
1229
|
+
"type": "boolean"
|
|
1230
|
+
},
|
|
1231
|
+
"flexibleTramvaiVersions": {
|
|
1232
|
+
"title": "add caret range specifier for tramvai dependencies",
|
|
1233
|
+
"description": "minimal versions are inferred from package.json",
|
|
1234
|
+
"default": true,
|
|
1229
1235
|
"type": "boolean"
|
|
1230
1236
|
},
|
|
1231
1237
|
"deps": {
|
|
@@ -1746,7 +1752,13 @@
|
|
|
1746
1752
|
"properties": {
|
|
1747
1753
|
"defaultTramvaiDependencies": {
|
|
1748
1754
|
"title": "Should default dependencies list be added to shared list",
|
|
1749
|
-
"description": "It includes the list of commonly used dependencies in the child-apps\nBy default, it is enabled in application in case of",
|
|
1755
|
+
"description": "It includes the list of commonly used dependencies in the child-apps\nBy default, it is enabled in application in case of tramvai/module-child-app is specified in package.json\nand for child-apps",
|
|
1756
|
+
"type": "boolean"
|
|
1757
|
+
},
|
|
1758
|
+
"flexibleTramvaiVersions": {
|
|
1759
|
+
"title": "add caret range specifier for tramvai dependencies",
|
|
1760
|
+
"description": "minimal versions are inferred from package.json",
|
|
1761
|
+
"default": true,
|
|
1750
1762
|
"type": "boolean"
|
|
1751
1763
|
},
|
|
1752
1764
|
"deps": {
|
|
@@ -2267,7 +2279,13 @@
|
|
|
2267
2279
|
"properties": {
|
|
2268
2280
|
"defaultTramvaiDependencies": {
|
|
2269
2281
|
"title": "Should default dependencies list be added to shared list",
|
|
2270
|
-
"description": "It includes the list of commonly used dependencies in the child-apps\nBy default, it is enabled in application in case of",
|
|
2282
|
+
"description": "It includes the list of commonly used dependencies in the child-apps\nBy default, it is enabled in application in case of tramvai/module-child-app is specified in package.json\nand for child-apps",
|
|
2283
|
+
"type": "boolean"
|
|
2284
|
+
},
|
|
2285
|
+
"flexibleTramvaiVersions": {
|
|
2286
|
+
"title": "add caret range specifier for tramvai dependencies",
|
|
2287
|
+
"description": "minimal versions are inferred from package.json",
|
|
2288
|
+
"default": true,
|
|
2271
2289
|
"type": "boolean"
|
|
2272
2290
|
},
|
|
2273
2291
|
"deps": {
|
|
@@ -126,6 +126,7 @@ describe('JSON schema для tramvai.json', () => {
|
|
|
126
126
|
"serverApiDir": "src/api",
|
|
127
127
|
"shared": {
|
|
128
128
|
"deps": [],
|
|
129
|
+
"flexibleTramvaiVersions": true,
|
|
129
130
|
},
|
|
130
131
|
"sourceMap": false,
|
|
131
132
|
"splitChunks": {
|
|
@@ -182,6 +183,7 @@ describe('JSON schema для tramvai.json', () => {
|
|
|
182
183
|
"root": "src/module",
|
|
183
184
|
"shared": {
|
|
184
185
|
"deps": [],
|
|
186
|
+
"flexibleTramvaiVersions": true,
|
|
185
187
|
},
|
|
186
188
|
"sourceMap": false,
|
|
187
189
|
"terser": {
|
|
@@ -287,10 +287,16 @@ export interface CliConfigEntry extends ConfigEntry {
|
|
|
287
287
|
/**
|
|
288
288
|
* @title Should default dependencies list be added to shared list
|
|
289
289
|
* @description It includes the list of commonly used dependencies in the child-apps
|
|
290
|
-
* By default, it is enabled in application in case of
|
|
290
|
+
* By default, it is enabled in application in case of tramvai/module-child-app is specified in package.json
|
|
291
291
|
* and for child-apps
|
|
292
292
|
*/
|
|
293
293
|
defaultTramvaiDependencies?: boolean;
|
|
294
|
+
/**
|
|
295
|
+
* @title add caret range specifier for tramvai dependencies
|
|
296
|
+
* @description minimal versions are inferred from package.json
|
|
297
|
+
* @default true
|
|
298
|
+
*/
|
|
299
|
+
flexibleTramvaiVersions: boolean;
|
|
294
300
|
/**
|
|
295
301
|
* @title list of the dependencies that will be shared
|
|
296
302
|
* @default []
|
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
import { execSync } from 'child_process';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
interface Payload {
|
|
4
|
+
request?: number;
|
|
5
|
+
fallback: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Try to detect port synchronously considering the fact, that if user requests
|
|
10
|
+
* a port explicitly, we should not try to detect a free one.
|
|
11
|
+
*
|
|
12
|
+
* Also, handle zero port (it means any random port) as the edge case,
|
|
13
|
+
* because we must pass a final number to the config manager.
|
|
14
|
+
*/
|
|
15
|
+
export const detectPortSync = ({ request, fallback }: Payload): number => {
|
|
16
|
+
if (request !== undefined && request !== 0) {
|
|
17
|
+
return request;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const commandResult = execSync(`npx detect-port ${request ?? fallback}`);
|
|
5
21
|
|
|
6
22
|
return parseInt(commandResult.toString('utf-8'), 10);
|
|
7
23
|
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// map of packages that is not in unified versioning
|
|
2
|
+
// but we still want to update it
|
|
3
|
+
// actual version to update will be calculated from the some of the @tramvai/module
|
|
4
|
+
export const DEPENDANT_LIBS_MAP = new Map([
|
|
5
|
+
['@tinkoff/logger', '@tramvai/module-log'],
|
|
6
|
+
['@tinkoff/dippy', '@tramvai/core'],
|
|
7
|
+
['@tinkoff/router', '@tramvai/module-router'],
|
|
8
|
+
['@tinkoff/url', '@tramvai/module-common'],
|
|
9
|
+
['@tinkoff/errors', '@tramvai/module-common'],
|
|
10
|
+
['@tinkoff/roles', '@tramvai/module-authenticate'],
|
|
11
|
+
['@tinkoff/pubsub', '@tramvai/module-common'],
|
|
12
|
+
['@tinkoff/hook-runner', '@tramvai/module-common'],
|
|
13
|
+
['@tinkoff/htmlpagebuilder', '@tramvai/module-render'],
|
|
14
|
+
['@tinkoff/browser-timings', '@tramvai/module-metrics'],
|
|
15
|
+
['@tinkoff/meta-tags-generate', '@tramvai/module-render'],
|
|
16
|
+
['@tinkoff/pack-polyfills', ''],
|
|
17
|
+
['@tinkoff/browserslist-config', '@tramvai/cli'],
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
export const isUnifiedVersion = (name: string) => {
|
|
21
|
+
return name.startsWith('@tramvai');
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const isDependantLib = (name: string) => {
|
|
25
|
+
return DEPENDANT_LIBS_MAP.has(name);
|
|
26
|
+
};
|