@tramvai/cli 5.53.81 → 5.53.111

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 (196) hide show
  1. package/README.md +1 -1
  2. package/bin/const.js +5 -0
  3. package/bin/platform.js +12 -6
  4. package/bin/spawn.js +6 -0
  5. package/lib/api/analyze/index.d.ts.map +1 -1
  6. package/lib/api/analyze/index.js +1 -13
  7. package/lib/api/analyze/index.js.map +1 -1
  8. package/lib/api/benchmark/build.d.ts +1 -6
  9. package/lib/api/benchmark/build.d.ts.map +1 -1
  10. package/lib/api/benchmark/build.js +59 -23
  11. package/lib/api/benchmark/build.js.map +1 -1
  12. package/lib/api/benchmark/const.d.ts +2 -0
  13. package/lib/api/benchmark/const.d.ts.map +1 -0
  14. package/lib/api/benchmark/const.js +5 -0
  15. package/lib/api/benchmark/const.js.map +1 -0
  16. package/lib/api/benchmark/index.d.ts +4 -6
  17. package/lib/api/benchmark/index.d.ts.map +1 -1
  18. package/lib/api/benchmark/index.js.map +1 -1
  19. package/lib/api/benchmark/start.d.ts +1 -7
  20. package/lib/api/benchmark/start.d.ts.map +1 -1
  21. package/lib/api/benchmark/start.js +56 -49
  22. package/lib/api/benchmark/start.js.map +1 -1
  23. package/lib/api/benchmark/types.d.ts +76 -12
  24. package/lib/api/benchmark/types.d.ts.map +1 -1
  25. package/lib/api/benchmark/utils/compilationUtils.d.ts +4 -0
  26. package/lib/api/benchmark/utils/compilationUtils.d.ts.map +1 -0
  27. package/lib/api/benchmark/utils/compilationUtils.js +157 -0
  28. package/lib/api/benchmark/utils/compilationUtils.js.map +1 -0
  29. package/lib/api/benchmark/utils/stats.d.ts +2 -7
  30. package/lib/api/benchmark/utils/stats.d.ts.map +1 -1
  31. package/lib/api/benchmark/utils/stats.js +36 -22
  32. package/lib/api/benchmark/utils/stats.js.map +1 -1
  33. package/lib/api/build/index.d.ts +1 -0
  34. package/lib/api/build/index.d.ts.map +1 -1
  35. package/lib/api/build/index.js.map +1 -1
  36. package/lib/api/index.js +1 -1
  37. package/lib/api/index.js.map +1 -1
  38. package/lib/api/start/index.d.ts +1 -0
  39. package/lib/api/start/index.d.ts.map +1 -1
  40. package/lib/api/start/index.js.map +1 -1
  41. package/lib/builder/webpack/analyzePlugins/rsdoctor.d.ts +5 -5
  42. package/lib/builder/webpack/analyzePlugins/rsdoctor.d.ts.map +1 -1
  43. package/lib/builder/webpack/analyzePlugins/rsdoctor.js +7 -9
  44. package/lib/builder/webpack/analyzePlugins/rsdoctor.js.map +1 -1
  45. package/lib/builder/webpack/index.d.ts.map +1 -1
  46. package/lib/builder/webpack/index.js +14 -12
  47. package/lib/builder/webpack/index.js.map +1 -1
  48. package/lib/builder/webpack/providers/build/client.d.ts.map +1 -1
  49. package/lib/builder/webpack/providers/build/client.js +3 -2
  50. package/lib/builder/webpack/providers/build/client.js.map +1 -1
  51. package/lib/builder/webpack/providers/build/server.d.ts.map +1 -1
  52. package/lib/builder/webpack/providers/build/server.js +3 -2
  53. package/lib/builder/webpack/providers/build/server.js.map +1 -1
  54. package/lib/builder/webpack/providers/shared.d.ts.map +1 -1
  55. package/lib/builder/webpack/providers/shared.js +39 -5
  56. package/lib/builder/webpack/providers/shared.js.map +1 -1
  57. package/lib/builder/webpack/providers/start/shared.d.ts.map +1 -1
  58. package/lib/builder/webpack/providers/start/shared.js +6 -2
  59. package/lib/builder/webpack/providers/start/shared.js.map +1 -1
  60. package/lib/builder/webpack/tokens.d.ts +10 -16
  61. package/lib/builder/webpack/tokens.d.ts.map +1 -1
  62. package/lib/cli/index.d.ts.map +1 -1
  63. package/lib/cli/index.js +12 -12
  64. package/lib/cli/index.js.map +1 -1
  65. package/lib/commands/analyze/command.d.ts +1 -1
  66. package/lib/commands/analyze/command.d.ts.map +1 -1
  67. package/lib/commands/benchmark/benchmark.d.ts +3 -1
  68. package/lib/commands/benchmark/benchmark.d.ts.map +1 -1
  69. package/lib/commands/benchmark/benchmark.js +130 -31
  70. package/lib/commands/benchmark/benchmark.js.map +1 -1
  71. package/lib/commands/benchmark/command.d.ts +9 -0
  72. package/lib/commands/benchmark/command.d.ts.map +1 -1
  73. package/lib/commands/benchmark/command.js +12 -0
  74. package/lib/commands/benchmark/command.js.map +1 -1
  75. package/lib/commands/build/command.d.ts.map +1 -1
  76. package/lib/commands/build/command.js +5 -0
  77. package/lib/commands/build/command.js.map +1 -1
  78. package/lib/commands/start/command.d.ts.map +1 -1
  79. package/lib/commands/start/command.js +5 -0
  80. package/lib/commands/start/command.js.map +1 -1
  81. package/lib/commands/update/checkVersionValidator.d.ts +1 -1
  82. package/lib/commands/update/checkVersionValidator.d.ts.map +1 -1
  83. package/lib/commands/update/checkVersionValidator.js +3 -2
  84. package/lib/commands/update/checkVersionValidator.js.map +1 -1
  85. package/lib/commands/update/command.d.ts +1 -1
  86. package/lib/commands/update/dependantLibs.d.ts +1 -1
  87. package/lib/commands/update/dependantLibs.d.ts.map +1 -1
  88. package/lib/commands/update/dependantLibs.js +3 -2
  89. package/lib/commands/update/dependantLibs.js.map +1 -1
  90. package/lib/commands/update/update.d.ts.map +1 -1
  91. package/lib/commands/update/update.js +6 -3
  92. package/lib/commands/update/update.js.map +1 -1
  93. package/lib/commands/update/updatePackageJson.d.ts +1 -1
  94. package/lib/commands/update/updatePackageJson.d.ts.map +1 -1
  95. package/lib/commands/update/updatePackageJson.js +7 -7
  96. package/lib/commands/update/updatePackageJson.js.map +1 -1
  97. package/lib/config/configManager.d.ts +2 -0
  98. package/lib/config/configManager.d.ts.map +1 -1
  99. package/lib/config/configManager.js +2 -0
  100. package/lib/config/configManager.js.map +1 -1
  101. package/lib/di/tokens/config.d.ts +5 -8
  102. package/lib/di/tokens/config.d.ts.map +1 -1
  103. package/lib/library/webpack/blocks/css.d.ts.map +1 -1
  104. package/lib/library/webpack/blocks/css.js +42 -15
  105. package/lib/library/webpack/blocks/css.js.map +1 -1
  106. package/lib/library/webpack/blocks/js.d.ts.map +1 -1
  107. package/lib/library/webpack/blocks/js.js +57 -11
  108. package/lib/library/webpack/blocks/js.js.map +1 -1
  109. package/lib/library/webpack/common/main.d.ts.map +1 -1
  110. package/lib/library/webpack/common/main.js +7 -0
  111. package/lib/library/webpack/common/main.js.map +1 -1
  112. package/lib/library/webpack/utils/browserslist.d.ts +4 -0
  113. package/lib/library/webpack/utils/browserslist.d.ts.map +1 -0
  114. package/lib/library/webpack/utils/browserslist.js +27 -0
  115. package/lib/library/webpack/utils/browserslist.js.map +1 -0
  116. package/lib/library/webpack/utils/rsdoctor.d.ts +2 -0
  117. package/lib/library/webpack/utils/rsdoctor.d.ts.map +1 -0
  118. package/lib/library/webpack/utils/rsdoctor.js +27 -0
  119. package/lib/library/webpack/utils/rsdoctor.js.map +1 -0
  120. package/lib/library/webpack/utils/threadLoader.d.ts.map +1 -1
  121. package/lib/library/webpack/utils/threadLoader.js +3 -3
  122. package/lib/library/webpack/utils/threadLoader.js.map +1 -1
  123. package/lib/library/webpack/utils/transpiler.d.ts.map +1 -1
  124. package/lib/library/webpack/utils/transpiler.js +3 -16
  125. package/lib/library/webpack/utils/transpiler.js.map +1 -1
  126. package/lib/schema/autogeneratedSchema.json +240 -120
  127. package/lib/typings/build/Builder.d.ts +6 -2
  128. package/lib/typings/build/Builder.d.ts.map +1 -1
  129. package/lib/typings/configEntry/cli.d.ts +9 -0
  130. package/lib/typings/configEntry/cli.d.ts.map +1 -1
  131. package/lib/utils/commands/dependencies/getLatestPackageVersion.d.ts +1 -1
  132. package/lib/utils/commands/dependencies/getLatestPackageVersion.d.ts.map +1 -1
  133. package/lib/utils/commands/dependencies/getLatestPackageVersion.js +4 -2
  134. package/lib/utils/commands/dependencies/getLatestPackageVersion.js.map +1 -1
  135. package/lib/utils/commands/dependencies/packageHasVersion.d.ts +1 -1
  136. package/lib/utils/commands/dependencies/packageHasVersion.d.ts.map +1 -1
  137. package/lib/utils/commands/dependencies/packageHasVersion.js +3 -2
  138. package/lib/utils/commands/dependencies/packageHasVersion.js.map +1 -1
  139. package/package.json +19 -18
  140. package/schema.json +240 -120
  141. package/src/api/analyze/index.ts +3 -16
  142. package/src/api/benchmark/__integration__/start.test.ts +10 -12
  143. package/src/api/benchmark/build.ts +75 -30
  144. package/src/api/benchmark/const.ts +1 -0
  145. package/src/api/benchmark/index.ts +4 -6
  146. package/src/api/benchmark/start.ts +69 -65
  147. package/src/api/benchmark/types.ts +82 -14
  148. package/src/api/benchmark/utils/compilationUtils.ts +213 -0
  149. package/src/api/benchmark/utils/stats.ts +45 -28
  150. package/src/api/build/index.ts +1 -0
  151. package/src/api/index.ts +1 -1
  152. package/src/api/start/index.ts +1 -0
  153. package/src/builder/webpack/analyzePlugins/rsdoctor.ts +11 -14
  154. package/src/builder/webpack/index.ts +16 -21
  155. package/src/builder/webpack/providers/build/client.ts +7 -2
  156. package/src/builder/webpack/providers/build/server.ts +7 -2
  157. package/src/builder/webpack/providers/shared.ts +53 -5
  158. package/src/builder/webpack/providers/start/shared.ts +7 -2
  159. package/src/cli/index.ts +3 -2
  160. package/src/commands/analyze/command.ts +1 -1
  161. package/src/commands/benchmark/benchmark.ts +168 -33
  162. package/src/commands/benchmark/command.ts +12 -0
  163. package/src/commands/build/command.ts +6 -0
  164. package/src/commands/new/templates/shared/package.json.hbs +1 -1
  165. package/src/commands/start/command.ts +6 -0
  166. package/src/commands/update/checkVersionValidator.ts +4 -2
  167. package/src/commands/update/dependantLibs.ts +3 -1
  168. package/src/commands/update/update.ts +6 -3
  169. package/src/commands/update/updatePackageJson.spec.ts +19 -3
  170. package/src/commands/update/updatePackageJson.ts +7 -2
  171. package/src/config/configManager.ts +4 -0
  172. package/src/library/webpack/blocks/css.ts +52 -16
  173. package/src/library/webpack/blocks/js.ts +61 -12
  174. package/src/library/webpack/common/main.ts +8 -0
  175. package/src/library/webpack/utils/browserslist.ts +29 -0
  176. package/src/library/webpack/utils/rsdoctor.ts +26 -0
  177. package/src/library/webpack/utils/threadLoader.ts +1 -0
  178. package/src/library/webpack/utils/transpiler.ts +3 -18
  179. package/src/models/config.spec.ts +4 -0
  180. package/src/schema/autogeneratedSchema.json +240 -120
  181. package/src/schema/tramvai.spec.ts +2 -0
  182. package/src/typings/build/Builder.ts +7 -2
  183. package/src/typings/configEntry/cli.ts +11 -0
  184. package/src/utils/commands/dependencies/getLatestPackageVersion.ts +4 -1
  185. package/src/utils/commands/dependencies/packageHasVersion.ts +7 -2
  186. package/lib/api/analyze/providers/shared.d.ts +0 -3
  187. package/lib/api/analyze/providers/shared.d.ts.map +0 -1
  188. package/lib/api/analyze/providers/shared.js +0 -23
  189. package/lib/api/analyze/providers/shared.js.map +0 -1
  190. package/lib/builder/webpack/providers/analyze/shared.d.ts +0 -3
  191. package/lib/builder/webpack/providers/analyze/shared.d.ts.map +0 -1
  192. package/lib/builder/webpack/providers/analyze/shared.js +0 -141
  193. package/lib/builder/webpack/providers/analyze/shared.js.map +0 -1
  194. package/src/api/analyze/providers/shared.ts +0 -26
  195. package/src/api/benchmark/utils/stats.spec.ts +0 -36
  196. package/src/builder/webpack/providers/analyze/shared.ts +0 -160
