@jsenv/core 25.1.1 → 25.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 (57) hide show
  1. package/dist/browser_runtime/browser_runtime_91c5a3b8.js.map +2 -2
  2. package/dist/build_manifest.js +4 -4
  3. package/dist/compile_proxy/asset-manifest.json +2 -2
  4. package/dist/compile_proxy/{compile_proxy_e3b0c442_809f35f7.js.map → compile_proxy.html__inline__20_809f35f7.js.map} +0 -0
  5. package/dist/compile_proxy/{compile_proxy_7ad5faa6.html → compile_proxy_8dfaee51.html} +3 -4
  6. package/dist/redirector/asset-manifest.json +2 -2
  7. package/dist/redirector/{redirector_e3b0c442_e391410e.js.map → redirector.html__inline__15_e391410e.js.map} +0 -0
  8. package/dist/redirector/{redirector_eb92e8a7.html → redirector_3e9a97b9.html} +3 -4
  9. package/dist/toolbar/asset-manifest.json +1 -1
  10. package/dist/toolbar/{toolbar_f7b8a263.html → toolbar_361afb84.html} +2 -3
  11. package/dist/toolbar_injector/asset-manifest.json +2 -2
  12. package/dist/toolbar_injector/{toolbar_injector_49e4756e.js → toolbar_injector_fac1e995.js} +2 -2
  13. package/dist/toolbar_injector/{toolbar_injector_49e4756e.js.map → toolbar_injector_fac1e995.js.map} +2 -2
  14. package/package.json +13 -9
  15. package/readme.md +73 -79
  16. package/src/buildProject.js +21 -13
  17. package/src/commonJsToJavaScriptModule.js +8 -7
  18. package/src/dev_server.js +2 -0
  19. package/src/execute.js +2 -0
  20. package/src/executeTestPlan.js +4 -1
  21. package/src/internal/building/buildUsingRollup.js +4 -2
  22. package/src/internal/building/build_stats.js +3 -0
  23. package/src/internal/building/build_url_generator.js +153 -0
  24. package/src/internal/building/css/parseCssRessource.js +32 -26
  25. package/src/internal/building/html/parseHtmlRessource.js +93 -68
  26. package/src/internal/building/js/parseJsRessource.js +4 -7
  27. package/src/internal/building/parseRessource.js +3 -0
  28. package/src/internal/building/ressource_builder.js +64 -62
  29. package/src/internal/building/ressource_builder_util.js +17 -5
  30. package/src/internal/building/rollup_plugin_jsenv.js +259 -189
  31. package/src/internal/building/url_fetcher.js +16 -7
  32. package/src/internal/building/url_loader.js +1 -5
  33. package/src/internal/building/url_versioning.js +0 -173
  34. package/src/internal/compiling/babel_plugin_import_metadata.js +7 -11
  35. package/src/internal/compiling/babel_plugin_proxy_external_imports.js +31 -0
  36. package/src/internal/compiling/compile-directory/compile-asset.js +8 -4
  37. package/src/internal/compiling/compile-directory/getOrGenerateCompiledFile.js +43 -8
  38. package/src/internal/compiling/compile-directory/updateMeta.js +4 -8
  39. package/src/internal/compiling/compile-directory/validateCache.js +1 -2
  40. package/src/internal/compiling/compileFile.js +22 -10
  41. package/src/internal/compiling/createCompiledFileService.js +22 -24
  42. package/src/internal/compiling/html_source_file_service.js +9 -9
  43. package/src/internal/compiling/js-compilation-service/babelHelper.js +10 -13
  44. package/src/internal/compiling/js-compilation-service/babel_plugin_babel_helpers_as_jsenv_imports.js +4 -2
  45. package/src/internal/compiling/js-compilation-service/jsenvTransform.js +16 -7
  46. package/src/internal/compiling/js-compilation-service/transformJs.js +9 -5
  47. package/src/internal/compiling/jsenvCompilerForHtml.js +226 -184
  48. package/src/internal/compiling/jsenvCompilerForJavaScript.js +15 -11
  49. package/src/internal/compiling/startCompileServer.js +79 -19
  50. package/src/internal/compiling/transformResultToCompilationResult.js +47 -25
  51. package/src/internal/executing/executePlan.js +2 -0
  52. package/src/internal/fetchUrl.js +3 -2
  53. package/src/internal/jsenv_remote_directory.js +156 -0
  54. package/src/internal/origin_directory_converter.js +62 -0
  55. package/src/internal/response_validation.js +11 -24
  56. package/src/internal/sourceMappingURLUtils.js +10 -0
  57. package/src/internal/url_conversion.js +1 -0
