@jsenv/core 27.0.0-alpha.21 → 27.0.0-alpha.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "27.0.0-alpha.21",
3
+ "version": "27.0.0-alpha.24",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -11,8 +11,7 @@
11
11
  "node": ">=16.13.0"
12
12
  },
13
13
  "publishConfig": {
14
- "access": "public",
15
- "registry": "https://registry.npmjs.org"
14
+ "access": "public"
16
15
  },
17
16
  "type": "module",
18
17
  "imports": {},
@@ -67,7 +66,7 @@
67
66
  "@jsenv/node-esm-resolution": "0.0.4",
68
67
  "@jsenv/server": "12.6.1",
69
68
  "@jsenv/uneval": "1.6.0",
70
- "@jsenv/utils": "1.4.0",
69
+ "@jsenv/utils": "1.4.1",
71
70
  "construct-style-sheets-polyfill": "3.1.0",
72
71
  "cssnano": "5.1.7",
73
72
  "cssnano-preset-default": "5.2.7",
@@ -111,4 +110,4 @@
111
110
  "redux": "4.1.2",
112
111
  "rollup": "2.70.1"
113
112
  }
114
- }
113
+ }
@@ -21,12 +21,11 @@ import {
21
21
  pluginCORS,
22
22
  fetchFileSystem,
23
23
  } from "@jsenv/server"
24
- import { Abort, raceProcessTeardownEvents } from "@jsenv/abort"
25
24
  import { createLogger } from "@jsenv/logger"
26
25
 
26
+ import { initProcessAutorestart } from "@jsenv/utils/file_watcher/process_auto_restart.js"
27
27
  import { createTaskLog } from "@jsenv/utils/logs/task_log.js"
28
28
  import { watchFiles } from "@jsenv/utils/file_watcher/file_watcher.js"
29
- import { setupFileRestart } from "@jsenv/utils/file_watcher/file_restart.js"
30
29
  import { executeCommand } from "@jsenv/utils/command/command.js"
31
30
 