@@ -0,0 +1,213 @@
1
+ import fs from 'node:fs/promises';
2
+
3
+ import { CompilationStats, LoaderTransformData, MinimalLoaderData, PluginData } from '../types';
4
+
5
+ export async function getServerCompilationTimings(
6
+ benchmarkStartTime: string,
7
+ attemptStartTime: number,
8
+ attempt: number
9
+ ) {
10
+ return getCompilationTimings(benchmarkStartTime, attemptStartTime, attempt, 'server');
11
+ }
12
+
13
+ export async function getClientCompilationTimings(
14
+ benchmarkStartTime: string,
15
+ attemptStartTime: number,
16
+ attempt: number
17
+ ) {
18
+ return getCompilationTimings(benchmarkStartTime, attemptStartTime, attempt, 'client');
19
+ }
20
+
21
+ async function getCompilationTimings(
22
+ benchmarkStartTime: string,
23
+ attemptStartTime: number,
24
+ attempt: number,
25
+ type: 'client' | 'server'
26
+ ): Promise<CompilationStats> {
27
+ try {
28
+ const rsdoctorData = await getReportData(
29
+ await processReport(benchmarkStartTime, attempt, type)
30
+ );
31
+
32
+ const { summary, loader, plugin } = rsdoctorData;
33
+
34
+ const totalBuildCosts = calculateTotalCosts(summary, attemptStartTime);
35
+ const loaderBuildCosts = calculateLoadersCosts(loader);
36
+ const pluginBuildCosts = calculatePluginsCosts(plugin);
37
+
38
+ return { totalBuildCosts, loaderBuildCosts, pluginBuildCosts };
39
+ } catch (err) {
40
+ throw new Error(`Failed to get rsdoctor report!\n${err}`);
41
+ }
42
+ }
43
+
44
+ async function getReportData(reportPath: string) {
45
+ const rsdoctorRawStats = await fs.readFile(reportPath, 'utf-8');
46
+ const rsdoctorStats = JSON.parse(rsdoctorRawStats);
47
+
48
+ return rsdoctorStats.data;
49
+ }
50
+
51
+ async function processReport(
52
+ benchmarkStartTime: string,
53
+ attempt: number,
54
+ type: 'client' | 'server'
55
+ ) {
56
+ const reportBasePath = `./.rsdoctor/${benchmarkStartTime}`;
57
+ const reportPath = `${reportBasePath}/${type}-rsdoctor-data-${attempt + 1}.json`;
58
+
59
+ await fs.mkdir(reportBasePath, { recursive: true });
60
+ await fs.rename(`./.rsdoctor/${type}-rsdoctor-data.json`, reportPath);
61
+
62
+ return reportPath;
63
+ }
64
+
65
+ function mergeIntervals(intervals: [number, number][]) {
66
+ // Sort from small to large
67
+ intervals.sort((a, b) => a[0] - b[0]);
68
+ // The previous interval, the next interval, store the result
69
+ let previous;
70
+ let current;
71
+ const result: [number, number][] = [];
72
+
73
+ for (let i = 0; i < intervals.length; i++) {
74
+ current = intervals[i];
75
+ // If the first interval or the current interval does not overlap with the previous interval, add the current interval to the result
76
+ if (!previous || current[0] > previous[1]) {
77
+ // Assign the current interval to the previous interval
78
+ previous = current;
79
+ result.push(current);
80
+ } else {
81
+ // Otherwise, the two intervals overlap
82
+ // Update the end time of the previous interval
83
+ previous[1] = Math.max(previous[1], current[1]);
84
+ }
85
+ }
86
+
87
+ return result;
88
+ }
89
+
90
+ function getLoadersCosts(
91
+ filter: (loader: MinimalLoaderData) => boolean,
92
+ loaders: MinimalLoaderData[]
93
+ ) {
94
+ const match: { [pid: number | string]: [start: number, end: number][] } = {};
95
+ const others: { [pid: number | string]: [start: number, end: number][] } = {};
96
+
97
+ loaders.forEach((e) => {
98
+ if (filter(e)) {
99
+ if (!match[e.pid]) match[e.pid] = [];
100
+ match[e.pid].push([e.startAt, e.endAt]);
101
+ } else {
102
+ if (!others[e.pid]) others[e.pid] = [];
103
+ others[e.pid].push([e.startAt, e.endAt]);
104
+ }
105
+ });
106
+
107
+ let costs = 0;
108
+
109
+ const pids = Object.keys(match);
110
+
111
+ for (let i = 0; i < pids.length; i++) {
112
+ const pid = pids[i];
113
+ const _match = mergeIntervals(match[pid]);
114
+ // between in loader.startAt and loader.endAt
115
+ const _others = mergeIntervals(others[pid] || []).filter(([s, e]) =>
116
+ _match.some((el) => s >= el[0] && e <= el[1])
117
+ );
118
+
119
+ // eslint-disable-next-line no-param-reassign
120
+ const matchSum = _match.length ? _match.reduce((t, c) => (t += c[1] - c[0]), 0) : 0;
121
+ // eslint-disable-next-line no-param-reassign
122
+ const othersSum = _others.length ? _others.reduce((t, c) => (t += c[1] - c[0]), 0) : 0;
123
+
124
+ costs += matchSum - othersSum;
125
+ }
126
+
127
+ return costs;
128
+ }
129
+
130
+ function calculateTotalCosts(
131
+ summary: { costs: { name: string; cost: string }[] },
132
+ attemptStartTime: number
133
+ ) {
134
+ const { costs: buildCosts } = summary;
135
+ const buildCostsMap = buildCosts.reduce((acc, cost) => {
136
+ acc[cost.name] = cost;
137
+ return acc;
138
+ }, {});
139
+
140
+ const result: Record<string, number> = {};
141
+
142
+ for (const buildCostName in buildCostsMap) {
143
+ if (buildCostName === 'bootstrap->beforeCompile') {
144
+ // start of bootstrap is start of first build, so use attemptStarTime instead
145
+ result[buildCostName] =
146
+ buildCostsMap['beforeCompile->afterCompile'].startAt - attemptStartTime;
147
+ } else {
148
+ result[buildCostName] = buildCostsMap[buildCostName].costs;
149
+ }
150
+ }
151
+
152
+ return result;
153
+ }
154
+
155
+ function calculateLoadersCosts(loaders: { loaders: LoaderTransformData[] }[]) {
156
+ const filteredLoaders: MinimalLoaderData[] = [];
157
+ const uniqueLoaders = new Map<
158
+ string,
159
+ {
160
+ files: number;
161
+ path: string;
162
+ }
163
+ >();
164
+
165
+ loaders.forEach((data) => {
166
+ data.loaders.forEach((fl) => {
167
+ const uniqueLoader = uniqueLoaders.get(fl.loader);
168
+ if (uniqueLoader) {
169
+ uniqueLoaders.set(fl.loader, {
170
+ files: uniqueLoader.files + 1,
171
+ path: fl.path,
172
+ });
173
+ } else {
174
+ uniqueLoaders.set(fl.loader, { files: 1, path: fl.path });
175
+ }
176
+
177
+ return filteredLoaders.push({
178
+ loader: fl.loader,
179
+ startAt: fl.startAt,
180
+ endAt: fl.endAt,
181
+ pid: fl.pid,
182
+ });
183
+ });
184
+ });
185
+
186
+ const costs: Record<string, number> = {};
187
+ uniqueLoaders.forEach((_, loaderName: string) => {
188
+ costs[loaderName] = getLoadersCosts((item) => item.loader === loaderName, filteredLoaders);
189
+ });
190
+
191
+ return costs;
192
+ }
193
+
194
+ function calculatePluginsCosts(plugins: PluginData) {
195
+ const pluginCosts: Record<string, number> = {};
196
+
197
+ for (const hookName in plugins) {
198
+ const hookCalls = plugins[hookName];
199
+
200
+ hookCalls.forEach((plugin) => {
201
+ const pluginName = plugin.tapName;
202
+ const pluginCost = plugin.costs;
203
+
204
+ if (pluginCosts[pluginName]) {
205
+ pluginCosts[pluginName] += pluginCost;
206
+ } else {
207
+ pluginCosts[pluginName] = pluginCost;
208
+ }
209
+ });
210
+ }
211
+
212
+ return pluginCosts;
213
+ }
@@ -1,45 +1,62 @@
1
- import type { RunStats, Stats } from '../types';
1
+ import type { RunStats, Samples, CompilationStats } from '../types';
2
2
 
