@jsenv/core 27.0.0-alpha.12 → 27.0.0-alpha.13

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 (116) hide show
  1. package/main.js +4 -0
  2. package/package.json +13 -7
  3. package/readme.md +4 -12
  4. package/src/build/build.js +438 -387
  5. package/src/build/build_urls_generator.js +23 -20
  6. package/src/build/graph_utils.js +31 -0
  7. package/src/build/{inject_version_mappings.js → inject_global_version_mappings.js} +31 -14
  8. package/src/build/inject_service_worker_urls.js +66 -12
  9. package/src/build/resync_ressource_hints.js +83 -0
  10. package/src/dev/plugins/autoreload/babel_plugin_metadata_import_meta_hot.js +1 -1
  11. package/src/dev/plugins/autoreload/client/import_meta_hot.js +3 -1
  12. package/src/dev/plugins/autoreload/html_hot_dependencies.js +2 -2
  13. package/src/dev/plugins/autoreload/jsenv_plugin_autoreload.js +61 -51
  14. package/src/dev/plugins/autoreload/sse_service.js +23 -3
  15. package/src/dev/plugins/explorer/jsenv_plugin_explorer.js +2 -2
  16. package/src/dev/plugins/toolbar/jsenv_plugin_toolbar.js +3 -1
  17. package/src/dev/start_dev_server.js +10 -5
  18. package/src/execute/execute.js +10 -4
  19. package/src/execute/run.js +17 -54
  20. package/src/execute/runtimes/browsers/from_playwright.js +167 -146
  21. package/src/execute/runtimes/node/node_process.js +281 -37
  22. package/src/omega/{runtime_support/default_runtime_support.js → compat/default_runtime_compat.js} +3 -5
  23. package/src/omega/{runtime_support/features_compatibility.js → compat/features_compats.js} +30 -7
  24. package/src/omega/{runtime_support/runtime_support.js → compat/runtime_compat.js} +14 -16
  25. package/src/omega/errors.js +51 -58
  26. package/src/omega/fetched_content_compliance.js +24 -0
  27. package/src/omega/kitchen.js +396 -280
  28. package/src/omega/server/file_service.js +9 -11
  29. package/src/omega/url_graph/url_graph_load.js +13 -7
  30. package/src/omega/url_graph/url_graph_report.js +7 -5
  31. package/src/omega/url_graph.js +22 -10
  32. package/src/omega/web_workers.js +42 -0
  33. package/src/plugins/bundling/css/bundle_css.js +17 -0
  34. package/src/plugins/bundling/js_classic_workers/bundle_js_classic_workers.js +13 -0
  35. package/src/{build/plugins/bundle_js_module/jsenv_plugin_bundle_js_module.js → plugins/bundling/js_module/bundle_js_module.js} +100 -75
  36. package/src/plugins/bundling/jsenv_plugin_bundling.js +51 -0
  37. package/src/{omega/core_plugins → plugins}/commonjs_globals/jsenv_plugin_commonjs_globals.js +48 -41
  38. package/src/plugins/file_urls/jsenv_plugin_file_urls.js +66 -0
  39. package/src/{omega/core_plugins → plugins}/filesystem_magic/jsenv_plugin_filesystem_magic.js +7 -4
  40. package/src/{omega/core_plugins → plugins}/html_supervisor/client/error_in_document.js +0 -0
  41. package/src/{omega/core_plugins → plugins}/html_supervisor/client/error_in_notification.js +0 -0
  42. package/src/{omega/core_plugins → plugins}/html_supervisor/client/html_supervisor_installer.js +3 -2
  43. package/src/{omega/core_plugins → plugins}/html_supervisor/client/html_supervisor_setup.js +0 -0
  44. package/src/{omega/core_plugins → plugins}/html_supervisor/client/perf_browser.js +0 -0
  45. package/src/{omega/core_plugins → plugins}/html_supervisor/client/uneval_exception.js +0 -0
  46. package/src/{omega/core_plugins → plugins}/html_supervisor/jsenv_plugin_html_supervisor.js +38 -46
  47. package/src/plugins/http_urls/jsenv_plugin_http_urls.js +12 -0
  48. package/src/{omega/core_plugins → plugins}/import_meta_scenarios/jsenv_plugin_import_meta_scenarios.js +26 -8
  49. package/src/plugins/import_meta_url/client/import_meta_url_browser.js +52 -0
  50. package/src/plugins/import_meta_url/client/import_meta_url_commonjs.mjs +9 -0
  51. package/src/{omega/core_plugins → plugins}/importmap/jsenv_plugin_importmap.js +37 -31
  52. package/src/{omega/core_plugins → plugins}/inject_globals/jsenv_plugin_inject_globals.js +4 -6
  53. package/src/{omega/core_plugins → plugins}/inline/client/inline_content.js +0 -0
  54. package/src/{omega/core_plugins → plugins}/inline/jsenv_plugin_data_urls.js +18 -14
  55. package/src/{omega/core_plugins/inline/jsenv_plugin_js_and_css_inside_html.js → plugins/inline/jsenv_plugin_html_inline_content.js} +61 -40
  56. package/src/plugins/inline/jsenv_plugin_inline.js +36 -0
  57. package/src/{omega/core_plugins → plugins}/inline/jsenv_plugin_inline_query_param.js +6 -6
  58. package/src/plugins/inline/jsenv_plugin_js_inline_content.js +263 -0
  59. package/src/plugins/leading_slash/jsenv_plugin_leading_slash.js +13 -0
  60. package/src/plugins/minification/css/minify_css.js +9 -0
  61. package/src/plugins/minification/html/minify_html.js +15 -0
  62. package/src/{build/plugins/minify_js/jsenv_plugin_minify_js.js → plugins/minification/js/minify_js.js} +6 -22
  63. package/src/plugins/minification/jsenv_plugin_minification.js +77 -0
  64. package/src/plugins/minification/json/minify_json.js +8 -0
  65. package/src/{omega/core_plugins → plugins}/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +15 -15
  66. package/src/{omega → plugins}/plugin_controller.js +18 -10
  67. package/src/plugins/plugins.js +50 -0
  68. package/src/plugins/transpilation/as_js_classic/client/s.js +808 -0
  69. package/src/plugins/transpilation/as_js_classic/client/s.js.md +1 -0
  70. package/src/plugins/transpilation/as_js_classic/helpers/babel_plugin_transform_import_meta_url.js +47 -0
  71. package/src/plugins/transpilation/as_js_classic/helpers/systemjs_old.js +43 -0
  72. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js +178 -0
  73. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_script_type_module_as_classic.js +156 -0
  74. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_top_level_await.js +37 -0
  75. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_workers_type_module_as_classic.js +133 -0
  76. package/src/{omega/core_plugins → plugins/transpilation}/babel/global_this/babel_plugin_global_this_as_jsenv_import.js +0 -0
  77. package/src/{omega/core_plugins → plugins/transpilation}/babel/global_this/client/global_this.js +0 -0
  78. package/src/{omega/core_plugins → plugins/transpilation}/babel/helpers/babel_plugin_babel_helpers_as_jsenv_imports.js +0 -0
  79. package/src/{omega/core_plugins → plugins/transpilation}/babel/helpers/babel_plugin_structure.js +3 -21
  80. package/src/{omega/core_plugins → plugins/transpilation}/babel/helpers/babel_plugins_compatibility.js +0 -0
  81. package/src/{omega/core_plugins → plugins/transpilation}/babel/jsenv_plugin_babel.js +29 -27
  82. package/src/{omega/core_plugins → plugins/transpilation}/babel/new_stylesheet/babel_plugin_new_stylesheet_as_jsenv_import.js +0 -0
  83. package/src/{omega/core_plugins → plugins/transpilation}/babel/new_stylesheet/client/.eslintrc.cjs +0 -0
  84. package/src/{omega/core_plugins → plugins/transpilation}/babel/new_stylesheet/client/new_stylesheet.js +0 -0
  85. package/src/{omega/core_plugins → plugins/transpilation}/babel/regenerator_runtime/babel_plugin_regenerator_runtime_as_jsenv_import.js +0 -0
  86. package/src/{omega/core_plugins → plugins/transpilation}/babel/regenerator_runtime/client/regenerator_runtime.js +0 -0
  87. package/src/plugins/transpilation/css_parcel/jsenv_plugin_css_parcel.js +18 -0
  88. package/src/{omega/core_plugins → plugins/transpilation}/import_assertions/helpers/babel_plugin_metadata_import_assertions.js +0 -0
  89. package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +243 -0
  90. package/src/plugins/transpilation/jsenv_plugin_transpilation.js +40 -0
  91. package/src/plugins/url_references/css/css_urls.js +49 -0
  92. package/src/plugins/url_references/html/html_urls.js +273 -0
  93. package/src/plugins/url_references/js/js_urls.js +170 -0
  94. package/src/plugins/url_references/jsenv_plugin_url_references.js +18 -0
  95. package/src/plugins/url_references/webmanifest/webmanifest_urls.js +17 -0
  96. package/src/{omega/core_plugins → plugins}/url_resolution/jsenv_plugin_url_resolution.js +12 -5
  97. package/src/{omega/core_plugins → plugins}/url_version/jsenv_plugin_url_version.js +8 -8
  98. package/src/preview/preview.js +3 -0
  99. package/src/test/execute_plan.js +18 -11
  100. package/src/test/execute_test_plan.js +5 -6
  101. package/src/test/logs_file_execution.js +8 -7
  102. package/src/build/plugins/minify_html/jsenv_plugin_minify_html.js +0 -30
  103. package/src/execute/runtimes/node/controlled_process.js +0 -316
  104. package/src/omega/core_plugins/file_urls/jsenv_plugin_file_urls.js +0 -67
  105. package/src/omega/core_plugins/import_assertions/helpers/json_module.js +0 -12
  106. package/src/omega/core_plugins/import_assertions/helpers/text_module.js +0 -6
  107. package/src/omega/core_plugins/import_assertions/jsenv_plugin_import_assertions.js +0 -211
  108. package/src/omega/core_plugins/inline/jsenv_plugin_inline.js +0 -13
  109. package/src/omega/core_plugins/inline/jsenv_plugin_new_inline_content.js +0 -207
  110. package/src/omega/core_plugins/leading_slash/jsenv_plugin_leading_slash.js +0 -12
  111. package/src/omega/core_plugins.js +0 -42
  112. package/src/omega/url_mentions/css_url_mentions.js +0 -63
  113. package/src/omega/url_mentions/html_url_mentions.js +0 -185
  114. package/src/omega/url_mentions/js_module_url_mentions.js +0 -91
  115. package/src/omega/url_mentions/parse_url_mentions.js +0 -37
  116. package/src/omega/url_mentions/worker_classic_url_mentions.js +0 -37