@@ -5,6 +5,7 @@ import { fetchUrl as jsenvFetchUrl } from "@jsenv/core/src/internal/fetchUrl.js"
5
5
  import { validateResponse } from "@jsenv/core/src/internal/response_validation.js"
6
6
 
7
7
  export const createUrlFetcher = ({
8
+ jsenvRemoteDirectory,
8
9
  asOriginalUrl,
9
10
  asProjectUrl,
10
11
  applyUrlMappings,
@@ -13,18 +14,28 @@ export const createUrlFetcher = ({
13
14
  }) => {
14
15
  const urlRedirectionMap = {}
15
16
 
16
- const fetchUrl = async (url, { signal, urlTrace, contentTypeExpected }) => {
17
+ const fetchUrl = async (
18
+ url,
19
+ { signal, urlTrace, contentTypeExpected, crossorigin },
20
+ ) => {
17
21
  const urlToFetch = applyUrlMappings(url)
18
-
19
22
  const response = await jsenvFetchUrl(urlToFetch, {
20
23
  signal,
21
24
  ignoreHttpsError: true,
25
+ credentials:
26
+ crossorigin === "anonymous" || crossorigin === ""
27
+ ? "same-origin"
28
+ : crossorigin === "use-credentials"
29
+ ? "include"
30
+ : undefined,
22
31
  })
23
32
  const responseUrl = response.url
24
-
33
+ const originalUrl =
34
+ asOriginalUrl(responseUrl) || asProjectUrl(responseUrl) || responseUrl
25
35
  const responseValidity = await validateResponse(response, {
26
- originalUrl:
27
- asOriginalUrl(responseUrl) || asProjectUrl(responseUrl) || responseUrl,
36
+ originalUrl: jsenvRemoteDirectory.isFileUrlForRemoteUrl(originalUrl)
37
+ ? jsenvRemoteDirectory.remoteUrlFromFileUrl(originalUrl)
38
+ : originalUrl,
28
39
  urlTrace,
29
40
  contentTypeExpected,
30
41
  })
@@ -56,11 +67,9 @@ export const createUrlFetcher = ({
56
67
  beforeThrowingResponseValidationError(responseValidationError)
57
68
  throw responseValidationError
58
69
  }
59
-
60
70
  if (url !== responseUrl) {
61
71
  urlRedirectionMap[url] = responseUrl
62
72
  }
63
-
64
73
  return response
65
74
  }
66
75
 
@@ -8,7 +8,6 @@ export const createUrlLoader = ({
8
8
  allowJson,
9
9
  urlImporterMap,
10
10
 
11
- asServerUrl,
12
11
  asProjectUrl,
13
12
  asOriginalUrl,
14
13
 
@@ -16,15 +15,12 @@ export const createUrlLoader = ({
16
15
  }) => {
17
16
  const urlResponseBodyMap = {}
18
17
 
19
- const loadUrl = async (rollupUrl, { signal, logger }) => {
20
- let url = asServerUrl(rollupUrl)
21
-
18
+ const loadUrl = async (url, { signal, logger }) => {
22
19
  const customLoader = urlCustomLoaders[url]
23
20
  if (customLoader) {
24
21
  const result = await customLoader()
25
22
  return result
26
23
  }
27
-
28
24
  const response = await urlFetcher.fetchUrl(url, {
29
25
  signal,
30
26
  contentTypeExpected: [
@@ -1,177 +1,4 @@
1
1
  import { createHash } from "crypto"
2
- import {
3
- urlToParentUrl,
4
- urlToBasename,
5
- urlToExtension,
6
- } from "@jsenv/filesystem"
7
-
8
- export const createUrlVersioner = ({
9
- entryPointUrls,
10
- asOriginalUrl,
11
- lineBreakNormalization,
12
- }) => {
13
- const availableNameGenerator = createAvailableNameGenerator()
14
-
15
- const computeBuildRelativeUrl = (ressource, precomputation) => {
16
- const pattern = getFilenamePattern({
17
- ressource,
18
- entryPointUrls,
19
- asOriginalUrl,
20
- precomputeBuildRelativeUrl,
21
- })
22
-
23
- const buildRelativeUrl = generateBuildRelativeUrl(
24
- ressource.url,
25
- ressource.bufferAfterBuild,
26
- {
27
- pattern,
28
- getName: precomputation
29
- ? () => urlToBasename(ressource.url)
30
- : () =>
31
- availableNameGenerator.getAvailableNameForPattern(
32
- urlToBasename(ressource.url),
33
- pattern,
34
- ),
35
- contentType: ressource.contentType,
36
- lineBreakNormalization,
37
- },
38
- )
39
- return buildRelativeUrl
40
- }
41
-
42
- const precomputeBuildRelativeUrl = (ressource, bufferAfterBuild = "") => {
43
- if (ressource.buildRelativeUrl) {
44
- return ressource.buildRelativeUrl
45
- }
46
- if (ressource.precomputedBuildRelativeUrl) {
47
- return ressource.precomputedBuildRelativeUrl
48
- }
49
-
50
- ressource.bufferAfterBuild = bufferAfterBuild
51
- const precomputedBuildRelativeUrl = computeBuildRelativeUrl(ressource, true)
52
- ressource.bufferAfterBuild = undefined
53
- ressource.precomputedBuildRelativeUrl = precomputedBuildRelativeUrl
54
- return precomputedBuildRelativeUrl
55
- }
56
-
57
- return {
58
- computeBuildRelativeUrl,
59
- precomputeBuildRelativeUrl,
60
- }
61
- }
62
-
63
- const createAvailableNameGenerator = () => {
64
- const cache = {}
65
- const getAvailableNameForPattern = (name, pattern) => {
66
- let names = cache[pattern]
67
- if (!names) {
68
- names = []
69
- cache[pattern] = names
70
- }
71
-
72
- let nameCandidate = name
73
- let integer = 1
74
- // eslint-disable-next-line no-constant-condition
75
- while (true) {
76
- if (!names.includes(nameCandidate)) {
77
- names.push(nameCandidate)
78
- return nameCandidate
79
- }
80
- integer++
81
- nameCandidate = `${name}${integer}`
82
- }
83
- }
84
-
85
- return {
86
- getAvailableNameForPattern,
87
- }
88
- }
89
-
90
- const getFilenamePattern = ({
91
- ressource,
92
- entryPointUrls,
93
- asOriginalUrl,
94
- precomputeBuildRelativeUrl,
95
- }) => {
96
- if (ressource.isEntryPoint) {
97
- const originalUrl = asOriginalUrl(ressource.url)
98
- const entryPointBuildRelativeUrl = entryPointUrls[originalUrl]
99
- return entryPointBuildRelativeUrl
100
- }
101
-
102
- // inline ressource inherits location
103
- if (ressource.isInline) {
104
- // inherit parent directory location because it's an inline file
105
- const importerBuildRelativeUrl = precomputeBuildRelativeUrl(
106
- ressource.importer,
107
- )
108
- const name = urlToBasename(`file://${importerBuildRelativeUrl}`)
109
- return `${name}_[hash][extname]`
110
- }
111
-
112
- // importmap.
113
- // we want to force the fileName for the importmap
114
- // so that we don't have to rewrite its content
115
- // the goal is to put the importmap at the same relative path
116
- // than in the project
117
- if (ressource.contentType === "application/importmap+json") {
118
- const importmapRessourceUrl = ressource.url
119
- const name = urlToBasename(importmapRessourceUrl)
120
- return `${name}_[hash][extname]`
121
- }
122
-
123
- // service worker:
124
- // - MUST be at the root (same level than the HTML file)
125
- // otherwise it might be registered for the scope "/assets/" instead of "/"
126
- // - MUST not be versioned
127
- if (ressource.isServiceWorker) {
128
- return "[name][extname]"
129
- }
130
-
131
- if (ressource.isWorker) {
132
- return "[name]_[hash][extname]"
133
- }
134
-
135
- if (ressource.isJsModule) {
136
- return "[name]_[hash].js"
137
- }
138
-
139
- return ressource.urlVersioningDisabled
140
- ? "assets/[name][extname]"
141
- : "assets/[name]_[hash][extname]"
142
- }
143
-
144
- const generateBuildRelativeUrl = (
145
- fileUrl,
146
- fileContent,
147
- {
148
- getName,
149
- pattern,
150
- contentType = "application/octet-stream",
151
- lineBreakNormalization = false,
152
- } = {},
153
- ) => {
154
- pattern = typeof pattern === "function" ? pattern() : pattern
155
- if (pattern.startsWith("./")) pattern = pattern.slice(2)
156
- const buildRelativeUrl = renderFileNamePattern(pattern, {
157
- dirname: () => urlToParentUrl(fileUrl),
158
- name: getName,
159
- hash: () =>
160
- generateContentHash(fileContent, {
161
- contentType,
162
- lineBreakNormalization,
163
- }),
164
- extname: () => urlToExtension(fileUrl),
165
- })
166
- return buildRelativeUrl
167
- }
168
-
169
- const renderFileNamePattern = (pattern, replacements) => {
170
- return pattern.replace(/\[(\w+)\]/g, (_match, type) => {
171
- const replacement = replacements[type]()
172
- return replacement
173
- })
174
- }
175
2
 
176
3
  // https://github.com/rollup/rollup/blob/19e50af3099c2f627451a45a84e2fa90d20246d5/src/utils/FileEmitter.ts#L47
177
4
  export const generateContentHash = (
@@ -2,21 +2,17 @@ import { babelPluginImportVisitor } from "./babel_plugin_import_visitor.js"
2
2
 
3
3
  export const babelPluginImportMetadata = (babel) => {
4
4
  return {
5
- ...babelPluginImportVisitor(
6
- babel,
7
- // During the build we throw when for import call expression where
8
- // sepcifier or type is dynamic.
9
- // Here there is no strong need to throw because keeping the source code intact
10
- // will throw an error when browser will execute the code
11
- ({ state, specifierPath }) => {
5
+ ...babelPluginImportVisitor(babel, ({ state, specifierPath }) => {
6
+ const specifierNode = specifierPath.node
7
+ if (specifierNode.type === "StringLiteral") {
8
+ const specifier = specifierNode.value
12
9
  const { metadata } = state.file
13
-
14
10
  metadata.dependencies = [
15
11
  ...(metadata.dependencies ? metadata.dependencies : []),
16
- specifierPath.node.value,
12
+ specifier,
17
13
  ]
18
- },
19
- ),
14
+ }
15
+ }),
20
16
  name: "import-metadata",
21
17
  }
22
18
  }
@@ -0,0 +1,31 @@
1
+ import { urlToRelativeUrl, fileSystemPathToUrl } from "@jsenv/filesystem"
2
+
3
+ import { babelPluginImportVisitor } from "./babel_plugin_import_visitor.js"
4
+
5
+ export const babelPluginProxyExternalImports = (
6
+ babel,
7
+ { jsenvRemoteDirectory },
8
+ ) => {
9
+ return {
10
+ ...babelPluginImportVisitor(babel, ({ specifierPath, state }) => {
11
+ const specifierNode = specifierPath.node
12
+ if (specifierNode.type === "StringLiteral") {
13
+ const specifier = specifierNode.value
14
+ if (
15
+ jsenvRemoteDirectory.isRemoteUrl(specifier) &&
16
+ !jsenvRemoteDirectory.isPreservedUrl(specifier)
17
+ ) {
18
+ const fileUrl = jsenvRemoteDirectory.fileUrlFromRemoteUrl(specifier)
19
+ const importerFileUrl = fileSystemPathToUrl(state.filename)
20
+ const urlRelativeToProject = urlToRelativeUrl(
21
+ fileUrl,
22
+ importerFileUrl,
23
+ )
24
+ const specifierProxy = `./${urlRelativeToProject}`
25
+ specifierPath.replaceWith(babel.types.stringLiteral(specifierProxy))
26
+ }
27
+ }
28
+ }),
29
+ name: "proxy-external-imports",
30
+ }
31
+ }
@@ -1,4 +1,4 @@
1
- import { urlToFilename } from "@jsenv/filesystem"
1
+ import { urlToFilename, urlToOrigin, urlToPathname } from "@jsenv/filesystem"
2
2
 
3
3
  export const urlIsCompilationAsset = (url) => {
4
4
  const filename = urlToFilename(url)
@@ -13,8 +13,12 @@ export const urlIsCompilationAsset = (url) => {
13
13
  }
14
14
 
15
15
  export const getMetaJsonFileUrl = (compileFileUrl) =>
16
- generateCompiledFileAssetUrl(compileFileUrl, "meta.json")
16
+ generateCompilationAssetUrl(compileFileUrl, "meta.json")
17
17
 
18
- export const generateCompiledFileAssetUrl = (compiledFileUrl, assetName) => {
19
- return `${compiledFileUrl}__asset__${assetName}`
18
+ export const generateCompilationAssetUrl = (compiledFileUrl, assetName) => {
19
+ // we want to remove eventual search params from url
20
+ const origin = urlToOrigin(compiledFileUrl)
21
+ const pathname = urlToPathname(compiledFileUrl)
22
+ const compilationAssetUrl = `${origin}${pathname}__asset__${assetName}`
23
+ return compilationAssetUrl
20
24
  }
@@ -1,6 +1,6 @@
1
+ import { timeStart, timeFunction } from "@jsenv/server"
1
2
  import { urlToFileSystemPath, readFile } from "@jsenv/filesystem"
2
3
  import { createDetailedMessage } from "@jsenv/logger"
3
- import { timeStart, timeFunction } from "@jsenv/server"
4
4
 
5
5
  import { validateCache } from "./validateCache.js"
6
6
  import { getMetaJsonFileUrl } from "./compile-asset.js"
@@ -14,6 +14,8 @@ export const getOrGenerateCompiledFile = async ({
14
14
  projectDirectoryUrl,
15
15
  originalFileUrl,
16
16
  compiledFileUrl = originalFileUrl,
17
+ jsenvRemoteDirectory,
18
+
17
19
  compileCacheStrategy,
18
20
  compileCacheSourcesValidation,
19
21
  compileCacheAssetsValidation,
@@ -61,8 +63,11 @@ export const getOrGenerateCompiledFile = async ({
61
63
  const lockTiming = lockTimeEnd()
62
64
  const { meta, compileResult, compileResultStatus, timing } =
63
65
  await computeCompileReport({
66
+ projectDirectoryUrl,
64
67
  originalFileUrl,
65
68
  compiledFileUrl,
69
+ jsenvRemoteDirectory,
70
+
66
71
  compile,
67
72
  compileCacheStrategy,
68
73
  compileCacheSourcesValidation,
@@ -89,14 +94,17 @@ export const getOrGenerateCompiledFile = async ({
89
94
  }
90
95
 
91
96
  const computeCompileReport = async ({
97
+ // projectDirectoryUrl,
98
+ logger,
92
99
  originalFileUrl,
93
100
  compiledFileUrl,
101
+ jsenvRemoteDirectory,
102
+
94
103
  compile,
95
104
  compileCacheStrategy,
96
105
  compileCacheSourcesValidation,
97
106
  compileCacheAssetsValidation,
98
107
  request,
99
- logger,
100
108
  }) => {
101
109
  const [readCacheTiming, cacheValidity] = await timeFunction(
102
110
  "read cache",
@@ -128,10 +136,41 @@ const computeCompileReport = async ({
128
136
  }
129
137
 
130
138
  const metaIsValid = cacheValidity.meta ? cacheValidity.meta.isValid : false
139
+
140
+ const fetchOriginalFile = async () => {
141
+ // The original file might be behind an http url.
142
+ // In that case jsenv try first to read file from filesystem
143
+ // in ".jsenv/.http/" directory. If not found, the url
144
+ // is fetched and file is written in that ".jsenv/.http/" directory.
145
+ // After that the only way to re-fetch this ressource is
146
+ // to delete the content of ".jsenv/.http/"
147
+ try {
148
+ const code = await readFile(originalFileUrl)
149
+ return { code }
150
+ } catch (e) {
151
+ // when file is not found and the file is referenced with an http url
152
+ if (
153
+ e &&
154
+ e.code === "ENOENT" &&
155
+ jsenvRemoteDirectory.isFileUrlForRemoteUrl(originalFileUrl)
156
+ ) {
157
+ const responseBodyAsBuffer =
158
+ await jsenvRemoteDirectory.loadFileUrlFromRemote(
159
+ originalFileUrl,
160
+ request,
161
+ )
162
+ const code = String(responseBodyAsBuffer)
163
+ return { code }
164
+ }
165
+ throw e
166
+ }
167
+ }
168
+ const { code } = await fetchOriginalFile()
131
169
  const [compileTiming, compileResult] = await timeFunction("compile", () =>
132
170
  callCompile({
133
171
  logger,
134
172
  originalFileUrl,
173
+ code,
135
174
  compile,
136
175
  }),
137
176
  )
@@ -169,12 +208,9 @@ const computeCompileReport = async ({
169
208
  }
170
209
  }
171
210
 
172
- const callCompile = async ({ logger, originalFileUrl, compile }) => {
211
+ const callCompile = async ({ logger, code, originalFileUrl, compile }) => {
173
212
  logger.debug(`compile ${originalFileUrl}`)
174
-
175
- const compileReturnValue = await compile({
176
- code: await readFile(originalFileUrl),
177
- })
213
+ const compileReturnValue = await compile({ code })
178
214
  if (typeof compileReturnValue !== "object" || compileReturnValue === null) {
179
215
  throw new TypeError(
180
216
  `compile must return an object, got ${compileReturnValue}`,
@@ -200,7 +236,6 @@ const callCompile = async ({ logger, originalFileUrl, compile }) => {
200
236
  `compile must return a compiledSource string, got ${compiledSource}`,
201
237
  )
202
238
  }
203
-
204
239
  return {
205
240
  contentType,
206
241
  compiledSource,
@@ -30,14 +30,10 @@ export const updateMeta = async ({
30
30
  const promises = []
31
31
  if (isNew || isUpdated) {
32
32
  // ensure source that does not leads to concrete files are not capable to invalidate the cache
33
- const sourcesToRemove = []
34
- sources.forEach((sourceFileUrl) => {
35
- const sourceFileExists = testFilePresence(sourceFileUrl)
36
- if (sourceFileExists) {
37
- return
38
- }
39
-
40
- sourcesToRemove.push(sourceFileUrl)
33
+ const sourcesToRemove = sources.filter((sourceFileUrl) => {
34
+ return (
35
+ sourceFileUrl.startsWith("file://") && !testFilePresence(sourceFileUrl)
36
+ )
41
37
  })
42
38
  const sourceNotFoundCount = sourcesToRemove.length
43
39
  if (sourceNotFoundCount > 0) {
@@ -1,7 +1,6 @@
1
- import { resolveUrl, bufferToEtag } from "@jsenv/filesystem"
2
-
3
1
  import { fileURLToPath } from "node:url"
4
2
  import { readFileSync, statSync } from "node:fs"
3
+ import { resolveUrl, bufferToEtag } from "@jsenv/filesystem"
5
4
 
6
5
  export const validateCache = async ({
7
6
  compiledFileUrl,
@@ -14,10 +14,13 @@ export const compileFile = async ({
14
14
  logger,
15
15
 
16
16
  projectDirectoryUrl,
17
+ jsenvRemoteDirectory,
17
18
  originalFileUrl,
18
19
  compiledFileUrl,
20
+
19
21
  projectFileRequestedCallback = () => {},
20
22
  request,
23
+ responseHeaders = {},
21
24
  pushResponse,
22
25
  importmapInfos,
23
26
  compile,
@@ -35,6 +38,11 @@ export const compileFile = async ({
35
38
  )
36
39
  }
37
40
 
41
+ projectFileRequestedCallback(
42
+ urlToRelativeUrl(originalFileUrl, projectDirectoryUrl),
43
+ request,
44
+ )
45
+
38
46
  const clientCacheDisabled = request.headers["cache-control"] === "no-cache"
39
47
 
40
48
  try {
@@ -44,6 +52,8 @@ export const compileFile = async ({
44
52
  projectDirectoryUrl,
45
53
  originalFileUrl,
46
54
  compiledFileUrl,
55
+ jsenvRemoteDirectory,
56
+
47
57
  request,
48
58
  compileCacheStrategy,
49
59
  compileCacheSourcesValidation,
@@ -78,13 +88,15 @@ export const compileFile = async ({
78
88
  compileResult.compiledMtime = Date.now()
79
89
  }
80
90
 
81
- const {
82
- contentType,
83
- compiledEtag,
84
- compiledMtime,
85
- compiledSource,
86
- responseHeaders = {},
87
- } = compileResult
91
+ const { contentType, compiledEtag, compiledMtime, compiledSource } =
92
+ compileResult
93
+
94
+ if (compileResult.responseHeaders) {
95
+ responseHeaders = {
96
+ ...responseHeaders,
97
+ ...compileResult.responseHeaders,
98
+ }
99
+ }
88
100
 
89
101
  if (compileResultStatus !== "cached" && compileCacheStrategy !== "none") {
90
102
  // we MUST await updateMeta otherwise we might get 404
@@ -207,7 +219,6 @@ export const compileFile = async ({
207
219
  }
208
220
  // on the correspondig file
209
221
  const json = JSON.stringify(data)
210
-
211
222
  return {
212
223
  status: 500,
213
224
  statusText: "parse error",
@@ -219,13 +230,14 @@ export const compileFile = async ({
219
230
  body: json,
220
231
  }
221
232
  }
222
-
233
+ if (error && error.asResponse) {
234
+ return error.asResponse()
235
+ }
223
236
  if (error && error.statusText === "Unexpected directory operation") {
224
237
  return {
225
238
  status: 403,
226
239
  }
227
240
  }
228
-
229
241
  return convertFileSystemErrorToResponseProperties(error)
230
242
  }
231
243
  }
@@ -38,7 +38,9 @@ export const createCompiledFileService = ({
38
38
  logger,
39
39
 
40
40
  projectDirectoryUrl,
41
+ jsenvDirectoryRelativeUrl,
41
42
  outDirectoryRelativeUrl,
43
+ jsenvRemoteDirectory,
42
44
 
43
45
  runtimeSupport,
44
46
  babelPluginMap,
@@ -89,12 +91,9 @@ export const createCompiledFileService = ({
89
91
 
90
92
  const importmapInfos = {}
91
93
 
92
- return (request, { pushResponse, redirectRequest }) => {
94
+ return async (request, { pushResponse, redirectRequest }) => {
93
95
  const { origin, ressource } = request
94
- // we use "ressourceToPathname" to remove eventual query param from the url
95
- // Without this a pattern like "**/*.js" would not match "file.js?t=1"
96
- // This would result in file not being compiled when they should
97
- const requestUrl = `${origin}${ressourceToPathname(ressource)}`
96
+ const requestUrl = `${origin}${ressource}`
98
97
 
99
98
  const requestCompileInfo = serverUrlToCompileInfo(requestUrl, {
100
99
  outDirectoryRelativeUrl,
@@ -140,8 +139,6 @@ export const createCompiledFileService = ({
140
139
  }
141
140
 
142
141
  const originalFileRelativeUrl = afterCompileId
143
- projectFileRequestedCallback(originalFileRelativeUrl, request)
144
-
145
142
  const originalFileUrl = `${projectDirectoryUrl}${originalFileRelativeUrl}`
146
143
  const compileDirectoryRelativeUrl = `${outDirectoryRelativeUrl}${compileId}/`
147
144
  const compileDirectoryUrl = resolveDirectoryUrl(
@@ -152,23 +149,22 @@ export const createCompiledFileService = ({
152
149
  originalFileRelativeUrl,
153
150
  compileDirectoryUrl,
154
151
  )
155
-
156
152
  const compiler = getCompiler({ originalFileUrl, compileMeta })
157
153
  // no compiler -> serve original file
158
- // we don't redirect otherwise it complexify ressource tracking
159
- // and url resolution
154
+ // we redirect "internally" (we dont send 304 to the browser)
155
+ // to keep ressource tracking and url resolution simple
160
156
  if (!compiler) {
161
157
  return redirectRequest({
162
158
  pathname: `/${originalFileRelativeUrl}`,
163
159
  })
164
160
  }
165
-
166
161
  // compile this if needed
167
162
  const compileResponsePromise = compileFile({
168
163
  compileServerOperation,
169
164
  logger,
170
165
 
171
166
  projectDirectoryUrl,
167
+ jsenvRemoteDirectory,
172
168
  originalFileUrl,
173
169
  compiledFileUrl,
174
170
 
@@ -181,14 +177,16 @@ export const createCompiledFileService = ({
181
177
  return compiler({
182
178
  logger,
183
179
 
184
- code,
185
- url: originalFileUrl,
186
- compiledUrl: compiledFileUrl,
187
180
  projectDirectoryUrl,
181
+ jsenvRemoteDirectory,
188
182
  compileServerOrigin: request.origin,
183
+ jsenvDirectoryRelativeUrl,
189
184
  outDirectoryRelativeUrl,
190
- compileId,
185
+ url: originalFileUrl,
186
+ compiledUrl: compiledFileUrl,
191
187
  request,
188
+
189
+ compileId,
192
190
  babelPluginMap: shakeBabelPluginMap({
193
191
  babelPluginMap,
194
192
  missingFeatureNames: groupMap[compileId].missingFeatureNames,
@@ -204,6 +202,7 @@ export const createCompiledFileService = ({
204
202
  topLevelAwait,
205
203
  prependSystemJs,
206
204
 
205
+ code,
207
206
  sourcemapMethod,
208
207
  sourcemapExcludeSources,
209
208
  jsenvEventSourceClientInjection,
@@ -238,6 +237,14 @@ const canAvoidSystemJs = ({
238
237
  }
239
238
 
240
239
  const getCompiler = ({ originalFileUrl, compileMeta }) => {
240
+ // we remove eventual query param from the url
241
+ // Without this a pattern like "**/*.js" would not match "file.js?t=1"
242
+ // This would result in file not being compiled when they should
243
+ // Ideally we would do a first pass with the query param and a second without
244
+ const urlObject = new URL(originalFileUrl)
245
+ urlObject.search = ""
246
+ originalFileUrl = urlObject.href
247
+
241
248
  const { jsenvCompiler, customCompiler } = urlToMeta({
242
249
  url: originalFileUrl,
243
250
  structuredMetaMap: compileMeta,
@@ -307,12 +314,3 @@ const contentTypeExtensions = {
307
314
  "application/importmap+json": ".importmap",
308
315
  // "text/css": ".css",
309
316
  }
310
-
311
- const ressourceToPathname = (ressource) => {
312
- const searchSeparatorIndex = ressource.indexOf("?")
313
- const pathname =
314
- searchSeparatorIndex === -1
315
- ? ressource
316
- : ressource.slice(0, searchSeparatorIndex)
317
- return pathname
318
- }