@jsenv/core 23.1.4 → 23.3.0

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 (66) hide show
  1. package/dist/jsenv_browser_system.js +36 -99
  2. package/dist/jsenv_browser_system.js.map +12 -21
  3. package/dist/jsenv_compile_proxy.js +18 -82
  4. package/dist/jsenv_compile_proxy.js.map +11 -21
  5. package/dist/jsenv_exploring_index.js +127 -274
  6. package/dist/jsenv_exploring_index.js.map +76 -90
  7. package/dist/jsenv_exploring_redirector.js +21 -89
  8. package/dist/jsenv_exploring_redirector.js.map +13 -25
  9. package/dist/jsenv_toolbar.js +81 -149
  10. package/dist/jsenv_toolbar.js.map +50 -61
  11. package/dist/jsenv_toolbar_injector.js +56 -124
  12. package/dist/jsenv_toolbar_injector.js.map +27 -41
  13. package/package.json +15 -19
  14. package/src/buildProject.js +130 -122
  15. package/src/execute.js +47 -47
  16. package/src/executeTestPlan.js +107 -125
  17. package/src/importUsingChildProcess.js +2 -1
  18. package/src/internal/browser-launcher/executeHtmlFile.js +32 -12
  19. package/src/internal/browser-utils/fetch-browser.js +4 -29
  20. package/src/internal/browser-utils/fetchUsingXHR.js +5 -7
  21. package/src/internal/building/buildUsingRollup.js +59 -24
  22. package/src/internal/building/build_logs.js +7 -6
  23. package/src/internal/building/createJsenvRollupPlugin.js +10 -33
  24. package/src/internal/building/ressource_builder.js +3 -6
  25. package/src/internal/building/sourcemap_loader.js +4 -5
  26. package/src/internal/building/url_fetcher.js +2 -5
  27. package/src/internal/building/url_loader.js +3 -6
  28. package/src/internal/building/url_trace.js +3 -4
  29. package/src/internal/compiling/compileFile.js +1 -2
  30. package/src/internal/compiling/createCompiledFileService.js +12 -9
  31. package/src/internal/compiling/startCompileServer.js +85 -133
  32. package/src/internal/executing/coverage/generateCoverageJsonFile.js +20 -3
  33. package/src/internal/executing/coverage/relativeUrlToEmptyCoverage.js +18 -30
  34. package/src/internal/executing/coverage/reportToCoverage.js +44 -24
  35. package/src/internal/executing/coverage/v8CoverageFromNodeV8Directory.js +2 -15
  36. package/src/internal/executing/createSummaryLog.js +48 -37
  37. package/src/internal/executing/executeConcurrently.js +96 -52
  38. package/src/internal/executing/executePlan.js +93 -67
  39. package/src/internal/executing/executionLogs.js +31 -38
  40. package/src/internal/executing/execution_colors.js +9 -0
  41. package/src/internal/executing/generateExecutionSteps.js +3 -2
  42. package/src/internal/executing/launchAndExecute.js +207 -271
  43. package/src/internal/exploring/fetchExploringJson.js +3 -4
  44. package/src/internal/fetchUrl.js +6 -2
  45. package/src/internal/logs/msAsDuration.js +1 -1
  46. package/src/internal/node-launcher/createChildProcessOptions.js +4 -5
  47. package/src/internal/node-launcher/createControllableNodeProcess.js +120 -229
  48. package/src/internal/node-launcher/kill_process_tree.js +76 -0
  49. package/src/internal/node-launcher/nodeControllableFile.mjs +16 -10
  50. package/src/internal/{promise_track_race.js → promise_race.js} +2 -2
  51. package/src/internal/runtime/s.js +25 -24
  52. package/src/internal/toolbar/util/animation.js +3 -7
  53. package/src/internal/toolbar/util/fetching.js +1 -30
  54. package/src/jsenvServiceWorkerFinalizer.js +1 -2
  55. package/src/launchBrowser.js +146 -139
  56. package/src/launchNode.js +29 -17
  57. package/src/playwright_browser_versions.js +3 -3
  58. package/src/requireUsingChildProcess.js +2 -1
  59. package/src/startExploring.js +55 -74
  60. package/src/internal/createCallbackList.js +0 -21
  61. package/src/internal/executeJsenvAsyncFunction.js +0 -34
  62. package/src/internal/executing/logUtils.js +0 -30
  63. package/src/internal/executing/writeLog.js +0 -106
  64. package/src/internal/executing/writeLog.test-manual.js +0 -62
  65. package/src/internal/logs/log_style.js +0 -52
  66. package/src/internal/trackRessources.js +0 -23
