@tramvai/cli 5.46.1 → 5.47.1

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 (49) hide show
  1. package/lib/library/babel/index.d.ts +1 -1
  2. package/lib/library/babel/index.d.ts.map +1 -1
  3. package/lib/library/babel/index.js +5 -23
  4. package/lib/library/babel/index.js.map +1 -1
  5. package/lib/library/swc/index.d.ts.map +1 -1
  6. package/lib/library/swc/index.js +6 -20
  7. package/lib/library/swc/index.js.map +1 -1
  8. package/lib/library/webpack/application/client/common.d.ts.map +1 -1
  9. package/lib/library/webpack/application/client/common.js +6 -1
  10. package/lib/library/webpack/application/client/common.js.map +1 -1
  11. package/lib/library/webpack/plugins/PolyfillCondition.d.ts +8 -0
  12. package/lib/library/webpack/plugins/PolyfillCondition.d.ts.map +1 -0
  13. package/lib/library/webpack/plugins/PolyfillCondition.js +46 -0
  14. package/lib/library/webpack/plugins/PolyfillCondition.js.map +1 -0
  15. package/lib/library/webpack/utils/polyfills/const.d.ts +3 -0
  16. package/lib/library/webpack/utils/polyfills/const.d.ts.map +1 -0
  17. package/lib/library/webpack/utils/polyfills/const.js +49 -0
  18. package/lib/library/webpack/utils/polyfills/const.js.map +1 -0
  19. package/lib/library/webpack/utils/polyfills/polyfillCondition.d.ts +8 -0
  20. package/lib/library/webpack/utils/polyfills/polyfillCondition.d.ts.map +1 -0
  21. package/lib/library/webpack/utils/polyfills/polyfillCondition.js +51 -0
  22. package/lib/library/webpack/utils/polyfills/polyfillCondition.js.map +1 -0
  23. package/lib/library/webpack/utils/polyfills/specToFeature.d.ts +7 -0
  24. package/lib/library/webpack/utils/polyfills/specToFeature.d.ts.map +1 -0
  25. package/lib/library/webpack/utils/polyfills/specToFeature.js +207 -0
  26. package/lib/library/webpack/utils/polyfills/specToFeature.js.map +1 -0
  27. package/lib/library/webpack/utils/transpiler.d.ts +2 -0
  28. package/lib/library/webpack/utils/transpiler.d.ts.map +1 -1
  29. package/lib/library/webpack/utils/transpiler.js +25 -3
  30. package/lib/library/webpack/utils/transpiler.js.map +1 -1
  31. package/lib/schema/autogeneratedSchema.json +3 -6
  32. package/lib/typings/configEntry/cli.d.ts +1 -2
  33. package/lib/typings/configEntry/cli.d.ts.map +1 -1
  34. package/package.json +5 -3
  35. package/schema.json +3 -6
  36. package/src/library/babel/index.ts +5 -28
  37. package/src/library/babel/plugins/lazy-component/lazy-component.spec.ts +2 -1
  38. package/src/library/babel/plugins/lazy-component/legacy-universal-replace.spec.ts +2 -1
  39. package/src/library/swc/index.ts +7 -26
  40. package/src/library/webpack/application/client/common.ts +7 -1
  41. package/src/library/webpack/plugins/PolyfillCondition.ts +62 -0
  42. package/src/library/webpack/utils/polyfills/__integration__/__snapshots__/condition.test.ts.snap +1348 -0
  43. package/src/library/webpack/utils/polyfills/__integration__/condition.test.ts +128 -0
  44. package/src/library/webpack/utils/polyfills/const.ts +46 -0
  45. package/src/library/webpack/utils/polyfills/polyfillCondition.ts +63 -0
  46. package/src/library/webpack/utils/polyfills/specToFeature.ts +243 -0
  47. package/src/library/webpack/utils/transpiler.ts +32 -2
  48. package/src/schema/autogeneratedSchema.json +3 -6
  49. package/src/typings/configEntry/cli.ts +1 -2
