@jsenv/core 24.5.8 → 24.6.4

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 (39) hide show
  1. package/dist/browser_runtime/asset-manifest.json +1 -1
  2. package/dist/browser_runtime/{browser_runtime-c7288751.js → browser_runtime-bb0e3aa4.js} +37 -27
  3. package/dist/browser_runtime/{browser_runtime-c7288751.js.map → browser_runtime-bb0e3aa4.js.map} +3 -3
  4. package/dist/build_manifest.js +5 -5
  5. package/dist/compile_proxy/asset-manifest.json +1 -1
  6. package/dist/compile_proxy/{compile_proxy-a3969633.html → compile_proxy-6eb67db4.html} +39 -34
  7. package/dist/compile_proxy/{compile_proxy.html__inline__20-9c92c170.js.map → compile_proxy.html__inline__20-9e168143.js.map} +3 -2
  8. package/dist/redirector/asset-manifest.json +1 -1
  9. package/dist/redirector/{redirector-a6b8d640.html → redirector-b6ad84bf.html} +39 -34
  10. package/dist/redirector/{redirector.html__inline__15-58430672.js.map → redirector.html__inline__15-3a34a156.js.map} +3 -2
  11. package/dist/toolbar/asset-manifest.json +1 -1
  12. package/dist/toolbar/{toolbar-84985f43.html → toolbar-1fbf8dcb.html} +86 -61
  13. package/dist/toolbar/{toolbar.main-7aa01366.js.map → toolbar.main-a5ef2c60.js.map} +3 -2
  14. package/dist/toolbar_injector/asset-manifest.json +1 -1
  15. package/dist/toolbar_injector/{toolbar_injector-8edcae04.js → toolbar_injector-997dbaa0.js} +16 -16
  16. package/dist/toolbar_injector/{toolbar_injector-8edcae04.js.map → toolbar_injector-997dbaa0.js.map} +4 -4
  17. package/package.json +34 -33
  18. package/readme.md +23 -35
  19. package/src/buildProject.js +4 -7
  20. package/src/dev_server.js +6 -2
  21. package/src/executeTestPlan.js +12 -6
  22. package/src/internal/browser_launcher/executeHtmlFile.js +2 -1
  23. package/src/internal/browser_launcher/from_playwright.js +4 -0
  24. package/src/internal/building/buildUsingRollup.js +15 -11
  25. package/src/internal/building/rollup_plugin_jsenv.js +65 -53
  26. package/src/internal/building/url_loader.js +3 -0
  27. package/src/internal/compiling/createCompiledFileService.js +7 -7
  28. package/src/internal/compiling/js-compilation-service/jsenvTransform.js +12 -55
  29. package/src/internal/compiling/js-compilation-service/transformJs.js +8 -5
  30. package/src/internal/compiling/jsenvCompilerForHtml.js +4 -4
  31. package/src/internal/compiling/jsenvCompilerForJavaScript.js +2 -2
  32. package/src/internal/compiling/startCompileServer.js +2 -2
  33. package/src/internal/executing/createSummaryLog.js +30 -4
  34. package/src/internal/executing/executeConcurrently.js +22 -8
  35. package/src/internal/executing/executePlan.js +12 -6
  36. package/src/internal/executing/executionLogs.js +14 -4
  37. package/src/internal/executing/gc.js +9 -0
  38. package/src/internal/logs/byte.js +10 -0
  39. package/src/internal/compiling/js-compilation-service/findAsyncPluginNameInBabelPluginMap.js +0 -9
@@ -15,7 +15,7 @@ import {
15
15
  } from "@jsenv/core/src/internal/generateGroupMap/runtime_support.js"
16
16
  import { featuresCompatMap } from "@jsenv/core/src/internal/generateGroupMap/featuresCompatMap.js"
17
17
  import { createRuntimeCompat } from "@jsenv/core/src/internal/generateGroupMap/runtime_compat.js"
18
- import { createJsenvRollupPlugin } from "./rollup_plugin_jsenv.js"
18
+ import { createRollupPlugins } from "./rollup_plugin_jsenv.js"
19
19
 