@@ -42,15 +42,11 @@ export const createFileService = ({
42
42
  const { runtimeName, runtimeVersion } = parseUserAgentHeader(
43
43
  request.headers["user-agent"],
44
44
  )
45
- const runtimeSupport = {
46
- [runtimeName]: runtimeVersion,
47
- }
48
- const reference = kitchen.createReference({
45
+ const [reference, urlInfo] = kitchen.prepareEntryPoint({
49
46
  parentUrl: inferParentFromRequest(request, rootDirectoryUrl),
50
47
  type: "entry_point",
51
48
  specifier: request.ressource,
52
49
  })
53
- const requestedUrlInfo = kitchen.resolveReference(reference)
54
50
  const referenceFromGraph = urlGraph.inferReference(
55
51
  reference.url,
56
52
  reference.parentUrl,
@@ -58,11 +54,13 @@ export const createFileService = ({
58
54
  try {
59
55
  await kitchen.cook({
60
56
  reference: referenceFromGraph || reference,
61
- urlInfo: requestedUrlInfo,
57
+ urlInfo,
62
58
  outDirectoryUrl: `${rootDirectoryUrl}.jsenv/${scenario}/${runtimeName}@${runtimeVersion}/`,
63
- runtimeSupport,
59
+ clientRuntimeCompat: {
60
+ [runtimeName]: runtimeVersion,
61
+ },
64
62
  })
65
- const { response, contentType, content } = requestedUrlInfo
63
+ const { response, contentType, content } = urlInfo
66
64
  if (response) {
67
65
  return response
68
66
  }
@@ -86,11 +84,11 @@ export const createFileService = ({
86
84
  statusText: e.reason,
87
85
  statusMessage: e.message,
88
86
  headers: {
89
- "content-type": requestedUrlInfo.contentType,
90
- "content-length": Buffer.byteLength(requestedUrlInfo.content),
87
+ "content-type": urlInfo.contentType,
88
+ "content-length": Buffer.byteLength(urlInfo.content),
91
89
  "cache-control": "no-store",
92
90
  },
93
- body: requestedUrlInfo.content,
91
+ body: urlInfo.content,
94
92
  }
95
93
  }
96
94
  if (code === "EISDIR") {
@@ -5,23 +5,24 @@ export const loadUrlGraph = async ({
5
5
  kitchen,
6
6
  startLoading,
7
7
  outDirectoryUrl,
8
- runtimeSupport,
8
+ clientRuntimeCompat,
9
9
  }) => {
10
10
  if (outDirectoryUrl) {
11
11
  await ensureEmptyDirectory(outDirectoryUrl)
12
12
  }
13
13
  const promises = []
14
+ const promiseMap = new Map()
14
15
  const cook = ({ urlInfo, ...rest }) => {
15
- const promiseFromData = urlInfo.data.promise
16
+ const promiseFromData = promiseMap.get(urlInfo)
16
17
  if (promiseFromData) return promiseFromData
17
18
  const promise = _cook({
18
19
  urlInfo,
19
20
  outDirectoryUrl,
20
- runtimeSupport,
21
+ clientRuntimeCompat,
21
22
  ...rest,
22
23
  })
23
24
  promises.push(promise)
24
- urlInfo.data.promise = promise
25
+ promiseMap.set(urlInfo, promise)
25
26
  return promise
26
27
  }
27
28
  const _cook = async ({ urlInfo, ...rest }) => {
@@ -32,21 +33,25 @@ export const loadUrlGraph = async ({
32
33
  })
33
34
  const { references } = urlInfo
34
35
  references.forEach((reference) => {
36
+ // we use reference.generatedUrl to mimic what a browser would do:
37
+ // do a fetch to the specifier as found in the file
38
+ const referencedUrlInfo = urlGraph.reuseOrCreateUrlInfo(
39
+ reference.generatedUrl,
40
+ )
35
41
  cook({
36
42
  reference,
37
- urlInfo: urlGraph.getUrlInfo(reference.url),
43
+ urlInfo: referencedUrlInfo,
38
44
  })
39
45
  })
40
46
  }
41
47
  startLoading(
42
48
  ({ trace, parentUrl = kitchen.rootDirectoryUrl, type, specifier }) => {
43
- const entryReference = kitchen.createReference({
49
+ const [entryReference, entryUrlInfo] = kitchen.prepareEntryPoint({
44
50
  trace,
45
51
  parentUrl,
46
52
  type,
47
53
  specifier,
48
54
  })
49
- const entryUrlInfo = kitchen.resolveReference(entryReference)
50
55
  entryUrlInfo.data.isEntryPoint = true
51
56
  cook({
52
57
  reference: entryReference,
@@ -66,4 +71,5 @@ export const loadUrlGraph = async ({
66
71
  await waitAll()
67
72
  }
68
73
  await waitAll()
74
+ promiseMap.clear()
69
75
  }
@@ -39,8 +39,10 @@ const createUrlGraphReport = (urlGraph) => {
39
39
  return
40
40
  }
41
41
  const urlInfo = urlInfos[url]
42
- // ignore inline files, they are already taken into account in the file where they appear
43
- if (urlInfo.isInline) {
42
+ // ignore:
43
+ // - inline files: they are already taken into account in the file where they appear
44
+ // - external files: we don't know their content
45
+ if (urlInfo.isInline || urlInfo.external) {
44
46
  return
45
47
  }
46
48
  // file loaded via import assertion are already inside the graph
@@ -49,9 +51,9 @@ const createUrlGraphReport = (urlGraph) => {
49
51
  // and only the js module remain (likely bundled)
50
52
  const urlObject = new URL(urlInfo.url)
51
53
  if (
52
- urlObject.searchParams.has("json_module") ||
53
- urlObject.searchParams.has("css_module") ||
54
- urlObject.searchParams.has("text_module")
54
+ urlObject.searchParams.has("as_json_module") ||
55
+ urlObject.searchParams.has("as_css_module") ||
56
+ urlObject.searchParams.has("as_text_module")
55
57
  ) {
56
58
  return
57
59
  }
@@ -44,9 +44,19 @@ export const createUrlGraph = () => {
44
44
  const updateReferences = (urlInfo, references) => {
45
45
  const dependencyUrls = []
46
46
  references.forEach((reference) => {
47
- if (!dependencyUrls.includes(reference.url)) {
48
- dependencyUrls.push(reference.url)
47
+ if (reference.isRessourceHint) {
48
+ // ressource hint are a special kind of reference.
49
+ // They are a sort of weak reference to an url.
50
+ // We ignore them so that url referenced only by ressource hints
51
+ // have url.dependents.size === 0 and can be considered as not used
52
+ // It means html won't consider url referenced solely
53
+ // by <link> as dependency and it's fine
54
+ return
49
55
  }
56
+ if (dependencyUrls.includes(reference.url)) {
57
+ return
58
+ }
59
+ dependencyUrls.push(reference.url)
50
60
  })
51
61
  pruneDependencies(
52
62
  urlInfo,
@@ -115,19 +125,21 @@ export const createUrlGraph = () => {
115
125
  const createUrlInfo = (url) => {
116
126
  return {
117
127
  data: {}, // plugins can put whatever they want here
128
+ references: [],
129
+ dependencies: new Set(),
130
+ dependents: new Set(),
131
+ type: undefined, // "html", "css", "js_classic", "js_module", "importmap", "json", "webmanifest", ...
132
+ subtype: undefined, // "worker", "service_worker", "shared_worker" for js, otherwise undefined
133
+ contentType: "", // "text/html", "text/css", "text/javascript", "application/json", ...
118
134
  url,
135
+ filename: "",
119
136
  generatedUrl: null,
120
137
  isInline: false,
121
138
  inlineUrlSite: null,
122
- contentType: "",
123
- originalContent: "",
124
- content: "",
139
+ external: false,
140
+ originalContent: undefined,
141
+ content: undefined,
125
142
  sourcemap: null,
126
143
  sourcemapReference: null,
127
- type: "",
128
- subtype: "",
129
- references: [],
130
- dependencies: new Set(),
131
- dependents: new Set(),
132
144
  }
133
145
  }
@@ -0,0 +1,42 @@
1
+ // the following apis are creating js entry points:
2
+ // - new Worker()
3
+ // - new SharedWorker()
4
+ // - navigator.serviceWorker.register()
5
+ export const isWebWorkerEntryPointReference = (reference) => {
6
+ if (reference.subtype === "new_url_first_arg") {
7
+ return ["worker", "service_worker", "shared_worker"].includes(
8
+ reference.expectedSubtype,
9
+ )
10
+ }
11
+ return [
12
+ "new_worker_first_arg",
13
+ "new_shared_worker_first_arg",
14
+ "service_worker_register_first_arg",
15
+ ].includes(reference.subtype)
16
+ }
17
+
18
+ export const isWebWorkerUrlInfo = (urlInfo) => {
19
+ return (
20
+ urlInfo.subtype === "worker" ||
21
+ urlInfo.subtype === "service_worker" ||
22
+ urlInfo.subtype === "shared_worker"
23
+ )
24
+ }
25
+
26
+ // export const isEntryPoint = (urlInfo, urlGraph) => {
27
+ // if (urlInfo.data.isEntryPoint) {
28
+ // return true
29
+ // }
30
+ // if (isWebWorker(urlInfo)) {
31
+ // // - new Worker("a.js") -> "a.js" is an entry point
32
+ // // - self.importScripts("b.js") -> "b.js" is not an entry point
33
+ // // So the following logic applies to infer if the file is a web worker entry point
34
+ // // "When a non-webworker file references a worker file, the worker file is an entry point"
35
+ // const dependents = Array.from(urlInfo.dependents)
36
+ // return dependents.some((dependentUrl) => {
37
+ // const dependentUrlInfo = urlGraph.getUrlInfo(dependentUrl)
38
+ // return !isWebWorker(dependentUrlInfo)
39
+ // })
40
+ // }
41
+ // return false
42
+ // }
@@ -0,0 +1,17 @@
1
+ import { bundleWithParcel } from "@jsenv/utils/css_ast/parcel_css.js"
2
+
3
+ export const bundleCss = ({ cssUrlInfos, context }) => {
4
+ const bundledCssUrlInfos = {}
5
+ cssUrlInfos.forEach((cssUrlInfo) => {
6
+ const { code, map } = bundleWithParcel(cssUrlInfo, context)
7
+ bundledCssUrlInfos[cssUrlInfo.url] = {
8
+ data: {
9
+ generatedBy: "parcel",
10
+ },
11
+ contentType: "text/css",
12
+ content: String(code),
13
+ sourcemap: map,
14
+ }
15
+ })
16
+ return bundledCssUrlInfos
17
+ }
@@ -0,0 +1,13 @@
1
+ /*
2
+ * TODO:
3
+ * for each js_classic where subtype is a worker
4
+ * take the url info and find importScripts calls
5
+ * and replace them with the corresponding url info file content
6
+ * we'll ikely need to save the importScripts node location to be able to do that
7
+ */
8
+
9
+ // import { createMagicSource } from "@jsenv/utils/sourcemap/magic_source.js"
10
+
11
+ export const bundleJsClassicWorkers = () => {
12
+ return {}
13
+ }
@@ -1,43 +1,32 @@
1
- import { isFileSystemPath, urlToRelativeUrl } from "@jsenv/filesystem"
1
+ import { isFileSystemPath } from "@jsenv/filesystem"
2
+ import { createDetailedMessage } from "@jsenv/logger"
2
3
 
3
4
  import { applyRollupPlugins } from "@jsenv/utils/js_ast/apply_rollup_plugins.js"
4
5
  import { sourcemapConverter } from "@jsenv/utils/sourcemap/sourcemap_converter.js"
5
6
  import { fileUrlConverter } from "@jsenv/core/src/omega/file_url_converter.js"
6
7
 
7
- export const jsenvPluginBundleJsModule = () => {
8
- return {
9
- name: "jsenv:bundle_js_module",
10
- appliesDuring: {
11
- build: true,
12
- },
13
- bundle: {
14
- js_module: async (
15
- jsModuleUrlInfos,
16
- {
17
- signal,
18
- logger,
19
- rootDirectoryUrl,
20
- buildDirectoryUrl,
21
- urlGraph,
22
- runtimeSupport,
23
- sourcemaps,
24
- },
25
- ) => {
26
- const { jsModuleBundleUrlInfos } = await buildWithRollup({
27
- signal,
28
- logger,
29
- rootDirectoryUrl,
30
- buildDirectoryUrl,
31
- urlGraph,
32
- jsModuleUrlInfos,
8
+ export const bundleJsModule = async ({ jsModuleUrlInfos, context }) => {
9
+ const {
10
+ signal,
11
+ logger,
12
+ rootDirectoryUrl,
13
+ buildDirectoryUrl,
14
+ urlGraph,
15
+ runtimeCompat,
16
+ sourcemaps,
17
+ } = context
18
+ const { jsModuleBundleUrlInfos } = await buildWithRollup({
19
+ signal,
20
+ logger,
21
+ rootDirectoryUrl,
22
+ buildDirectoryUrl,
23
+ urlGraph,
24
+ jsModuleUrlInfos,
33
25
 
34
- runtimeSupport,
35
- sourcemaps,
36
- })
37
- return jsModuleBundleUrlInfos
38
- },
39
- },
40
- }
26
+ runtimeCompat,
27
+ sourcemaps,
28
+ })
29
+ return jsModuleBundleUrlInfos
41
30
  }
42
31
 
43
32
  export const buildWithRollup = async ({
@@ -48,36 +37,46 @@ export const buildWithRollup = async ({
48
37
  urlGraph,
49
38
  jsModuleUrlInfos,
50
39
 
51
- runtimeSupport,
40
+ runtimeCompat,
52
41
  sourcemaps,
53
42
  }) => {
54
43
  const resultRef = { current: null }
55
- await applyRollupPlugins({
56
- rollupPlugins: [
57
- rollupPluginJsenv({
58
- signal,
59
- logger,
60
- rootDirectoryUrl,
61
- buildDirectoryUrl,
62
- urlGraph,
63
- jsModuleUrlInfos,
44
+ try {
45
+ await applyRollupPlugins({
46
+ rollupPlugins: [
47
+ rollupPluginJsenv({
48
+ signal,
49
+ logger,
50
+ rootDirectoryUrl,
51
+ buildDirectoryUrl,
52
+ urlGraph,
53
+ jsModuleUrlInfos,
64
54
 
65
- runtimeSupport,
66
- sourcemaps,
67
- resultRef,
68
- }),
69
- ],
70
- inputOptions: {
71
- input: [],
72
- onwarn: (warning) => {
73
- if (warning.code === "CIRCULAR_DEPENDENCY") {
74
- return
75
- }
76
- logger.warn(String(warning))
55
+ runtimeCompat,
56
+ sourcemaps,
57
+ resultRef,
58
+ }),
59
+ ],
60
+ inputOptions: {
61
+ input: [],
62
+ onwarn: (warning) => {
63
+ if (warning.code === "CIRCULAR_DEPENDENCY") {
64
+ return
65
+ }
66
+ logger.warn(String(warning))
67
+ },
77
68
  },
78
- },
79
- })
80
- return resultRef.current
69
+ })
70
+ return resultRef.current
71
+ } catch (e) {
72
+ if (e.code === "MISSING_EXPORT") {
73
+ const detailedMessage = createDetailedMessage(e.message, {
74
+ frame: e.frame,
75
+ })
76
+ throw new Error(detailedMessage, { cause: e })
77
+ }
78
+ throw e
79
+ }
81
80
  }
82
81
 
83
82
  const rollupPluginJsenv = ({
@@ -119,6 +118,7 @@ const rollupPluginJsenv = ({
119
118
  implicitlyLoadedAfterOneOf: previousNonEntryPointModuleId
120
119
  ? [previousNonEntryPointModuleId]
121
120
  : null,
121
+ preserveSignature: "allow-extension",
122
122
  })
123
123
  previousNonEntryPointModuleId = id
124
124
  })
@@ -135,8 +135,12 @@ const rollupPluginJsenv = ({
135
135
  // buildRelativeUrl: rollupFileInfo.fileName,
136
136
  data: {
137
137
  generatedBy: "rollup",
138
+ usesImport:
139
+ rollupFileInfo.imports.length > 0 ||
140
+ rollupFileInfo.dynamicImports.length > 0,
141
+ usesExport: rollupFileInfo.exports.length > 0,
138
142
  },
139
- contentType: "application/javascript",
143
+ contentType: "text/javascript",
140
144
  content: rollupFileInfo.code,
141
145
  sourcemap: rollupFileInfo.map,
142
146
  }
@@ -144,7 +148,7 @@ const rollupPluginJsenv = ({
144
148
  if (rollupFileInfo.facadeModuleId) {
145
149
  url = fileUrlConverter.asFileUrl(rollupFileInfo.facadeModuleId)
146
150
  } else {
147
- url = new URL(rollupFileInfo.fileName, rootDirectoryUrl).href
151
+ url = new URL(rollupFileInfo.fileName, buildDirectoryUrl).href
148
152
  }
149
153
  jsModuleBundleUrlInfos[url] = jsModuleBundleUrlInfo
150
154
  }
@@ -167,19 +171,12 @@ const rollupPluginJsenv = ({
167
171
  return `[name].js`
168
172
  },
169
173
  chunkFileNames: (chunkInfo) => {
170
- // preserves relative path parts:
171
- // the goal is to maintain the original relative path (relative to the root directory)
172
- // so that later in the build process, when resolving these urls, we are able to
173
- // re-resolve the specifier againt the original parent url and find the original url
174
- if (chunkInfo.facadeModuleId) {
175
- const fileUrl = fileUrlConverter.asFileUrl(chunkInfo.facadeModuleId)
176
- const relativePath = urlToRelativeUrl(fileUrl, rootDirectoryUrl)
177
- return relativePath
178
- }
179
- // chunk generated dynamically by rollup to share code.
180
- // we prefix with "__rollup__/" to avoid potential conflict of filename
181
- // between this one and a file with the same name existing in the root directory
182
- return `__rollup__/${chunkInfo.name}.js`
174
+ const insideJs = willBeInsideJsDirectory({
175
+ chunkInfo,
176
+ fileUrlConverter,
177
+ jsModuleUrlInfos,
178
+ })
179
+ return insideJs ? `js/${chunkInfo.name}.js` : `${chunkInfo.name}.js`
183
180
  },
184
181
  // https://rollupjs.org/guide/en/#outputpaths
185
182
  // paths: (id) => {
@@ -197,7 +194,7 @@ const rollupPluginJsenv = ({
197
194
  urlImporters[url] = importer
198
195
  }
199
196
  if (!url.startsWith("file:")) {
200
- return { url, external: true }
197
+ return { id: url, external: true }
201
198
  }
202
199
  const filePath = fileUrlConverter.asFilePath(url)
203
200
  return filePath
@@ -225,3 +222,31 @@ const rollupPluginJsenv = ({
225
222
  },
226
223
  }
227
224
  }
225
+
226
+ const willBeInsideJsDirectory = ({
227
+ chunkInfo,
228
+ fileUrlConverter,
229
+ jsModuleUrlInfos,
230
+ }) => {
231
+ // if the chunk is generated dynamically by rollup
232
+ // for an entry point jsenv will put that file inside js/ directory
233
+ // if it's generated dynamically for a file already in js/ directory
234
+ // both will be inside the js/ directory
235
+ if (!chunkInfo.facadeModuleId) {
236
+ // generated by rollup
237
+ return true
238
+ }
239
+ const url = fileUrlConverter.asFileUrl(chunkInfo.facadeModuleId)
240
+ const jsModuleUrlInfo = jsModuleUrlInfos.find(
241
+ (jsModuleUrlInfo) => jsModuleUrlInfo.url === url,
242
+ )
243
+ if (!jsModuleUrlInfo) {
244
+ // generated by rollup
245
+ return true
246
+ }
247
+ if (!jsModuleUrlInfo.data.isEntryPoint) {
248
+ // not an entry point, jsenv will put it inside js/ directory
249
+ return true
250
+ }
251
+ return false
252
+ }
@@ -0,0 +1,51 @@
1
+ import { bundleCss } from "./css/bundle_css.js"
2
+ import { bundleJsClassicWorkers } from "./js_classic_workers/bundle_js_classic_workers.js"
3
+ import { bundleJsModule } from "./js_module/bundle_js_module.js"
4
+
5
+ export const jsenvPluginBundling = (bundling) => {
6
+ if (typeof bundling === "boolean") {
7
+ bundling = {
8
+ css: bundling,
9
+ js_classic_workers: bundling,
10
+ js_module: bundling,
11
+ }
12
+ } else if (typeof bundling !== "object") {
13
+ throw new Error(`bundling must be a boolean or an object, got ${bundling}`)
14
+ }
15
+ Object.keys(bundling).forEach((key) => {
16
+ if (bundling[key] === true) bundling[key] = {}
17
+ })
18
+
19
+ return {
20
+ name: "jsenv:bundling",
21
+ appliesDuring: {
22
+ build: true,
23
+ },
24
+ bundle: {
25
+ css: bundling.css
26
+ ? (cssUrlInfos, context) =>
27
+ bundleCss({
28
+ cssUrlInfos,
29
+ context,
30
+ options: bundling.css,
31
+ })
32
+ : undefined,
33
+ js_classic: bundling.js_classic
34
+ ? (jsClassicUrlInfos, context) =>
35
+ bundleJsClassicWorkers({
36
+ jsClassicUrlInfos,
37
+ context,
38
+ options: bundling.js_classic_workers,
39
+ })
40
+ : undefined,
41
+ js_module: bundling.js_module
42
+ ? (jsModuleUrlInfos, context) =>
43
+ bundleJsModule({
44
+ jsModuleUrlInfos,
45
+ context,
46
+ options: bundling.js_module,
47
+ })
48
+ : undefined,
49
+ },
50
+ }
51
+ }
@@ -11,50 +11,57 @@ import { applyBabelPlugins } from "@jsenv/utils/js_ast/apply_babel_plugins.js"
11
11
  import { createMagicSource } from "@jsenv/utils/sourcemap/magic_source.js"
12
12
 
13
13
  export const jsenvPluginCommonJsGlobals = () => {
14
+ const transformCommonJsGlobals = async (urlInfo, { scenario }) => {
15
+ const isJsModule = urlInfo.type === "js_module"
16
+
17
+ const replaceMap = {
18
+ "process.env.NODE_ENV": `("${
19
+ scenario === "dev" || scenario === "test" ? "dev" : "prod"
20
+ }")`,
21
+ "global": "globalThis",
22
+ "__filename": isJsModule
23
+ ? `import.meta.url.slice('file:///'.length)`
24
+ : `document.currentScript.src`,
25
+ "__dirname": isJsModule
26
+ ? `import.meta.url.slice('file:///'.length).replace(/[\\\/\\\\][^\\\/\\\\]*$/, '')`
27
+ : `new URL('./', document.currentScript.src).href`,
28
+ }
29
+ const { metadata } = await applyBabelPlugins({
30
+ babelPlugins: [
31
+ [
32
+ babelPluginMetadataExpressionPaths,
33
+ {
34
+ replaceMap,
35
+ allowConflictingReplacements: true,
36
+ },
37
+ ],
38
+ ],
39
+ urlInfo,
40
+ })
41
+ const { expressionPaths } = metadata
42
+ const keys = Object.keys(expressionPaths)
43
+ if (keys.length === 0) {
44
+ return null
45
+ }
46
+ const magicSource = createMagicSource(urlInfo.content)
47
+ keys.forEach((key) => {
48
+ expressionPaths[key].forEach((path) => {
49
+ magicSource.replace({
50
+ start: path.node.start,
51
+ end: path.node.end,
52
+ replacement: replaceMap[key],
53
+ })
54
+ })
55
+ })
56
+ return magicSource.toContentAndSourcemap()
57
+ }
58
+
14
59
  return {
15
60
  name: "jsenv:commonjs_globals",
16
61
  appliesDuring: "*",
17
- transform: {
18
- js_module: async ({ url, generatedUrl, content }, { scenario }) => {
19
- const replaceMap = {
20
- "process.env.NODE_ENV": `("${
21
- scenario === "dev" || scenario === "test" ? "dev" : "prod"
22
- }")`,
23
- "global": "globalThis",
24
- "__filename": `import.meta.url.slice('file:///'.length)`,
25
- "__dirname": `import.meta.url.slice('file:///'.length).replace(/[\\\/\\\\][^\\\/\\\\]*$/, '')`,
26
- }
27
- const { metadata } = await applyBabelPlugins({
28
- babelPlugins: [
29
- [
30
- babelPluginMetadataExpressionPaths,
31
- {
32
- replaceMap,
33
- allowConflictingReplacements: true,
34
- },
35
- ],
36
- ],
37
- url,
38
- generatedUrl,
39
- content,
40
- })
41
- const { expressionPaths } = metadata
42
- const keys = Object.keys(expressionPaths)
43
- if (keys.length === 0) {
44
- return null
45
- }
46
- const magicSource = createMagicSource(content)
47
- keys.forEach((key) => {
48
- expressionPaths[key].forEach((path) => {
49
- magicSource.replace({
50
- start: path.node.start,
51
- end: path.node.end,
52
- replacement: replaceMap[key],
53
- })
54
- })
55
- })
56
- return magicSource.toContentAndSourcemap()
57
- },
62
+ transformUrlContent: {
63
+ js_classic: transformCommonJsGlobals,
64
+ js_module: transformCommonJsGlobals,
58
65
  },
59
66
  }
60
67
  }