@jsenv/core 24.5.7 → 24.6.3

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 (34) hide show
  1. package/dist/browser_runtime/browser_runtime-c7288751.js +58 -41
  2. package/dist/browser_runtime/browser_runtime-c7288751.js.map +3 -1
  3. package/dist/build_manifest.js +4 -4
  4. package/dist/compile_proxy/asset-manifest.json +1 -1
  5. package/dist/compile_proxy/{compile_proxy-501d6fa3.html → compile_proxy-28148b58.html} +26 -21
  6. package/dist/compile_proxy/{compile_proxy.html__inline__20-cbaf7522.js.map → compile_proxy.html__inline__20-4887fb1d.js.map} +3 -3
  7. package/dist/event_source_client/event_source_client-9f14c8b9.js +11 -5
  8. package/dist/event_source_client/event_source_client-9f14c8b9.js.map +1 -1
  9. package/dist/redirector/asset-manifest.json +1 -1
  10. package/dist/redirector/{redirector-d614cffb.html → redirector-3c05dbb2.html} +26 -21
  11. package/dist/redirector/{redirector.html__inline__15-2953c307.js.map → redirector.html__inline__15-19e529b9.js.map} +3 -3
  12. package/dist/toolbar/asset-manifest.json +1 -1
  13. package/dist/toolbar/{toolbar-c23caf7b.html → toolbar-bab473ea.html} +61 -36
  14. package/dist/toolbar/{toolbar.main-bdbf37d1.js.map → toolbar.main-eb8acf83.js.map} +3 -3
  15. package/dist/toolbar_injector/asset-manifest.json +1 -1
  16. package/dist/toolbar_injector/{toolbar_injector-52ec0940.js → toolbar_injector-5e32f96a.js} +11 -10
  17. package/dist/toolbar_injector/{toolbar_injector-52ec0940.js.map → toolbar_injector-5e32f96a.js.map} +4 -3
  18. package/package.json +33 -32
  19. package/readme.md +13 -15
  20. package/src/buildProject.js +1 -2
  21. package/src/executeTestPlan.js +12 -6
  22. package/src/internal/browser_detection/user_agent_data.js +1 -1
  23. package/src/internal/browser_launcher/executeHtmlFile.js +2 -1
  24. package/src/internal/browser_launcher/from_playwright.js +4 -0
  25. package/src/internal/building/buildUsingRollup.js +15 -9
  26. package/src/internal/building/rollup_plugin_jsenv.js +65 -53
  27. package/src/internal/compiling/js-compilation-service/jsenvTransform.js +3 -0
  28. package/src/internal/compiling/js-compilation-service/transformJs.js +6 -1
  29. package/src/internal/executing/createSummaryLog.js +30 -4
  30. package/src/internal/executing/executeConcurrently.js +22 -8
  31. package/src/internal/executing/executePlan.js +12 -6
  32. package/src/internal/executing/executionLogs.js +14 -4
  33. package/src/internal/executing/gc.js +9 -0
  34. package/src/internal/logs/byte.js +10 -0