32
31
  export const startBuildServer = async ({
@@ -34,155 +33,164 @@ export const startBuildServer = async ({
34
33
  handleSIGINT = true,
35
34
  logLevel,
36
35
  buildCommandLogLevel = "warn",
37
- protocol,
36
+ protocol = "http",
38
37
  http2,
39
38
  certificate,
40
39
  privateKey,
41
40
  listenAnyIp,
42
41
  ip,
43
- port,
42
+ port = 9779,
44
43
 
45
44
  rootDirectoryUrl,
46
45
  buildDirectoryUrl,
47
46
  buildCommand,
47
+ mainBuildFile,
48
48
  watchedFilePatterns,
49
49
  cooldownBetweenFileEvents,
50
50
  autorestart,
51
51
  }) => {
52
- const operation = Abort.startOperation()
53
- operation.addAbortSignal(signal)
54
- if (handleSIGINT) {
55
- operation.addAbortSource((abort) => {
56
- return raceProcessTeardownEvents(
57
- {
58
- SIGINT: true,
59
- },
60
- abort,
61
- )
62
- })
52
+ const autorestartProcess = await initProcessAutorestart({
53
+ signal,
54
+ handleSIGINT,
55
+ ...(autorestart
56
+ ? {
57
+ enabled: true,
58
+ logLevel: autorestart.logLevel,
59
+ urlToRestart: autorestart.url,
60
+ urlsToWatch: [
61
+ ...(autorestart.urlsToWatch || []),
62
+ new URL("package.json", rootDirectoryUrl),
63
+ new URL("jsenv.config.mjs", rootDirectoryUrl),
64
+ ],
65
+ }
66
+ : {
67
+ enabled: false,
68
+ }),
69
+ })
70
+ if (autorestartProcess.isPrimary) {
71
+ return {
72
+ origin: `${protocol}://127.0.0.1:${port}`,
73
+ stop: () => {
74
+ autorestartProcess.stop()
75
+ },
76
+ }
63
77
  }
64
- setupFileRestart({
65
- signal: operation.signal,
66
- autorestart,
67
- injectedUrlsToWatch: [
68
- new URL("package.json", rootDirectoryUrl),
69
- new URL("jsenv.config.mjs", rootDirectoryUrl),
70
- ],
71
- job: async () => {
72
- const logger = createLogger({ logLevel })
78
+ signal = autorestartProcess.signal
79
+ const logger = createLogger({ logLevel })
73
80
 
74
- let buildPromise
75
- let abortController
76
- const runBuild = async () => {
77
- const buildTask = createTaskLog(logger, `execute build command`)
78
- abortController = new AbortController()
79
- operation.addAbortCallback(() => {
80
- abortController.abort()
81
- })
82
- buildPromise = executeCommand(buildCommand, {
83
- cwd: rootDirectoryUrl,
84
- logLevel: buildCommandLogLevel,
85
- signal: abortController.signal,
86
- })
87
- try {
88
- await buildPromise
89
- buildTask.done()
90
- } catch (e) {
91
- if (e.code === "ABORT_ERR") {
92
- buildTask.fail(`execute build command aborted`)
93
- } else {
94
- buildTask.fail()
95
- throw e
96
- }
97
- }
81
+ let buildPromise
82
+ let abortController
83
+ const runBuild = async () => {
84
+ const buildTask = createTaskLog(logger, `execute build command`)
85
+ buildPromise = executeCommand(buildCommand, {
86
+ cwd: rootDirectoryUrl,
87
+ logLevel: buildCommandLogLevel,
88
+ signal,
89
+ })
90
+ try {
91
+ await buildPromise
92
+ buildTask.done()
93
+ } catch (e) {
94
+ if (e.code === "ABORT_ERR") {
95
+ buildTask.fail(`execute build command aborted`)
96
+ } else {
97
+ buildTask.fail()
98
+ throw e
98
99
  }
100
+ }
101
+ }
99
102
 
100
- const startServerTask = createTaskLog(logger, "start build server")
101
- const server = await startServer({
102
- signal,
103
- stopOnExit: false,
104
- stopOnSIGINT: false,
105
- stopOnInternalError: false,
106
- keepProcessAlive: true,
107
- logLevel,
108
- startLog: false,
109
-
110
- protocol,
111
- http2,
112
- certificate,
113
- privateKey,
114
- listenAnyIp,
115
- ip,
116
- port,
117
- plugins: {
118
- ...pluginCORS({
119
- accessControlAllowRequestOrigin: true,
120
- accessControlAllowRequestMethod: true,
121
- accessControlAllowRequestHeaders: true,
122
- accessControlAllowedRequestHeaders: [
123
- ...jsenvAccessControlAllowedHeaders,
124
- "x-jsenv-execution-id",
125
- ],
126
- accessControlAllowCredentials: true,
127
- }),
128
- ...pluginServerTiming(),
129
- ...pluginRequestWaitingCheck({
130
- requestWaitingMs: 60 * 1000,
131
- }),
132
- },
133
- sendErrorDetails: true,
134
- requestToResponse: async (request) => {
135
- await buildPromise
136
- const urlIsVersioned = new URL(
137
- request.ressource,
138
- request.origin,
139
- ).searchParams.has("v")
103
+ const startServerTask = createTaskLog(logger, "start build server")
104
+ const server = await startServer({
105
+ signal,
106
+ stopOnExit: false,
107
+ stopOnSIGINT: false,
108
+ stopOnInternalError: false,
109
+ keepProcessAlive: true,
110
+ logLevel,
111
+ startLog: false,
140
112
 
141
- return fetchFileSystem(
142
- new URL(request.ressource.slice(1), buildDirectoryUrl),
143
- {
144
- headers: request.headers,
145
- cacheControl: urlIsVersioned
146
- ? `private,max-age=${SECONDS_IN_30_DAYS},immutable`
147
- : "private,max-age=0,must-revalidate",
148
- etagEnabled: true,
149
- compressionEnabled: !request.pathname.endsWith(".mp4"),
150
- rootDirectoryUrl: buildDirectoryUrl,
151
- canReadDirectory: true,
152
- },
153
- )
113
+ protocol,
114
+ http2,
115
+ certificate,
116
+ privateKey,
117
+ listenAnyIp,
118
+ ip,
119
+ port,
120
+ plugins: {
121
+ ...pluginCORS({
122
+ accessControlAllowRequestOrigin: true,
123
+ accessControlAllowRequestMethod: true,
124
+ accessControlAllowRequestHeaders: true,
125
+ accessControlAllowedRequestHeaders: [
126
+ ...jsenvAccessControlAllowedHeaders,
127
+ "x-jsenv-execution-id",
128
+ ],
129
+ accessControlAllowCredentials: true,
130
+ }),
131
+ ...pluginServerTiming(),
132
+ ...pluginRequestWaitingCheck({
133
+ requestWaitingMs: 60 * 1000,
134
+ }),
135
+ },
136
+ sendErrorDetails: true,
137
+ requestToResponse: async (request) => {
138
+ await buildPromise
139
+ const urlIsVersioned = new URL(
140
+ request.ressource,
141
+ request.origin,
142
+ ).searchParams.has("v")
143
+ if (mainBuildFile && request.ressource === "/") {
144
+ request = {
145
+ ...request,
146
+ ressource: `/${mainBuildFile}`,
147
+ }
148
+ }
149
+ return fetchFileSystem(
150
+ new URL(request.ressource.slice(1), buildDirectoryUrl),
151
+ {
152
+ headers: request.headers,
153
+ cacheControl: urlIsVersioned
154
+ ? `private,max-age=${SECONDS_IN_30_DAYS},immutable`
155
+ : "private,max-age=0,must-revalidate",
156
+ etagEnabled: true,
157
+ compressionEnabled: !request.pathname.endsWith(".mp4"),
158
+ rootDirectoryUrl: buildDirectoryUrl,
159
+ canReadDirectory: true,
154
160
  },
155
- })
156
- startServerTask.done()
157
- logger.info(``)
158
- Object.keys(server.origins).forEach((key) => {
159
- logger.info(`- ${server.origins[key]}`)
160
- })
161
- logger.info(``)
161
+ )
162
+ },
163
+ })
164
+ startServerTask.done()
165
+ logger.info(``)
166
+ Object.keys(server.origins).forEach((key) => {
167
+ logger.info(`- ${server.origins[key]}`)
168
+ })
169
+ logger.info(``)
162
170
 
163
- const unregisterDirectoryLifecyle = watchFiles({
164
- rootDirectoryUrl,
165
- watchedFilePatterns,
166
- cooldownBetweenFileEvents,
167
- fileChangeCallback: ({ url, event }) => {
168
- abortController.abort()
169
- // setTimeout is to ensure the abortController.abort() above
170
- // is properly taken into account so that logs about abort comes first
171
- // then logs about re-running the build happens
172
- setTimeout(() => {
173
- logger.info(
174
- `${url.slice(rootDirectoryUrl.length)} ${event} -> rebuild`,
175
- )
176
- runBuild()
177
- })
178
- },
171
+ const unregisterDirectoryLifecyle = watchFiles({
172
+ rootDirectoryUrl,
173
+ watchedFilePatterns,
174
+ cooldownBetweenFileEvents,
175
+ fileChangeCallback: ({ url, event }) => {
176
+ abortController.abort()
177
+ // setTimeout is to ensure the abortController.abort() above
178
+ // is properly taken into account so that logs about abort comes first
179
+ // then logs about re-running the build happens
180
+ setTimeout(() => {
181
+ logger.info(`${url.slice(rootDirectoryUrl.length)} ${event} -> rebuild`)
182
+ runBuild()
179
183
  })
180
- operation.addAbortCallback(() => {
181
- unregisterDirectoryLifecyle()
182
- })
183
- runBuild()
184
184
  },
185
185
  })
186
+ signal.addEventListener("abort", () => {
187
+ unregisterDirectoryLifecyle()
188
+ })
189
+ runBuild()
190
+ return {
191
+ origin: server.origin,
192
+ stop: () => server.stop(),
193
+ }
186
194
  }
187
195
 
188
196
  const SECONDS_IN_30_DAYS = 60 * 60 * 24 * 30
@@ -1,6 +1,7 @@
1
1
  import { assertAndNormalizeDirectoryUrl } from "@jsenv/filesystem"
2
2
  import { createLogger } from "@jsenv/logger"
3
3
 
4
+ import { initProcessAutorestart } from "@jsenv/utils/file_watcher/process_auto_restart.js"
4
5
  import { createTaskLog } from "@jsenv/utils/logs/task_log.js"
5
6
  import { getCorePlugins } from "@jsenv/core/src/plugins/plugins.js"
6
7
  import { createUrlGraph } from "@jsenv/core/src/omega/url_graph.js"
@@ -12,9 +13,10 @@ import { jsenvPluginToolbar } from "./plugins/toolbar/jsenv_plugin_toolbar.js"
12
13
 
13
14
  export const startDevServer = async ({
14
15
  signal = new AbortController().signal,
16
+ handleSIGINT,
15
17
  logLevel,
16
- port,
17
- protocol,
18
+ port = 3456,
19
+ protocol = "http",
18
20
  listenAnyIp,
19
21
  // it's better to use http1 by default because it allows to get statusText in devtools
20
22
  // which gives valuable information when there is errors
@@ -30,6 +32,7 @@ export const startDevServer = async ({
30
32
  injectedGlobals,
31
33
  nodeEsmResolution,
32
34
  fileSystemMagicResolution,
35
+ transpilation,
33
36
  autoreload = true,
34
37
  explorerGroups = {
35
38
  source: {
@@ -41,11 +44,39 @@ export const startDevServer = async ({
41
44
  },
42
45
  },
43
46
  toolbar = false,
47
+ autorestart,
44
48
  }) => {
49
+ rootDirectoryUrl = assertAndNormalizeDirectoryUrl(rootDirectoryUrl)
50
+ const autorestartProcess = await initProcessAutorestart({
51
+ signal,
52
+ handleSIGINT,
53
+ ...(autorestart
54
+ ? {
55
+ enabled: true,
56
+ logLevel: autorestart.logLevel,
57
+ urlToRestart: autorestart.url,
58
+ urlsToWatch: [
59
+ ...(autorestart.urlsToWatch || []),
60
+ new URL("package.json", rootDirectoryUrl),
61
+ new URL("jsenv.config.mjs", rootDirectoryUrl),
62
+ ],
63
+ }
64
+ : {
65
+ enabled: false,
66
+ }),
67
+ })
68
+ if (autorestartProcess.isPrimary) {
69
+ return {
70
+ origin: `${protocol}://127.0.0.1:${port}`,
71
+ stop: () => {
72
+ autorestartProcess.stop()
73
+ },
74
+ }
75
+ }
76
+
45
77
  const logger = createLogger({ logLevel })
46
78
  const startServerTask = createTaskLog(logger, "start server")
47
79
 
48
- rootDirectoryUrl = assertAndNormalizeDirectoryUrl(rootDirectoryUrl)
49
80
  const urlGraph = createUrlGraph()
50
81
  const kitchen = createKitchen({
51
82
  signal,
@@ -65,6 +96,7 @@ export const startDevServer = async ({
65
96
  injectedGlobals,
66
97
  nodeEsmResolution,
67
98
  fileSystemMagicResolution,
99
+ transpilation,
68
100
  autoreload,
69
101
  }),
70
102
  jsenvPluginExplorer({
@@ -98,5 +130,8 @@ export const startDevServer = async ({
98
130
  kitchen.pluginController.callHooks("destroy")
99
131
  }
100
132
  })
101
- return server
133
+ return {
134
+ origin: server.origin,
135
+ stop: server.stop,
136
+ }
102
137
  }
@@ -23,6 +23,7 @@ export const execute = async ({
23
23
  collectConsole,
24
24
  collectCoverage,
25
25
  coverageTempDirectoryUrl,
26
+ collectPerformance = false,
26
27
  runtime,
27
28
  runtimeParams,
28
29
 
@@ -33,6 +34,7 @@ export const execute = async ({
33
34
  fileSystemMagicResolution,
34
35
  injectedGlobals,
35
36
  transpilation,
37
+ htmlSupervisor = true,
36
38
 
37
39
  port,
38
40
  protocol,
@@ -75,10 +77,14 @@ export const execute = async ({
75
77
  plugins: [
76
78
  ...plugins,
77
79
  ...getCorePlugins({
80
+ rootDirectoryUrl,
81
+ urlGraph,
78
82
  scenario,
83
+
84
+ htmlSupervisor,
85
+ injectedGlobals,
79
86
  nodeEsmResolution,
80
87
  fileSystemMagicResolution,
81
- injectedGlobals,
82
88
  transpilation,
83
89
  }),
84
90
  ],
@@ -120,6 +126,7 @@ export const execute = async ({
120
126
  collectConsole,
121
127
  collectCoverage,
122
128
  coverageTempDirectoryUrl,
129
+ collectPerformance,
123
130
  runtime,
124
131
  runtimeParams,
125
132
  })
@@ -11,8 +11,7 @@ export const run = async ({
11
11
  collectConsole = false,
12
12
  collectCoverage = false,
13
13
  coverageTempDirectoryUrl,
14
- // measurePerformance,
15
- // collectPerformance = false,
14
+ collectPerformance = false,
16
15
 
17
16
  runtime,
18
17
  runtimeParams,
@@ -117,6 +116,7 @@ export const run = async ({
117
116
  signal: runOperation.signal,
118
117
  logger,
119
118
  ...runtimeParams,
119
+ collectPerformance,
120
120
  keepRunning,
121
121
  stopSignal,
122
122
  onConsole: (log) => onConsoleRef.current(log),
@@ -35,7 +35,7 @@ export const createRuntimeFromPlaywright = ({
35
35
  server,
36
36
 
37
37
  // measurePerformance,
38
- // collectPerformance,
38
+ collectPerformance,
39
39
  collectCoverage = false,
40
40
  coverageForceIstanbul,
41
41
  urlShouldBeCovered,
@@ -167,6 +167,39 @@ export const createRuntimeFromPlaywright = ({
167
167
  return result
168
168
  })
169
169
  }
170
+
171
+ if (collectPerformance) {
172
+ resultTransformer = composeTransformer(
173
+ resultTransformer,
174
+ async (result) => {
175
+ const performance = await page.evaluate(
176
+ /* eslint-disable no-undef */
177
+ /* istanbul ignore next */
178
+ () => {
179
+ const { performance } = window
180
+ if (!performance) {
181
+ return null
182
+ }
183
+ const measures = {}
184
+ const measurePerfEntries = performance.getEntriesByType("measure")
185
+ measurePerfEntries.forEach((measurePerfEntry) => {
186
+ measures[measurePerfEntry.name] = measurePerfEntry.duration
187
+ })
188
+ return {
189
+ timeOrigin: performance.timeOrigin,
190
+ timing: performance.timing.toJSON(),
191
+ navigation: performance.navigation.toJSON(),
192
+ measures,
193
+ }
194
+ /* eslint-enable no-undef */
195
+ },
196
+ )
197
+ result.performance = performance
198
+ return result
199
+ },
200
+ )
201
+ }
202
+
170
203
  const fileClientUrl = new URL(fileRelativeUrl, `${server.origin}/`).href
171
204
 
172
205
  // https://github.com/GoogleChrome/puppeteer/blob/v1.4.0/docs/api.md#event-console
@@ -1,17 +1,33 @@
1
1
  import v8 from "node:v8"
2
2
  import { uneval } from "@jsenv/uneval"
3
+ import { startObservingPerformances } from "./node_execution_performance.js"
3
4
 
4
5
  const ACTIONS_AVAILABLE = {
5
- "execute-using-dynamic-import": async ({ fileUrl }) => {
6
- const namespace = await import(fileUrl)
7
- const namespaceResolved = {}
8
- await Promise.all([
9
- ...Object.keys(namespace).map(async (key) => {
10
- const value = await namespace[key]
11
- namespaceResolved[key] = value
12
- }),
13
- ])
14
- return namespaceResolved
6
+ "execute-using-dynamic-import": async ({ fileUrl, collectPerformance }) => {
7
+ const getNamespace = async () => {
8
+ const namespace = await import(fileUrl)
9
+ const namespaceResolved = {}
10
+ await Promise.all([
11
+ ...Object.keys(namespace).map(async (key) => {
12
+ const value = await namespace[key]
13
+ namespaceResolved[key] = value
14
+ }),
15
+ ])
16
+ return namespaceResolved
17
+ }
18
+ if (collectPerformance) {
19
+ const getPerformance = startObservingPerformances()
20
+ const namespace = await getNamespace()
21
+ const performance = await getPerformance()
22
+ return {
23
+ namespace,
24
+ performance,
25
+ }
26
+ }
27
+ const namespace = await getNamespace()
28
+ return {
29
+ namespace,
30
+ }
15
31
  },
16
32
  "execute-using-require": async ({ fileUrl }) => {
17
33
  const { createRequire } = await import("module")
@@ -0,0 +1,67 @@
1
+ import { PerformanceObserver, performance } from "node:perf_hooks"
2
+
3
+ export const startObservingPerformances = () => {
4
+ const measureEntries = []
5
+ // https://nodejs.org/dist/latest-v16.x/docs/api/perf_hooks.html
6
+ const perfObserver = new PerformanceObserver(
7
+ (
8
+ // https://nodejs.org/dist/latest-v16.x/docs/api/perf_hooks.html#perf_hooks_class_performanceobserverentrylist
9
+ list,
10
+ ) => {
11
+ const perfMeasureEntries = list.getEntriesByType("measure")
12
+ measureEntries.push(...perfMeasureEntries)
13
+ },
14
+ )
15
+ perfObserver.observe({
16
+ entryTypes: ["measure"],
17
+ })
18
+ return async () => {
19
+ // wait for node to call the performance observer
20
+ await new Promise((resolve) => {
21
+ setTimeout(resolve)
22
+ })
23
+ performance.clearMarks()
24
+ perfObserver.disconnect()
25
+ return {
26
+ ...readNodePerformance(),
27
+ measures: measuresFromMeasureEntries(measureEntries),
28
+ }
29
+ }
30
+ }
31
+
32
+ const readNodePerformance = () => {
33
+ const nodePerformance = {
34
+ nodeTiming: asPlainObject(performance.nodeTiming),
35
+ timeOrigin: performance.timeOrigin,
36
+ eventLoopUtilization: performance.eventLoopUtilization(),
37
+ }
38
+ return nodePerformance
39
+ }
40
+
41
+ // remove getters that cannot be stringified
42
+ const asPlainObject = (objectWithGetters) => {
43
+ const objectWithoutGetters = {}
44
+ Object.keys(objectWithGetters).forEach((key) => {
45
+ objectWithoutGetters[key] = objectWithGetters[key]
46
+ })
47
+ return objectWithoutGetters
48
+ }
49
+
50
+ const measuresFromMeasureEntries = (measureEntries) => {
51
+ const measures = {}
52
+ // Sort to ensure measures order is predictable
53
+ // It seems to be already predictable on Node 16+ but
54
+ // it's not the case on Node 14.
55
+ measureEntries.sort((a, b) => {
56
+ return a.startTime - b.startTime
57
+ })
58
+ measureEntries.forEach(
59
+ (
60
+ // https://nodejs.org/dist/latest-v16.x/docs/api/perf_hooks.html#perf_hooks_class_performanceentry
61
+ perfMeasureEntry,
62
+ ) => {
63
+ measures[perfMeasureEntry.name] = perfMeasureEntry.duration
64
+ },
65
+ )
66
+ return measures
67
+ }
@@ -35,10 +35,9 @@ nodeProcess.run = async ({
35
35
  stopSignal,
36
36
  onConsole,
37
37
 
38
- measurePerformance,
39
- collectPerformance,
40
38
  collectCoverage = false,
41
39
  coverageForceIstanbul,
40
+ collectPerformance,
42
41
 
43
42
  debugPort,
44
43
  debugMode,
@@ -191,9 +190,7 @@ nodeProcess.run = async ({
191
190
  actionType: "execute-using-dynamic-import",
192
191
  actionParams: {
193
192
  fileUrl: new URL(fileRelativeUrl, rootDirectoryUrl).href,
194
- measurePerformance,
195
193
  collectPerformance,
196
- collectCoverage,
197
194
  },
198
195
  })
199
196
  const winner = await winnerPromise
@@ -246,7 +243,7 @@ nodeProcess.run = async ({
246
243
  }
247
244
  return {
248
245
  status: "completed",
249
- namespace: value,
246
+ ...value,
250
247
  }
251
248
  }
252
249
 
@@ -670,9 +670,11 @@ const applyReferenceEffectsOnUrlInfo = (reference, urlInfo, context) => {
670
670
  }
671
671
  urlInfo.contentType = reference.contentType
672
672
  urlInfo.originalContent =
673
- urlInfo.originalContent === undefined
674
- ? reference.content
675
- : urlInfo.originalContent
673
+ context === "build"
674
+ ? urlInfo.originalContent === undefined
675
+ ? reference.content
676
+ : urlInfo.originalContent
677
+ : reference.content
676
678
  urlInfo.content = reference.content
677
679
  }
678
680
  if (isWebWorkerEntryPointReference(reference)) {
@@ -23,7 +23,6 @@ import { composeTwoSourcemaps } from "@jsenv/utils/sourcemap/sourcemap_compositi
23
23
  import { babelPluginTransformImportMetaUrl } from "./helpers/babel_plugin_transform_import_meta_url.js"
24
24
  import { jsenvPluginScriptTypeModuleAsClassic } from "./jsenv_plugin_script_type_module_as_classic.js"
25
25
  import { jsenvPluginWorkersTypeModuleAsClassic } from "./jsenv_plugin_workers_type_module_as_classic.js"
26
- import { jsenvPluginTopLevelAwait } from "./jsenv_plugin_top_level_await.js"
27
26
 
28
27
  const require = createRequire(import.meta.url)
29
28
 
@@ -40,7 +39,6 @@ export const jsenvPluginAsJsClassic = ({ systemJsInjection }) => {
40
39
  jsenvPluginWorkersTypeModuleAsClassic({
41
40
  generateJsClassicFilename,
42
41
  }),
43
- jsenvPluginTopLevelAwait(),
44
42
  ]
45
43
  }
46
44
 
@@ -31,9 +31,12 @@ export const getBaseBabelPluginStructure = ({ url, isSupported }) => {
31
31
  requireBabelPlugin("@babel/plugin-proposal-unicode-property-regex")
32
32
  }
33
33
  if (isBabelPluginNeeded("transform-async-to-promises")) {
34
- babelPluginStructure["transform-async-to-promises"] = requireBabelPlugin(
35
- "babel-plugin-transform-async-to-promises",
36
- )
34
+ babelPluginStructure["transform-async-to-promises"] = [
35
+ requireBabelPlugin("babel-plugin-transform-async-to-promises"),
36
+ {
37
+ topLevelAwait: "ignore", // will be handled by "jsenv:top_level_await" plugin
38
+ },
39
+ ]
37
40
  }
38
41
  if (isBabelPluginNeeded("transform-arrow-functions")) {
39
42
  babelPluginStructure["transform-arrow-functions"] = requireBabelPlugin(
@@ -11,6 +11,7 @@ import { jsenvPluginCssParcel } from "./css_parcel/jsenv_plugin_css_parcel.js"
11
11
  import { jsenvPluginImportAssertions } from "./import_assertions/jsenv_plugin_import_assertions.js"
12
12
  import { jsenvPluginAsJsClassic } from "./as_js_classic/jsenv_plugin_as_js_classic.js"
13
13
  import { jsenvPluginBabel } from "./babel/jsenv_plugin_babel.js"
14
+ import { jsenvPluginTopLevelAwait } from "./jsenv_plugin_top_level_await.js"
14
15
 
15
16
  export const jsenvPluginTranspilation = ({
16
17
  importAssertions = true,
@@ -35,6 +36,9 @@ export const jsenvPluginTranspilation = ({
35
36
  ...(jsModuleAsJsClassic
36
37
  ? [jsenvPluginAsJsClassic({ systemJsInjection })]
37
38
  : []),
39
+ // topLevelAwait must come after js_module_as_js_classic because it's related to the module format
40
+ // so we want to wait to know the module format before transforming things related to top level await
41
+ ...(topLevelAwait ? [jsenvPluginTopLevelAwait(topLevelAwait)] : []),
38
42
  ...(css ? [jsenvPluginCssParcel()] : []),
39
43
  ]
40
44
  }