3
- export const getSamplesStats = (samples: number[]): Stats => {
4
- const n = samples.length;
3
+ function getMeanValue(samples: number[]) {
4
+ if (samples.length === 0) {
5
+ return;
6
+ }
5
7
 
6
8
  let sum = 0;
7
9
 
8
- for (let i = 0; i < n; i++) {
10
+ for (let i = 0; i < samples.length; i++) {
9
11
  sum += samples[i];
10
12
  }
11
13
 
12
- const mean = sum / n;
14
+ return sum / samples.length;
15
+ }
13
16
 
14
- sum = 0;
17
+ function getCompilationMeanStats(allStats) {
18
+ const result = {} as CompilationStats;
15
19
 
16
- for (let i = 0; i < n; i++) {
17
- sum += (samples[i] - mean) * (samples[i] - mean);
18
- }
20
+ const stats: CompilationStats = allStats[0];
19
21
 
20
- const std = Math.sqrt(sum / n);
21
- const variance = (100 * std) / mean;
22
+ for (const section in stats) {
23
+ for (const metricName in stats[section]) {
24
+ const samples = allStats.reduce((acc, item) => {
25
+ acc.push(item[section][metricName]);
26
+ return acc;
27
+ }, []);
22
28
 
23
- return {
24
- samples,
25
- mean,
26
- std,
27
- variance,
28
- };
29
- };
29
+ if (!result[section]) {
30
+ result[section] = {};
31
+ }
32
+ const meanValue = getMeanValue(samples);
33
+
34
+ // ignore values less than 10ms
35
+ if (meanValue > 10) {
36
+ result[section][metricName] = meanValue;
37
+ }
38
+ }
39
+ }
40
+
41
+ return result;
42
+ }
30
43
 
31
44
  export const getResultStats = ({
32
- clientSamples,
33
- serverSamples,
45
+ clientBuildTimeSamples,
46
+ clientCompilationTimings,
47
+ clientMaxMemoryRssSamples,
48
+ serverBuildTimeSamples,
49
+ serverCompilationTimings,
50
+ serverMaxMemoryRssSamples,
34
51
  maxMemoryRssSamples,
35
- }: {
36
- clientSamples: number[];
37
- serverSamples: number[];
38
- maxMemoryRssSamples: number[];
39
- }): RunStats => {
52
+ }: Samples): RunStats => {
40
53
  return {
41
- client: getSamplesStats(clientSamples),
42
- server: getSamplesStats(serverSamples),
43
- maxMemoryRss: getSamplesStats(maxMemoryRssSamples),
54
+ serverBuildTime: getMeanValue(serverBuildTimeSamples),
55
+ serverCompilationStats: getCompilationMeanStats(serverCompilationTimings),
56
+ clientBuildTime: getMeanValue(clientBuildTimeSamples),
57
+ clientCompilationStats: getCompilationMeanStats(clientCompilationTimings),
58
+ maxMemoryRss: getMeanValue(maxMemoryRssSamples),
59
+ clientMaxMemoryRss: getMeanValue(clientMaxMemoryRssSamples),
60
+ serverMaxMemoryRss: getMeanValue(serverMaxMemoryRssSamples),
44
61
  };
45
62
  };