@@ -0,0 +1,128 @@
1
+ import fs from 'node:fs';
2
+ import { fastify } from 'fastify';
3
+ import { getPort } from '@tramvai/internal-test-utils/utils/getPort';
4
+ import { initPlaywright } from '@tramvai/test-pw';
5
+ import { getMaxBrowserVersionsByFeatures, getPolyfillCondition } from '../polyfillCondition';
6
+ import { getSpecToFeatureDict } from '../specToFeature';
7
+
8
+ const polyfillEntryPath = require.resolve('@tinkoff/pack-polyfills');
9
+ const polyfillsEntryContent = fs.readFileSync(polyfillEntryPath, 'utf-8');
10
+
11
+ // import 'core-js/modules/es.array.at'; => 'es.array.at'
12
+ const usedFeatures = [...polyfillsEntryContent.matchAll(/core-js\/modules\/(.*)'/gm)].map(
13
+ (item) => item[1]
14
+ );
15
+
16
+ jest.setTimeout(3 * 60 * 1000);
17
+
18
+ describe('polyfills', () => {
19
+ let server;
20
+ let port;
21
+ let testUrl;
22
+
23
+ beforeAll(async () => {
24
+ server = fastify();
25
+ port = await getPort();
26
+ testUrl = `http://localhost:${port}`;
27
+
28
+ server.get('*', () => '<html></html>');
29
+ server.listen({ port });
30
+ });
31
+
32
+ afterAll(() => {
33
+ server.close();
34
+ });
35
+
36
+ describe('spec to feature generator', () => {
37
+ it('should generate feature: expression dictionary', () => {
38
+ const specToFeatureDict = getSpecToFeatureDict();
39
+
40
+ expect(specToFeatureDict).toMatchSnapshot('featureDict');
41
+ });
42
+
43
+ it('all feature expresssion should be valid', async () => {
44
+ const specToFeatureDict = getSpecToFeatureDict();
45
+ const { getPageWrapper, browser } = await initPlaywright(testUrl);
46
+
47
+ const { page } = await getPageWrapper(testUrl);
48
+
49
+ const specExpressionsResult = await page.evaluate(
50
+ ([specDict]) => {
51
+ const evalResult: Record<string, string> = {};
52
+
53
+ for (const featureName in specDict) {
54
+ const expression = specDict[featureName];
55
+ try {
56
+ // eslint-disable-next-line no-eval
57
+ const result = eval(`Boolean(${expression})`);
58
+ evalResult[featureName] = result;
59
+ } catch (err) {
60
+ evalResult[featureName] = '';
61
+ }
62
+ }
63
+
64
+ return evalResult;
65
+ },
66
+ [specToFeatureDict]
67
+ );
68
+
69
+ expect(specExpressionsResult).toMatchSnapshot('expressionsResult');
70
+
71
+ const failedSpecExpressions = [];
72
+
73
+ // Неподдерживаемые в браузерах спецификации
74
+ const ignoredSpecs = [
75
+ 'es.async-disposable-stack',
76
+ 'es.disposable-stack',
77
+ 'es.suppressed-error',
78
+ 'es.web.immediate',
79
+ 'web.immediate',
80
+ 'es.observable',
81
+ ];
82
+
83
+ // Проверяем что не прошли проверку только esnext фичи и несколько исключений
84
+ for (const specName in specExpressionsResult) {
85
+ const specResult = specExpressionsResult[specName];
86
+
87
+ if (!specResult && !specName.includes('esnext') && !ignoredSpecs.includes(specName)) {
88
+ failedSpecExpressions.push(`${specName} - ${specToFeatureDict[specName]}`);
89
+ }
90
+ }
91
+
92
+ expect(failedSpecExpressions.length).toBe(0);
93
+
94
+ await browser.close();
95
+ });
96
+ });
97
+
98
+ describe('polyfill condition', () => {
99
+ it('should generate max browser versions dict', () => {
100
+ const browserVersions = getMaxBrowserVersionsByFeatures(usedFeatures);
101
+
102
+ expect(browserVersions).toMatchSnapshot('browserVersions');
103
+ });
104
+
105
+ it('should generate valid polyfill condition', async () => {
106
+ const browserVersions = getMaxBrowserVersionsByFeatures(usedFeatures);
107
+ const polyfillCondition = getPolyfillCondition(browserVersions);
108
+
109
+ expect(polyfillCondition).toMatchSnapshot('polyfillCondition');
110
+
111
+ const { getPageWrapper, browser } = await initPlaywright(testUrl);
112
+
113
+ const { page } = await getPageWrapper(testUrl);
114
+
115
+ const polyfillConditionResult = await page.evaluate(
116
+ ([expression]) => {
117
+ // eslint-disable-next-line no-eval
118
+ return eval(expression);
119
+ },
120
+ [polyfillCondition]
121
+ );
122
+
123
+ expect(polyfillConditionResult).toBe(false);
124
+
125
+ browser.close();
126
+ });
127
+ });
128
+ });
@@ -0,0 +1,46 @@
1
+ // List of ignore polyfills
2
+ // they are impossible or very difficult to support check in the browser
3
+ export const ignoredPolyfills = [
4
+ 'es.json.to-string-tag',
5
+ 'es.error.to-string',
6
+ 'es.aggregate-error.cause',
7
+ 'es.iterator',
8
+ 'es.object.to-string',
9
+ 'es.array.species',
10
+ 'es.date.to-primitive',
11
+ 'es.function.has-instance',
12
+ 'es.string.at-alternative',
13
+ 'es.math.to-string-tag',
14
+ 'esnext.math.to-string-tag',
15
+ 'es.reflect.to-string-tag',
16
+ 'esnext.reflect.to-string-tag',
17
+ 'esnext.function.metadata',
18
+ 'esnext.composite-key',
19
+ 'esnext.composite-symbol',
20
+ 'web.dom-collections.for-each',
21
+ 'web.dom-collections.iterator',
22
+ 'web.dom-exception.to-string-tag',
23
+ 'web.dom-exception.stack',
24
+ 'es.array.unscopables.flat-map',
25
+ 'es.array.unscopables.flat',
26
+ 'es.array.push',
27
+ 'es.set.difference.v2',
28
+ 'es.set.intersection.v2',
29
+ 'es.set.is-disjoint-from.v2',
30
+ 'es.set.is-subset-of.v2',
31
+ 'es.set.is-superset-of.v2',
32
+ 'es.set.symmetric-difference.v2',
33
+ 'es.set.union.v2',
34
+ ];
35
+
36
+ export const browsers = [
37
+ 'chrome',
38
+ 'safari',
39
+ 'firefox',
40
+ 'opera',
41
+ 'edge',
42
+ 'chrome-android',
43
+ 'ios',
44
+ 'opera_mobile',
45
+ 'samsung',
46
+ ];
@@ -0,0 +1,63 @@
1
+ import compat from 'core-js-compat';
2
+ import { coerce, compare } from 'semver';
3
+ import { getSpecToFeatureDict } from './specToFeature';
4
+ import { ignoredPolyfills, browsers } from './const';
5
+
6
+ type BrowserVersions = Record<string, { version: string; spec: string }>;
7
+
8
+ export function getMaxBrowserVersionsByFeatures(usedFeatures: string[]) {
9
+ const { data } = compat;
10
+ const browserVersions: BrowserVersions = {};
11
+
12
+ usedFeatures.forEach((spec) => {
13
+ if (ignoredPolyfills.includes(spec)) {
14
+ return;
15
+ }
16
+
17
+ const specBrowsers = data[spec];
18
+
19
+ if (!specBrowsers) {
20
+ return;
21
+ }
22
+
23
+ browsers.forEach((browserName) => {
24
+ const maxBrowserVersion = specBrowsers[browserName];
25
+
26
+ if (
27
+ maxBrowserVersion &&
28
+ (!browserVersions[browserName] ||
29
+ compare(coerce(browserVersions[browserName].version), coerce(maxBrowserVersion)) === -1)
30
+ ) {
31
+ browserVersions[browserName] = { version: maxBrowserVersion, spec };
32
+ }
33
+ });
34
+ });
35
+
36
+ return browserVersions;
37
+ }
38
+
39
+ export function getPolyfillCondition(browserVersions: BrowserVersions) {
40
+ const supportConditions = new Set();
41
+
42
+ Object.values(browserVersions).forEach(({ spec }) =>
43
+ supportConditions.add(`!(${getSpecToFeature(spec)})`)
44
+ );
45
+
46
+ const polyfillCondition = [...supportConditions].join(' || ');
47
+
48
+ return polyfillCondition;
49
+ }
50
+
51
+ /**
52
+ * Converting the name of the specification into an expression for checking support in runtime
53
+ * es.string.at => String.prototype.at
54
+ * es.object.assign => Object.assign
55
+ */
56
+ let specToFeatureDictCache;
57
+ function getSpecToFeature(spec) {
58
+ if (!specToFeatureDictCache) {
59
+ specToFeatureDictCache = getSpecToFeatureDict();
60
+ }
61
+
62
+ return specToFeatureDictCache[spec];
63
+ }
@@ -0,0 +1,243 @@
1
+ import path from 'node:path';
2
+ import camelCaseName from '@tinkoff/utils/string/camelCaseName';
3
+ import { ignoredPolyfills } from './const';
4
+
5
+ // built-in-definitions.js file is not listed in the package.json exports of package, so it cannot be imported
6
+ // workaround this by using require with an absolute path to file
7
+ const pathToDep = require.resolve('babel-plugin-polyfill-corejs3/package.json');
8
+ const definitions = require(path.join(path.dirname(pathToDep), '/lib/built-in-definitions.js'));
9
+
10
+ // A list of new primitives, their support in browsers was added recently
11
+ const newPrimitivies = {
12
+ 'weak-map': 'window.WeakMap',
13
+ 'weak-set': 'window.WeakSet',
14
+ 'async-disposable-stack': 'window.AsyncDisposableStack',
15
+ 'disposable-stack': 'window.DisposableStack',
16
+ 'suppressed-error': 'window.SuppressedError',
17
+ 'web.immediate': 'window.setImmediate',
18
+ observable: 'window.Observable',
19
+ };
20
+
21
+ // A list of primitives for which there are no polyfills, but they are needed as a base for methods like JSON.stringify
22
+ const missingBuiltIns = {
23
+ ...newPrimitivies,
24
+ 'typed-array': 'window.Int8Array',
25
+ 'uint8-array': 'window.Uint8Array',
26
+ string: 'window.String',
27
+ array: 'window.Array',
28
+ object: 'window.Object',
29
+ math: 'window.Math',
30
+ function: 'window.Function',
31
+ json: 'window.JSON',
32
+ };
33
+
34
+ // Exclude fetch builtin, because its treated as object.constructor
35
+ const excludedBuiltIns = ['fetch'];
36
+ const isBuiltInExcluded = (builtInName) => excludedBuiltIns.includes(builtInName);
37
+
38
+ // Exclude iterators
39
+ // we do not provide polyfills for them and their support check is much more complicated
40
+ // es.iterator, es.async-iterator, esnext.async-iterator, esnext.iterator
41
+ const isSpecExcluded = (specName) =>
42
+ /(es(next)?)?\.(async-)?iterator/.test(specName) || ignoredPolyfills.includes(specName);
43
+
44
+ const specToFeatureDict = {};
45
+ function _addFeature(specName: string, primitive: string, method: string, isInstance: boolean) {
46
+ if (specToFeatureDict[specName]) {
47
+ return;
48
+ }
49
+
50
+ let checkExpression = isInstance
51
+ ? `'${method}' in ${primitive}.prototype`
52
+ : `${primitive}.${method}`;
53
+
54
+ // For new primitives, we add a check for the existence of the primitive itself.
55
+ // for example WeakMap && WeakMap.from
56
+ // since WeakMap itself may not be supported in the browser, WeakMap check support may also be required
57
+ const isPrimitiveNew = Boolean(Object.values(newPrimitivies).includes(primitive));
58
+ if (isPrimitiveNew) {
59
+ checkExpression = `${primitive} && ${checkExpression}`;
60
+ }
61
+
62
+ specToFeatureDict[specName] = checkExpression;
63
+ specToFeatureDict[specName.replace('es.', 'esnext.')] = checkExpression;
64
+ }
65
+
66
+ const addStaticFeature = (specName: string, primitive: string, method: string) =>
67
+ _addFeature(specName, primitive, method, false);
68
+ const addInstanceFeature = (specName: string, primitive: string, method: string) =>
69
+ _addFeature(specName, primitive, method, true);
70
+
71
+ const methods = {};
72
+ function addMethod(specName, expression) {
73
+ methods[specName] = expression;
74
+ }
75
+
76
+ const instanceMethods = new Set(['web.url.to-json']);
77
+ const globals = new Set();
78
+ function _addGlobal(globalList: string[], isInstance: boolean) {
79
+ globalList.forEach((globalSpecName) => {
80
+ globals.add(globalSpecName);
81
+
82
+ if (isInstance) {
83
+ instanceMethods.add(globalSpecName);
84
+ }
85
+ });
86
+ }
87
+ const addInstanceGlobal = (globalList: string[]) => _addGlobal(globalList, true);
88
+ const addGlobal = (globalList: string[]) => _addGlobal(globalList, false);
89
+
90
+ /**
91
+ * For conversion, a dictionary of the form `spec: feature` needs to be created
92
+ * we use a file from babel-plugin-polyfill-corejs3 for this - https://github.com/babel/babel-polyfills/blob/main/packages/babel-plugin-polyfill-corejs3/src/built-in-definitions.ts
93
+ * as a result we get dictinary like { 'es.array.at: 'Array.prototype.at', 'es.object.assign': 'Object.assign' }
94
+ */
95
+ export function getSpecToFeatureDict(): Record<string, string> {
96
+ const { BuiltIns, InstanceProperties, StaticProperties } = definitions;
97
+
98
+ // JS primitives: Number, Reflect, Set, Map...
99
+ const builtIns = Object.keys(BuiltIns).reduce((acc, builtInKey) => {
100
+ const { name: builtInName, global } = BuiltIns[builtInKey];
101
+
102
+ if (isBuiltInExcluded(builtInKey)) return acc;
103
+
104
+ addGlobal(global);
105
+
106
+ const removeBaseMethodNames = (builtInName) =>
107
+ builtInName.replace('.constructor', '').replace('.to-string', '');
108
+
109
+ acc[removeBaseMethodNames(builtInName)] = `window.${builtInKey}`;
110
+ acc[removeBaseMethodNames(builtInName).replace('es.', 'esnext.')] = `window.${builtInKey}`;
111
+
112
+ return acc;
113
+ }, {});
114
+
115
+ // Some primitives are missing, so we add them manually
116
+ Object.keys(missingBuiltIns).forEach((missingBuiltInName) => {
117
+ builtIns[`es.${missingBuiltInName}`] = `${missingBuiltIns[missingBuiltInName]}`;
118
+ builtIns[`esnext.${missingBuiltInName}`] = `${missingBuiltIns[missingBuiltInName]}`;
119
+ });
120
+
121
+ function parseSpec(spec: string) {
122
+ // es.string.push
123
+ const splitName = spec.split('.');
124
+ // es.string
125
+ const builtInName = splitName.slice(0, -1).join('.');
126
+ // String
127
+ const primitiveExpr = builtIns[builtInName];
128
+ // push
129
+ const methodName = splitName.at(-1);
130
+
131
+ return {
132
+ builtInName,
133
+ primitiveExpr,
134
+ methodName,
135
+ };
136
+ }
137
+
138
+ // Instance methods, for example [1, 2, 3].at(), 'some_string'.toLowerCase()...
139
+ Object.keys(InstanceProperties).forEach((instancePropertyName) => {
140
+ const { name: instanceSpecName, global } = InstanceProperties[instancePropertyName];
141
+ if (isSpecExcluded(instanceSpecName)) return;
142
+
143
+ const { primitiveExpr, methodName } = parseSpec(instanceSpecName);
144
+
145
+ addMethod(methodName, instancePropertyName);
146
+ addInstanceGlobal(global);
147
+
148
+ // Some instance methods have no parent
149
+ // for example Symbol.constructor is es.Symbol
150
+ if (!primitiveExpr) return;
151
+
152
+ addInstanceFeature(instanceSpecName, primitiveExpr, instancePropertyName);
153
+ });
154
+
155
+ // Static methods for example Object.assign(), RegExp.escape()...
156
+ Object.keys(StaticProperties).forEach((primitiveName) => {
157
+ const staticPrimitiveProperties = StaticProperties[primitiveName];
158
+
159
+ Object.keys(staticPrimitiveProperties).forEach((staticPropertyName) => {
160
+ const { name: staticSpecName, global } = staticPrimitiveProperties[staticPropertyName];
161
+ if (isSpecExcluded(staticSpecName)) return;
162
+
163
+ const { methodName } = parseSpec(staticSpecName);
164
+ addGlobal(global);
165
+ addMethod(methodName, staticPropertyName);
166
+
167
+ // For some reason, several static properties have names that match a builtin
168
+ // we ignore such properties since their support in browsers appeared at the same time as the builtin itself
169
+ // for example Promise and Promise.all
170
+ if (builtIns[staticSpecName]) return;
171
+
172
+ addStaticFeature(staticSpecName, primitiveName, staticPropertyName);
173
+ });
174
+ });
175
+
176
+ function isFeatureExists(specName) {
177
+ return Boolean(builtIns[specName]) || Boolean(specToFeatureDict[specName]);
178
+ }
179
+
180
+ // Each spec has a list of globals, which also need to be converted into an expression for support check
181
+ // but not all globals can have their method name determined unambiguously
182
+ [...globals].forEach((globalSpecName: string) => {
183
+ if (!isFeatureExists(globalSpecName)) {
184
+ if (isSpecExcluded(globalSpecName)) return;
185
+
186
+ const { methodName, primitiveExpr, builtInName } = parseSpec(globalSpecName);
187
+
188
+ // es.array-buffer.from
189
+ const globalNameSplit = globalSpecName.split('.');
190
+
191
+ // Trying to find a support check expression for a method from the already bypassed spec
192
+ // for example, array and typed-array have the findLastIndex method, but typed-array is listed in global
193
+ const featureMethod = methodName === 'constructor' ? 'constructor' : methods[methodName];
194
+
195
+ // We consider a method to be simple if its name does not contain a '-'
196
+ // every, filter, map can be left as it is, the method in the language is called the same way
197
+ const isMethodSimple = !/-/.test(methodName);
198
+
199
+ // Primitives don't have a method, so its length is 2
200
+ // for example es.symbol или es.string
201
+ const isPrimitive = globalNameSplit.length === 2;
202
+ if (isPrimitive) {
203
+ builtIns[globalSpecName] = `${BuiltIns[globalSpecName]}`;
204
+ return;
205
+ }
206
+
207
+ // Trying to determine the type of method from global static or instance
208
+ const globalInstancePrimitives = [
209
+ 'es.array-buffer',
210
+ 'es.typed-array',
211
+ 'es.symbol',
212
+ 'web.url-search-params',
213
+ 'esnext.weak-map',
214
+ 'esnext.weak-set',
215
+ 'uint8-array',
216
+ ];
217
+ const isInstanceMethod =
218
+ globalInstancePrimitives.includes(builtInName) || instanceMethods.has(globalSpecName);
219
+
220
+ let method: string;
221
+ if (featureMethod) {
222
+ method = featureMethod;
223
+ } else if (isMethodSimple) {
224
+ method = methodName;
225
+ } else if (primitiveExpr) {
226
+ // couldn't find a similar method in the original list and it contains '-'
227
+ // speculatively translating it to camelCase web.url.can-parse => URL.canParse
228
+ method = camelCaseName(methodName);
229
+ }
230
+
231
+ isInstanceMethod
232
+ ? addInstanceFeature(globalSpecName, primitiveExpr, method)
233
+ : addStaticFeature(globalSpecName, primitiveExpr, method);
234
+ }
235
+ });
236
+
237
+ return fixBrokenSpec({ ...builtIns, ...specToFeatureDict });
238
+ }
239
+
240
+ function fixBrokenSpec(specs: Record<string, string>) {
241
+ specs['es.string.italics'] = "'italics' in window.String.prototype";
242
+ return specs;
243
+ }
@@ -1,5 +1,7 @@
1
1
  import type Config from 'webpack-chain';
2
2
  import { sync as resolve } from 'resolve';
3
+ import envTargets from '@tinkoff/browserslist-config';
4
+ import browserslist from 'browserslist';
3
5
  import type { ConfigManager } from '../../../config/configManager';
4
6
  import { getSwcOptions } from '../../swc';
5
7
  import { babelConfigFactory } from '../../babel';
@@ -10,6 +12,7 @@ import type { CliConfigEntry, ReactCompilerOptions } from '../../../typings/conf
10
12
  export type TranspilerConfig = {
11
13
  env: Env;
12
14
  target: Target;
15
+ actualTarget: Target;
13
16
  modern: boolean;
14
17
  isServer: boolean;
15
18
  generateDataQaTag: boolean;
@@ -23,6 +26,7 @@ export type TranspilerConfig = {
23
26
  hot: boolean;
24
27
  excludesPresetEnv: string[];
25
28
  rootDir: string;
29
+ browsersListTargets: string[];
26
30
  reactCompiler: boolean | ReactCompilerOptions;
27
31
  /**
28
32
  * Enable or disable `loose` transformations:
@@ -67,19 +71,43 @@ export const getTranspilerConfig = (
67
71
  const {
68
72
  generateDataQaTag,
69
73
  alias,
74
+ target,
75
+ rootDir,
70
76
  enableFillActionNamePlugin,
71
77
  excludesPresetEnv,
72
78
  experiments: { enableFillDeclareActionNamePlugin, reactCompiler },
73
79
  } = configManager;
74
80
  const { env, modern } = configManager;
81
+ const isServer = configManager.buildType === 'server';
75
82
 
76
83
  if (alias) {
77
84
  console.warn(`"alias" option deprecated and ignored as cli now supports baseUrl and paths from the app's tsconfig.json file.
78
85
  Just check or add configuration to your tsconfig file and remove alias from tramvai.json`);
79
86
  }
80
87
 
88
+ let actualTarget = target;
89
+
90
+ if (!target) {
91
+ if (isServer) {
92
+ actualTarget = 'node';
93
+ } else if (modern) {
94
+ actualTarget = 'modern';
95
+ }
96
+ }
97
+
98
+ const browserslistConfigRaw = browserslist.findConfig(rootDir);
99
+
100
+ // Set defaults if the explicit config for browserslist was not found or the config does not contain the necessary targets
101
+ const browserslistQuery =
102
+ browserslistConfigRaw?.[actualTarget] ?? envTargets[actualTarget] ?? envTargets.defaults;
103
+
104
+ const browsersListTargets = browserslist(browserslistQuery, {
105
+ mobileToDesktop: true,
106
+ env: actualTarget,
107
+ });
108
+
81
109
  return {
82
- isServer: configManager.buildType === 'server',
110
+ isServer,
83
111
  env,
84
112
  generateDataQaTag,
85
113
  modern,
@@ -89,7 +117,9 @@ Just check or add configuration to your tsconfig file and remove alias from tram
89
117
  excludesPresetEnv,
90
118
  enableFillActionNamePlugin,
91
119
  rootDir: configManager.rootDir,
92
- target: configManager.target,
120
+ target,
121
+ actualTarget,
122
+ browsersListTargets,
93
123
  loader: true,
94
124
  modules: false,
95
125
  typescript: false,
@@ -1016,8 +1016,7 @@
1016
1016
  ]
1017
1017
  },
1018
1018
  "excludesPresetEnv": {
1019
- "title": "List of modules to exclude from `@babel/preset-env`",
1020
- "description": "Option doesn't affect build with swc loader",
1019
+ "title": "List of modules to exclude from `@babel/preset-env` and `swc-loader`",
1021
1020
  "type": "array",
1022
1021
  "items": {
1023
1022
  "type": "string"
@@ -1808,8 +1807,7 @@
1808
1807
  "additionalProperties": false
1809
1808
  },
1810
1809
  "excludesPresetEnv": {
1811
- "title": "List of modules to exclude from `@babel/preset-env`",
1812
- "description": "Option doesn't affect build with swc loader",
1810
+ "title": "List of modules to exclude from `@babel/preset-env` and `swc-loader`",
1813
1811
  "type": "array",
1814
1812
  "items": {
1815
1813
  "type": "string"
@@ -2560,8 +2558,7 @@
2560
2558
  "additionalProperties": false
2561
2559
  },
2562
2560
  "excludesPresetEnv": {
2563
- "title": "List of modules to exclude from `@babel/preset-env`",
2564
- "description": "Option doesn't affect build with swc loader",
2561
+ "title": "List of modules to exclude from `@babel/preset-env` and `swc-loader`",
2565
2562
  "type": "array",
2566
2563
  "items": {
2567
2564
  "type": "string"
@@ -142,8 +142,7 @@ export interface CliConfigEntry extends ConfigEntry {
142
142
  */
143
143
  experiments: Experiments;
144
144
  /**
145
- * @title List of modules to exclude from `@babel/preset-env`
146
- * @description Option doesn't affect build with swc loader
145
+ * @title List of modules to exclude from `@babel/preset-env` and `swc-loader`
147
146
  */
148
147
  excludesPresetEnv?: string[];
149
148
  /**