@jsenv/core 25.0.0-alpha.4 → 25.1.1
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 +2 -2
- package/readme.md +25 -10
- package/src/executeTestPlan.js +11 -0
- package/src/internal/building/html/parseHtmlRessource.js +17 -23
- package/src/internal/building/js/parseJsRessource.js +1 -6
- package/src/internal/building/ressource_builder.js +8 -2
- package/src/internal/building/rollup_plugin_jsenv.js +3 -0
- package/src/internal/building/url_versioning.js +2 -2
- package/src/internal/compiling/compileHtml.js +15 -28
- package/src/internal/compiling/html_source_file_service.js +9 -10
- package/src/internal/compiling/jsenvCompilerForHtml.js +441 -209
- package/src/internal/compiling/startCompileServer.js +5 -2
- package/src/internal/jsenvCoreDirectoryUrl.js +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/core",
|
|
3
|
-
"version": "25.
|
|
3
|
+
"version": "25.1.1",
|
|
4
4
|
"description": "Tool to develop, test and build js projects",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"url": "https://github.com/jsenv/jsenv-core"
|
|
9
9
|
},
|
|
10
10
|
"engines": {
|
|
11
|
-
"node": ">=
|
|
11
|
+
"node": ">=16.13.0"
|
|
12
12
|
},
|
|
13
13
|
"publishConfig": {
|
|
14
14
|
"access": "public"
|
package/readme.md
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
# jsenv [](https://www.npmjs.com/package/@jsenv/core) [](https://github.com/jsenv/jsenv-core/actions?workflow=main) [](https://codecov.io/gh/jsenv/jsenv-core)
|
|
2
2
|
|
|
3
|
-
_@jsenv/core_ is a quick start pack to launch a js project.
|
|
3
|
+
_@jsenv/core_ is a quick start pack to launch a js project. It provides what you need from the beginning: develoment, testing and building all in one.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Jsenv integrates naturally with standard HTML, CSS and JS: you don't have to pick a JavaScript framework.
|
|
6
6
|
|
|
7
|
-
#
|
|
7
|
+
# Overview
|
|
8
|
+
|
|
9
|
+
This section demos 3 things jsenv provides:
|
|
10
|
+
|
|
11
|
+
1. A test runner
|
|
12
|
+
2. A dev server
|
|
13
|
+
3. A build script
|
|
14
|
+
|
|
15
|
+
Don't be fooled by the apparent simplicity of the following demos, jsenv can be used on more complex scenarios as well.
|
|
16
|
+
|
|
17
|
+
## Test runner overview
|
|
8
18
|
|
|
9
19
|
Let's assume you want to test `countDogs` exported by _animals.js_ file.
|
|
10
20
|
|
|
@@ -94,7 +104,7 @@ total duration: 1.2 seconds
|
|
|
94
104
|
|
|
95
105
|
To read more about testing in jsenv, check [jsenv test runner documentation](./docs/testing/readme.md#jsenv-test-runner).
|
|
96
106
|
|
|
97
|
-
|
|
107
|
+
## Dev server overview
|
|
98
108
|
|
|
99
109
|
You want to execute the following _main.html_ file in a browser.
|
|
100
110
|
|
|
@@ -155,7 +165,7 @@ Browser navigates to _main.html_ and execute the file. Hello world is displayed
|
|
|
155
165
|
|
|
156
166
|
To read more about jsenv dev server, check [jsenv dev server documentation](./docs/dev_server/readme.md#jsenv-dev-server).
|
|
157
167
|
|
|
158
|
-
|
|
168
|
+
## Build overview
|
|
159
169
|
|
|
160
170
|
Following the steps below turns a `main.html` into an optimized `dist/main.prod.html`.
|
|
161
171
|
Only the content of html files is shown below because the content of non-html files is trivial.
|
|
@@ -253,7 +263,7 @@ Jsenv was first created to write tests that could be executed in different runti
|
|
|
253
263
|
- A test runner to execute test files
|
|
254
264
|
- A build tool to optimize files for production
|
|
255
265
|
|
|
256
|
-
Jsenv relies on standard web features
|
|
266
|
+
Jsenv relies on **standard web features**. Each standard listed below is potentially supported natively by the browser. When browser supports all of them, jsenv will use source files without modification. Otherwise, the files are compiled to be executable in the browser.
|
|
257
267
|
|
|
258
268
|
- `<script type="module">`
|
|
259
269
|
- `<script type="importmap">`
|
|
@@ -266,7 +276,7 @@ Jsenv relies on standard web features. Each standard listed below is potentially
|
|
|
266
276
|
|
|
267
277
|
Amongst other use cases, the ease of use and flexibility of jsenv makes it a great tool to start and learn web development.
|
|
268
278
|
|
|
269
|
-
First because jsenv is a tool that was built to run raw js, html and css. It starts from the **simplest form of coding
|
|
279
|
+
First because jsenv is a tool that was built to run raw js, html and css. It starts from the **simplest form of coding**. If a browser can run your code, so can jsenv without configuration or things to learn. There is no magic that will bite you right away or later. Jsenv can be configured to add more stuff later, on demand.
|
|
270
280
|
|
|
271
281
|
Second because jsenv is compatible with the latest standards. Even some that are not yet mature in the js ecosystem, such as import maps. This will makes you at ease with technologies that will be part of the ecosystem once you are confortable with coding.
|
|
272
282
|
|
|
@@ -347,9 +357,12 @@ This file helps to see jsenv configuration quickly and share it between files. T
|
|
|
347
357
|
|
|
348
358
|
## babel.config.cjs
|
|
349
359
|
|
|
350
|
-
|
|
360
|
+
You need a babel config file when:
|
|
361
|
+
|
|
362
|
+
- Your code use non standard concepts. Examples: JSX, TypeScript.
|
|
363
|
+
- You need to be compatible with browsers where some features used by your codebase are not available. Examples: `async/await`, destructuring.
|
|
351
364
|
|
|
352
|
-
It's recommended to
|
|
365
|
+
It's recommended to start with the following _babel.config.cjs_
|
|
353
366
|
|
|
354
367
|
```js
|
|
355
368
|
/*
|
|
@@ -364,14 +377,16 @@ module.exports = {
|
|
|
364
377
|
}
|
|
365
378
|
```
|
|
366
379
|
|
|
380
|
+
This babel config file will be used as explained in [Browser support](./docs/config/browser_support.md). It can also be used to enable [JSX](./docs/config/react.md#Using-JSX) and [TypeScript](./docs/config/typescript.md).
|
|
381
|
+
|
|
367
382
|
# See also
|
|
368
383
|
|
|
369
384
|
| Link | Description |
|
|
370
385
|
| ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------- |
|
|
371
386
|
| [Browser support](./docs/config/browser_support.md) | Document how to configure browser support |
|
|
372
387
|
| [Web workers](./docs/config/web_workers.md) | Document how to use web workers |
|
|
388
|
+
| [NPM package](./docs/config/npm_package.md) | Document how to use a NPM package |
|
|
373
389
|
| [React](./docs/config/react.md) | Document how to enable react/preact and JSX |
|
|
374
|
-
| [CommonJS modules](./docs/config/commonjs.md) | Document how to use code written in CommonJS |
|
|
375
390
|
| [TypeScript (Experimental)](./docs/config/typescript.md) | Document how to enable TypeScript |
|
|
376
391
|
| [@jsenv/template-pwa](https://github.com/jsenv/jsenv-template-pwa) | GitHub repository template for a progressive web application |
|
|
377
392
|
| [@jsenv/template-node-package](https://github.com/jsenv/jsenv-template-node-package) | GitHub repository template for a node package |
|
package/src/executeTestPlan.js
CHANGED
|
@@ -254,6 +254,17 @@ export const executeTestPlan = async ({
|
|
|
254
254
|
await Promise.all(promises)
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
+
// Sometimes on windows test plan scripts never ends
|
|
258
|
+
// I suspect it's some node process keeping the process alive
|
|
259
|
+
// because not properly killed for some reason.
|
|
260
|
+
// (It can be reproduced on @jsenv/importmap-node-module where playwright is not involved)
|
|
261
|
+
// The hotfix for now is to manually call process.exit() in on windows
|
|
262
|
+
if (process.platform === "win32") {
|
|
263
|
+
setTimeout(() => {
|
|
264
|
+
process.exit()
|
|
265
|
+
}, 2000).unref()
|
|
266
|
+
}
|
|
267
|
+
|
|
257
268
|
return {
|
|
258
269
|
testPlanAborted: result.aborted,
|
|
259
270
|
testPlanSummary: result.planSummary,
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
replaceHtmlNode,
|
|
25
25
|
getHtmlNodeAttributeByName,
|
|
26
26
|
stringifyHtmlAst,
|
|
27
|
-
|
|
27
|
+
getIdForInlineHtmlNode,
|
|
28
28
|
removeHtmlNodeAttribute,
|
|
29
29
|
setHtmlNodeText,
|
|
30
30
|
getHtmlNodeTextNode,
|
|
@@ -234,11 +234,10 @@ const regularScriptTextNodeVisitor = (
|
|
|
234
234
|
return null
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
)
|
|
237
|
+
const scriptId = getIdForInlineHtmlNode(script, scripts)
|
|
238
|
+
const ressourceSpecifier = `${urlToFilename(
|
|
239
|
+
htmlRessource.url,
|
|
240
|
+
)}__inline__${scriptId}.js`
|
|
242
241
|
const jsReference = notifyReferenceFound({
|
|
243
242
|
referenceLabel: "html inline script",
|
|
244
243
|
contentTypeExpected: "application/javascript",
|
|
@@ -333,11 +332,10 @@ const moduleScriptTextNodeVisitor = (
|
|
|
333
332
|
return null
|
|
334
333
|
}
|
|
335
334
|
|
|
336
|
-
const
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
)
|
|
335
|
+
const scriptId = getIdForInlineHtmlNode(script, scripts)
|
|
336
|
+
const ressourceSpecifier = `${urlToFilename(
|
|
337
|
+
htmlRessource.url,
|
|
338
|
+
)}__inline__${scriptId}.js`
|
|
341
339
|
const jsReference = notifyReferenceFound({
|
|
342
340
|
referenceLabel: "html inline module script",
|
|
343
341
|
contentTypeExpected: "application/javascript",
|
|
@@ -445,16 +443,14 @@ const importmapScriptTextNodeVisitor = (
|
|
|
445
443
|
return null
|
|
446
444
|
}
|
|
447
445
|
|
|
446
|
+
const importmapScriptId = getIdForInlineHtmlNode(script, scripts)
|
|
448
447
|
const importmapReference = notifyReferenceFound({
|
|
449
448
|
referenceLabel: "html inline importmap",
|
|
450
449
|
contentTypeExpected: "application/importmap+json",
|
|
451
|
-
ressourceSpecifier:
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
`${urlToFilename(htmlRessource.url)}__inline__[id].importmap`,
|
|
455
|
-
),
|
|
450
|
+
ressourceSpecifier: `${urlToFilename(
|
|
451
|
+
htmlRessource.url,
|
|
452
|
+
)}__inline__${importmapScriptId}.importmap`,
|
|
456
453
|
...referenceLocationFromHtmlNode(script),
|
|
457
|
-
|
|
458
454
|
contentType: "application/importmap+json",
|
|
459
455
|
bufferBeforeBuild: Buffer.from(textNode.value),
|
|
460
456
|
isInline: true,
|
|
@@ -648,16 +644,14 @@ const styleTextNodeVisitor = (
|
|
|
648
644
|
return null
|
|
649
645
|
}
|
|
650
646
|
|
|
647
|
+
const styleId = getIdForInlineHtmlNode(style, styles)
|
|
651
648
|
const inlineStyleReference = notifyReferenceFound({
|
|
652
649
|
referenceLabel: "html style",
|
|
653
650
|
contentTypeExpected: "text/css",
|
|
654
|
-
ressourceSpecifier:
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
`${urlToFilename(htmlRessource.url)}__inline__[id].css`,
|
|
658
|
-
),
|
|
651
|
+
ressourceSpecifier: `${urlToFilename(
|
|
652
|
+
htmlRessource.url,
|
|
653
|
+
)}__inline__${styleId}.css`,
|
|
659
654
|
...referenceLocationFromHtmlNode(style),
|
|
660
|
-
|
|
661
655
|
contentType: "text/css",
|
|
662
656
|
bufferBeforeBuild: Buffer.from(textNode.value),
|
|
663
657
|
isInline: true,
|
|
@@ -14,8 +14,8 @@ export const parseJsRessource = async (
|
|
|
14
14
|
const jsUrl = jsRessource.url
|
|
15
15
|
const jsString = String(jsRessource.bufferBeforeBuild)
|
|
16
16
|
const jsSourcemapUrl = getJavaScriptSourceMappingUrl(jsString)
|
|
17
|
-
let sourcemapReference
|
|
18
17
|
|
|
18
|
+
let sourcemapReference
|
|
19
19
|
if (jsSourcemapUrl) {
|
|
20
20
|
sourcemapReference = notifyReferenceFound({
|
|
21
21
|
referenceLabel: "js sourcemapping comment",
|
|
@@ -76,13 +76,10 @@ export const parseJsRessource = async (
|
|
|
76
76
|
code = result.code
|
|
77
77
|
map = result.map
|
|
78
78
|
}
|
|
79
|
-
|
|
80
79
|
jsRessource.buildEnd(code)
|
|
81
|
-
|
|
82
80
|
if (!map) {
|
|
83
81
|
return
|
|
84
82
|
}
|
|
85
|
-
|
|
86
83
|
// In theory code should never be modified once buildEnd() is called
|
|
87
84
|
// because buildRelativeUrl might be versioned based on file content
|
|
88
85
|
// There is an exception for sourcemap because we want to update sourcemap.file
|
|
@@ -99,7 +96,6 @@ export const parseJsRessource = async (
|
|
|
99
96
|
`${urlToFilename(jsBuildUrl)}.map`,
|
|
100
97
|
jsBuildUrl,
|
|
101
98
|
)
|
|
102
|
-
|
|
103
99
|
map.file = urlToFilename(jsBuildUrl)
|
|
104
100
|
if (map.sources) {
|
|
105
101
|
map.sources = map.sources.map((source) => {
|
|
@@ -114,7 +110,6 @@ export const parseJsRessource = async (
|
|
|
114
110
|
}
|
|
115
111
|
const mapAsText = JSON.stringify(map, null, " ")
|
|
116
112
|
sourcemapRessource.buildEnd(mapAsText)
|
|
117
|
-
|
|
118
113
|
const sourcemapBuildUrl = resolveUrl(
|
|
119
114
|
sourcemapRessource.buildRelativeUrl,
|
|
120
115
|
buildDirectoryUrl,
|
|
@@ -948,8 +948,14 @@ export const createRessourceBuilder = (
|
|
|
948
948
|
}
|
|
949
949
|
return {
|
|
950
950
|
...htmlUrlSite,
|
|
951
|
-
line:
|
|
952
|
-
|
|
951
|
+
line:
|
|
952
|
+
typeof urlSite.line === "number"
|
|
953
|
+
? htmlUrlSite.line + urlSite.line
|
|
954
|
+
: htmlUrlSite.line,
|
|
955
|
+
column:
|
|
956
|
+
typeof urlSite.column === "number"
|
|
957
|
+
? htmlUrlSite.column + urlSite.column
|
|
958
|
+
: htmlUrlSite.column,
|
|
953
959
|
}
|
|
954
960
|
}
|
|
955
961
|
|
|
@@ -690,6 +690,9 @@ export const createRollupPlugins = async ({
|
|
|
690
690
|
// we compile for rollup, let top level await untouched
|
|
691
691
|
// it will be converted, if needed, during "renderChunk" hook
|
|
692
692
|
topLevelAwait: "ignore",
|
|
693
|
+
// if we put babel helpers, rollup might try to share them and a file
|
|
694
|
+
// might try to import from an inline script resulting in 404.
|
|
695
|
+
babelHelpersInjectionAsImport: false,
|
|
693
696
|
})
|
|
694
697
|
let code = transformResult.code
|
|
695
698
|
let map = transformResult.map
|
|
@@ -65,8 +65,8 @@ const createAvailableNameGenerator = () => {
|
|
|
65
65
|
const getAvailableNameForPattern = (name, pattern) => {
|
|
66
66
|
let names = cache[pattern]
|
|
67
67
|
if (!names) {
|
|
68
|
-
cache[pattern] = []
|
|
69
68
|
names = []
|
|
69
|
+
cache[pattern] = names
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
let nameCandidate = name
|
|
@@ -133,7 +133,7 @@ const getFilenamePattern = ({
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
if (ressource.isJsModule) {
|
|
136
|
-
return "[name]_[hash]
|
|
136
|
+
return "[name]_[hash].js"
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
return ressource.urlVersioningDisabled
|
|
@@ -495,35 +495,22 @@ export const createInlineScriptHash = (script) => {
|
|
|
495
495
|
return hash.digest("hex").slice(0, 8)
|
|
496
496
|
}
|
|
497
497
|
|
|
498
|
-
export const
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
const htmlNodeLocation = getHtmlNodeLocation(nodeCandidate)
|
|
510
|
-
if (!htmlNodeLocation) return false
|
|
511
|
-
return htmlNodeLocation.line === line
|
|
512
|
-
})
|
|
513
|
-
if (lineTaken) {
|
|
514
|
-
return `${line}.${column}`
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
return line
|
|
518
|
-
},
|
|
519
|
-
})
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
const renderNamePattern = (pattern, replacements) => {
|
|
523
|
-
return pattern.replace(/\[(\w+)\]/g, (_match, type) => {
|
|
524
|
-
const replacement = replacements[type]()
|
|
525
|
-
return replacement
|
|
498
|
+
export const getIdForInlineHtmlNode = (node, nodes) => {
|
|
499
|
+
const idAttribute = getHtmlNodeAttributeByName(node, "id")
|
|
500
|
+
if (idAttribute) {
|
|
501
|
+
return idAttribute.value
|
|
502
|
+
}
|
|
503
|
+
const { line, column } = getHtmlNodeLocation(node) || {}
|
|
504
|
+
const lineTaken = nodes.some((nodeCandidate) => {
|
|
505
|
+
if (nodeCandidate === node) return false
|
|
506
|
+
const htmlNodeLocation = getHtmlNodeLocation(nodeCandidate)
|
|
507
|
+
if (!htmlNodeLocation) return false
|
|
508
|
+
return htmlNodeLocation.line === line
|
|
526
509
|
})
|
|
510
|
+
if (lineTaken) {
|
|
511
|
+
return `${line}.${column}`
|
|
512
|
+
}
|
|
513
|
+
return line
|
|
527
514
|
}
|
|
528
515
|
|
|
529
516
|
const parseHtmlAsSingleElement = (html) => {
|
|
@@ -41,7 +41,7 @@ import {
|
|
|
41
41
|
removeHtmlNodeAttribute,
|
|
42
42
|
getHtmlNodeTextNode,
|
|
43
43
|
setHtmlNodeText,
|
|
44
|
-
|
|
44
|
+
getIdForInlineHtmlNode,
|
|
45
45
|
} from "./compileHtml.js"
|
|
46
46
|
import { jsenvCoreDirectoryUrl } from "../jsenvCoreDirectoryUrl.js"
|
|
47
47
|
|
|
@@ -121,8 +121,8 @@ export const createTransformHtmlSourceFileService = ({
|
|
|
121
121
|
jsenvScriptInjection,
|
|
122
122
|
jsenvEventSourceClientInjection,
|
|
123
123
|
jsenvToolbarInjection,
|
|
124
|
-
onInlineModuleScript: ({ scriptContent,
|
|
125
|
-
const inlineScriptUrl = resolveUrl(
|
|
124
|
+
onInlineModuleScript: ({ scriptContent, scriptSpecifier }) => {
|
|
125
|
+
const inlineScriptUrl = resolveUrl(scriptSpecifier, fileUrl)
|
|
126
126
|
htmlInlineScriptMap.set(inlineScriptUrl, {
|
|
127
127
|
htmlFileUrl: fileUrl,
|
|
128
128
|
scriptContent,
|
|
@@ -248,19 +248,18 @@ const transformHTMLSourceFile = async ({
|
|
|
248
248
|
// inline
|
|
249
249
|
const textNode = getHtmlNodeTextNode(script)
|
|
250
250
|
if (typeAttribute && typeAttribute.value === "module" && textNode) {
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
)
|
|
251
|
+
const scriptId = getIdForInlineHtmlNode(script, scripts)
|
|
252
|
+
const scriptSpecifier = `${urlToFilename(
|
|
253
|
+
fileUrl,
|
|
254
|
+
)}__inline__${scriptId}.js`
|
|
256
255
|
onInlineModuleScript({
|
|
257
256
|
scriptContent: textNode.value,
|
|
258
|
-
|
|
257
|
+
scriptSpecifier,
|
|
259
258
|
})
|
|
260
259
|
setHtmlNodeText(
|
|
261
260
|
script,
|
|
262
261
|
`window.__jsenv__.executeFileUsingDynamicImport(${JSON.stringify(
|
|
263
|
-
`./${
|
|
262
|
+
`./${scriptSpecifier}`,
|
|
264
263
|
)})`,
|
|
265
264
|
)
|
|
266
265
|
return
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
resolveUrl,
|
|
3
|
+
urlToFilename,
|
|
4
|
+
urlToBasename,
|
|
5
|
+
urlToRelativeUrl,
|
|
6
|
+
urlIsInsideOf,
|
|
7
|
+
} from "@jsenv/filesystem"
|
|
2
8
|
import { moveImportMap, composeTwoImportMaps } from "@jsenv/importmap"
|
|
3
9
|
import { createDetailedMessage } from "@jsenv/logger"
|
|
4
10
|
|
|
11
|
+
import { jsenvDistDirectoryUrl } from "@jsenv/core/src/internal/jsenvCoreDirectoryUrl.js"
|
|
5
12
|
import {
|
|
6
13
|
BROWSER_RUNTIME_BUILD_URL,
|
|
7
14
|
EVENT_SOURCE_CLIENT_BUILD_URL,
|
|
@@ -23,7 +30,7 @@ import {
|
|
|
23
30
|
stringifyHtmlAst,
|
|
24
31
|
getHtmlNodeAttributeByName,
|
|
25
32
|
getHtmlNodeTextNode,
|
|
26
|
-
|
|
33
|
+
getIdForInlineHtmlNode,
|
|
27
34
|
removeHtmlNodeAttribute,
|
|
28
35
|
setHtmlNodeText,
|
|
29
36
|
visitHtmlAst,
|
|
@@ -39,6 +46,7 @@ export const compileHtml = async ({
|
|
|
39
46
|
url,
|
|
40
47
|
compiledUrl,
|
|
41
48
|
projectDirectoryUrl,
|
|
49
|
+
compileServerOrigin,
|
|
42
50
|
outDirectoryRelativeUrl,
|
|
43
51
|
compileId,
|
|
44
52
|
|
|
@@ -104,248 +112,472 @@ export const compileHtml = async ({
|
|
|
104
112
|
],
|
|
105
113
|
})
|
|
106
114
|
|
|
107
|
-
|
|
108
|
-
|
|
115
|
+
const sources = []
|
|
116
|
+
const sourcesContent = []
|
|
117
|
+
const assets = []
|
|
118
|
+
const assetsContent = []
|
|
119
|
+
|
|
120
|
+
const addHtmlSourceFile = ({ url, content }) => {
|
|
121
|
+
sources.push(url)
|
|
122
|
+
sourcesContent.push(content)
|
|
123
|
+
}
|
|
124
|
+
addHtmlSourceFile({ url, content: code })
|
|
125
|
+
|
|
109
126
|
const { scripts } = parseHtmlAstRessources(htmlAst)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const importMapResponse = await fetchUrl(importmapInfo.url)
|
|
125
|
-
if (importMapResponse.status === 200) {
|
|
126
|
-
const importmapAsText = await importMapResponse.text()
|
|
127
|
-
let htmlImportmap = JSON.parse(importmapAsText)
|
|
128
|
-
htmlImportmap = moveImportMap(
|
|
129
|
-
htmlImportmap,
|
|
130
|
-
importmapInfo.url,
|
|
131
|
-
url,
|
|
132
|
-
)
|
|
133
|
-
sources.push(importmapInfo.url)
|
|
134
|
-
sourcesContent.push(importmapAsText)
|
|
135
|
-
return htmlImportmap
|
|
136
|
-
}
|
|
137
|
-
logger.warn(
|
|
138
|
-
createDetailedMessage(
|
|
139
|
-
importMapResponse.status === 404
|
|
140
|
-
? `importmap script file cannot be found.`
|
|
141
|
-
: `importmap script file unexpected response status (${importMapResponse.status}).`,
|
|
142
|
-
{
|
|
143
|
-
"importmap url": importmapInfo.url,
|
|
144
|
-
"html url": url,
|
|
145
|
-
},
|
|
146
|
-
),
|
|
147
|
-
)
|
|
148
|
-
return {}
|
|
149
|
-
},
|
|
150
|
-
}
|
|
151
|
-
} else {
|
|
152
|
-
importmapInfo = {
|
|
153
|
-
script,
|
|
154
|
-
url: compiledUrl,
|
|
155
|
-
load: () => {
|
|
156
|
-
const jsenvImportmap = getDefaultImportmap(compiledUrl, {
|
|
157
|
-
projectDirectoryUrl,
|
|
158
|
-
compileDirectoryUrl: `${projectDirectoryUrl}${compileId}/${outDirectoryRelativeUrl}`,
|
|
159
|
-
})
|
|
160
|
-
const htmlImportmap = JSON.parse(
|
|
161
|
-
getHtmlNodeTextNode(script).value,
|
|
162
|
-
)
|
|
163
|
-
const importmap = composeTwoImportMaps(
|
|
164
|
-
jsenvImportmap,
|
|
165
|
-
htmlImportmap,
|
|
166
|
-
)
|
|
167
|
-
return importmap
|
|
168
|
-
},
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
})
|
|
174
|
-
if (importmapInfo) {
|
|
175
|
-
const importmap = await importmapInfo.load()
|
|
176
|
-
const importmapAsText = JSON.stringify(importmap, null, " ")
|
|
177
|
-
replaceHtmlNode(
|
|
178
|
-
importmapInfo.script,
|
|
179
|
-
`<script type="${
|
|
180
|
-
moduleOutFormat === "systemjs" ? "systemjs-importmap" : "importmap"
|
|
181
|
-
}">${importmapAsText}</script>`,
|
|
182
|
-
{
|
|
183
|
-
attributesToIgnore: ["src"],
|
|
184
|
-
},
|
|
185
|
-
)
|
|
186
|
-
importmapInfo.inlinedFrom = importmapInfo.url
|
|
187
|
-
importmapInfo.text = importmapAsText
|
|
188
|
-
} else {
|
|
189
|
-
const defaultImportMap = getDefaultImportmap(compiledUrl, {
|
|
190
|
-
projectDirectoryUrl,
|
|
191
|
-
compileDirectoryUrl: `${projectDirectoryUrl}${outDirectoryRelativeUrl}${compileId}/`,
|
|
127
|
+
const htmlDependencies = collectHtmlDependenciesFromAst(htmlAst)
|
|
128
|
+
|
|
129
|
+
const htmlAssetGenerators = []
|
|
130
|
+
const htmlMutations = []
|
|
131
|
+
const addHtmlAssetGenerator = (htmlAssetGenerator) => {
|
|
132
|
+
htmlAssetGenerators.push(htmlAssetGenerator)
|
|
133
|
+
}
|
|
134
|
+
const addHtmlMutation = (htmlMutation) => {
|
|
135
|
+
htmlMutations.push(htmlMutation)
|
|
136
|
+
}
|
|
137
|
+
const addHtmlDependency = ({ htmlNode, specifier }) => {
|
|
138
|
+
htmlDependencies.push({
|
|
139
|
+
htmlNode,
|
|
140
|
+
specifier,
|
|
192
141
|
})
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const importmapInfo = await visitImportmapScript({
|
|
145
|
+
logger,
|
|
146
|
+
url,
|
|
147
|
+
compiledUrl,
|
|
148
|
+
projectDirectoryUrl,
|
|
149
|
+
compileId,
|
|
150
|
+
outDirectoryRelativeUrl,
|
|
151
|
+
scripts,
|
|
152
|
+
addHtmlSourceFile,
|
|
153
|
+
})
|
|
154
|
+
const importmap = (await importmapInfo.load()) || {}
|
|
155
|
+
const importmapAsText = JSON.stringify(importmap, null, " ")
|
|
156
|
+
importmapInfo.inlinedFrom = importmapInfo.url
|
|
157
|
+
importmapInfo.text = importmapAsText
|
|
158
|
+
addHtmlMutation(() => {
|
|
159
|
+
if (importmapInfo.needsInjection) {
|
|
160
|
+
manipulateHtmlAst(htmlAst, {
|
|
161
|
+
scriptInjections: [
|
|
162
|
+
{
|
|
163
|
+
type:
|
|
164
|
+
moduleOutFormat === "systemjs"
|
|
165
|
+
? "systemjs-importmap"
|
|
166
|
+
: "importmap",
|
|
167
|
+
// in case there is no importmap, force the presence
|
|
168
|
+
// so that '@jsenv/core/' are still remapped
|
|
169
|
+
text: importmapAsText,
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
})
|
|
173
|
+
} else {
|
|
174
|
+
replaceHtmlNode(
|
|
175
|
+
importmapInfo.script,
|
|
176
|
+
`<script type="${
|
|
177
|
+
moduleOutFormat === "systemjs" ? "systemjs-importmap" : "importmap"
|
|
178
|
+
}">${importmapAsText}</script>`,
|
|
196
179
|
{
|
|
197
|
-
|
|
198
|
-
moduleOutFormat === "systemjs" ? "systemjs-importmap" : "importmap",
|
|
199
|
-
// in case there is no importmap, force the presence
|
|
200
|
-
// so that '@jsenv/core/' are still remapped
|
|
201
|
-
text: importmapAsText,
|
|
180
|
+
attributesToIgnore: ["src"],
|
|
202
181
|
},
|
|
203
|
-
|
|
204
|
-
})
|
|
205
|
-
importmapInfo = {
|
|
206
|
-
url: compiledUrl,
|
|
207
|
-
text: importmapAsText,
|
|
182
|
+
)
|
|
208
183
|
}
|
|
209
|
-
}
|
|
184
|
+
})
|
|
210
185
|
onHtmlImportmapInfo({
|
|
211
186
|
htmlUrl: url,
|
|
212
187
|
importmapInfo,
|
|
213
188
|
})
|
|
214
189
|
|
|
215
|
-
|
|
216
|
-
|
|
190
|
+
await visitScripts({
|
|
191
|
+
logger,
|
|
192
|
+
projectDirectoryUrl,
|
|
193
|
+
compileServerOrigin,
|
|
194
|
+
url,
|
|
195
|
+
compiledUrl,
|
|
196
|
+
scripts,
|
|
197
|
+
addHtmlSourceFile,
|
|
198
|
+
addHtmlAssetGenerator,
|
|
199
|
+
addHtmlMutation,
|
|
200
|
+
addHtmlDependency,
|
|
201
|
+
|
|
202
|
+
babelPluginMap,
|
|
203
|
+
moduleOutFormat,
|
|
204
|
+
importMetaFormat,
|
|
205
|
+
topLevelAwait,
|
|
206
|
+
sourcemapMethod,
|
|
207
|
+
})
|
|
208
|
+
await Promise.all(
|
|
209
|
+
htmlAssetGenerators.map(async (htmlAssetGenerator) => {
|
|
210
|
+
const assetInfos = await htmlAssetGenerator()
|
|
211
|
+
assetInfos.forEach((assetInfo) => {
|
|
212
|
+
assets.push(assetInfo.url)
|
|
213
|
+
assetsContent.push(assetInfo.content)
|
|
214
|
+
})
|
|
215
|
+
}),
|
|
216
|
+
)
|
|
217
|
+
htmlAssetGenerators.length = 0
|
|
218
|
+
|
|
219
|
+
htmlMutations.forEach((htmlMutation) => {
|
|
220
|
+
htmlMutation()
|
|
221
|
+
})
|
|
222
|
+
htmlMutations.length = 0
|
|
223
|
+
const htmlAfterTransformation = stringifyHtmlAst(htmlAst)
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
contentType: "text/html",
|
|
227
|
+
compiledSource: htmlAfterTransformation,
|
|
228
|
+
sources,
|
|
229
|
+
sourcesContent,
|
|
230
|
+
assets,
|
|
231
|
+
assetsContent,
|
|
232
|
+
dependencies: htmlDependencies.map(({ specifier }) => {
|
|
233
|
+
return specifier
|
|
234
|
+
}),
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const visitImportmapScript = async ({
|
|
239
|
+
logger,
|
|
240
|
+
url,
|
|
241
|
+
compiledUrl,
|
|
242
|
+
projectDirectoryUrl,
|
|
243
|
+
compileId,
|
|
244
|
+
outDirectoryRelativeUrl,
|
|
245
|
+
scripts,
|
|
246
|
+
addHtmlSourceFile,
|
|
247
|
+
}) => {
|
|
248
|
+
const importmapScripts = scripts.filter((script) => {
|
|
249
|
+
const typeAttribute = getHtmlNodeAttributeByName(script, "type")
|
|
250
|
+
const type = typeAttribute ? typeAttribute.value : "application/javascript"
|
|
251
|
+
return type === "importmap"
|
|
252
|
+
})
|
|
253
|
+
if (importmapScripts.length === 0) {
|
|
254
|
+
return {
|
|
255
|
+
needsInjection: true,
|
|
256
|
+
url: compiledUrl,
|
|
257
|
+
load: () => {
|
|
258
|
+
const defaultImportMap = getDefaultImportmap(compiledUrl, {
|
|
259
|
+
projectDirectoryUrl,
|
|
260
|
+
compileDirectoryUrl: `${projectDirectoryUrl}${outDirectoryRelativeUrl}${compileId}/`,
|
|
261
|
+
})
|
|
262
|
+
return defaultImportMap
|
|
263
|
+
},
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (importmapScripts.length > 1) {
|
|
268
|
+
logger.error("HTML file must contain max 1 importmap")
|
|
269
|
+
}
|
|
270
|
+
const firstImportmapScript = importmapScripts[0]
|
|
271
|
+
const srcAttribute = getHtmlNodeAttributeByName(firstImportmapScript, "src")
|
|
272
|
+
const src = srcAttribute ? srcAttribute.value : ""
|
|
273
|
+
if (src) {
|
|
274
|
+
const importmapUrl = resolveUrl(src, url)
|
|
275
|
+
const importmapInfo = {
|
|
276
|
+
script: firstImportmapScript,
|
|
277
|
+
url: importmapUrl,
|
|
278
|
+
load: async () => {
|
|
279
|
+
const importMapResponse = await fetchUrl(importmapUrl)
|
|
280
|
+
if (importMapResponse.status === 200) {
|
|
281
|
+
const importmapAsText = await importMapResponse.text()
|
|
282
|
+
addHtmlSourceFile({
|
|
283
|
+
url: importmapUrl,
|
|
284
|
+
content: importmapAsText,
|
|
285
|
+
})
|
|
286
|
+
let htmlImportmap = JSON.parse(importmapAsText)
|
|
287
|
+
htmlImportmap = moveImportMap(htmlImportmap, importmapUrl, url)
|
|
288
|
+
return htmlImportmap
|
|
289
|
+
}
|
|
290
|
+
logger.warn(
|
|
291
|
+
createDetailedMessage(
|
|
292
|
+
importMapResponse.status === 404
|
|
293
|
+
? `importmap script file cannot be found.`
|
|
294
|
+
: `importmap script file unexpected response status (${importMapResponse.status}).`,
|
|
295
|
+
{
|
|
296
|
+
"importmap url": importmapInfo.url,
|
|
297
|
+
"html url": url,
|
|
298
|
+
},
|
|
299
|
+
),
|
|
300
|
+
)
|
|
301
|
+
return null
|
|
302
|
+
},
|
|
303
|
+
}
|
|
304
|
+
return importmapInfo
|
|
305
|
+
}
|
|
306
|
+
const importmapInfo = {
|
|
307
|
+
script: firstImportmapScript,
|
|
308
|
+
url: compiledUrl,
|
|
309
|
+
load: () => {
|
|
310
|
+
const jsenvImportmap = getDefaultImportmap(compiledUrl, {
|
|
311
|
+
projectDirectoryUrl,
|
|
312
|
+
compileDirectoryUrl: `${projectDirectoryUrl}${compileId}/${outDirectoryRelativeUrl}`,
|
|
313
|
+
})
|
|
314
|
+
const htmlImportmap = JSON.parse(
|
|
315
|
+
getHtmlNodeTextNode(firstImportmapScript).value,
|
|
316
|
+
)
|
|
317
|
+
const importmap = composeTwoImportMaps(jsenvImportmap, htmlImportmap)
|
|
318
|
+
return importmap
|
|
319
|
+
},
|
|
320
|
+
}
|
|
321
|
+
return importmapInfo
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const visitScripts = async ({
|
|
325
|
+
logger,
|
|
326
|
+
projectDirectoryUrl,
|
|
327
|
+
compileServerOrigin,
|
|
328
|
+
url,
|
|
329
|
+
compiledUrl,
|
|
330
|
+
scripts,
|
|
331
|
+
addHtmlSourceFile,
|
|
332
|
+
addHtmlAssetGenerator,
|
|
333
|
+
addHtmlMutation,
|
|
334
|
+
addHtmlDependency,
|
|
335
|
+
|
|
336
|
+
babelPluginMap,
|
|
337
|
+
moduleOutFormat,
|
|
338
|
+
importMetaFormat,
|
|
339
|
+
topLevelAwait,
|
|
340
|
+
sourcemapMethod,
|
|
341
|
+
}) => {
|
|
217
342
|
scripts.forEach((script) => {
|
|
218
343
|
const typeAttribute = getHtmlNodeAttributeByName(script, "type")
|
|
344
|
+
const type = typeAttribute ? typeAttribute.value : "application/javascript"
|
|
219
345
|
const srcAttribute = getHtmlNodeAttributeByName(script, "src")
|
|
220
346
|
const src = srcAttribute ? srcAttribute.value : ""
|
|
221
|
-
// remote module script
|
|
222
|
-
if (typeAttribute && typeAttribute.value === "module" && src) {
|
|
223
|
-
if (moduleOutFormat === "systemjs") {
|
|
224
|
-
removeHtmlNodeAttribute(script, typeAttribute)
|
|
225
|
-
}
|
|
226
|
-
removeHtmlNodeAttribute(script, srcAttribute)
|
|
227
|
-
const jsenvMethod =
|
|
228
|
-
moduleOutFormat === "systemjs"
|
|
229
|
-
? "executeFileUsingSystemJs"
|
|
230
|
-
: "executeFileUsingDynamicImport"
|
|
231
|
-
setHtmlNodeText(
|
|
232
|
-
script,
|
|
233
|
-
`window.__jsenv__.${jsenvMethod}(${JSON.stringify(src)})`,
|
|
234
|
-
)
|
|
235
|
-
return
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// inline module script
|
|
239
347
|
const textNode = getHtmlNodeTextNode(script)
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
348
|
+
|
|
349
|
+
if (type === "module") {
|
|
350
|
+
if (src) {
|
|
351
|
+
addHtmlMutation(() => {
|
|
352
|
+
if (moduleOutFormat === "systemjs") {
|
|
353
|
+
removeHtmlNodeAttribute(script, typeAttribute)
|
|
354
|
+
}
|
|
355
|
+
removeHtmlNodeAttribute(script, srcAttribute)
|
|
356
|
+
const jsenvMethod =
|
|
357
|
+
moduleOutFormat === "systemjs"
|
|
358
|
+
? "executeFileUsingSystemJs"
|
|
359
|
+
: "executeFileUsingDynamicImport"
|
|
360
|
+
setHtmlNodeText(
|
|
361
|
+
script,
|
|
362
|
+
`window.__jsenv__.${jsenvMethod}(${JSON.stringify(src)})`,
|
|
363
|
+
)
|
|
364
|
+
})
|
|
365
|
+
return
|
|
243
366
|
}
|
|
244
|
-
|
|
245
|
-
const
|
|
367
|
+
|
|
368
|
+
const scriptId = getIdForInlineHtmlNode(script, scripts)
|
|
369
|
+
const inlineScriptName = `${scriptId}.js`
|
|
370
|
+
const scriptOriginalUrl = resolveUrl(inlineScriptName, url)
|
|
371
|
+
const scriptCompiledUrl = generateCompiledFileAssetUrl(
|
|
246
372
|
compiledUrl,
|
|
247
|
-
|
|
248
|
-
)
|
|
249
|
-
const specifier = `./${urlToRelativeUrl(scriptAssetUrl, compiledUrl)}`
|
|
250
|
-
inlineScriptsContentMap[specifier] = textNode.value
|
|
251
|
-
const jsenvMethod =
|
|
252
|
-
moduleOutFormat === "systemjs"
|
|
253
|
-
? "executeFileUsingSystemJs"
|
|
254
|
-
: "executeFileUsingDynamicImport"
|
|
255
|
-
setHtmlNodeText(
|
|
256
|
-
script,
|
|
257
|
-
`window.__jsenv__.${jsenvMethod}(${JSON.stringify(specifier)})`,
|
|
373
|
+
inlineScriptName,
|
|
258
374
|
)
|
|
259
|
-
|
|
375
|
+
addHtmlAssetGenerator(async () => {
|
|
376
|
+
return transformHtmlScript({
|
|
377
|
+
projectDirectoryUrl,
|
|
378
|
+
url: scriptOriginalUrl,
|
|
379
|
+
compiledUrl: scriptCompiledUrl,
|
|
380
|
+
code: textNode.value,
|
|
381
|
+
|
|
382
|
+
type: "module",
|
|
383
|
+
babelPluginMap,
|
|
384
|
+
moduleOutFormat,
|
|
385
|
+
importMetaFormat,
|
|
386
|
+
topLevelAwait,
|
|
387
|
+
sourcemapMethod,
|
|
388
|
+
})
|
|
389
|
+
})
|
|
390
|
+
const specifier = `./${urlToRelativeUrl(scriptCompiledUrl, compiledUrl)}`
|
|
391
|
+
addHtmlMutation(() => {
|
|
392
|
+
if (moduleOutFormat === "systemjs") {
|
|
393
|
+
removeHtmlNodeAttribute(script, typeAttribute)
|
|
394
|
+
}
|
|
395
|
+
removeHtmlNodeAttribute(script, srcAttribute)
|
|
396
|
+
const jsenvMethod =
|
|
397
|
+
moduleOutFormat === "systemjs"
|
|
398
|
+
? "executeFileUsingSystemJs"
|
|
399
|
+
: "executeFileUsingDynamicImport"
|
|
400
|
+
setHtmlNodeText(
|
|
401
|
+
script,
|
|
402
|
+
`window.__jsenv__.${jsenvMethod}(${JSON.stringify(specifier)})`,
|
|
403
|
+
)
|
|
404
|
+
})
|
|
405
|
+
addHtmlDependency({
|
|
260
406
|
htmlNode: script,
|
|
261
407
|
specifier,
|
|
262
408
|
})
|
|
263
409
|
return
|
|
264
410
|
}
|
|
265
|
-
})
|
|
266
|
-
const htmlAfterTransformation = stringifyHtmlAst(htmlAst)
|
|
267
411
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
const scriptBeforeCompilation = inlineScriptsContentMap[scriptSrc]
|
|
278
|
-
let scriptTransformResult
|
|
279
|
-
try {
|
|
280
|
-
scriptTransformResult = await transformJs({
|
|
281
|
-
code: scriptBeforeCompilation,
|
|
282
|
-
url: scriptOriginalFileUrl,
|
|
283
|
-
compiledUrl: scriptCompiledFileUrl,
|
|
412
|
+
if (type === "application/javascript" || type === "text/javascript") {
|
|
413
|
+
if (src) {
|
|
414
|
+
const htmlServerUrl = url.replace(
|
|
415
|
+
projectDirectoryUrl,
|
|
416
|
+
`${compileServerOrigin}/`,
|
|
417
|
+
)
|
|
418
|
+
const scriptOriginalServerUrl = resolveUrl(src, htmlServerUrl)
|
|
419
|
+
const scriptOriginalUrl = scriptOriginalServerUrl.replace(
|
|
420
|
+
`${compileServerOrigin}/`,
|
|
284
421
|
projectDirectoryUrl,
|
|
422
|
+
)
|
|
423
|
+
const fileIsInsideJsenvDistDirectory = urlIsInsideOf(
|
|
424
|
+
scriptOriginalUrl,
|
|
425
|
+
jsenvDistDirectoryUrl,
|
|
426
|
+
)
|
|
427
|
+
if (fileIsInsideJsenvDistDirectory) {
|
|
428
|
+
return
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const scriptCompiledUrl = generateCompiledFileAssetUrl(
|
|
432
|
+
compiledUrl,
|
|
433
|
+
urlToFilename(scriptOriginalUrl),
|
|
434
|
+
)
|
|
435
|
+
addHtmlAssetGenerator(async () => {
|
|
436
|
+
// we fetch scriptOriginalUrl on purpose because we do
|
|
437
|
+
// the transformation here and not in compile server
|
|
438
|
+
// (because compile server would think it's a module script
|
|
439
|
+
// and add things like systemjs)
|
|
440
|
+
const scriptResponse = await fetchUrl(scriptOriginalUrl)
|
|
441
|
+
if (scriptResponse.status !== 200) {
|
|
442
|
+
logger.warn(
|
|
443
|
+
createDetailedMessage(
|
|
444
|
+
scriptResponse.status === 404
|
|
445
|
+
? `script file cannot be found.`
|
|
446
|
+
: `script file unexpected response status (${scriptResponse.status}).`,
|
|
447
|
+
{
|
|
448
|
+
"script url": script.url,
|
|
449
|
+
"html url": url,
|
|
450
|
+
},
|
|
451
|
+
),
|
|
452
|
+
)
|
|
453
|
+
return []
|
|
454
|
+
}
|
|
455
|
+
const scriptAsText = await scriptResponse.text()
|
|
456
|
+
addHtmlSourceFile({
|
|
457
|
+
url: scriptOriginalUrl,
|
|
458
|
+
content: scriptAsText,
|
|
459
|
+
})
|
|
460
|
+
return transformHtmlScript({
|
|
461
|
+
projectDirectoryUrl,
|
|
462
|
+
url: scriptOriginalUrl,
|
|
463
|
+
compiledUrl: scriptCompiledUrl,
|
|
464
|
+
code: scriptAsText,
|
|
285
465
|
|
|
466
|
+
type: "classic",
|
|
467
|
+
babelPluginMap,
|
|
468
|
+
moduleOutFormat,
|
|
469
|
+
importMetaFormat,
|
|
470
|
+
topLevelAwait,
|
|
471
|
+
sourcemapMethod,
|
|
472
|
+
})
|
|
473
|
+
})
|
|
474
|
+
addHtmlMutation(() => {
|
|
475
|
+
srcAttribute.value = `./${urlToRelativeUrl(
|
|
476
|
+
scriptCompiledUrl,
|
|
477
|
+
compiledUrl,
|
|
478
|
+
)}`
|
|
479
|
+
})
|
|
480
|
+
return
|
|
481
|
+
}
|
|
482
|
+
const scriptId = getIdForInlineHtmlNode(script, scripts)
|
|
483
|
+
const inlineScriptName = `${scriptId}.js`
|
|
484
|
+
const scriptOriginalUrl = resolveUrl(inlineScriptName, url)
|
|
485
|
+
const scriptCompiledUrl = generateCompiledFileAssetUrl(
|
|
486
|
+
compiledUrl,
|
|
487
|
+
inlineScriptName,
|
|
488
|
+
)
|
|
489
|
+
addHtmlAssetGenerator(async () => {
|
|
490
|
+
const htmlAssets = await transformHtmlScript({
|
|
491
|
+
projectDirectoryUrl,
|
|
492
|
+
url: scriptOriginalUrl,
|
|
493
|
+
compiledUrl: scriptCompiledUrl,
|
|
494
|
+
code: textNode.value,
|
|
495
|
+
|
|
496
|
+
type: "classic",
|
|
286
497
|
babelPluginMap,
|
|
287
498
|
moduleOutFormat,
|
|
288
499
|
importMetaFormat,
|
|
289
500
|
topLevelAwait,
|
|
501
|
+
sourcemapMethod,
|
|
290
502
|
})
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
const code = scriptBeforeCompilation
|
|
301
|
-
assets = [...assets, scriptAssetUrl]
|
|
302
|
-
assetsContent = [...assetsContent, code]
|
|
303
|
-
return
|
|
304
|
-
}
|
|
305
|
-
throw e
|
|
306
|
-
}
|
|
307
|
-
const sourcemapFileUrl = resolveUrl(
|
|
308
|
-
`${scriptBasename}.map`,
|
|
309
|
-
scriptCompiledFileUrl,
|
|
310
|
-
)
|
|
503
|
+
addHtmlMutation(() => {
|
|
504
|
+
setHtmlNodeText(script, htmlAssets[0].content)
|
|
505
|
+
})
|
|
506
|
+
return htmlAssets
|
|
507
|
+
})
|
|
508
|
+
return
|
|
509
|
+
}
|
|
510
|
+
})
|
|
511
|
+
}
|
|
311
512
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
513
|
+
const transformHtmlScript = async ({
|
|
514
|
+
projectDirectoryUrl,
|
|
515
|
+
url,
|
|
516
|
+
compiledUrl,
|
|
517
|
+
code,
|
|
518
|
+
type,
|
|
317
519
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
]
|
|
332
|
-
}
|
|
333
|
-
}),
|
|
334
|
-
)
|
|
335
|
-
sources.push(url)
|
|
336
|
-
sourcesContent.push(code)
|
|
520
|
+
babelPluginMap,
|
|
521
|
+
moduleOutFormat,
|
|
522
|
+
importMetaFormat,
|
|
523
|
+
topLevelAwait,
|
|
524
|
+
sourcemapMethod,
|
|
525
|
+
}) => {
|
|
526
|
+
let transformResult
|
|
527
|
+
try {
|
|
528
|
+
transformResult = await transformJs({
|
|
529
|
+
code,
|
|
530
|
+
url,
|
|
531
|
+
compiledUrl,
|
|
532
|
+
projectDirectoryUrl,
|
|
337
533
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
534
|
+
babelPluginMap,
|
|
535
|
+
moduleOutFormat: type === "module" ? moduleOutFormat : "global",
|
|
536
|
+
importMetaFormat,
|
|
537
|
+
topLevelAwait: type === "module" ? topLevelAwait : false,
|
|
538
|
+
babelHelpersInjectionAsImport: type === "module" ? undefined : false,
|
|
539
|
+
})
|
|
540
|
+
} catch (e) {
|
|
541
|
+
// If there is a syntax error in inline script
|
|
542
|
+
// we put the raw script without transformation.
|
|
543
|
+
// when systemjs will try to instantiate to script it
|
|
544
|
+
// will re-throw this syntax error.
|
|
545
|
+
// Thanks to this we see the syntax error in the
|
|
546
|
+
// document and livereloading still works
|
|
547
|
+
// because we gracefully handle this error
|
|
548
|
+
if (e.code === "PARSE_ERROR") {
|
|
549
|
+
return [{ url, content: code }]
|
|
550
|
+
}
|
|
551
|
+
throw e
|
|
348
552
|
}
|
|
553
|
+
|
|
554
|
+
code = transformResult.code
|
|
555
|
+
let map = transformResult.map
|
|
556
|
+
const sourcemapUrl = resolveUrl(
|
|
557
|
+
`${urlToBasename(compiledUrl)}.map`,
|
|
558
|
+
compiledUrl,
|
|
559
|
+
)
|
|
560
|
+
if (sourcemapMethod === "inline") {
|
|
561
|
+
code = setJavaScriptSourceMappingUrl(code, sourcemapToBase64Url(map))
|
|
562
|
+
return [
|
|
563
|
+
{
|
|
564
|
+
url: compiledUrl,
|
|
565
|
+
content: code,
|
|
566
|
+
},
|
|
567
|
+
]
|
|
568
|
+
}
|
|
569
|
+
const sourcemapSpecifier = urlToRelativeUrl(sourcemapUrl, compiledUrl)
|
|
570
|
+
code = setJavaScriptSourceMappingUrl(code, sourcemapSpecifier)
|
|
571
|
+
return [
|
|
572
|
+
{
|
|
573
|
+
url: compiledUrl,
|
|
574
|
+
content: code,
|
|
575
|
+
},
|
|
576
|
+
{
|
|
577
|
+
url: sourcemapUrl,
|
|
578
|
+
content: JSON.stringify(map, null, " "),
|
|
579
|
+
},
|
|
580
|
+
]
|
|
349
581
|
}
|
|
350
582
|
|
|
351
583
|
// transform <link type="modulepreload"> into <link type="preload">
|
|
@@ -42,7 +42,10 @@ import {
|
|
|
42
42
|
sourcemapMainFileInfo,
|
|
43
43
|
sourcemapMappingFileInfo,
|
|
44
44
|
} from "../jsenvInternalFiles.js"
|
|
45
|
-
import {
|
|
45
|
+
import {
|
|
46
|
+
jsenvCoreDirectoryUrl,
|
|
47
|
+
jsenvDistDirectoryUrl,
|
|
48
|
+
} from "../jsenvCoreDirectoryUrl.js"
|
|
46
49
|
import { babelPluginReplaceExpressions } from "../babel_plugin_replace_expressions.js"
|
|
47
50
|
import { babelPluginGlobalThisAsJsenvImport } from "./babel_plugin_global_this_as_jsenv_import.js"
|
|
48
51
|
import { babelPluginNewStylesheetAsJsenvImport } from "./babel_plugin_new_stylesheet_as_jsenv_import.js"
|
|
@@ -945,7 +948,7 @@ const createSourceFileService = ({
|
|
|
945
948
|
.href
|
|
946
949
|
const fileIsInsideJsenvDistDirectory = urlIsInsideOf(
|
|
947
950
|
fileUrl,
|
|
948
|
-
|
|
951
|
+
jsenvDistDirectoryUrl,
|
|
949
952
|
)
|
|
950
953
|
|
|
951
954
|
const responsePromise = fetchFileSystem(fileUrl, {
|