@@ -21,6 +21,7 @@ export type Params = WithConfig<{
21
21
  env?: Record<string, string>;
22
22
  fileCache?: boolean;
23
23
  withBuildStats?: boolean;
24
+ benchmark?: boolean;
24
25
  withModulesStats?: boolean;
25
26
 
26
27
  // `package` target parameters
package/src/api/index.ts CHANGED
@@ -33,8 +33,8 @@ const app = createApp({
33
33
  commands: {
34
34
  start: () => import('./start'),
35
35
  build: () => import('./build'),
36
- benchmark: () => import('./benchmark'),
37
36
  analyze: () => import('./analyze'),
37
+ benchmark: () => import('./benchmark'),
38
38
  'start-prod': () => import('./start-prod'),
39
39
  },
40
40
  providers: [
@@ -27,6 +27,7 @@ export type Params = WithConfig<{
27
27
  noClientRebuild?: boolean;
28
28
  resolveSymlinks?: boolean;
29
29
  showConfig?: boolean;
30
+ benchmark?: boolean;
30
31
  withBuildStats?: boolean;
31
32
  // @todo: not working?
32
33
  env?: Record<string, string>;
@@ -1,26 +1,23 @@
1
- import type Config from 'webpack-chain';
2
- import { RsdoctorWebpackPlugin } from '@rsdoctor/webpack-plugin';
1
+ import type { RsdoctorWebpackPlugin } from '@rsdoctor/webpack-plugin';
3
2
  import { AnalyzePlugin } from '../types';
4
3
 
4
+ type options = ConstructorParameters<typeof RsdoctorWebpackPlugin<[]>>;
5
5
  export class RsdoctorAnalyzePlugin extends AnalyzePlugin {
6
6
  requireDeps = [];
7
7
 
8
- options: [RsdoctorWebpackPlugin<[]>['options']] = [
8
+ options: options = [
9
9
  {
10
- features: ['loader', 'plugins', 'resolver'],
10
+ linter: {
11
+ level: 'Ignore',
12
+ },
11
13
  },
12
14
  ];
13
15
 
14
- plugin = RsdoctorWebpackPlugin;
15
-
16
- patchConfig = (config: Config): Config => {
17
- super.patchConfigInternal(config);
18
- // https://github.com/web-infra-dev/rsdoctor/issues/717
19
- config.set('experiments', { backCompat: true });
20
-
21
- return config;
22
- };
23
-
24
16
  // rsdoctor поднимает dev server
25
17
  afterBuild = () => new Promise(() => null);
18
+
19
+ get plugin() {
20
+ // eslint-disable-next-line import/no-unresolved
21
+ return require('@rsdoctor/webpack-plugin').RsdoctorWebpackMultiplePlugin;
22
+ }
26
23
  }
@@ -27,7 +27,6 @@ import { buildClientProviders } from './providers/build/client';
27
27
  import { buildServerProviders } from './providers/build/server';
28
28
  import { CONFIG_MANAGER_TOKEN } from '../../di/tokens';
29
29
  import { buildApplicationServerProviders } from './providers/build/application/server';
30
- import { analyzeSharedProviders } from './providers/analyze/shared';
31
30
 
32
31
  const BUILDER_NAME = 'webpack';
33
32
 
@@ -53,6 +52,14 @@ export const webpackProviders: Provider[] = [
53
52
  ...(shouldBuildServer ? startServerProviders : []),
54
53
  ]);
55
54
 
55
+ const configManager = di.get(CONFIG_MANAGER_TOKEN);
56
+ if (configManager.analyze) {
57
+ di.register({
58
+ provide: WEBPACK_ANALYZE_PLUGIN_NAME_TOKEN,
59
+ useValue: configManager.analyze,
60
+ });
61
+ }
62
+
56
63
  await runHandlers(di.get({ token: INIT_HANDLER_TOKEN, optional: true, multi: true }));
57
64
 
58
65
  const getBuildStats = di.get(GET_BUILD_STATS_TOKEN);
@@ -89,9 +96,13 @@ export const webpackProviders: Provider[] = [
89
96
  ...(shouldBuildServer ? buildServerProviders : []),
90
97
  ]);
91
98
 
92
- await runHandlers(di.get({ token: INIT_HANDLER_TOKEN, optional: true, multi: true }));
93
-
94
99
  const configManager = di.get(CONFIG_MANAGER_TOKEN);
100
+ if (configManager.analyze) {
101
+ di.register({
102
+ provide: WEBPACK_ANALYZE_PLUGIN_NAME_TOKEN,
103
+ useValue: configManager.analyze,
104
+ });
105
+ }
95
106
 
96
107
  if (configManager.type === 'application') {
97
108
  registerProviders(di, [
@@ -99,6 +110,8 @@ export const webpackProviders: Provider[] = [
99
110
  ]);
100
111
  }
101
112
 
113
+ await runHandlers(di.get({ token: INIT_HANDLER_TOKEN, optional: true, multi: true }));
114
+
102
115
  const getBuildStats = di.get(GET_BUILD_STATS_TOKEN);
103
116
 
104
117
  await runHandlers(
@@ -113,24 +126,6 @@ export const webpackProviders: Provider[] = [
113
126
  getBuildStats,
114
127
  };
115
128
  },
116
- async analyze({ plugin }) {
117
- di.register({
118
- provide: WEBPACK_ANALYZE_PLUGIN_NAME_TOKEN,
119
- useValue: plugin || 'bundle',
120
- });
121
-
122
- registerProviders(di, analyzeSharedProviders);
123
-
124
- await runHandlers(di.get({ token: INIT_HANDLER_TOKEN, optional: true, multi: true }));
125
-
126
- await runHandlers(
127
- di.get({ token: PROCESS_HANDLER_TOKEN, optional: true, multi: true })
128
- );
129
-
130
- await runHandlers(
131
- di.get({ token: CLOSE_HANDLER_TOKEN, optional: true, multi: true })
132
- );
133
- },
134
129
  on(event, callback) {
135
130
  di.get(EVENT_EMITTER_TOKEN).on(event, callback);
136
131
  },
@@ -6,6 +6,7 @@ import {
6
6
  CLIENT_CONFIG_MANAGER_TOKEN,
7
7
  CLOSE_HANDLER_TOKEN,
8
8
  PROCESS_HANDLER_TOKEN,
9
+ WEBPACK_ANALYZE_PLUGIN_TOKEN,
9
10
  WEBPACK_CLIENT_COMPILER_TOKEN,
10
11
  WEBPACK_CLIENT_CONFIG_TOKEN,
11
12
  } from '../../tokens';
@@ -27,12 +28,16 @@ export const buildClientProviders: Provider[] = [
27
28
  }),
28
29
  provide({
29
30
  provide: WEBPACK_CLIENT_COMPILER_TOKEN,
30
- useFactory: ({ webpackConfig, di }) => {
31
- return createCompiler(toWebpackConfig(webpackConfig), di);
31
+ useFactory: ({ webpackConfig, di, analyzePlugin }) => {
32
+ return createCompiler(
33
+ toWebpackConfig(analyzePlugin ? analyzePlugin.patchConfig(webpackConfig) : webpackConfig),
34
+ di
35
+ );
32
36
  },
33
37
  deps: {
34
38
  webpackConfig: WEBPACK_CLIENT_CONFIG_TOKEN,
35
39
  di: DI_TOKEN,
40
+ analyzePlugin: { token: WEBPACK_ANALYZE_PLUGIN_TOKEN, optional: true },
36
41
  },
37
42
  }),
38
43
  provide({
@@ -8,6 +8,7 @@ import {
8
8
  INIT_HANDLER_TOKEN,
9
9
  PROCESS_HANDLER_TOKEN,
10
10
  SERVER_CONFIG_MANAGER_TOKEN,
11
+ WEBPACK_ANALYZE_PLUGIN_TOKEN,
11
12
  WEBPACK_SERVER_COMPILER_TOKEN,
12
13
  WEBPACK_SERVER_CONFIG_TOKEN,
13
14
  } from '../../tokens';
@@ -18,12 +19,16 @@ import { createCompiler } from '../../utils/compiler';
18
19
  export const buildServerProviders: Provider[] = [
19
20
  provide({
20
21
  provide: WEBPACK_SERVER_COMPILER_TOKEN,
21
- useFactory: ({ webpackConfig, di }) => {
22
- return createCompiler(toWebpackConfig(webpackConfig), di);
22
+ useFactory: ({ webpackConfig, di, analyzePlugin }) => {
23
+ return createCompiler(
24
+ toWebpackConfig(analyzePlugin ? analyzePlugin.patchConfig(webpackConfig) : webpackConfig),
25
+ di
26
+ );
23
27
  },
24
28
  deps: {
25
29
  webpackConfig: WEBPACK_SERVER_CONFIG_TOKEN,
26
30
  di: DI_TOKEN,
31
+ analyzePlugin: { token: WEBPACK_ANALYZE_PLUGIN_TOKEN, optional: true },
27
32
  },
28
33
  }),
29
34
  provide({
@@ -3,6 +3,8 @@ import { provide } from '@tinkoff/dippy';
3
3
  import { EventEmitter } from 'events';
4
4
  import { CONFIG_MANAGER_TOKEN, WITH_BUILD_STATS_TOKEN } from '../../../di/tokens';
5
5
  import { closeWorkerPool, warmupWorkerPool } from '../../../library/webpack/utils/threadLoader';
6
+ import { calculateBuildTime } from '../utils/calculateBuildTime';
7
+ import { maxMemoryRss } from '../utils/maxMemoryRss';
6
8
  import {
7
9
  CLOSE_HANDLER_TOKEN,
8
10
  EVENT_EMITTER_TOKEN,
@@ -10,10 +12,26 @@ import {
10
12
  INIT_HANDLER_TOKEN,
11
13
  WEBPACK_CLIENT_COMPILER_TOKEN,
12
14
  WEBPACK_SERVER_COMPILER_TOKEN,
15
+ WEBPACK_ANALYZE_PLUGIN_NAME_TOKEN,
16
+ WEBPACK_ANALYZE_PLUGIN_TOKEN,
13
17
  } from '../tokens';
14
- import { calculateBuildTime } from '../utils/calculateBuildTime';
15
18
  import { emitWebpackEvents } from '../utils/webpackEvents';
16
- import { maxMemoryRss } from '../utils/maxMemoryRss';
19
+ import { BundleAnalyzePlugin } from '../analyzePlugins/bundle';
20
+ import { StatoscopeAnalyzePlugin } from '../analyzePlugins/statoscope';
21
+ import { WhyBundledAnalyzePlugin } from '../analyzePlugins/whyBundled';
22
+ import { RsdoctorAnalyzePlugin } from '../analyzePlugins/rsdoctor';
23
+ import type { AnalyzePlugin } from '../types';
24
+
25
+ interface Type<T> extends Function {
26
+ new (...args: any[]): T;
27
+ }
28
+
29
+ const pluginMap: Record<string, Type<AnalyzePlugin>> = {
30
+ bundle: BundleAnalyzePlugin,
31
+ whybundled: WhyBundledAnalyzePlugin,
32
+ statoscope: StatoscopeAnalyzePlugin,
33
+ rsdoctor: RsdoctorAnalyzePlugin,
34
+ };
17
35
 
18
36
  export const sharedProviders: Provider[] = [
19
37
  provide({
@@ -31,8 +49,12 @@ export const sharedProviders: Provider[] = [
31
49
  const getMaxMemoryRss = maxMemoryRss();
32
50
  return () => {
33
51
  return {
34
- clientBuildTime: getClientTime?.(),
35
- serverBuildTime: getServerTime?.(),
52
+ client: {
53
+ buildTime: getClientTime?.(),
54
+ },
55
+ server: {
56
+ buildTime: getServerTime?.(),
57
+ },
36
58
  maxMemoryRss: getMaxMemoryRss?.(),
37
59
  };
38
60
  };
@@ -43,6 +65,27 @@ export const sharedProviders: Provider[] = [
43
65
  serverCompiler: { token: WEBPACK_SERVER_COMPILER_TOKEN, optional: true },
44
66
  },
45
67
  }),
68
+ provide({
69
+ provide: WEBPACK_ANALYZE_PLUGIN_TOKEN,
70
+ useFactory: ({ pluginName }) => {
71
+ if (!pluginName) {
72
+ return;
73
+ }
74
+
75
+ const PluginClass = pluginMap[pluginName];
76
+
77
+ if (!PluginClass) {
78
+ throw new Error(
79
+ 'Set correct value for --analytics cli option, <bundle|whybundled|statoscope|rsdoctor>\n'
80
+ );
81
+ }
82
+
83
+ return new PluginClass();
84
+ },
85
+ deps: {
86
+ pluginName: WEBPACK_ANALYZE_PLUGIN_NAME_TOKEN,
87
+ },
88
+ }),
46
89
  provide({
47
90
  provide: EVENT_EMITTER_TOKEN,
48
91
  useClass: EventEmitter,
@@ -77,13 +120,18 @@ export const sharedProviders: Provider[] = [
77
120
  provide({
78
121
  provide: CLOSE_HANDLER_TOKEN,
79
122
  multi: true,
80
- useFactory: ({ configManager }) => {
123
+ useFactory: ({ configManager, analyzePlugin }) => {
81
124
  return async () => {
82
125
  await closeWorkerPool(configManager);
126
+
127
+ if (analyzePlugin) {
128
+ return analyzePlugin.afterBuild();
129
+ }
83
130
  };
84
131
  },
85
132
  deps: {
86
133
  configManager: CONFIG_MANAGER_TOKEN,
134
+ analyzePlugin: { token: WEBPACK_ANALYZE_PLUGIN_TOKEN, optional: true },
87
135
  },
88
136
  }),
89
137
  ];
@@ -9,6 +9,7 @@ import {
9
9
  WEBPACK_COMPILER_TOKEN,
10
10
  WEBPACK_SERVER_COMPILER_TOKEN,
11
11
  WEBPACK_SERVER_CONFIG_TOKEN,
12
+ WEBPACK_ANALYZE_PLUGIN_TOKEN,
12
13
  } from '../../tokens';
13
14
  import { createDevServer } from '../../devServer/setup';
14
15
  import { CONFIG_MANAGER_TOKEN, STATIC_SERVER_TOKEN } from '../../../../di/tokens';
@@ -16,8 +17,11 @@ import { CONFIG_MANAGER_TOKEN, STATIC_SERVER_TOKEN } from '../../../../di/tokens
16
17
  export const startSharedProviders: Provider[] = [
17
18
  provide({
18
19
  provide: WEBPACK_COMPILER_TOKEN,
19
- useFactory: ({ clientConfig, serverConfig }) => {
20
- const configs = [clientConfig, serverConfig].filter(Boolean).map(toWebpackConfig);
20
+ useFactory: ({ clientConfig, serverConfig, analyzePlugin }) => {
21
+ const configs = [clientConfig, serverConfig]
22
+ .filter(Boolean)
23
+ .map((config) => (analyzePlugin ? analyzePlugin.patchConfig(config) : config))
24
+ .map(toWebpackConfig);
21
25
  const multiCompiler = webpack(configs);
22
26
  const { inputFileSystem } = multiCompiler.compilers[0];
23
27
 
@@ -51,6 +55,7 @@ export const startSharedProviders: Provider[] = [
51
55
  deps: {
52
56
  clientConfig: { token: WEBPACK_CLIENT_CONFIG_TOKEN, optional: true },
53
57
  serverConfig: { token: WEBPACK_SERVER_CONFIG_TOKEN, optional: true },
58
+ analyzePlugin: { token: WEBPACK_ANALYZE_PLUGIN_TOKEN, optional: true },
54
59
  },
55
60
  }),
56
61
  provide({
package/src/cli/index.ts CHANGED
@@ -11,8 +11,8 @@ import buildCommand from '../commands/build/command';
11
11
  import { StartCommand } from '../commands/start/command';
12
12
  import lintCommand from '../commands/lint/command';
13
13
  import taskCommand from '../commands/task/command';
14
- import analyze from '../commands/analyze/command';
15
14
  import generate from '../commands/generate/command';
15
+ import analyze from '../commands/analyze/command';
16
16
  import newCommand from '../commands/new/command';
17
17
  import updateCommand from '../commands/update/command';
18
18
  import addCommand from '../commands/add/command';
@@ -27,15 +27,16 @@ import { getRootFile } from '../utils/getRootFile';
27
27
  import { getTramvaiConfig } from '../utils/getTramvaiConfig';
28
28
  import { syncJsonFile } from '../utils/syncJsonFile';
29
29
  import { AnalyticsService, resolveDependenciesProperties } from '../models/analytics/analytics';
30
+ import AnalyzeCommand from '../commands/analyze/command';
30
31
 
31
32
  async function loadCommands(): Promise<CommandMap> {
32
33
  return [
33
34
  buildCommand,
35
+ AnalyzeCommand,
34
36
  StartProdCommand,
35
37
  StartCommand,
36
38
  lintCommand,
37
39
  taskCommand,
38
- analyze,
39
40
  generate,
40
41
  newCommand,
41
42
  updateCommand,
@@ -8,7 +8,7 @@ import { checkReactCompilerDependencies } from '../../validators/commands/checkR
8
8
 
9
9
  export type Params = {
10
10
  target: string;
11
- plugin?: 'bundle' | 'whybundled' | 'statoscope';
11
+ plugin?: 'bundle' | 'whybundled' | 'statoscope' | 'rsdoctor';
12
12
  showConfig?: boolean;
13
13
  };
14
14