@jsenv/core 27.0.0-alpha.22 → 27.0.0-alpha.25
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 +3 -4
- package/src/build/build.js +22 -10
- package/src/build/resync_ressource_hints.js +7 -22
- package/src/dev/start_dev_server.js +2 -0
- package/src/execute/execute.js +8 -1
- package/src/execute/run.js +2 -2
- package/src/execute/runtimes/browsers/from_playwright.js +34 -1
- package/src/execute/runtimes/node/controllable_file.mjs +26 -10
- package/src/execute/runtimes/node/node_execution_performance.js +67 -0
- package/src/execute/runtimes/node/node_process.js +2 -5
- package/src/omega/kitchen.js +1 -1
- package/src/omega/url_graph.js +10 -1
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js +9 -20
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_script_type_module_as_classic.js +152 -52
- package/src/plugins/transpilation/babel/helpers/babel_plugin_structure.js +6 -3
- package/src/plugins/transpilation/fetch_original_url_info.js +30 -0
- package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +62 -80
- package/src/plugins/transpilation/{as_js_classic/jsenv_plugin_top_level_await.js → jsenv_plugin_top_level_await.js} +0 -0
- package/src/plugins/transpilation/jsenv_plugin_transpilation.js +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/core",
|
|
3
|
-
"version": "27.0.0-alpha.
|
|
3
|
+
"version": "27.0.0-alpha.25",
|
|
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": {},
|
|
@@ -111,4 +110,4 @@
|
|
|
111
110
|
"redux": "4.1.2",
|
|
112
111
|
"rollup": "2.70.1"
|
|
113
112
|
}
|
|
114
|
-
}
|
|
113
|
+
}
|
package/src/build/build.js
CHANGED
|
@@ -349,10 +349,30 @@ ${Object.keys(rawGraph.urlInfos).join("\n")}`,
|
|
|
349
349
|
// - injecting "?as_js_classic" for the first time
|
|
350
350
|
// - injecting "?as_js_classic" because the parentUrl has it
|
|
351
351
|
if (reference.original) {
|
|
352
|
+
const referenceOriginalUrl = reference.original.url
|
|
353
|
+
let originalBuildUrl
|
|
354
|
+
if (urlIsInsideOf(referenceOriginalUrl, buildDirectoryUrl)) {
|
|
355
|
+
originalBuildUrl = referenceOriginalUrl
|
|
356
|
+
} else {
|
|
357
|
+
originalBuildUrl = Object.keys(rawUrls).find(
|
|
358
|
+
(key) => rawUrls[key] === referenceOriginalUrl,
|
|
359
|
+
)
|
|
360
|
+
}
|
|
361
|
+
let rawUrl
|
|
362
|
+
if (urlIsInsideOf(reference.url, buildDirectoryUrl)) {
|
|
363
|
+
// rawUrl = rawUrls[reference.url] || reference.url
|
|
364
|
+
const originalBuildUrl =
|
|
365
|
+
buildUrlRedirections[referenceOriginalUrl]
|
|
366
|
+
rawUrl = originalBuildUrl
|
|
367
|
+
? rawUrls[originalBuildUrl]
|
|
368
|
+
: reference.url
|
|
369
|
+
} else {
|
|
370
|
+
rawUrl = reference.url
|
|
371
|
+
}
|
|
352
372
|
// the url info do not exists yet (it will be created after this "normalize" hook)
|
|
353
373
|
// And the content will be generated when url is cooked by url graph loader.
|
|
354
374
|
// Here we just want to reserve an url for that file
|
|
355
|
-
const buildUrl = buildUrlsGenerator.generate(
|
|
375
|
+
const buildUrl = buildUrlsGenerator.generate(rawUrl, {
|
|
356
376
|
urlInfo: {
|
|
357
377
|
data: {
|
|
358
378
|
...reference.data,
|
|
@@ -364,15 +384,8 @@ ${Object.keys(rawGraph.urlInfos).join("\n")}`,
|
|
|
364
384
|
filename: reference.filename,
|
|
365
385
|
},
|
|
366
386
|
})
|
|
367
|
-
const originalUrl = reference.original.url
|
|
368
|
-
const originalBuildUrl = urlIsInsideOf(
|
|
369
|
-
reference.url,
|
|
370
|
-
buildDirectoryUrl,
|
|
371
|
-
)
|
|
372
|
-
? originalUrl
|
|
373
|
-
: Object.keys(rawUrls).find((key) => rawUrls[key] === originalUrl)
|
|
374
387
|
buildUrlRedirections[originalBuildUrl] = buildUrl
|
|
375
|
-
rawUrls[buildUrl] =
|
|
388
|
+
rawUrls[buildUrl] = rawUrl
|
|
376
389
|
return buildUrl
|
|
377
390
|
}
|
|
378
391
|
if (reference.isInline) {
|
|
@@ -811,7 +824,6 @@ ${Object.keys(finalGraph.urlInfos).join("\n")}`,
|
|
|
811
824
|
finalGraph,
|
|
812
825
|
rawUrls,
|
|
813
826
|
buildUrls,
|
|
814
|
-
buildUrlRedirections,
|
|
815
827
|
})
|
|
816
828
|
const cleanupActions = []
|
|
817
829
|
GRAPH.forEach(finalGraph, (urlInfo) => {
|
|
@@ -1,21 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Update <link rel="preload"> and friends after build (once we know everything)
|
|
3
|
+
*
|
|
4
|
+
* - Used to remove ressource hint targeting an url that is no longer used:
|
|
5
|
+
* - Happens because of import assertions transpilation (file is inlined into JS)
|
|
6
|
+
*/
|
|
7
|
+
|
|
1
8
|
import {
|
|
2
9
|
parseHtmlString,
|
|
3
10
|
visitHtmlAst,
|
|
4
11
|
stringifyHtmlAst,
|
|
5
12
|
getHtmlNodeAttributeByName,
|
|
6
|
-
assignHtmlNodeAttributes,
|
|
7
13
|
removeHtmlNode,
|
|
8
14
|
} from "@jsenv/utils/html_ast/html_ast.js"
|
|
9
15
|
|
|
10
16
|
import { GRAPH } from "./graph_utils.js"
|
|
11
17
|
|
|
12
|
-
// update ressource hint that where targeting a file that has changed during build
|
|
13
|
-
// (happens for import assertions and file modified by "?as_js_classic")
|
|
14
18
|
export const resyncRessourceHints = async ({
|
|
15
19
|
finalGraphKitchen,
|
|
16
20
|
finalGraph,
|
|
17
21
|
buildUrls,
|
|
18
|
-
buildUrlRedirections,
|
|
19
22
|
}) => {
|
|
20
23
|
const ressourceHintActions = []
|
|
21
24
|
GRAPH.forEach(finalGraph, (urlInfo) => {
|
|
@@ -40,24 +43,6 @@ export const resyncRessourceHints = async ({
|
|
|
40
43
|
removeHtmlNode(linkNode)
|
|
41
44
|
return
|
|
42
45
|
}
|
|
43
|
-
const buildUrlRedirected = buildUrlRedirections[buildUrl]
|
|
44
|
-
if (buildUrlRedirected) {
|
|
45
|
-
const urlInfoRedirected = finalGraph.getUrlInfo(buildUrlRedirected)
|
|
46
|
-
hrefAttribute.value = urlInfoRedirected.data.buildUrlSpecifier
|
|
47
|
-
|
|
48
|
-
if (
|
|
49
|
-
urlInfo.type === "js_module" &&
|
|
50
|
-
urlInfoRedirected.type === "js_classic"
|
|
51
|
-
) {
|
|
52
|
-
const relAttribute = getHtmlNodeAttributeByName(linkNode, "rel")
|
|
53
|
-
if (relAttribute && relAttribute.value === "modulepreload") {
|
|
54
|
-
assignHtmlNodeAttributes(linkNode, {
|
|
55
|
-
rel: "preload",
|
|
56
|
-
as: "script",
|
|
57
|
-
})
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
46
|
}
|
|
62
47
|
visitHtmlAst(htmlAst, (node) => {
|
|
63
48
|
if (node.nodeName !== "link") {
|
|
@@ -32,6 +32,7 @@ export const startDevServer = async ({
|
|
|
32
32
|
injectedGlobals,
|
|
33
33
|
nodeEsmResolution,
|
|
34
34
|
fileSystemMagicResolution,
|
|
35
|
+
transpilation,
|
|
35
36
|
autoreload = true,
|
|
36
37
|
explorerGroups = {
|
|
37
38
|
source: {
|
|
@@ -95,6 +96,7 @@ export const startDevServer = async ({
|
|
|
95
96
|
injectedGlobals,
|
|
96
97
|
nodeEsmResolution,
|
|
97
98
|
fileSystemMagicResolution,
|
|
99
|
+
transpilation,
|
|
98
100
|
autoreload,
|
|
99
101
|
}),
|
|
100
102
|
jsenvPluginExplorer({
|
package/src/execute/execute.js
CHANGED
|
@@ -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
|
})
|
package/src/execute/run.js
CHANGED
|
@@ -11,8 +11,7 @@ export const run = async ({
|
|
|
11
11
|
collectConsole = false,
|
|
12
12
|
collectCoverage = false,
|
|
13
13
|
coverageTempDirectoryUrl,
|
|
14
|
-
|
|
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
|
-
|
|
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
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
246
|
+
...value,
|
|
250
247
|
}
|
|
251
248
|
}
|
|
252
249
|
|
package/src/omega/kitchen.js
CHANGED
|
@@ -451,7 +451,7 @@ export const createKitchen = ({
|
|
|
451
451
|
currentUrlInfo !== newUrlInfo &&
|
|
452
452
|
currentUrlInfo.dependents.size === 0
|
|
453
453
|
) {
|
|
454
|
-
|
|
454
|
+
context.urlGraph.deleteUrlInfo(currentReference.url)
|
|
455
455
|
}
|
|
456
456
|
return [nextReference, newUrlInfo]
|
|
457
457
|
},
|
package/src/omega/url_graph.js
CHANGED
|
@@ -4,7 +4,16 @@ import { urlToRelativeUrl } from "@jsenv/filesystem"
|
|
|
4
4
|
export const createUrlGraph = () => {
|
|
5
5
|
const urlInfos = {}
|
|
6
6
|
const getUrlInfo = (url) => urlInfos[url]
|
|
7
|
-
const deleteUrlInfo = (url) =>
|
|
7
|
+
const deleteUrlInfo = (url) => {
|
|
8
|
+
const urlInfo = urlInfos[url]
|
|
9
|
+
if (urlInfo) {
|
|
10
|
+
delete urlInfos[url]
|
|
11
|
+
if (urlInfo.sourcemapReference) {
|
|
12
|
+
deleteUrlInfo(urlInfo.sourcemapReference.url)
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
8
17
|
const reuseOrCreateUrlInfo = (url) => {
|
|
9
18
|
const existingUrlInfo = urlInfos[url]
|
|
10
19
|
if (existingUrlInfo) return existingUrlInfo
|
|
@@ -15,15 +15,15 @@ import { createRequire } from "node:module"
|
|
|
15
15
|
import { readFileSync, urlToFilename } from "@jsenv/filesystem"
|
|
16
16
|
|
|
17
17
|
import { requireBabelPlugin } from "@jsenv/babel-plugins"
|
|
18
|
-
|
|
19
18
|
import { applyBabelPlugins } from "@jsenv/utils/js_ast/apply_babel_plugins.js"
|
|
20
19
|
import { injectQueryParams } from "@jsenv/utils/urls/url_utils.js"
|
|
21
20
|
import { createMagicSource } from "@jsenv/utils/sourcemap/magic_source.js"
|
|
22
21
|
import { composeTwoSourcemaps } from "@jsenv/utils/sourcemap/sourcemap_composition_v3.js"
|
|
22
|
+
|
|
23
|
+
import { fetchOriginalUrlInfo } from "../fetch_original_url_info.js"
|
|
23
24
|
import { babelPluginTransformImportMetaUrl } from "./helpers/babel_plugin_transform_import_meta_url.js"
|
|
24
25
|
import { jsenvPluginScriptTypeModuleAsClassic } from "./jsenv_plugin_script_type_module_as_classic.js"
|
|
25
26
|
import { jsenvPluginWorkersTypeModuleAsClassic } from "./jsenv_plugin_workers_type_module_as_classic.js"
|
|
26
|
-
import { jsenvPluginTopLevelAwait } from "./jsenv_plugin_top_level_await.js"
|
|
27
27
|
|
|
28
28
|
const require = createRequire(import.meta.url)
|
|
29
29
|
|
|
@@ -40,7 +40,6 @@ export const jsenvPluginAsJsClassic = ({ systemJsInjection }) => {
|
|
|
40
40
|
jsenvPluginWorkersTypeModuleAsClassic({
|
|
41
41
|
generateJsClassicFilename,
|
|
42
42
|
}),
|
|
43
|
-
jsenvPluginTopLevelAwait(),
|
|
44
43
|
]
|
|
45
44
|
}
|
|
46
45
|
|
|
@@ -72,28 +71,18 @@ const asJsClassic = ({ systemJsInjection, systemJsClientFileUrl }) => {
|
|
|
72
71
|
return urlTransformed
|
|
73
72
|
},
|
|
74
73
|
fetchUrlContent: async (urlInfo, context) => {
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
searchParams.delete("as_js_classic")
|
|
81
|
-
const originalUrl = urlObject.href
|
|
82
|
-
const originalReference = {
|
|
83
|
-
...(context.reference.original || context.reference),
|
|
74
|
+
const originalUrlInfo = await fetchOriginalUrlInfo({
|
|
75
|
+
urlInfo,
|
|
76
|
+
context,
|
|
77
|
+
searchParam: "as_js_classic",
|
|
84
78
|
// override the expectedType to "js_module"
|
|
85
79
|
// because when there is ?as_js_classic it means the underlying ressource
|
|
86
80
|
// is a js_module
|
|
87
81
|
expectedType: "js_module",
|
|
88
|
-
}
|
|
89
|
-
originalReference.url = originalUrl
|
|
90
|
-
const originalUrlInfo = context.urlGraph.reuseOrCreateUrlInfo(
|
|
91
|
-
originalReference.url,
|
|
92
|
-
)
|
|
93
|
-
await context.fetchUrlContent({
|
|
94
|
-
reference: originalReference,
|
|
95
|
-
urlInfo: originalUrlInfo,
|
|
96
82
|
})
|
|
83
|
+
if (!originalUrlInfo) {
|
|
84
|
+
return null
|
|
85
|
+
}
|
|
97
86
|
const isJsEntryPoint =
|
|
98
87
|
// in general html files are entry points
|
|
99
88
|
// but during build js can be sepcified as an entry point
|
package/src/plugins/transpilation/as_js_classic/jsenv_plugin_script_type_module_as_classic.js
CHANGED
|
@@ -2,7 +2,8 @@ import {
|
|
|
2
2
|
getHtmlNodeAttributeByName,
|
|
3
3
|
getHtmlNodeTextNode,
|
|
4
4
|
parseHtmlString,
|
|
5
|
-
|
|
5
|
+
removeHtmlNodeAttributeByName,
|
|
6
|
+
assignHtmlNodeAttributes,
|
|
6
7
|
stringifyHtmlAst,
|
|
7
8
|
visitHtmlAst,
|
|
8
9
|
htmlNodePosition,
|
|
@@ -30,51 +31,163 @@ export const jsenvPluginScriptTypeModuleAsClassic = ({
|
|
|
30
31
|
return null
|
|
31
32
|
}
|
|
32
33
|
const htmlAst = parseHtmlString(urlInfo.content)
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
const
|
|
34
|
+
const preloadAsScriptNodes = []
|
|
35
|
+
const modulePreloadNodes = []
|
|
36
|
+
const moduleScriptNodes = []
|
|
37
|
+
const classicScriptNodes = []
|
|
38
|
+
const visitLinkNodes = (node) => {
|
|
39
|
+
if (node.nodeName !== "link") {
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
const relAttribute = getHtmlNodeAttributeByName(node, "rel")
|
|
43
|
+
const rel = relAttribute ? relAttribute.value : undefined
|
|
44
|
+
if (rel === "modulepreload") {
|
|
45
|
+
modulePreloadNodes.push(node)
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
if (rel === "preload") {
|
|
49
|
+
const asAttribute = getHtmlNodeAttributeByName(node, "as")
|
|
50
|
+
const as = asAttribute ? asAttribute.value : undefined
|
|
51
|
+
if (as === "script") {
|
|
52
|
+
preloadAsScriptNodes.push(node)
|
|
53
|
+
}
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const visitScriptNodes = (node) => {
|
|
36
58
|
if (node.nodeName !== "script") {
|
|
37
59
|
return
|
|
38
60
|
}
|
|
39
61
|
const typeAttribute = getHtmlNodeAttributeByName(node, "type")
|
|
40
|
-
|
|
62
|
+
const type = typeAttribute ? typeAttribute.value : undefined
|
|
63
|
+
if (type === "module") {
|
|
64
|
+
moduleScriptNodes.push(node)
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
if (type === undefined || type === "text/javascript") {
|
|
68
|
+
classicScriptNodes.push(node)
|
|
41
69
|
return
|
|
42
70
|
}
|
|
43
|
-
|
|
71
|
+
}
|
|
72
|
+
visitHtmlAst(htmlAst, (node) => {
|
|
73
|
+
visitLinkNodes(node)
|
|
74
|
+
visitScriptNodes(node)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
const classicScriptUrls = []
|
|
78
|
+
const moduleScriptUrls = []
|
|
79
|
+
classicScriptNodes.forEach((classicScriptNode) => {
|
|
80
|
+
const srcAttribute = getHtmlNodeAttributeByName(
|
|
81
|
+
classicScriptNode,
|
|
82
|
+
"src",
|
|
83
|
+
)
|
|
84
|
+
if (srcAttribute) {
|
|
85
|
+
const url = new URL(srcAttribute.value, urlInfo.url).href
|
|
86
|
+
classicScriptUrls.push(url)
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
moduleScriptNodes.forEach((moduleScriptNode) => {
|
|
90
|
+
const srcAttribute = getHtmlNodeAttributeByName(
|
|
91
|
+
moduleScriptNode,
|
|
92
|
+
"src",
|
|
93
|
+
)
|
|
94
|
+
if (srcAttribute) {
|
|
95
|
+
const url = new URL(srcAttribute.value, urlInfo.url).href
|
|
96
|
+
moduleScriptUrls.push(url)
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
const jsModuleUrls = []
|
|
101
|
+
const getReferenceAsJsClassic = async (reference) => {
|
|
102
|
+
const [newReference, newUrlInfo] = context.referenceUtils.update(
|
|
103
|
+
reference,
|
|
104
|
+
{
|
|
105
|
+
expectedType: "js_classic",
|
|
106
|
+
specifier: injectQueryParamsIntoSpecifier(reference.specifier, {
|
|
107
|
+
as_js_classic: "",
|
|
108
|
+
}),
|
|
109
|
+
filename: generateJsClassicFilename(reference.url),
|
|
110
|
+
},
|
|
111
|
+
)
|
|
112
|
+
const jsModuleUrl = newUrlInfo.url
|
|
113
|
+
if (!jsModuleUrls.includes(jsModuleUrl)) {
|
|
114
|
+
jsModuleUrls.push(newUrlInfo.url)
|
|
115
|
+
// during dev it means js modules will be cooked before server sends the HTML
|
|
116
|
+
// it's ok because:
|
|
117
|
+
// - during dev script_type_module are supported (dev use a recent browser)
|
|
118
|
+
// - even if browser is not supported it still works it's jus a bit slower
|
|
119
|
+
// because it needs to decide if systemjs will be injected or not
|
|
120
|
+
await context.cook({
|
|
121
|
+
reference: newReference,
|
|
122
|
+
urlInfo: newUrlInfo,
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
return [newReference, newUrlInfo]
|
|
126
|
+
}
|
|
127
|
+
const actions = []
|
|
128
|
+
preloadAsScriptNodes.forEach((preloadAsScriptNode) => {
|
|
129
|
+
const hrefAttribute = getHtmlNodeAttributeByName(
|
|
130
|
+
preloadAsScriptNode,
|
|
131
|
+
"href",
|
|
132
|
+
)
|
|
133
|
+
const href = hrefAttribute.value
|
|
134
|
+
const url = new URL(href, urlInfo.url).href
|
|
135
|
+
const expectedScriptType = moduleScriptUrls.includes(url)
|
|
136
|
+
? "module"
|
|
137
|
+
: "classic"
|
|
138
|
+
// keep in mind:
|
|
139
|
+
// when the url is not referenced by a <script type="module">
|
|
140
|
+
// we assume we want to preload "classic" but it might not be the case
|
|
141
|
+
// but it's unlikely to happen and people should use "modulepreload" in that case anyway
|
|
142
|
+
if (expectedScriptType === "module") {
|
|
143
|
+
actions.push(async () => {
|
|
144
|
+
const [newReference] = await getReferenceAsJsClassic(
|
|
145
|
+
context.referenceUtils.findByGeneratedSpecifier(href),
|
|
146
|
+
)
|
|
147
|
+
assignHtmlNodeAttributes(preloadAsScriptNode, {
|
|
148
|
+
href: newReference.generatedSpecifier,
|
|
149
|
+
})
|
|
150
|
+
removeHtmlNodeAttributeByName(preloadAsScriptNode, "crossorigin")
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
modulePreloadNodes.forEach((modulePreloadNode) => {
|
|
155
|
+
const hrefAttribute = getHtmlNodeAttributeByName(
|
|
156
|
+
modulePreloadNode,
|
|
157
|
+
"href",
|
|
158
|
+
)
|
|
159
|
+
const href = hrefAttribute.value
|
|
160
|
+
actions.push(async () => {
|
|
161
|
+
const [newReference] = await getReferenceAsJsClassic(
|
|
162
|
+
context.referenceUtils.findByGeneratedSpecifier(href),
|
|
163
|
+
)
|
|
164
|
+
assignHtmlNodeAttributes(modulePreloadNode, {
|
|
165
|
+
rel: "preload",
|
|
166
|
+
as: "script",
|
|
167
|
+
href: newReference.generatedSpecifier,
|
|
168
|
+
})
|
|
169
|
+
})
|
|
170
|
+
})
|
|
171
|
+
moduleScriptNodes.forEach((moduleScriptNode) => {
|
|
172
|
+
const srcAttribute = getHtmlNodeAttributeByName(
|
|
173
|
+
moduleScriptNode,
|
|
174
|
+
"src",
|
|
175
|
+
)
|
|
44
176
|
if (srcAttribute) {
|
|
45
177
|
actions.push(async () => {
|
|
46
178
|
const specifier = srcAttribute.value
|
|
47
|
-
const
|
|
48
|
-
context.referenceUtils.findByGeneratedSpecifier(specifier)
|
|
49
|
-
const [newReference, newUrlInfo] = context.referenceUtils.update(
|
|
50
|
-
reference,
|
|
51
|
-
{
|
|
52
|
-
expectedType: "js_classic",
|
|
53
|
-
specifier: injectQueryParamsIntoSpecifier(specifier, {
|
|
54
|
-
as_js_classic: "",
|
|
55
|
-
}),
|
|
56
|
-
filename: generateJsClassicFilename(reference.url),
|
|
57
|
-
},
|
|
179
|
+
const [newReference] = await getReferenceAsJsClassic(
|
|
180
|
+
context.referenceUtils.findByGeneratedSpecifier(specifier),
|
|
58
181
|
)
|
|
59
|
-
|
|
182
|
+
removeHtmlNodeAttributeByName(moduleScriptNode, "type")
|
|
60
183
|
srcAttribute.value = newReference.generatedSpecifier
|
|
61
|
-
// during dev it means js modules will be cooked before server sends the HTML
|
|
62
|
-
// it's ok because:
|
|
63
|
-
// - during dev script_type_module are supported (dev use a recent browser)
|
|
64
|
-
// - even if browser is not supported it still works it's jus a bit slower
|
|
65
|
-
// because it needs to decide if systemjs will be injected or not
|
|
66
|
-
await context.cook({
|
|
67
|
-
reference: newReference,
|
|
68
|
-
urlInfo: newUrlInfo,
|
|
69
|
-
})
|
|
70
|
-
jsModuleUrlInfos.push(newUrlInfo)
|
|
71
184
|
})
|
|
72
185
|
return
|
|
73
186
|
}
|
|
74
|
-
const textNode = getHtmlNodeTextNode(
|
|
187
|
+
const textNode = getHtmlNodeTextNode(moduleScriptNode)
|
|
75
188
|
actions.push(async () => {
|
|
76
189
|
const { line, column, lineEnd, columnEnd, isOriginal } =
|
|
77
|
-
htmlNodePosition.readNodePosition(
|
|
190
|
+
htmlNodePosition.readNodePosition(moduleScriptNode, {
|
|
78
191
|
preferOriginal: true,
|
|
79
192
|
})
|
|
80
193
|
let inlineScriptUrl = generateInlineContentUrl({
|
|
@@ -86,7 +199,7 @@ export const jsenvPluginScriptTypeModuleAsClassic = ({
|
|
|
86
199
|
columnEnd,
|
|
87
200
|
})
|
|
88
201
|
const [inlineReference] = context.referenceUtils.foundInline({
|
|
89
|
-
node,
|
|
202
|
+
node: moduleScriptNode,
|
|
90
203
|
type: "script_src",
|
|
91
204
|
expectedType: "js_module",
|
|
92
205
|
// we remove 1 to the line because imagine the following html:
|
|
@@ -99,39 +212,26 @@ export const jsenvPluginScriptTypeModuleAsClassic = ({
|
|
|
99
212
|
contentType: "application/javascript",
|
|
100
213
|
content: textNode.value,
|
|
101
214
|
})
|
|
102
|
-
const [
|
|
215
|
+
const [, newUrlInfo] = await getReferenceAsJsClassic(
|
|
103
216
|
inlineReference,
|
|
104
|
-
{
|
|
105
|
-
expectedType: "js_classic",
|
|
106
|
-
specifier: injectQueryParamsIntoSpecifier(inlineScriptUrl, {
|
|
107
|
-
as_js_classic: "",
|
|
108
|
-
}),
|
|
109
|
-
filename: generateJsClassicFilename(inlineReference.url),
|
|
110
|
-
},
|
|
111
217
|
)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
urlInfo: newUrlInfo,
|
|
115
|
-
})
|
|
116
|
-
removeHtmlNodeAttribute(node, typeAttribute)
|
|
117
|
-
setHtmlNodeGeneratedText(node, {
|
|
218
|
+
removeHtmlNodeAttributeByName(moduleScriptNode, "type")
|
|
219
|
+
setHtmlNodeGeneratedText(moduleScriptNode, {
|
|
118
220
|
generatedText: newUrlInfo.content,
|
|
119
221
|
generatedBy: "jsenv:script_type_module_as_classic",
|
|
120
222
|
})
|
|
121
|
-
jsModuleUrlInfos.push(newUrlInfo)
|
|
122
223
|
})
|
|
123
|
-
}
|
|
124
|
-
visitHtmlAst(htmlAst, (node) => {
|
|
125
|
-
visitScriptTypeModule(node)
|
|
126
224
|
})
|
|
225
|
+
|
|
127
226
|
if (actions.length === 0) {
|
|
128
227
|
return null
|
|
129
228
|
}
|
|
130
229
|
await Promise.all(actions.map((action) => action()))
|
|
131
230
|
if (systemJsInjection) {
|
|
132
|
-
const needsSystemJs =
|
|
133
|
-
(
|
|
134
|
-
|
|
231
|
+
const needsSystemJs = jsModuleUrls.some(
|
|
232
|
+
(jsModuleUrl) =>
|
|
233
|
+
context.urlGraph.getUrlInfo(jsModuleUrl).data.jsClassicFormat ===
|
|
234
|
+
"system",
|
|
135
235
|
)
|
|
136
236
|
if (needsSystemJs) {
|
|
137
237
|
const [systemJsReference] = context.referenceUtils.inject({
|
|
@@ -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"] =
|
|
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(
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export const fetchOriginalUrlInfo = async ({
|
|
2
|
+
urlInfo,
|
|
3
|
+
context,
|
|
4
|
+
searchParam,
|
|
5
|
+
expectedType,
|
|
6
|
+
}) => {
|
|
7
|
+
const urlObject = new URL(urlInfo.url)
|
|
8
|
+
const { searchParams } = urlObject
|
|
9
|
+
if (!searchParams.has(searchParam)) {
|
|
10
|
+
return null
|
|
11
|
+
}
|
|
12
|
+
searchParams.delete(searchParam)
|
|
13
|
+
const originalUrl = urlObject.href
|
|
14
|
+
const originalReference = {
|
|
15
|
+
...(context.reference.original || context.reference),
|
|
16
|
+
expectedType,
|
|
17
|
+
}
|
|
18
|
+
originalReference.url = originalUrl
|
|
19
|
+
const originalUrlInfo = context.urlGraph.reuseOrCreateUrlInfo(
|
|
20
|
+
originalReference.url,
|
|
21
|
+
)
|
|
22
|
+
await context.fetchUrlContent({
|
|
23
|
+
reference: originalReference,
|
|
24
|
+
urlInfo: originalUrlInfo,
|
|
25
|
+
})
|
|
26
|
+
if (originalUrlInfo.dependents.size === 0) {
|
|
27
|
+
context.urlGraph.deleteUrlInfo(originalUrlInfo.url)
|
|
28
|
+
}
|
|
29
|
+
return originalUrlInfo
|
|
30
|
+
}
|
|
@@ -5,6 +5,7 @@ import { createMagicSource } from "@jsenv/utils/sourcemap/magic_source.js"
|
|
|
5
5
|
import { injectQueryParamsIntoSpecifier } from "@jsenv/utils/urls/url_utils.js"
|
|
6
6
|
import { JS_QUOTES } from "@jsenv/utils/string/js_quotes.js"
|
|
7
7
|
|
|
8
|
+
import { fetchOriginalUrlInfo } from "../fetch_original_url_info.js"
|
|
8
9
|
import { babelPluginMetadataImportAssertions } from "./helpers/babel_plugin_metadata_import_assertions.js"
|
|
9
10
|
|
|
10
11
|
export const jsenvPluginImportAssertions = () => {
|
|
@@ -95,125 +96,106 @@ const jsenvPluginAsModules = () => {
|
|
|
95
96
|
const asJsonModule = {
|
|
96
97
|
name: `jsenv:as_json_module`,
|
|
97
98
|
appliesDuring: "*",
|
|
98
|
-
fetchUrlContent: (urlInfo, context) => {
|
|
99
|
-
|
|
99
|
+
fetchUrlContent: async (urlInfo, context) => {
|
|
100
|
+
const originalUrlInfo = await fetchOriginalUrlInfo({
|
|
100
101
|
urlInfo,
|
|
101
102
|
context,
|
|
102
103
|
searchParam: "as_json_module",
|
|
103
|
-
|
|
104
|
-
// here we could `export default ${jsonText}`:
|
|
105
|
-
// but js engine are optimized to recognize JSON.parse
|
|
106
|
-
// and use a faster parsing strategy
|
|
107
|
-
return `export default JSON.parse(${JSON.stringify(
|
|
108
|
-
urlInfo.content.trim(),
|
|
109
|
-
)})`
|
|
110
|
-
},
|
|
104
|
+
expectedType: "json",
|
|
111
105
|
})
|
|
106
|
+
if (!originalUrlInfo) {
|
|
107
|
+
return null
|
|
108
|
+
}
|
|
109
|
+
const jsonText = JSON.stringify(originalUrlInfo.content.trim())
|
|
110
|
+
return {
|
|
111
|
+
type: "js_module",
|
|
112
|
+
contentType: "text/javascript",
|
|
113
|
+
// here we could `export default ${jsonText}`:
|
|
114
|
+
// but js engine are optimized to recognize JSON.parse
|
|
115
|
+
// and use a faster parsing strategy
|
|
116
|
+
content: `export default JSON.parse(${jsonText})`,
|
|
117
|
+
}
|
|
112
118
|
},
|
|
113
119
|
}
|
|
114
120
|
|
|
115
121
|
const asCssModule = {
|
|
116
122
|
name: `jsenv:as_css_module`,
|
|
117
123
|
appliesDuring: "*",
|
|
118
|
-
fetchUrlContent: (urlInfo, context) => {
|
|
119
|
-
|
|
124
|
+
fetchUrlContent: async (urlInfo, context) => {
|
|
125
|
+
const originalUrlInfo = await fetchOriginalUrlInfo({
|
|
120
126
|
urlInfo,
|
|
121
127
|
context,
|
|
122
128
|
searchParam: "as_css_module",
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
const inlineContent = new InlineContent(${cssText}, { type: "text/css" })
|
|
135
|
-
const stylesheet = new CSSStyleSheet()
|
|
136
|
-
stylesheet.replaceSync(inlineContent.text)
|
|
137
|
-
export default stylesheet`
|
|
138
|
-
},
|
|
129
|
+
expectedType: "css",
|
|
130
|
+
})
|
|
131
|
+
if (!originalUrlInfo) {
|
|
132
|
+
return null
|
|
133
|
+
}
|
|
134
|
+
const cssText = JS_QUOTES.escapeSpecialChars(originalUrlInfo.content, {
|
|
135
|
+
// If template string is choosen and runtime do not support template literals
|
|
136
|
+
// it's ok because "jsenv:new_inline_content" plugin executes after this one
|
|
137
|
+
// and convert template strings into raw strings
|
|
138
|
+
canUseTemplateString: true,
|
|
139
139
|
})
|
|
140
|
+
return {
|
|
141
|
+
type: "js_module",
|
|
142
|
+
contentType: "text/javascript",
|
|
143
|
+
content: `import { InlineContent } from ${JSON.stringify(
|
|
144
|
+
inlineContentClientFileUrl,
|
|
145
|
+
)}
|
|
146
|
+
|
|
147
|
+
const inlineContent = new InlineContent(${cssText}, { type: "text/css" })
|
|
148
|
+
const stylesheet = new CSSStyleSheet()
|
|
149
|
+
stylesheet.replaceSync(inlineContent.text)
|
|
150
|
+
export default stylesheet`,
|
|
151
|
+
}
|
|
140
152
|
},
|
|
141
153
|
}
|
|
142
154
|
|
|
143
155
|
const asTextModule = {
|
|
144
156
|
name: `jsenv:as_text_module`,
|
|
145
157
|
appliesDuring: "*",
|
|
146
|
-
fetchUrlContent: (urlInfo, context) => {
|
|
147
|
-
|
|
158
|
+
fetchUrlContent: async (urlInfo, context) => {
|
|
159
|
+
const originalUrlInfo = await fetchOriginalUrlInfo({
|
|
148
160
|
urlInfo,
|
|
149
161
|
context,
|
|
150
162
|
searchParam: "as_text_module",
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
const inlineContent = new InlineContent(${textPlain}, { type: "text/plain" })
|
|
163
|
-
export default inlineContent.text`
|
|
164
|
-
},
|
|
163
|
+
expectedType: "text",
|
|
164
|
+
})
|
|
165
|
+
if (!originalUrlInfo) {
|
|
166
|
+
return null
|
|
167
|
+
}
|
|
168
|
+
const textPlain = JS_QUOTES.escapeSpecialChars(urlInfo.content, {
|
|
169
|
+
// If template string is choosen and runtime do not support template literals
|
|
170
|
+
// it's ok because "jsenv:new_inline_content" plugin executes after this one
|
|
171
|
+
// and convert template strings into raw strings
|
|
172
|
+
canUseTemplateString: true,
|
|
165
173
|
})
|
|
174
|
+
return {
|
|
175
|
+
type: "js_module",
|
|
176
|
+
contentType: "text/javascript",
|
|
177
|
+
content: `import { InlineContent } from ${JSON.stringify(
|
|
178
|
+
inlineContentClientFileUrl,
|
|
179
|
+
)}
|
|
180
|
+
|
|
181
|
+
const inlineContent = new InlineContent(${textPlain}, { type: "text/plain" })
|
|
182
|
+
export default inlineContent.text`,
|
|
183
|
+
}
|
|
166
184
|
},
|
|
167
185
|
}
|
|
168
186
|
|
|
169
187
|
return [asJsonModule, asCssModule, asTextModule]
|
|
170
188
|
}
|
|
171
189
|
|
|
172
|
-
const fetchOriginalUrl = async ({
|
|
173
|
-
urlInfo,
|
|
174
|
-
context,
|
|
175
|
-
searchParam,
|
|
176
|
-
expectedType,
|
|
177
|
-
convertToJsModule,
|
|
178
|
-
}) => {
|
|
179
|
-
const urlObject = new URL(urlInfo.url)
|
|
180
|
-
const { searchParams } = urlObject
|
|
181
|
-
if (!searchParams.has(searchParam)) {
|
|
182
|
-
return null
|
|
183
|
-
}
|
|
184
|
-
searchParams.delete(searchParam)
|
|
185
|
-
const originalUrl = urlObject.href
|
|
186
|
-
const originalReference = {
|
|
187
|
-
...(context.reference.original || context.reference),
|
|
188
|
-
expectedType,
|
|
189
|
-
}
|
|
190
|
-
originalReference.url = originalUrl
|
|
191
|
-
const originalUrlInfo = context.urlGraph.reuseOrCreateUrlInfo(
|
|
192
|
-
originalReference.url,
|
|
193
|
-
)
|
|
194
|
-
await context.fetchUrlContent({
|
|
195
|
-
reference: originalReference,
|
|
196
|
-
urlInfo: originalUrlInfo,
|
|
197
|
-
})
|
|
198
|
-
return {
|
|
199
|
-
type: "js_module",
|
|
200
|
-
contentType: "text/javascript",
|
|
201
|
-
content: convertToJsModule(originalUrlInfo, context),
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
190
|
const importAsInfos = {
|
|
206
191
|
json: {
|
|
207
192
|
searchParam: "as_json_module",
|
|
208
|
-
expectedType: "json",
|
|
209
193
|
},
|
|
210
194
|
css: {
|
|
211
195
|
searchParam: "as_css_module",
|
|
212
|
-
expectedType: "css",
|
|
213
196
|
},
|
|
214
197
|
text: {
|
|
215
198
|
searchParam: "as_text_module",
|
|
216
|
-
expectedType: "text",
|
|
217
199
|
},
|
|
218
200
|
}
|
|
219
201
|
|
|
File without changes
|
|
@@ -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
|
}
|