20
20
  export const buildUsingRollup = async ({
21
21
  buildOperation,
@@ -38,7 +38,6 @@ export const buildUsingRollup = async ({
38
38
  globals,
39
39
  babelPluginMap,
40
40
  runtimeSupport,
41
- transformTopLevelAwait,
42
41
 
43
42
  urlMappings,
44
43
  importResolutionMethod,
@@ -90,12 +89,12 @@ export const buildUsingRollup = async ({
90
89
  }
91
90
 
92
91
  const {
93
- jsenvRollupPlugin,
92
+ rollupPlugins,
94
93
  getLastErrorMessage,
95
94
  getResult,
96
95
  asOriginalUrl,
97
96
  asProjectUrl,
98
- } = await createJsenvRollupPlugin({
97
+ } = await createRollupPlugins({
99
98
  buildOperation,
100
99
  logger,
101
100
 
@@ -108,7 +107,6 @@ export const buildUsingRollup = async ({
108
107
  format,
109
108
  systemJsUrl,
110
109
  babelPluginMap,
111
- transformTopLevelAwait,
112
110
  node,
113
111
  browser,
114
112
  importAssertionsSupport,
@@ -142,7 +140,8 @@ export const buildUsingRollup = async ({
142
140
  buildOperation,
143
141
  logger,
144
142
 
145
- jsenvRollupPlugin,
143
+ rollupPlugins,
144
+ babelPluginMap,
146
145
  format,
147
146
  globals,
148
147
  globalName,
@@ -247,7 +246,8 @@ export const buildUsingRollup = async ({
247
246
  const useRollup = async ({
248
247
  buildOperation,
249
248
  logger,
250
- jsenvRollupPlugin,
249
+ rollupPlugins,
250
+ babelPluginMap,
251
251
  format,
252
252
  globals,
253
253
  globalName,
@@ -312,15 +312,19 @@ const useRollup = async ({
312
312
  input: [],
313
313
  preserveEntrySignatures,
314
314
  treeshake,
315
- plugins: [jsenvRollupPlugin],
315
+ plugins: rollupPlugins,
316
316
  acornInjectPlugins: [importAssertions],
317
317
  }
318
318
  const rollupOutputOptions = {
319
319
  // https://rollupjs.org/guide/en#experimentaltoplevelawait
320
320
  // experimentalTopLevelAwait: true,
321
- // we could put prefConst to true by checking 'transform-block-scoping'
322
- // presence in babelPluginMap
323
- preferConst: false,
321
+ // https://rollupjs.org/guide/en/#outputgeneratedcode
322
+ generatedCode: {
323
+ arrowFunctions: !babelPluginMap["transform-arrow-functions"],
324
+ constBindings: !babelPluginMap["transform-block-scoping"],
325
+ objectShorthand: !babelPluginMap["transform-shorthand-properties"],
326
+ reservedNamesAsProps: !babelPluginMap["transform-reserved-words"],
327
+ },
324
328
  // https://rollupjs.org/guide/en#output-dir
325
329
  dir: urlToFileSystemPath(buildDirectoryUrl),
326
330
  // https://rollupjs.org/guide/en#output-format
@@ -17,6 +17,7 @@ import {
17
17
  } from "@jsenv/filesystem"
18
18
  import { UNICODE } from "@jsenv/log"
19
19
 
20
+ import { transformJs } from "@jsenv/core/src/internal/compiling/js-compilation-service/transformJs.js"
20
21
  import { createUrlConverter } from "@jsenv/core/src/internal/url_conversion.js"
21
22
  import { createUrlFetcher } from "@jsenv/core/src/internal/building/url_fetcher.js"
22
23
  import { createUrlLoader } from "@jsenv/core/src/internal/building/url_loader.js"
@@ -48,7 +49,7 @@ import { getDefaultImportMap } from "../import-resolution/importmap-default.js"
48
49
  import { injectSourcemapInRollupBuild } from "./rollup_build_sourcemap.js"
49
50
  import { createBuildStats } from "./build_stats.js"
50
51
 
51
- export const createJsenvRollupPlugin = async ({
52
+ export const createRollupPlugins = async ({
52
53
  buildOperation,
53
54
  logger,
54
55
 
@@ -72,7 +73,6 @@ export const createJsenvRollupPlugin = async ({
72
73
  format,
73
74
  systemJsUrl,
74
75
  babelPluginMap,
75
- transformTopLevelAwait,
76
76
  node,
77
77
  importAssertionsSupport,
78
78
 
@@ -239,8 +239,40 @@ export const createJsenvRollupPlugin = async ({
239
239
  let minifyJs
240
240
  let minifyHtml
241
241
 
242
- const jsenvRollupPlugin = {}
243
-
242
+ const rollupPlugins = []
243
+ // When format is systemjs, rollup add async/await
244
+ // that might be unsupported by the runtime.
245
+ // in that case we have to transform the rollup output
246
+ if (babelPluginMap["transform-async-to-promises"] && format === "systemjs") {
247
+ rollupPlugins.push({
248
+ name: "jsenv_fix_async_await",
249
+ async renderChunk(code, chunk) {
250
+ let map = chunk.map
251
+ const result = await transformJs({
252
+ code,
253
+ url: chunk.facadeModuleId
254
+ ? asOriginalUrl(chunk.facadeModuleId)
255
+ : resolveUrl(chunk.fileName, buildDirectoryUrl),
256
+ projectDirectoryUrl,
257
+ babelPluginMap: {
258
+ "transform-async-to-promises":
259
+ babelPluginMap["transform-async-to-promises"],
260
+ },
261
+ // pass undefined when format is "systemjs" to avoid
262
+ // re-wrapping the code in systemjs format
263
+ moduleOutFormat: undefined,
264
+ babelHelpersInjectionAsImport: false,
265
+ transformGenerator: false,
266
+ })
267
+ code = result.code
268
+ map = result.map
269
+ return {
270
+ code,
271
+ map,
272
+ }
273
+ },
274
+ })
275
+ }
244
276
  if (minify) {
245
277
  const methodHooks = {
246
278
  minifyJs: async (...args) => {
@@ -271,27 +303,29 @@ export const createJsenvRollupPlugin = async ({
271
303
  return methodHooks.minifyHtml(html, minifyHtmlOptions)
272
304
  }
273
305
 
274
- jsenvRollupPlugin.renderChunk = async (code, chunk) => {
275
- let map = chunk.map
276
- const result = await minifyJs({
277
- url: chunk.facadeModuleId
278
- ? asOriginalUrl(chunk.facadeModuleId)
279
- : resolveUrl(chunk.fileName, buildDirectoryUrl),
280
- code,
281
- map,
282
- ...(format === "global" ? { toplevel: false } : { toplevel: true }),
283
- })
306
+ rollupPlugins.push({
307
+ name: "jsenv_minifier",
308
+ async renderChunk(code, chunk) {
309
+ let map = chunk.map
310
+ const result = await minifyJs({
311
+ url: chunk.facadeModuleId
312
+ ? asOriginalUrl(chunk.facadeModuleId)
313
+ : resolveUrl(chunk.fileName, buildDirectoryUrl),
314
+ code,
315
+ map,
316
+ ...(format === "global" ? { toplevel: false } : { toplevel: true }),
317
+ })
284
318
 
285
- code = result.code
286
- map = result.map
287
- return {
288
- code,
289
- map,
290
- }
291
- }
319
+ code = result.code
320
+ map = result.map
321
+ return {
322
+ code,
323
+ map,
324
+ }
325
+ },
326
+ })
292
327
  }
293
-
294
- Object.assign(jsenvRollupPlugin, {
328
+ rollupPlugins.unshift({
295
329
  name: "jsenv",
296
330
 
297
331
  async buildStart() {
@@ -1105,8 +1139,8 @@ export const createJsenvRollupPlugin = async ({
1105
1139
 
1106
1140
  async generateBundle(outputOptions, rollupResult) {
1107
1141
  const jsChunks = {}
1108
- // rollupResult can be mutated by late asset emission
1109
- // howeverl late chunk (js module) emission is not possible
1142
+ // To keep in mind: rollupResult object can be mutated by late asset emission
1143
+ // however late chunk (js module) emission is not possible
1110
1144
  // as rollup rightfully prevent late js emission
1111
1145
  Object.keys(rollupResult).forEach((fileName) => {
1112
1146
  const file = rollupResult[fileName]
@@ -1137,10 +1171,6 @@ export const createJsenvRollupPlugin = async ({
1137
1171
  jsChunks[fileName] = fileCopy
1138
1172
  }
1139
1173
  })
1140
- await ensureTopLevelAwaitTranspilationIfNeeded({
1141
- format,
1142
- transformTopLevelAwait,
1143
- })
1144
1174
 
1145
1175
  const jsModuleBuild = {}
1146
1176
  Object.keys(jsChunks).forEach((fileName) => {
@@ -1152,10 +1182,12 @@ export const createJsenvRollupPlugin = async ({
1152
1182
  !file.isEntry
1153
1183
 
1154
1184
  if (file.url in inlineModuleScripts && format === "systemjs") {
1155
- const magicString = new MagicString(file.code)
1185
+ const code = file.code
1186
+ const systemRegisterIndex = code.indexOf("System.register([")
1187
+ const magicString = new MagicString(code)
1156
1188
  magicString.overwrite(
1157
- 0,
1158
- "System.register([".length,
1189
+ systemRegisterIndex,
1190
+ systemRegisterIndex + "System.register([".length,
1159
1191
  `System.register("${fileName}", [`,
1160
1192
  )
1161
1193
  file.code = magicString.toString()
@@ -1366,7 +1398,7 @@ export const createJsenvRollupPlugin = async ({
1366
1398
  }
1367
1399
 
1368
1400
  return {
1369
- jsenvRollupPlugin,
1401
+ rollupPlugins,
1370
1402
  getLastErrorMessage: () => lastErrorMessage,
1371
1403
  getResult: () => {
1372
1404
  return {
@@ -1386,26 +1418,6 @@ export const createJsenvRollupPlugin = async ({
1386
1418
  }
1387
1419
  }
1388
1420
 
1389
- const ensureTopLevelAwaitTranspilationIfNeeded = async ({
1390
- format,
1391
- transformTopLevelAwait,
1392
- }) => {
1393
- if (!transformTopLevelAwait) {
1394
- return
1395
- }
1396
-
1397
- if (format === "esmodule") {
1398
- // transform-async-to-promises won't be able to transform top level await
1399
- // for "esmodule", so it would be useless
1400
- return
1401
- }
1402
-
1403
- if (format === "systemjs") {
1404
- // top level await is an async function for systemjs
1405
- return
1406
- }
1407
- }
1408
-
1409
1421
  const prepareEntryPoints = async (
1410
1422
  entryPointMap,
1411
1423
  {
@@ -119,6 +119,9 @@ export const createUrlLoader = ({
119
119
  projectDirectoryUrl,
120
120
  babelPluginMap,
121
121
  // moduleOutFormat: format // we are compiling for rollup output must be "esmodule"
122
+ // we compile for rollup, let top level await untouched
123
+ // it will be converted, if needed, during "renderChunk" hook
124
+ topLevelAwait: "ignore",
122
125
  })
123
126
  let code = transformResult.code
124
127
  let map = transformResult.map
@@ -41,10 +41,10 @@ export const createCompiledFileService = ({
41
41
  outDirectoryRelativeUrl,
42
42
 
43
43
  runtimeSupport,
44
- transformTopLevelAwait,
44
+ babelPluginMap,
45
45
  moduleOutFormat,
46
46
  importMetaFormat,
47
- babelPluginMap,
47
+ topLevelAwait,
48
48
  groupMap,
49
49
  customCompilers,
50
50
 
@@ -185,16 +185,16 @@ export const createCompiledFileService = ({
185
185
  request,
186
186
 
187
187
  runtimeSupport,
188
+ babelPluginMap: babelPluginMapFromCompileId(compileId, {
189
+ babelPluginMap,
190
+ groupMap,
191
+ }),
188
192
  moduleOutFormat:
189
193
  moduleOutFormat === undefined
190
194
  ? compileIdModuleFormats[compileId]
191
195
  : moduleOutFormat,
192
196
  importMetaFormat,
193
- transformTopLevelAwait,
194
- babelPluginMap: babelPluginMapFromCompileId(compileId, {
195
- babelPluginMap,
196
- groupMap,
197
- }),
197
+ topLevelAwait,
198
198
 
199
199
  sourcemapMethod,
200
200
  sourcemapExcludeSources,
@@ -5,11 +5,9 @@ import { babelPluginTransformImportMeta } from "@jsenv/core/src/internal/babel_p
5
5
  import {
6
6
  getMinimalBabelPluginMap,
7
7
  babelPluginsFromBabelPluginMap,
8
- extractSyntaxBabelPluginMap,
9
8
  } from "@jsenv/core/src/internal/compiling/babel_plugins.js"
10
9
  import { babelPluginImportMetadata } from "@jsenv/core/src/internal/compiling/babel_plugin_import_metadata.js"
11
10
 
12
- import { findAsyncPluginNameInBabelPluginMap } from "./findAsyncPluginNameInBabelPluginMap.js"
13
11
  import { ansiToHTML } from "./ansiToHTML.js"
14
12
  import { babelPluginRegeneratorRuntimeAsJsenvImport } from "./babel_plugin_regenerator_runtime_as_jsenv_import.js"
15
13
  import { babelPluginBabelHelpersAsJsenvImports } from "./babel_plugin_babel_helpers_as_jsenv_imports.js"
@@ -25,10 +23,9 @@ export const jsenvTransform = async ({
25
23
  babelPluginMap,
26
24
  moduleOutFormat,
27
25
  importMetaFormat = moduleOutFormat,
26
+ topLevelAwait,
28
27
 
29
28
  babelHelpersInjectionAsImport,
30
- allowTopLevelAwait,
31
- transformTopLevelAwait,
32
29
  transformGenerator,
33
30
  regeneratorRuntimeImportPath,
34
31
  sourcemapEnabled,
@@ -50,7 +47,14 @@ export const jsenvTransform = async ({
50
47
  sourceFileName: inputPath,
51
48
  // https://babeljs.io/docs/en/options#parseropts
52
49
  parserOpts: {
53
- allowAwaitOutsideFunction: allowTopLevelAwait,
50
+ allowAwaitOutsideFunction:
51
+ topLevelAwait === undefined ||
52
+ topLevelAwait === "return" ||
53
+ topLevelAwait === "simple" ||
54
+ topLevelAwait === "ignore",
55
+ },
56
+ generatorOpts: {
57
+ compact: false,
54
58
  },
55
59
  }
56
60
 
@@ -144,56 +148,9 @@ export const jsenvTransform = async ({
144
148
  "import-metadata": [babelPluginImportMetadata],
145
149
  }
146
150
 
147
- const asyncPluginName = findAsyncPluginNameInBabelPluginMap(babelPluginMap)
148
-
149
- if (
150
- moduleOutFormat === "systemjs" &&
151
- transformTopLevelAwait &&
152
- asyncPluginName
153
- ) {
154
- const babelPluginMapWithoutAsync = {
155
- ...babelPluginMap,
156
- "proposal-dynamic-import": [proposalDynamicImport],
157
- "transform-modules-systemjs": [transformModulesSystemJs],
158
- }
159
- delete babelPluginMapWithoutAsync[asyncPluginName]
160
-
161
- // put body inside something like (async () => {})()
162
- const result = await babelTransform({
163
- ast,
164
- code,
165
- options: {
166
- ...options,
167
- plugins: babelPluginsFromBabelPluginMap(babelPluginMapWithoutAsync),
168
- },
169
- })
170
-
171
- // we need to retranspile the await keywords now wrapped
172
- // inside Systemjs function.
173
- // They are ignored, at least by transform-async-to-promises
174
- // see https://github.com/rpetrich/babel-plugin-transform-async-to-promises/issues/26
175
- const { babelSyntaxPluginMap } = extractSyntaxBabelPluginMap(babelPluginMap)
176
- const finalResult = await babelTransform({
177
- // ast: result.ast,
178
- code: result.code,
179
- options: {
180
- ...options,
181
- // about inputSourceMap see
182
- // https://github.com/babel/babel/blob/eac4c5bc17133c2857f2c94c1a6a8643e3b547a7/packages/babel-core/src/transformation/file/generate.js#L57
183
- // https://github.com/babel/babel/blob/090c364a90fe73d36a30707fc612ce037bdbbb24/packages/babel-core/src/transformation/file/merge-map.js#L6s
184
- inputSourceMap: result.map,
185
- plugins: babelPluginsFromBabelPluginMap({
186
- ...babelSyntaxPluginMap,
187
- [asyncPluginName]: babelPluginMap[asyncPluginName],
188
- }),
189
- },
190
- })
191
-
192
- return {
193
- ...result,
194
- ...finalResult,
195
- metadata: { ...result.metadata, ...finalResult.metadata },
196
- }
151
+ const asyncToPromise = babelPluginMap["transform-async-to-promises"]
152
+ if (topLevelAwait && asyncToPromise) {
153
+ asyncToPromise.options.topLevelAwait = topLevelAwait
197
154
  }
198
155
 
199
156
  const babelTransformReturnValue = await babelTransform({
@@ -11,9 +11,8 @@ export const transformJs = async ({
11
11
  babelPluginMap,
12
12
  moduleOutFormat = "esmodule",
13
13
  importMetaFormat = moduleOutFormat,
14
- babelHelpersInjectionAsImport = true,
15
- allowTopLevelAwait = true,
16
- transformTopLevelAwait = true,
14
+ babelHelpersInjectionAsImport = moduleOutFormat === "esmodule",
15
+ topLevelAwait,
17
16
  transformGenerator = true,
18
17
  sourcemapEnabled = true,
19
18
  }) => {
@@ -33,6 +32,11 @@ export const transformJs = async ({
33
32
  if (typeof url !== "string") {
34
33
  throw new TypeError(`url must be a string, got ${url}`)
35
34
  }
35
+ if (babelHelpersInjectionAsImport && moduleOutFormat !== "esmodule") {
36
+ throw new Error(
37
+ `babelHelpersInjectionAsImport can be enabled only when "moduleOutFormat" is "esmodule"`,
38
+ )
39
+ }
36
40
 
37
41
  const transformResult = await jsenvTransform({
38
42
  code,
@@ -47,8 +51,7 @@ export const transformJs = async ({
47
51
  importMetaFormat,
48
52
 
49
53
  babelHelpersInjectionAsImport,
50
- allowTopLevelAwait,
51
- transformTopLevelAwait,
54
+ topLevelAwait,
52
55
  transformGenerator,
53
56
  sourcemapEnabled,
54
57
  })
@@ -42,10 +42,10 @@ export const compileHtml = async ({
42
42
  outDirectoryRelativeUrl,
43
43
  compileId,
44
44
 
45
- transformTopLevelAwait,
45
+ babelPluginMap,
46
46
  moduleOutFormat,
47
47
  importMetaFormat,
48
- babelPluginMap,
48
+ topLevelAwait,
49
49
 
50
50
  sourcemapMethod,
51
51
 
@@ -284,10 +284,10 @@ export const compileHtml = async ({
284
284
  compiledUrl: scriptCompiledFileUrl,
285
285
  projectDirectoryUrl,
286
286
 
287
- transformTopLevelAwait,
287
+ babelPluginMap,
288
288
  moduleOutFormat,
289
289
  importMetaFormat,
290
- babelPluginMap,
290
+ topLevelAwait,
291
291
  })
292
292
  } catch (e) {
293
293
  // If there is a syntax error in inline script
@@ -9,9 +9,9 @@ export const compileJavascript = async ({
9
9
  projectDirectoryUrl,
10
10
 
11
11
  babelPluginMap,
12
- transformTopLevelAwait,
13
12
  moduleOutFormat,
14
13
  importMetaFormat,
14
+ topLevelAwait,
15
15
 
16
16
  sourcemapExcludeSources,
17
17
  sourcemapMethod,
@@ -24,9 +24,9 @@ export const compileJavascript = async ({
24
24
  projectDirectoryUrl,
25
25
 
26
26
  babelPluginMap,
27
- transformTopLevelAwait,
28
27
  moduleOutFormat,
29
28
  importMetaFormat,
29
+ topLevelAwait,
30
30
  })
31
31
 
32
32
  return transformResultToCompilationResult(
@@ -82,9 +82,9 @@ export const startCompileServer = async ({
82
82
  projectFileCacheStrategy = "mtime",
83
83
 
84
84
  // js compile options
85
- transformTopLevelAwait = true,
86
85
  moduleOutFormat,
87
86
  importMetaFormat,
87
+ topLevelAwait,
88
88
  env = {},
89
89
  processEnvNodeEnv = process.env.NODE_ENV,
90
90
  replaceProcessEnvNodeEnv = true,
@@ -310,7 +310,7 @@ export const startCompileServer = async ({
310
310
  importDefaultExtension,
311
311
 
312
312
  runtimeSupport,
313
- transformTopLevelAwait,
313
+ topLevelAwait,
314
314
  groupMap: compileServerGroupMap,
315
315
  babelPluginMap,
316
316
  customCompilers,
@@ -1,16 +1,17 @@
1
1
  import { ANSI } from "@jsenv/log"
2
2
 
3
3
  import { msAsDuration } from "../logs/msAsDuration.js"
4
+ import { formatByte } from "../logs/byte.js"
4
5
  import { EXECUTION_COLORS } from "./execution_colors.js"
5
6
 
6
7
  export const createSummaryLog = (
7
8
  summary,
8
9
  ) => `-------------- summary -----------------
9
- ${createSummaryMessage(summary)}
10
+ ${createAllExecutionsSummary(summary)}
10
11
  total duration: ${msAsDuration(summary.duration)}
11
12
  ----------------------------------------`
12
13
 
13
- const createSummaryMessage = ({
14
+ const createAllExecutionsSummary = ({
14
15
  executionCount,
15
16
  abortedCount,
16
17
  timedoutCount,
@@ -24,7 +25,7 @@ const createSummaryMessage = ({
24
25
 
25
26
  const executionLabel =
26
27
  executionCount === 1 ? `1 execution` : `${executionCount} executions`
27
- return `${executionLabel}: ${createSummaryDetails({
28
+ return `${executionLabel}: ${createStatusSummary({
28
29
  executionCount,
29
30
  abortedCount,
30
31
  timedoutCount,
@@ -34,7 +35,32 @@ const createSummaryMessage = ({
34
35
  })}`
35
36
  }
36
37
 
37
- export const createSummaryDetails = ({
38
+ export const createIntermediateSummary = ({
39
+ executionCount,
40
+ abortedCount,
41
+ timedoutCount,
42
+ erroredCount,
43
+ completedCount,
44
+ cancelledCount,
45
+ memoryHeap,
46
+ }) => {
47
+ let intermediateSummary = createStatusSummary({
48
+ executionCount,
49
+ abortedCount,
50
+ timedoutCount,
51
+ erroredCount,
52
+ completedCount,
53
+ cancelledCount,
54
+ })
55
+
56
+ if (memoryHeap) {
57
+ intermediateSummary += ` / memory heap: ${formatByte(memoryHeap)}`
58
+ }
59
+
60
+ return intermediateSummary
61
+ }
62
+
63
+ const createStatusSummary = ({
38
64
  executionCount,
39
65
  abortedCount,
40
66
  timedoutCount,
@@ -1,4 +1,5 @@
1
1
  import { existsSync } from "node:fs"
2
+ import { memoryUsage } from "node:process"
2
3
  import wrapAnsi from "wrap-ansi"
3
4
  import cuid from "cuid"
4
5
  import { loggerToLevels } from "@jsenv/logger"
@@ -17,6 +18,7 @@ import { launchAndExecute } from "../executing/launchAndExecute.js"
17
18
  import { reportToCoverage } from "./coverage/reportToCoverage.js"
18
19
  import { formatExecuting, formatExecutionResult } from "./executionLogs.js"
19
20
  import { createSummaryLog } from "./createSummaryLog.js"
21
+ import { ensureGlobalGc } from "./gc.js"
20
22
 
21
23
  export const executeConcurrently = async (
22
24
  executionSteps,
@@ -28,16 +30,19 @@ export const executeConcurrently = async (
28
30
 
29
31
  projectDirectoryUrl,
30
32
  compileServer,
31
-
32
33
  babelPluginMap,
33
34
 
34
- defaultMsAllocatedPerExecution = 30000,
35
- cooldownBetweenExecutions = 0,
36
- maxExecutionsInParallel = 1,
37
- stopAfterExecute,
35
+ logSummary,
36
+ logMemoryHeapUsage,
38
37
  completedExecutionLogMerging,
39
38
  completedExecutionLogAbbreviation,
40
39
 
40
+ maxExecutionsInParallel,
41
+ defaultMsAllocatedPerExecution,
42
+ stopAfterExecute,
43
+ cooldownBetweenExecutions,
44
+ gcBetweenExecutions,
45
+
41
46
  coverage,
42
47
  coverageConfig,
43
48
  coverageIncludeMissing,
@@ -48,8 +53,6 @@ export const executeConcurrently = async (
48
53
 
49
54
  beforeExecutionCallback = () => {},
50
55
  afterExecutionCallback = () => {},
51
-
52
- logSummary,
53
56
  },
54
57
  ) => {
55
58
  if (completedExecutionLogMerging && !process.stdout.isTTY) {
@@ -62,12 +65,15 @@ export const executeConcurrently = async (
62
65
  const executionSpinner = executionLogsEnabled && process.stdout.isTTY
63
66
 
64
67
  const startMs = Date.now()
65
-
66
68
  const report = {}
67
69
  const executionCount = executionSteps.length
68
70
 
69
71
  let transformReturnValue = (value) => value
70
72
 
73
+ if (gcBetweenExecutions) {
74
+ ensureGlobalGc()
75
+ }
76
+
71
77
  const coverageTempDirectoryUrl = resolveUrl(
72
78
  coverageTempDirectoryRelativeUrl,
73
79
  projectDirectoryUrl,
@@ -185,6 +191,9 @@ export const executeConcurrently = async (
185
191
  timedoutCount,
186
192
  erroredCount,
187
193
  completedCount,
194
+ ...(logMemoryHeapUsage
195
+ ? { memoryHeap: memoryUsage().heapUsed }
196
+ : {}),
188
197
  }),
189
198
  })
190
199
  }
@@ -249,6 +258,10 @@ export const executeConcurrently = async (
249
258
  completedCount++
250
259
  }
251
260
 
261
+ if (gcBetweenExecutions) {
262
+ global.gc()
263
+ }
264
+
252
265
  if (executionLogsEnabled) {
253
266
  let log = formatExecutionResult(afterExecutionInfo, {
254
267
  completedExecutionLogAbbreviation,
@@ -257,6 +270,7 @@ export const executeConcurrently = async (
257
270
  timedoutCount,
258
271
  erroredCount,
259
272
  completedCount,
273
+ ...(logMemoryHeapUsage ? { memoryHeap: memoryUsage().heapUsed } : {}),
260
274
  })
261
275
  log = `${log}
262
276