@@ -1,8 +1,3 @@
1
- /* eslint-disable import/max-dependencies */
2
- import {
3
- createCancellationToken,
4
- composeCancellationToken,
5
- } from "@jsenv/cancellation"
6
1
  import {
7
2
  normalizeStructuredMetaMap,
8
3
  urlToFileSystemPath,
@@ -13,7 +8,6 @@ import {
13
8
  } from "@jsenv/filesystem"
14
9
  import { createLogger, createDetailedMessage } from "@jsenv/logger"
15
10
 
16
- import { executeJsenvAsyncFunction } from "./internal/executeJsenvAsyncFunction.js"
17
11
  import {
18
12
  assertProjectDirectoryUrl,
19
13
  assertProjectDirectoryExists,
@@ -26,11 +20,11 @@ import { generateCoverageTextLog } from "./internal/executing/coverage/generateC
26
20
  import { jsenvCoverageConfig } from "./jsenvCoverageConfig.js"
27
21
 
28
22
  export const executeTestPlan = async ({
23
+ signal = new AbortController().signal,
24
+ handleSIGINT = true,
29
25
  logLevel = "info",
30
26
  compileServerLogLevel = "warn",
31
27
  launchAndExecuteLogLevel = "warn",
32
- cancellationToken = createCancellationToken(),
33
- cancelOnSIGINT = false,
34
28
 
35
29
  projectDirectoryUrl,
36
30
  jsenvDirectoryRelativeUrl,
@@ -40,7 +34,7 @@ export const executeTestPlan = async ({
40
34
  testPlan,
41
35
  defaultMsAllocatedPerExecution,
42
36
 
43
- concurrencyLimit,
37
+ maxExecutionsInParallel,
44
38
 
45
39
  completedExecutionLogAbbreviation = false,
46
40
  completedExecutionLogMerging = false,
@@ -80,117 +74,107 @@ export const executeTestPlan = async ({
80
74
  customCompilers,
81
75
  jsenvDirectoryClean,
82
76
  }) => {
83
- const jsenvExecuteTestPlanFunction = async ({ jsenvCancellationToken }) => {
84
- cancellationToken = composeCancellationToken(
85
- cancellationToken,
86
- jsenvCancellationToken,
87
- )
88
-
89
- const logger = createLogger({ logLevel })
77
+ const logger = createLogger({ logLevel })
90
78
 
91
- cancellationToken.register((cancelError) => {
92
- if (cancelError.reason === "process SIGINT") {
93
- logger.info(`process SIGINT -> cancelling test execution`)
94
- }
95
- })
79
+ projectDirectoryUrl = assertProjectDirectoryUrl({ projectDirectoryUrl })
80
+ await assertProjectDirectoryExists({ projectDirectoryUrl })
96
81
 
97
- projectDirectoryUrl = assertProjectDirectoryUrl({ projectDirectoryUrl })
98
- await assertProjectDirectoryExists({ projectDirectoryUrl })
82
+ if (typeof testPlan !== "object") {
83
+ throw new Error(`testPlan must be an object, got ${testPlan}`)
84
+ }
99
85
 
100
- if (typeof testPlan !== "object") {
101
- throw new Error(`testPlan must be an object, got ${testPlan}`)
86
+ if (coverage) {
87
+ if (typeof coverageConfig !== "object") {
88
+ throw new TypeError(
89
+ `coverageConfig must be an object, got ${coverageConfig}`,
90
+ )
102
91
  }
103
-
104
- if (coverage) {
105
- if (typeof coverageConfig !== "object") {
106
- throw new TypeError(
107
- `coverageConfig must be an object, got ${coverageConfig}`,
108
- )
109
- }
110
- if (Object.keys(coverageConfig).length === 0) {
111
- logger.warn(
112
- `coverageConfig is an empty object. Nothing will be instrumented for coverage so your coverage will be empty`,
113
- )
114
- }
115
- if (!coverageAndExecutionAllowed) {
116
- const structuredMetaMapForExecute = normalizeStructuredMetaMap(
117
- {
118
- execute: testPlan,
119
- },
120
- "file:///",
121
- )
122
- const structuredMetaMapForCover = normalizeStructuredMetaMap(
123
- {
124
- cover: coverageConfig,
125
- },
126
- "file:///",
92
+ if (Object.keys(coverageConfig).length === 0) {
93
+ logger.warn(
94
+ `coverageConfig is an empty object. Nothing will be instrumented for coverage so your coverage will be empty`,
95
+ )
96
+ }
97
+ if (!coverageAndExecutionAllowed) {
98
+ const structuredMetaMapForExecute = normalizeStructuredMetaMap(
99
+ {
100
+ execute: testPlan,
101
+ },
102
+ "file:///",
103
+ )
104
+ const structuredMetaMapForCover = normalizeStructuredMetaMap(
105
+ {
106
+ cover: coverageConfig,
107
+ },
108
+ "file:///",
109
+ )
110
+ const patternsMatchingCoverAndExecute = Object.keys(
111
+ structuredMetaMapForExecute.execute,
112
+ ).filter((testPlanPattern) => {
113
+ return urlToMeta({
114
+ url: testPlanPattern,
115
+ structuredMetaMap: structuredMetaMapForCover,
116
+ }).cover
117
+ })
118
+
119
+ if (patternsMatchingCoverAndExecute.length) {
120
+ // I think it is an error, it would be strange, for a given file
121
+ // to be both covered and executed
122
+ throw new Error(
123
+ createDetailedMessage(`some file will be both covered and executed`, {
124
+ patterns: patternsMatchingCoverAndExecute,
125
+ }),
127
126
  )
128
- const patternsMatchingCoverAndExecute = Object.keys(
129
- structuredMetaMapForExecute.execute,
130
- ).filter((testPlanPattern) => {
131
- return urlToMeta({
132
- url: testPlanPattern,
133
- structuredMetaMap: structuredMetaMapForCover,
134
- }).cover
135
- })
136
-
137
- if (patternsMatchingCoverAndExecute.length) {
138
- // I think it is an error, it would be strange, for a given file
139
- // to be both covered and executed
140
- throw new Error(
141
- createDetailedMessage(
142
- `some file will be both covered and executed`,
143
- {
144
- patterns: patternsMatchingCoverAndExecute,
145
- },
146
- ),
147
- )
148
- }
149
127
  }
150
128
  }
129
+ }
151
130
 
152
- const result = await executePlan(testPlan, {
153
- logger,
154
- compileServerLogLevel,
155
- launchAndExecuteLogLevel,
156
- cancellationToken,
157
-
158
- projectDirectoryUrl,
159
- jsenvDirectoryRelativeUrl,
160
-
161
- importResolutionMethod,
162
- importDefaultExtension,
163
-
164
- defaultMsAllocatedPerExecution,
165
- concurrencyLimit,
166
- completedExecutionLogMerging,
167
- completedExecutionLogAbbreviation,
168
- logSummary,
169
- measureGlobalDuration,
170
-
171
- coverage,
172
- coverageConfig,
173
- coverageIncludeMissing,
174
- coverageForceIstanbul,
175
- coverageV8MergeConflictIsExpected,
176
-
177
- jsenvDirectoryClean,
178
- compileServerProtocol,
179
- compileServerPrivateKey,
180
- compileServerCertificate,
181
- compileServerIp,
182
- compileServerPort,
183
- compileServerCanReadFromFilesystem,
184
- compileServerCanWriteOnFilesystem,
185
- babelPluginMap,
186
- babelConfigFileUrl,
187
- customCompilers,
188
- })
189
-
190
- if (updateProcessExitCode && !executionIsPassed(result)) {
191
- process.exitCode = 1
192
- }
131
+ const result = await executePlan(testPlan, {
132
+ signal,
133
+ handleSIGINT,
134
+
135
+ logger,
136
+ compileServerLogLevel,
137
+ launchAndExecuteLogLevel,
138
+
139
+ projectDirectoryUrl,
140
+ jsenvDirectoryRelativeUrl,
141
+
142
+ importResolutionMethod,
143
+ importDefaultExtension,
144
+
145
+ defaultMsAllocatedPerExecution,
146
+ maxExecutionsInParallel,
147
+ completedExecutionLogMerging,
148
+ completedExecutionLogAbbreviation,
149
+ logSummary,
150
+ measureGlobalDuration,
151
+
152
+ coverage,
153
+ coverageConfig,
154
+ coverageIncludeMissing,
155
+ coverageForceIstanbul,
156
+ coverageV8MergeConflictIsExpected,
157
+
158
+ jsenvDirectoryClean,
159
+ compileServerProtocol,
160
+ compileServerPrivateKey,
161
+ compileServerCertificate,
162
+ compileServerIp,
163
+ compileServerPort,
164
+ compileServerCanReadFromFilesystem,
165
+ compileServerCanWriteOnFilesystem,
166
+ babelPluginMap,
167
+ babelConfigFileUrl,
168
+ customCompilers,
169
+ })
170
+
171
+ if (updateProcessExitCode && !executionIsPassed(result)) {
172
+ process.exitCode = 1
173
+ }
193
174
 
175
+ const planCoverage = result.planCoverage
176
+ // planCoverage can be null when execution is abortes
177
+ if (planCoverage) {
194
178
  const promises = []
195
179
  // keep this one first because it does ensureEmptyDirectory
196
180
  // and in case coverage json file gets written in the same directory
@@ -208,7 +192,7 @@ export const executeTestPlan = async ({
208
192
  )
209
193
  }
210
194
  promises.push(
211
- generateCoverageHtmlDirectory(result.planCoverage, {
195
+ generateCoverageHtmlDirectory(planCoverage, {
212
196
  projectDirectoryUrl,
213
197
  coverageHtmlDirectoryRelativeUrl,
214
198
  }),
@@ -219,11 +203,13 @@ export const executeTestPlan = async ({
219
203
  coverageJsonFileRelativeUrl,
220
204
  projectDirectoryUrl,
221
205
  )
222
- if (coverageJsonFileLog) {
223
- logger.info(`-> ${urlToFileSystemPath(coverageJsonFileUrl)}`)
224
- }
225
206
  promises.push(
226
- generateCoverageJsonFile(result.planCoverage, coverageJsonFileUrl),
207
+ generateCoverageJsonFile({
208
+ coverage: result.planCoverage,
209
+ coverageJsonFileUrl,
210
+ coverageJsonFileLog,
211
+ logger,
212
+ }),
227
213
  )
228
214
  }
229
215
  if (coverage && coverageTextLog) {
@@ -235,15 +221,11 @@ export const executeTestPlan = async ({
235
221
  )
236
222
  }
237
223
  await Promise.all(promises)
238
-
239
- return {
240
- testPlanSummary: result.planSummary,
241
- testPlanReport: result.planReport,
242
- testPlanCoverage: result.planCoverage,
243
- }
244
224
  }
245
225
 
246
- return executeJsenvAsyncFunction(jsenvExecuteTestPlanFunction, {
247
- cancelOnSIGINT,
248
- })
226
+ return {
227
+ testPlanSummary: result.planSummary,
228
+ testPlanReport: result.planReport,
229
+ testPlanCoverage: planCoverage,
230
+ }
249
231
  }
@@ -36,10 +36,11 @@ export const importUsingChildProcess = async (
36
36
 
37
37
  return {
38
38
  ...controllableNodeProcess,
39
- execute: async () => {
39
+ execute: async ({ signal }) => {
40
40
  try {
41
41
  const namespace =
42
42
  await controllableNodeProcess.requestActionOnChildProcess({
43
+ signal,
43
44
  actionType: "execute-using-import",
44
45
  actionParams: { fileUrl },
45
46
  })
@@ -14,7 +14,7 @@ import { escapeRegexpSpecialCharacters } from "../escapeRegexpSpecialCharacters.
14
14
  export const executeHtmlFile = async (
15
15
  fileRelativeUrl,
16
16
  {
17
- cancellationToken,
17
+ executeOperation,
18
18
  projectDirectoryUrl,
19
19
  compileServerOrigin,
20
20
  outDirectoryRelativeUrl,
@@ -26,6 +26,7 @@ export const executeHtmlFile = async (
26
26
  coverageConfig,
27
27
  coverageForceIstanbul,
28
28
  coveragePlaywrightAPIAvailable,
29
+ transformErrorHook,
29
30
  },
30
31
  ) => {
31
32
  const fileUrl = resolveUrl(fileRelativeUrl, projectDirectoryUrl)
@@ -45,11 +46,13 @@ export const executeHtmlFile = async (
45
46
  compileProxyProjectRelativeUrl,
46
47
  compileServerOrigin,
47
48
  )
49
+ executeOperation.throwIfAborted()
48
50
  await page.goto(compileProxyClientUrl)
49
51
 
50
52
  const coverageHandledFromOutside =
51
53
  coveragePlaywrightAPIAvailable && !coverageForceIstanbul
52
54
 
55
+ executeOperation.throwIfAborted()
53
56
  const browserRuntimeFeaturesReport = await page.evaluate(
54
57
  /* istanbul ignore next */
55
58
  ({ coverageHandledFromOutside }) => {
@@ -65,6 +68,7 @@ export const executeHtmlFile = async (
65
68
  try {
66
69
  let executionResult
67
70
  const { canAvoidCompilation, compileId } = browserRuntimeFeaturesReport
71
+ executeOperation.throwIfAborted()
68
72
  if (canAvoidCompilation) {
69
73
  executionResult = await executeSource({
70
74
  projectDirectoryUrl,
@@ -73,6 +77,7 @@ export const executeHtmlFile = async (
73
77
  page,
74
78
  collectCoverage,
75
79
  coverageConfig,
80
+ transformErrorHook,
76
81
  })
77
82
  } else {
78
83
  executionResult = await executeCompiledVersion({
@@ -83,6 +88,7 @@ export const executeHtmlFile = async (
83
88
  outDirectoryRelativeUrl,
84
89
  compileId,
85
90
  collectCoverage,
91
+ transformErrorHook,
86
92
  })
87
93
  }
88
94
 
@@ -114,19 +120,27 @@ export const executeHtmlFile = async (
114
120
  }
115
121
 
116
122
  return executionResult
117
- } catch (e) {
118
- // if browser is closed due to cancellation
123
+ } catch (error) {
124
+ // if browser is closed due to abort
119
125
  // before it is able to finish evaluate we can safely ignore
120
- // and rethrow with current cancelError
121
- if (
122
- e.message.match(/^Protocol error \(.*?\): Target closed/) &&
123
- cancellationToken.cancellationRequested
124
- ) {
125
- cancellationToken.throwIfRequested()
126
+ // and rethrow with current abort error
127
+ if (executeOperation.signal.aborted && isBrowserClosedError(error)) {
128
+ executeOperation.throwIfAborted()
126
129
  }
130
+ throw error
131
+ }
132
+ }
133
+
134
+ const isBrowserClosedError = (error) => {
135
+ if (error.message.match(/browserContext.newPage: Browser closed/)) {
136
+ return true
137
+ }
127
138
 
128
- throw e
139
+ if (error.message.match(/^Protocol error \(.*?\): Target closed/)) {
140
+ return true
129
141
  }
142
+
143
+ return false
130
144
  }
131
145
 
132
146
  const executeSource = async ({
@@ -136,6 +150,7 @@ const executeSource = async ({
136
150
  page,
137
151
  collectCoverage,
138
152
  coverageConfig,
153
+ transformErrorHook,
139
154
  }) => {
140
155
  let transformResult = (result) => result
141
156
 
@@ -196,6 +211,7 @@ const executeSource = async ({
196
211
  const error = evalException(exceptionSource, {
197
212
  projectDirectoryUrl,
198
213
  compileServerOrigin,
214
+ transformErrorHook,
199
215
  })
200
216
  return transformResult({
201
217
  status: "errored",
@@ -218,6 +234,7 @@ const executeCompiledVersion = async ({
218
234
  outDirectoryRelativeUrl,
219
235
  compileId,
220
236
  collectCoverage,
237
+ transformErrorHook,
221
238
  }) => {
222
239
  let transformResult = (result) => result
223
240
  if (collectCoverage) {
@@ -264,6 +281,7 @@ const executeCompiledVersion = async ({
264
281
  const error = evalException(exceptionSource, {
265
282
  projectDirectoryUrl,
266
283
  compileServerOrigin,
284
+ transformErrorHook,
267
285
  })
268
286
  return transformResult({
269
287
  status: "errored",
@@ -292,9 +310,9 @@ const generateCoverageForPage = (fileExecutionResultMap) => {
292
310
 
293
311
  const evalException = (
294
312
  exceptionSource,
295
- { projectDirectoryUrl, compileServerOrigin },
313
+ { projectDirectoryUrl, compileServerOrigin, transformErrorHook },
296
314
  ) => {
297
- const error = evalSource(exceptionSource)
315
+ let error = evalSource(exceptionSource)
298
316
 
299
317
  if (error && error instanceof Error) {
300
318
  const remoteRootRegexp = new RegExp(
@@ -303,6 +321,8 @@ const evalException = (
303
321
  )
304
322
  error.stack = error.stack.replace(remoteRootRegexp, projectDirectoryUrl)
305
323
  error.message = error.message.replace(remoteRootRegexp, projectDirectoryUrl)
324
+
325
+ error = transformErrorHook(error)
306
326
  }
307
327
 
308
328
  return error
@@ -1,36 +1,11 @@
1
- import { createCancellationToken } from "@jsenv/cancellation/main.browser.js"
2
1
  import { fetchUsingXHR } from "./fetchUsingXHR.js"
3
2
 
4
- const fetchNative = async (
5
- url,
6
- {
7
- cancellationToken = createCancellationToken(),
8
- mode = "cors",
9
- ...options
10
- } = {},
11
- ) => {
12
- const abortController = new AbortController()
13
-
14
- let cancelError
15
- cancellationToken.register((reason) => {
16
- cancelError = reason
17
- abortController.abort(reason)
3
+ const fetchNative = async (url, { mode = "cors", ...options } = {}) => {
4
+ const response = await window.fetch(url, {
5
+ mode,
6
+ ...options,
18
7
  })
19
8
 
20
- let response
21
- try {
22
- response = await window.fetch(url, {
23
- signal: abortController.signal,
24
- mode,
25
- ...options,
26
- })
27
- } catch (e) {
28
- if (cancelError && e.name === "AbortError") {
29
- throw cancelError
30
- }
31
- throw e
32
- }
33
-
34
9
  return {
35
10
  url: response.url,
36
11
  status: response.status,
@@ -1,13 +1,9 @@
1
- import { createCancellationToken } from "@jsenv/cancellation/main.browser.js"
2
1
  import { createDetailedMessage } from "@jsenv/logger"
3
- // ideally we should do some window.fetch detection (ensuring it has cancellation) and accordingly
4
- // fallback to this polyfill (or even use an existing polyfill would be better)
5
- // https://github.com/github/fetch/blob/master/fetch.js
6
2
 
7
3
  export const fetchUsingXHR = async (
8
4
  url,
9
5
  {
10
- cancellationToken = createCancellationToken(),
6
+ signal,
11
7
  method = "GET",
12
8
  credentials = "same-origin",
13
9
  headers = {},
@@ -52,9 +48,11 @@ export const fetchUsingXHR = async (
52
48
  bodyPromise.resolve()
53
49
  }
54
50
 
55
- cancellationToken.register((cancelError) => {
51
+ signal.addEventListener("abort", () => {
56
52
  xhr.abort()
57
- failure(cancelError)
53
+ const abortError = new Error("aborted")
54
+ abortError.name = "AbortError"
55
+ failure(abortError)
58
56
  })
59
57
 
60
58
  xhr.onreadystatechange = () => {
@@ -1,9 +1,10 @@
1
- import { createOperation } from "@jsenv/cancellation"
2
1
  import {
3
2
  urlToFileSystemPath,
4
3
  ensureEmptyDirectory,
5
4
  readFile,
6
5
  urlToRelativeUrl,
6
+ writeFile,
7
+ resolveUrl,
7
8
  } from "@jsenv/filesystem"
8
9
  import { createDetailedMessage } from "@jsenv/logger"
9
10
 
@@ -17,7 +18,7 @@ import { createRuntimeCompat } from "@jsenv/core/src/internal/generateGroupMap/r
17
18
  import { createJsenvRollupPlugin } from "./createJsenvRollupPlugin.js"
18
19
 
19
20
  export const buildUsingRollup = async ({
20
- cancellationToken,
21
+ buildOperation,
21
22
  logger,
22
23
 
23
24
  projectDirectoryUrl,
@@ -101,7 +102,7 @@ export const buildUsingRollup = async ({
101
102
  asOriginalUrl,
102
103
  asProjectUrl,
103
104
  } = await createJsenvRollupPlugin({
104
- cancellationToken,
105
+ buildOperation,
105
106
  logger,
106
107
 
107
108
  projectDirectoryUrl,
@@ -109,9 +110,6 @@ export const buildUsingRollup = async ({
109
110
  compileServerOrigin,
110
111
  compileDirectoryRelativeUrl,
111
112
  buildDirectoryUrl,
112
- assetManifestFile,
113
- assetManifestFileRelativeUrl,
114
- writeOnFileSystem,
115
113
 
116
114
  format,
117
115
  systemJsUrl,
@@ -142,7 +140,7 @@ export const buildUsingRollup = async ({
142
140
 
143
141
  try {
144
142
  await useRollup({
145
- cancellationToken,
143
+ buildOperation,
146
144
  logger,
147
145
 
148
146
  jsenvRollupPlugin,
@@ -189,9 +187,41 @@ export const buildUsingRollup = async ({
189
187
  throw e
190
188
  }
191
189
 
192
- const jsenvBuild = getResult()
190
+ const {
191
+ rollupBuild,
192
+ urlResponseBodyMap,
193
+ buildMappings,
194
+ buildManifest,
195
+ buildImportMap,
196
+ buildFileContents,
197
+ buildInlineFileContents,
198
+ buildStats,
199
+ } = getResult()
193
200
 
194
201
  if (writeOnFileSystem) {
202
+ if (buildDirectoryClean) {
203
+ await ensureEmptyDirectory(buildDirectoryUrl)
204
+ }
205
+
206
+ if (assetManifestFile) {
207
+ const assetManifestFileUrl = resolveUrl(
208
+ assetManifestFileRelativeUrl,
209
+ buildDirectoryUrl,
210
+ )
211
+ await writeFile(
212
+ assetManifestFileUrl,
213
+ JSON.stringify(buildManifest, null, " "),
214
+ )
215
+ }
216
+
217
+ const buildRelativeUrls = Object.keys(buildFileContents)
218
+ await Promise.all(
219
+ buildRelativeUrls.map(async (buildRelativeUrl) => {
220
+ const fileBuildUrl = resolveUrl(buildRelativeUrl, buildDirectoryUrl)
221
+ await writeFile(fileBuildUrl, buildFileContents[buildRelativeUrl])
222
+ }),
223
+ )
224
+
195
225
  await Promise.all(
196
226
  Object.keys(serviceWorkers).map(
197
227
  async (serviceWorkerProjectRelativeUrl) => {
@@ -203,7 +233,9 @@ export const buildUsingRollup = async ({
203
233
  serviceWorkerProjectRelativeUrl,
204
234
  serviceWorkerBuildRelativeUrl,
205
235
  serviceWorkerTransformer: (code) =>
206
- serviceWorkerFinalizer(code, jsenvBuild, {
236
+ serviceWorkerFinalizer(code, {
237
+ buildManifest,
238
+ rollupBuild,
207
239
  lineBreakNormalization,
208
240
  }),
209
241
 
@@ -214,11 +246,20 @@ export const buildUsingRollup = async ({
214
246
  )
215
247
  }
216
248
 
217
- return jsenvBuild
249
+ return {
250
+ rollupBuild,
251
+ urlResponseBodyMap,
252
+ buildMappings,
253
+ buildManifest,
254
+ buildImportMap,
255
+ buildFileContents,
256
+ buildInlineFileContents,
257
+ buildStats,
258
+ }
218
259
  }
219
260
 
220
261
  const useRollup = async ({
221
- cancellationToken,
262
+ buildOperation,
222
263
  logger,
223
264
  jsenvRollupPlugin,
224
265
  format,
@@ -228,9 +269,9 @@ const useRollup = async ({
228
269
  preserveEntrySignatures,
229
270
  // jsConcatenation,
230
271
  buildDirectoryUrl,
231
- buildDirectoryClean,
232
272
  asOriginalUrl,
233
273
  }) => {
274
+ buildOperation.throwIfAborted()
234
275
  const { rollup } = await import("rollup")
235
276
  const { importAssertions } = await import("acorn-import-assertions")
236
277
 
@@ -308,19 +349,13 @@ const useRollup = async ({
308
349
  : {}),
309
350
  }
310
351
 
311
- const rollupReturnValue = await createOperation({
312
- cancellationToken,
313
- start: () => rollup(rollupInputOptions),
314
- })
352
+ buildOperation.throwIfAborted()
353
+ const rollupReturnValue = await rollup(rollupInputOptions)
315
354
 
316
- if (buildDirectoryClean) {
317
- await ensureEmptyDirectory(buildDirectoryUrl)
318
- }
319
-
320
- const rollupOutputArray = await createOperation({
321
- cancellationToken,
322
- start: () => rollupReturnValue.generate(rollupOutputOptions),
323
- })
355
+ buildOperation.throwIfAborted()
356
+ const rollupOutputArray = await rollupReturnValue.generate(
357
+ rollupOutputOptions,
358
+ )
324
359
 
325
360
  return rollupOutputArray
326
361
  }