@@ -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
+ // rollup add async/await that might be unsupported by the runtime
244
+ // in that case we have to transform the rollup output
245
+ if (babelPluginMap["transform-async-to-promises"]) {
246
+ rollupPlugins.push({
247
+ name: "jsenv_fix_async_await",
248
+ async renderChunk(code, chunk) {
249
+ let map = chunk.map
250
+ const result = await transformJs({
251
+ code,
252
+ url: chunk.facadeModuleId
253
+ ? asOriginalUrl(chunk.facadeModuleId)
254
+ : resolveUrl(chunk.fileName, buildDirectoryUrl),
255
+ projectDirectoryUrl,
256
+ babelPluginMap: {
257
+ "transform-async-to-promises":
258
+ babelPluginMap["transform-async-to-promises"],
259
+ },
260
+ babelHelpersInjectionAsImport: false,
261
+ transformGenerator: false,
262
+ moduleOutFormat:
263
+ // pass undefined when format is "systemjs" to avoid
264
+ // re-wrapping the code in systemjs format
265
+ format === "systemjs" ? undefined : format,
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
  {
@@ -52,6 +52,9 @@ export const jsenvTransform = async ({
52
52
  parserOpts: {
53
53
  allowAwaitOutsideFunction: allowTopLevelAwait,
54
54
  },
55
+ generatorOpts: {
56
+ compact: false,
57
+ },
55
58
  }
56
59
 
57
60
  const babelHelperName = filePathToBabelHelperName(inputPath)
@@ -11,7 +11,7 @@ export const transformJs = async ({
11
11
  babelPluginMap,
12
12
  moduleOutFormat = "esmodule",
13
13
  importMetaFormat = moduleOutFormat,
14
- babelHelpersInjectionAsImport = true,
14
+ babelHelpersInjectionAsImport = moduleOutFormat === "esmodule",
15
15
  allowTopLevelAwait = true,
16
16
  transformTopLevelAwait = true,
17
17
  transformGenerator = true,
@@ -33,6 +33,11 @@ export const transformJs = async ({
33
33
  if (typeof url !== "string") {
34
34
  throw new TypeError(`url must be a string, got ${url}`)
35
35
  }
36
+ if (babelHelpersInjectionAsImport && moduleOutFormat !== "esmodule") {
37
+ throw new Error(
38
+ `babelHelpersInjectionAsImport can be enabled only when "moduleOutFormat" is "esmodule"`,
39
+ )
40
+ }
36
41
 
37
42
  const transformResult = await jsenvTransform({
38
43
  code,
@@ -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
 
@@ -24,13 +24,16 @@ export const executePlan = async (
24
24
  importResolutionMethod,
25
25
  importDefaultExtension,
26
26
 
27
+ logSummary,
28
+ logMemoryHeapUsage,
29
+ completedExecutionLogMerging,
30
+ completedExecutionLogAbbreviation,
31
+
27
32
  defaultMsAllocatedPerExecution,
28
33
  maxExecutionsInParallel,
34
+ gcBetweenExecutions,
29
35
  stopAfterExecute,
30
36
  cooldownBetweenExecutions,
31
- completedExecutionLogMerging,
32
- completedExecutionLogAbbreviation,
33
- logSummary,
34
37
 
35
38
  coverage,
36
39
  coverageConfig,
@@ -169,13 +172,16 @@ export const executePlan = async (
169
172
 
170
173
  babelPluginMap: compileServer.babelPluginMap,
171
174
 
175
+ logSummary,
176
+ logMemoryHeapUsage,
177
+ completedExecutionLogMerging,
178
+ completedExecutionLogAbbreviation,
179
+
172
180
  defaultMsAllocatedPerExecution,
173
181
  maxExecutionsInParallel,
174
182
  stopAfterExecute,
183
+ gcBetweenExecutions,
175
184
  cooldownBetweenExecutions,
176
- completedExecutionLogMerging,
177
- completedExecutionLogAbbreviation,
178
- logSummary,
179
185
 
180
186
  coverage,
181
187
  coverageConfig,
@@ -2,11 +2,18 @@ import { ANSI, UNICODE } from "@jsenv/log"
2
2
 
3
3
  import { msAsDuration } from "../logs/msAsDuration.js"
4
4
  import { EXECUTION_COLORS } from "./execution_colors.js"
5
- import { createSummaryDetails } from "./createSummaryLog.js"
5
+ import { createIntermediateSummary } from "./createSummaryLog.js"
6
6
 
7
7
  export const formatExecuting = (
8
8
  { executionIndex },
9
- { executionCount, abortedCount, timedoutCount, erroredCount, completedCount },
9
+ {
10
+ executionCount,
11
+ abortedCount,
12
+ timedoutCount,
13
+ erroredCount,
14
+ completedCount,
15
+ memoryHeap,
16
+ },
10
17
  ) => {
11
18
  const executionNumber = executionIndex + 1
12
19
  const description = ANSI.color(
@@ -16,12 +23,13 @@ export const formatExecuting = (
16
23
  const summary =
17
24
  executionIndex === 0
18
25
  ? ""
19
- : `(${createSummaryDetails({
26
+ : `(${createIntermediateSummary({
20
27
  executionCount: executionIndex,
21
28
  abortedCount,
22
29
  timedoutCount,
23
30
  erroredCount,
24
31
  completedCount,
32
+ memoryHeap,
25
33
  })})`
26
34
 
27
35
  return formatExecution({
@@ -45,6 +53,7 @@ export const formatExecutionResult = (
45
53
  timedoutCount,
46
54
  erroredCount,
47
55
  completedCount,
56
+ memoryHeap,
48
57
  },
49
58
  ) => {
50
59
  const executionNumber = executionIndex + 1
@@ -57,12 +66,13 @@ export const formatExecutionResult = (
57
66
  allocatedMs,
58
67
  })
59
68
 
60
- const summary = `(${createSummaryDetails({
69
+ const summary = `(${createIntermediateSummary({
61
70
  executionCount: executionNumber,
62
71
  abortedCount,
63
72
  timedoutCount,
64
73
  erroredCount,
65
74
  completedCount,
75
+ memoryHeap,
66
76
  })})`
67
77
 
68
78
  if (completedExecutionLogAbbreviation && status === "completed") {
@@ -0,0 +1,9 @@
1
+ import v8 from "node:v8"
2
+ import { runInNewContext } from "node:vm"
3
+
4
+ export const ensureGlobalGc = () => {
5
+ if (!global.gc) {
6
+ v8.setFlagsFromString("--expose_gc")
7
+ global.gc = runInNewContext("gc")
8
+ }
9
+ }
@@ -0,0 +1,10 @@
1
+ import { createRequire } from "module"
2
+
3
+ const require = createRequire(import.meta.url)
4
+
5
+ // https://github.com/visionmedia/bytes.js/
6
+ const bytes = require("bytes")
7
+
8
+ export const formatByte = (metricValue) => {
9
+ return bytes(metricValue, { decimalPlaces: 2, unitSeparator: " " })
10
+ }