@jsenv/core 24.4.8 → 24.5.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 (25) hide show
  1. package/dist/build_manifest.js +4 -4
  2. package/dist/compile_proxy/asset-manifest.json +1 -2
  3. package/dist/compile_proxy/{compile_proxy-e666f204.html → compile_proxy-1dfca609.html} +254 -218
  4. package/dist/redirector/asset-manifest.json +1 -2
  5. package/dist/redirector/{redirector-bee67b92.html → redirector-d1316407.html} +254 -218
  6. package/dist/toolbar/asset-manifest.json +1 -2
  7. package/dist/toolbar/{toolbar-d13f2c3c.html → toolbar-201c4093.html} +254 -218
  8. package/dist/toolbar_injector/asset-manifest.json +1 -1
  9. package/dist/toolbar_injector/{toolbar_injector-828ec83b.js → toolbar_injector-84042210.js} +2 -2
  10. package/dist/toolbar_injector/{toolbar_injector-828ec83b.js.map → toolbar_injector-84042210.js.map} +2 -2
  11. package/package.json +1 -1
  12. package/src/buildProject.js +2 -0
  13. package/src/internal/building/buildUsingRollup.js +16 -28
  14. package/src/internal/building/{bundleWorker.js → js/babel_plugin_inline_worker_imports.js} +25 -61
  15. package/src/internal/building/js/parseJsRessource.js +12 -13
  16. package/src/internal/building/js/transform_worker.js +55 -0
  17. package/src/internal/building/resolve_import_url_helper.js +2 -1
  18. package/src/internal/building/ressource_builder.js +59 -15
  19. package/src/internal/building/{createJsenvRollupPlugin.js → rollup_plugin_jsenv.js} +80 -9
  20. package/src/internal/building/url_loader.js +0 -2
  21. package/src/internal/compiling/createCompiledFileService.js +3 -3
  22. package/dist/compile_proxy/assets/s.js-fcba0e35.map +0 -246
  23. package/dist/redirector/assets/s.js-fcba0e35.map +0 -246
  24. package/dist/toolbar/assets/s.js-fcba0e35.map +0 -246
  25. package/src/internal/building/buildServiceWorker.js +0 -75
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "assets/jsenv-logo.svg": "assets/jsenv-logo-188b9ca6.svg",
3
- "toolbar_injector.js": "toolbar_injector-828ec83b.js"
3
+ "toolbar_injector.js": "toolbar_injector-84042210.js"
4
4
  }
@@ -746,7 +746,7 @@
746
746
  return then ? value.then(then) : value;
747
747
  }
748
748
 
749
- var TOOLBAR_BUILD_RELATIVE_URL = "dist/toolbar/toolbar-d13f2c3c.html";
749
+ var TOOLBAR_BUILD_RELATIVE_URL = "dist/toolbar/toolbar-201c4093.html";
750
750
 
751
751
  function _call(body, then, direct) {
752
752
  if (direct) {
@@ -970,4 +970,4 @@
970
970
 
971
971
  })();
972
972
 
973
- //# sourceMappingURL=toolbar_injector-828ec83b.js.map
973
+ //# sourceMappingURL=toolbar_injector-84042210.js.map
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
- "file": "toolbar_injector-828ec83b.js",
3
+ "file": "toolbar_injector-84042210.js",
4
4
  "sources": [
5
5
  "../../helpers/babel/typeof/typeof.js",
6
6
  "../../helpers/babel/defineProperty/defineProperty.js",
@@ -25,7 +25,7 @@
25
25
  "import { fetchUrl } from \"./fetch-browser.js\"\n\nexport const fetchJson = async (url, options = {}) => {\n const response = await fetchUrl(url, options)\n const object = await response.json()\n return object\n}\n",
26
26
  "import { fetchJson } from \"../../browser_utils/fetchJson.js\"\n\nexport const fetchExploringJson = async ({ signal } = {}) => {\n try {\n const exploringInfo = await fetchJson(\"/.jsenv/exploring.json\", {\n signal,\n })\n return exploringInfo\n } catch (e) {\n if (signal && signal.aborted && e.name === \"AbortError\") {\n throw e\n }\n throw new Error(\n `Cannot communicate with exploring server due to a network error\n--- error stack ---\n${e.stack}`,\n )\n }\n}\n",
27
27
  "export const updateIframeOverflowOnParentWindow = () => {\n if (!window.parent) {\n // can happen while parent iframe reloads\n return\n }\n\n const aTooltipIsOpened =\n document.querySelector(\"[data-tooltip-visible]\") ||\n document.querySelector(\"[data-tooltip-auto-visible]\")\n const settingsAreOpened = document.querySelector(\"#settings[data-active]\")\n\n if (aTooltipIsOpened || settingsAreOpened) {\n enableIframeOverflowOnParentWindow()\n } else {\n disableIframeOverflowOnParentWindow()\n }\n}\n\nlet iframeOverflowEnabled = false\nconst enableIframeOverflowOnParentWindow = () => {\n if (iframeOverflowEnabled) return\n iframeOverflowEnabled = true\n\n const iframe = getToolbarIframe()\n const transitionDuration = iframe.style.transitionDuration\n setStyles(iframe, { \"height\": \"100%\", \"transition-duration\": \"0ms\" })\n if (transitionDuration) {\n setTimeout(() => {\n setStyles(iframe, { \"transition-duration\": transitionDuration })\n })\n }\n}\n\nconst disableIframeOverflowOnParentWindow = () => {\n if (!iframeOverflowEnabled) return\n iframeOverflowEnabled = false\n\n const iframe = getToolbarIframe()\n const transitionDuration = iframe.style.transitionDuration\n setStyles(iframe, { \"height\": \"40px\", \"transition-duration\": \"0ms\" })\n if (transitionDuration) {\n setTimeout(() => {\n setStyles(iframe, { \"transition-duration\": transitionDuration })\n })\n }\n}\n\nexport const getToolbarIframe = () => {\n const iframes = Array.from(window.parent.document.querySelectorAll(\"iframe\"))\n return iframes.find((iframe) => iframe.contentWindow === window)\n}\n\nexport const forceHideElement = (element) => {\n element.setAttribute(\"data-force-hide\", \"\")\n}\n\nexport const removeForceHideElement = (element) => {\n element.removeAttribute(\"data-force-hide\")\n}\n\nexport const setStyles = (element, styles) => {\n const elementStyle = element.style\n const restoreStyles = Object.keys(styles).map((styleName) => {\n let restore\n if (styleName in elementStyle) {\n const currentStyle = elementStyle[styleName]\n restore = () => {\n elementStyle[styleName] = currentStyle\n }\n } else {\n restore = () => {\n delete elementStyle[styleName]\n }\n }\n\n elementStyle[styleName] = styles[styleName]\n\n return restore\n })\n return () => {\n restoreStyles.forEach((restore) => restore())\n }\n}\n\nexport const setAttributes = (element, attributes) => {\n Object.keys(attributes).forEach((name) => {\n element.setAttribute(name, attributes[name])\n })\n}\n\nexport const getDocumentScroll = () => {\n return {\n x: document.documentElement.scrollLeft,\n y: document.documentElement.scrollTop,\n }\n}\n\nexport const toolbarSectionIsActive = (element) => {\n return element.hasAttribute(\"data-active\")\n}\n\nexport const activateToolbarSection = (element) => {\n element.setAttribute(\"data-active\", \"\")\n}\n\nexport const deactivateToolbarSection = (element) => {\n element.removeAttribute(\"data-active\")\n}\n",
28
- "import { fetchExploringJson } from \"@jsenv/core/src/internal/dev_server/exploring/fetchExploringJson.js\"\nimport { setAttributes, setStyles } from \"./util/dom.js\"\n\n// eslint-disable-next-line no-undef\nconst TOOLBAR_BUILD_RELATIVE_URL = \"dist/toolbar/toolbar-d13f2c3c.html\"\nconst jsenvLogoSvgUrl = new URL(\"./jsenv-logo.svg\", import.meta.url)\n\nconst injectToolbar = async () => {\n await new Promise((resolve) => {\n if (window.requestIdleCallback) {\n window.requestIdleCallback(resolve)\n } else {\n window.requestAnimationFrame(resolve)\n }\n })\n\n const { jsenvDirectoryRelativeUrl } = await fetchExploringJson()\n const jsenvDirectoryServerUrl = resolveUrl(\n jsenvDirectoryRelativeUrl,\n document.location.origin,\n )\n\n const placeholder = getToolbarPlaceholder()\n\n const iframe = document.createElement(\"iframe\")\n setAttributes(iframe, {\n tabindex: -1,\n // sandbox: \"allow-forms allow-modals allow-pointer-lock allow-popups allow-presentation allow-same-origin allow-scripts allow-top-navigation-by-user-activation\",\n // allow: \"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; microphone; midi; payment; vr\",\n allowtransparency: true,\n })\n setStyles(iframe, {\n \"position\": \"fixed\",\n \"zIndex\": 1000,\n \"bottom\": 0,\n \"left\": 0,\n \"width\": \"100%\",\n \"height\": 0,\n /* ensure toolbar children are not focusable when hidden */\n \"visibility\": \"hidden\",\n \"transition-duration\": \"300ms\",\n \"transition-property\": \"height, visibility\",\n \"border\": \"none\",\n })\n const iframeLoadedPromise = iframeToLoadedPromise(iframe)\n const jsenvToolbarHtmlServerUrl = resolveUrl(\n TOOLBAR_BUILD_RELATIVE_URL,\n jsenvDirectoryServerUrl,\n )\n // set iframe src BEFORE putting it into the DOM (prevent firefox adding an history entry)\n iframe.setAttribute(\"src\", jsenvToolbarHtmlServerUrl)\n placeholder.parentNode.replaceChild(iframe, placeholder)\n\n await iframeLoadedPromise\n iframe.removeAttribute(\"tabindex\")\n\n const div = document.createElement(\"div\")\n div.innerHTML = `\n<div id=\"jsenv-toolbar-trigger\">\n <svg id=\"jsenv-toolbar-trigger-icon\">\n <use xlink:href=\"${jsenvLogoSvgUrl}#jsenv-logo\"></use>\n </svg>\n <style>\n #jsenv-toolbar-trigger {\n display: block;\n overflow: hidden;\n position: fixed;\n z-index: 1000;\n bottom: -32px;\n right: 20px;\n height: 40px;\n width: 40px;\n padding: 0;\n margin: 0;\n border-radius: 5px 5px 0 0;\n border: 1px solid rgba(0, 0, 0, 0.33);\n border-bottom: none;\n box-shadow: 0px 0px 6px 2px rgba(0, 0, 0, 0.46);\n background: transparent;\n text-align: center;\n transition: 600ms;\n }\n\n #jsenv-toolbar-trigger:hover {\n cursor: pointer;\n }\n\n #jsenv-toolbar-trigger[data-expanded] {\n bottom: 0;\n }\n\n #jsenv-toolbar-trigger-icon {\n width: 35px;\n height: 35px;\n opacity: 0;\n transition: 600ms;\n }\n\n #jsenv-toolbar-trigger[data-expanded] #jsenv-toolbar-trigger-icon {\n opacity: 1;\n }\n </style>\n</div>`\n const toolbarTrigger = div.firstElementChild\n iframe.parentNode.appendChild(toolbarTrigger)\n\n let timer\n toolbarTrigger.onmouseenter = () => {\n toolbarTrigger.setAttribute(\"data-animate\", \"\")\n timer = setTimeout(expandToolbarTrigger, 500)\n }\n toolbarTrigger.onmouseleave = () => {\n clearTimeout(timer)\n collapseToolbarTrigger()\n }\n toolbarTrigger.onfocus = () => {\n toolbarTrigger.removeAttribute(\"data-animate\")\n expandToolbarTrigger()\n }\n toolbarTrigger.onblur = () => {\n toolbarTrigger.removeAttribute(\"data-animate\")\n clearTimeout(timer)\n collapseToolbarTrigger()\n }\n toolbarTrigger.onclick = () => {\n sendCommandToToolbar(iframe, \"showToolbar\")\n }\n\n const showToolbarTrigger = () => {\n toolbarTrigger.style.display = \"block\"\n }\n\n const hideToolbarTrigger = () => {\n toolbarTrigger.style.display = \"none\"\n }\n\n const expandToolbarTrigger = () => {\n toolbarTrigger.setAttribute(\"data-expanded\", \"\")\n }\n\n const collapseToolbarTrigger = () => {\n toolbarTrigger.removeAttribute(\"data-expanded\", \"\")\n }\n\n hideToolbarTrigger()\n addToolbarEventCallback(iframe, \"toolbar-visibility-change\", (visible) => {\n if (visible) {\n hideToolbarTrigger()\n } else {\n showToolbarTrigger()\n }\n })\n addToolbarEventCallback(iframe, \"toolbar_ready\", () => {\n sendCommandToToolbar(iframe, \"renderToolbar\")\n })\n\n return iframe\n}\n\nconst addToolbarEventCallback = (iframe, eventName, callback) => {\n const messageEventCallback = (messageEvent) => {\n const { data } = messageEvent\n if (typeof data !== \"object\") {\n return\n }\n const { __jsenv__ } = data\n if (!__jsenv__) {\n return\n }\n if (__jsenv__.event !== eventName) {\n return\n }\n callback(__jsenv__.data)\n }\n\n window.addEventListener(\"message\", messageEventCallback, false)\n return () => {\n window.removeEventListener(\"message\", messageEventCallback, false)\n }\n}\n\nconst sendCommandToToolbar = (iframe, command, ...args) => {\n iframe.contentWindow.postMessage(\n {\n __jsenv__: {\n command,\n args,\n },\n },\n window.origin,\n )\n}\n\nconst getToolbarPlaceholder = () => {\n const placeholder = queryPlaceholder()\n if (placeholder) {\n if (document.body.contains(placeholder)) {\n return placeholder\n }\n // otherwise iframe would not be visible because in <head>\n console.warn(\n \"element with [data-jsenv-toolbar-placeholder] must be inside document.body\",\n )\n return createTooolbarPlaceholder()\n }\n return createTooolbarPlaceholder()\n}\n\nconst queryPlaceholder = () => {\n return document.querySelector(\"[data-jsenv-toolbar-placeholder]\")\n}\n\nconst createTooolbarPlaceholder = () => {\n const placeholder = document.createElement(\"span\")\n document.body.appendChild(placeholder)\n return placeholder\n}\n\nconst iframeToLoadedPromise = (iframe) => {\n return new Promise((resolve) => {\n const onload = () => {\n iframe.removeEventListener(\"load\", onload, true)\n resolve()\n }\n iframe.addEventListener(\"load\", onload, true)\n })\n}\n\nconst resolveUrl = (url, baseUrl) => String(new URL(url, baseUrl))\n\nif (document.readyState === \"complete\") {\n injectToolbar()\n} else {\n window.addEventListener(\"load\", injectToolbar)\n}\n"
28
+ "import { fetchExploringJson } from \"@jsenv/core/src/internal/dev_server/exploring/fetchExploringJson.js\"\nimport { setAttributes, setStyles } from \"./util/dom.js\"\n\n// eslint-disable-next-line no-undef\nconst TOOLBAR_BUILD_RELATIVE_URL = \"dist/toolbar/toolbar-201c4093.html\"\nconst jsenvLogoSvgUrl = new URL(\"./jsenv-logo.svg\", import.meta.url)\n\nconst injectToolbar = async () => {\n await new Promise((resolve) => {\n if (window.requestIdleCallback) {\n window.requestIdleCallback(resolve)\n } else {\n window.requestAnimationFrame(resolve)\n }\n })\n\n const { jsenvDirectoryRelativeUrl } = await fetchExploringJson()\n const jsenvDirectoryServerUrl = resolveUrl(\n jsenvDirectoryRelativeUrl,\n document.location.origin,\n )\n\n const placeholder = getToolbarPlaceholder()\n\n const iframe = document.createElement(\"iframe\")\n setAttributes(iframe, {\n tabindex: -1,\n // sandbox: \"allow-forms allow-modals allow-pointer-lock allow-popups allow-presentation allow-same-origin allow-scripts allow-top-navigation-by-user-activation\",\n // allow: \"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; microphone; midi; payment; vr\",\n allowtransparency: true,\n })\n setStyles(iframe, {\n \"position\": \"fixed\",\n \"zIndex\": 1000,\n \"bottom\": 0,\n \"left\": 0,\n \"width\": \"100%\",\n \"height\": 0,\n /* ensure toolbar children are not focusable when hidden */\n \"visibility\": \"hidden\",\n \"transition-duration\": \"300ms\",\n \"transition-property\": \"height, visibility\",\n \"border\": \"none\",\n })\n const iframeLoadedPromise = iframeToLoadedPromise(iframe)\n const jsenvToolbarHtmlServerUrl = resolveUrl(\n TOOLBAR_BUILD_RELATIVE_URL,\n jsenvDirectoryServerUrl,\n )\n // set iframe src BEFORE putting it into the DOM (prevent firefox adding an history entry)\n iframe.setAttribute(\"src\", jsenvToolbarHtmlServerUrl)\n placeholder.parentNode.replaceChild(iframe, placeholder)\n\n await iframeLoadedPromise\n iframe.removeAttribute(\"tabindex\")\n\n const div = document.createElement(\"div\")\n div.innerHTML = `\n<div id=\"jsenv-toolbar-trigger\">\n <svg id=\"jsenv-toolbar-trigger-icon\">\n <use xlink:href=\"${jsenvLogoSvgUrl}#jsenv-logo\"></use>\n </svg>\n <style>\n #jsenv-toolbar-trigger {\n display: block;\n overflow: hidden;\n position: fixed;\n z-index: 1000;\n bottom: -32px;\n right: 20px;\n height: 40px;\n width: 40px;\n padding: 0;\n margin: 0;\n border-radius: 5px 5px 0 0;\n border: 1px solid rgba(0, 0, 0, 0.33);\n border-bottom: none;\n box-shadow: 0px 0px 6px 2px rgba(0, 0, 0, 0.46);\n background: transparent;\n text-align: center;\n transition: 600ms;\n }\n\n #jsenv-toolbar-trigger:hover {\n cursor: pointer;\n }\n\n #jsenv-toolbar-trigger[data-expanded] {\n bottom: 0;\n }\n\n #jsenv-toolbar-trigger-icon {\n width: 35px;\n height: 35px;\n opacity: 0;\n transition: 600ms;\n }\n\n #jsenv-toolbar-trigger[data-expanded] #jsenv-toolbar-trigger-icon {\n opacity: 1;\n }\n </style>\n</div>`\n const toolbarTrigger = div.firstElementChild\n iframe.parentNode.appendChild(toolbarTrigger)\n\n let timer\n toolbarTrigger.onmouseenter = () => {\n toolbarTrigger.setAttribute(\"data-animate\", \"\")\n timer = setTimeout(expandToolbarTrigger, 500)\n }\n toolbarTrigger.onmouseleave = () => {\n clearTimeout(timer)\n collapseToolbarTrigger()\n }\n toolbarTrigger.onfocus = () => {\n toolbarTrigger.removeAttribute(\"data-animate\")\n expandToolbarTrigger()\n }\n toolbarTrigger.onblur = () => {\n toolbarTrigger.removeAttribute(\"data-animate\")\n clearTimeout(timer)\n collapseToolbarTrigger()\n }\n toolbarTrigger.onclick = () => {\n sendCommandToToolbar(iframe, \"showToolbar\")\n }\n\n const showToolbarTrigger = () => {\n toolbarTrigger.style.display = \"block\"\n }\n\n const hideToolbarTrigger = () => {\n toolbarTrigger.style.display = \"none\"\n }\n\n const expandToolbarTrigger = () => {\n toolbarTrigger.setAttribute(\"data-expanded\", \"\")\n }\n\n const collapseToolbarTrigger = () => {\n toolbarTrigger.removeAttribute(\"data-expanded\", \"\")\n }\n\n hideToolbarTrigger()\n addToolbarEventCallback(iframe, \"toolbar-visibility-change\", (visible) => {\n if (visible) {\n hideToolbarTrigger()\n } else {\n showToolbarTrigger()\n }\n })\n addToolbarEventCallback(iframe, \"toolbar_ready\", () => {\n sendCommandToToolbar(iframe, \"renderToolbar\")\n })\n\n return iframe\n}\n\nconst addToolbarEventCallback = (iframe, eventName, callback) => {\n const messageEventCallback = (messageEvent) => {\n const { data } = messageEvent\n if (typeof data !== \"object\") {\n return\n }\n const { __jsenv__ } = data\n if (!__jsenv__) {\n return\n }\n if (__jsenv__.event !== eventName) {\n return\n }\n callback(__jsenv__.data)\n }\n\n window.addEventListener(\"message\", messageEventCallback, false)\n return () => {\n window.removeEventListener(\"message\", messageEventCallback, false)\n }\n}\n\nconst sendCommandToToolbar = (iframe, command, ...args) => {\n iframe.contentWindow.postMessage(\n {\n __jsenv__: {\n command,\n args,\n },\n },\n window.origin,\n )\n}\n\nconst getToolbarPlaceholder = () => {\n const placeholder = queryPlaceholder()\n if (placeholder) {\n if (document.body.contains(placeholder)) {\n return placeholder\n }\n // otherwise iframe would not be visible because in <head>\n console.warn(\n \"element with [data-jsenv-toolbar-placeholder] must be inside document.body\",\n )\n return createTooolbarPlaceholder()\n }\n return createTooolbarPlaceholder()\n}\n\nconst queryPlaceholder = () => {\n return document.querySelector(\"[data-jsenv-toolbar-placeholder]\")\n}\n\nconst createTooolbarPlaceholder = () => {\n const placeholder = document.createElement(\"span\")\n document.body.appendChild(placeholder)\n return placeholder\n}\n\nconst iframeToLoadedPromise = (iframe) => {\n return new Promise((resolve) => {\n const onload = () => {\n iframe.removeEventListener(\"load\", onload, true)\n resolve()\n }\n iframe.addEventListener(\"load\", onload, true)\n })\n}\n\nconst resolveUrl = (url, baseUrl) => String(new URL(url, baseUrl))\n\nif (document.readyState === \"complete\") {\n injectToolbar()\n} else {\n window.addEventListener(\"load\", injectToolbar)\n}\n"
29
29
  ],
30
30
  "names": [
31
31
  "nativeTypeOf",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "24.4.8",
3
+ "version": "24.5.0",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -79,6 +79,7 @@ export const buildProject = async ({
79
79
  // https://github.com/cssnano/cssnano/tree/master/packages/cssnano-preset-default
80
80
  minifyCssOptions,
81
81
 
82
+ workers = {},
82
83
  serviceWorkers = {},
83
84
  serviceWorkerFinalizer,
84
85
 
@@ -237,6 +238,7 @@ export const buildProject = async ({
237
238
  minifyJsOptions,
238
239
  minifyCssOptions,
239
240
 
241
+ workers,
240
242
  serviceWorkers,
241
243
  serviceWorkerFinalizer,
242
244
 
@@ -8,7 +8,6 @@ import {
8
8
  } from "@jsenv/filesystem"
9
9
  import { createDetailedMessage } from "@jsenv/logger"
10
10
 
11
- import { buildServiceWorker } from "@jsenv/core/src/internal/building/buildServiceWorker.js"
12
11
  import { humanizeUrl } from "@jsenv/core/src/internal/building/url_trace.js"
13
12
  import {
14
13
  isNodePartOfSupportedRuntimes,
@@ -16,7 +15,7 @@ import {
16
15
  } from "@jsenv/core/src/internal/generateGroupMap/runtime_support.js"
17
16
  import { featuresCompatMap } from "@jsenv/core/src/internal/generateGroupMap/featuresCompatMap.js"
18
17
  import { createRuntimeCompat } from "@jsenv/core/src/internal/generateGroupMap/runtime_compat.js"
19
- import { createJsenvRollupPlugin } from "./createJsenvRollupPlugin.js"
18
+ import { createJsenvRollupPlugin } from "./rollup_plugin_jsenv.js"
20
19
 
21
20
  export const buildUsingRollup = async ({
22
21
  buildOperation,
@@ -48,6 +47,9 @@ export const buildUsingRollup = async ({
48
47
  externalImportSpecifiers,
49
48
  externalImportUrlPatterns,
50
49
  importPaths,
50
+ workers,
51
+ serviceWorkers,
52
+ serviceWorkerFinalizer,
51
53
 
52
54
  urlVersioning,
53
55
  urlVersionningForEntryPoints,
@@ -62,9 +64,6 @@ export const buildUsingRollup = async ({
62
64
  minifyJsOptions,
63
65
  minifyCssOptions,
64
66
  minifyHtmlOptions,
65
-
66
- serviceWorkers,
67
- serviceWorkerFinalizer,
68
67
  }) => {
69
68
  const node = isNodePartOfSupportedRuntimes(runtimeSupport)
70
69
  const browser = isBrowserPartOfSupportedRuntimes(runtimeSupport)
@@ -121,6 +120,9 @@ export const buildUsingRollup = async ({
121
120
  externalImportSpecifiers,
122
121
  externalImportUrlPatterns,
123
122
  importPaths,
123
+ workers,
124
+ serviceWorkers,
125
+ serviceWorkerFinalizer,
124
126
 
125
127
  urlVersioning,
126
128
  urlVersionningForEntryPoints,
@@ -157,7 +159,16 @@ export const buildUsingRollup = async ({
157
159
  if (e.plugin === "jsenv") {
158
160
  const jsenvPluginErrorMessage = getLastErrorMessage()
159
161
  if (jsenvPluginErrorMessage) {
162
+ // rollup is adding properties to the original error
163
+ // making it a bit harder to read
164
+ // It does not add useful information so we restore the error
165
+ delete e.code
166
+ delete e.hook
167
+ delete e.id
168
+ delete e.watchFiles
169
+ delete e.plugin
160
170
  e.message = jsenvPluginErrorMessage
171
+ throw e
161
172
  }
162
173
  throw e
163
174
  }
@@ -219,29 +230,6 @@ export const buildUsingRollup = async ({
219
230
  await writeFile(fileBuildUrl, buildFileContents[buildRelativeUrl])
220
231
  }),
221
232
  )
222
-
223
- await Promise.all(
224
- Object.keys(serviceWorkers).map(
225
- async (serviceWorkerProjectRelativeUrl) => {
226
- const serviceWorkerBuildRelativeUrl =
227
- serviceWorkers[serviceWorkerProjectRelativeUrl]
228
- await buildServiceWorker({
229
- projectDirectoryUrl,
230
- buildDirectoryUrl,
231
- serviceWorkerProjectRelativeUrl,
232
- serviceWorkerBuildRelativeUrl,
233
- serviceWorkerTransformer: (code) =>
234
- serviceWorkerFinalizer(code, {
235
- buildManifest,
236
- rollupBuild,
237
- lineBreakNormalization,
238
- }),
239
-
240
- minify,
241
- })
242
- },
243
- ),
244
- )
245
233
  }
246
234
 
247
235
  return {
@@ -1,73 +1,24 @@
1
- import { readFileSync } from "fs"
2
1
  import {
3
2
  resolveUrl,
4
- urlToFileSystemPath,
5
3
  fileSystemPathToUrl,
4
+ urlToFileSystemPath,
6
5
  } from "@jsenv/filesystem"
7
- import { createDetailedMessage } from "@jsenv/logger"
8
- import { require } from "@jsenv/core/src/internal/require.js"
9
-
10
- export const bundleWorker = ({ workerScriptUrl, workerScriptSourceMap }) => {
11
- const { code, map } = transformWorkerScript(workerScriptUrl, {
12
- workerScriptSourceMap,
13
- })
14
- return { code, map }
15
- }
16
6
 
17
- const transformWorkerScript = (
18
- scriptUrl,
19
- { workerScriptSourceMap, importerUrl },
7
+ export const babelPluginInlineWorkerImports = (
8
+ babel,
9
+ { readImportedScript },
20
10
  ) => {
21
- const scriptPath = urlToFileSystemPath(scriptUrl)
22
- let scriptContent
23
- try {
24
- scriptContent = String(readFileSync(scriptPath))
25
- } catch (e) {
26
- if (e.code === "ENOENT") {
27
- if (importerUrl) {
28
- throw new Error(
29
- createDetailedMessage(`no file found for an import in a worker.`, {
30
- ["worker url"]: importerUrl,
31
- ["imported url"]: scriptUrl,
32
- }),
33
- )
34
- }
35
- throw new Error(`no worker file at ${scriptUrl}`)
36
- }
37
- throw e
38
- }
39
-
40
- const { transformSync } = require("@babel/core")
41
- const { code, map } = transformSync(scriptContent, {
42
- filename: scriptPath,
43
- configFile: false,
44
- babelrc: false, // trust only these options, do not read any babelrc config file
45
- ast: false,
46
- inputSourceMap: workerScriptSourceMap,
47
- sourceMaps: true,
48
- // sourceFileName: scriptPath,
49
- plugins: [[babelPluginInlineImportScripts, {}]],
50
- })
51
- return { code, map }
52
- }
11
+ const { types } = babel
53
12
 
54
- const babelPluginInlineImportScripts = (api) => {
55
- const { types, parse } = api
56
13
  return {
57
- name: "transform-inline-import-scripts",
14
+ name: "transform-inline-worker-imports",
58
15
 
59
16
  visitor: {
60
- CallExpression: (
61
- path,
62
- {
63
- file: {
64
- opts: { filename },
65
- },
66
- },
67
- ) => {
17
+ CallExpression: (path, opts) => {
68
18
  const calleePath = path.get("callee")
69
19
 
70
20
  const replaceImportScriptsWithFileContents = () => {
21
+ const filename = opts.filename
71
22
  const fileUrl = fileSystemPathToUrl(filename)
72
23
 
73
24
  let previousArgType = ""
@@ -97,11 +48,24 @@ const babelPluginInlineImportScripts = (api) => {
97
48
 
98
49
  if (previousArgType === "local") {
99
50
  const nodes = importedUrls.reduce((previous, importedUrl) => {
100
- const importedScriptResult = transformWorkerScript(importedUrl, {
101
- importerUrl: fileUrl,
51
+ const importedScriptCode = readImportedScript(importedUrl)
52
+ const { ast } = babel.transformSync(importedScriptCode, {
53
+ filename: urlToFileSystemPath(importedUrl),
54
+ configFile: false,
55
+ babelrc: false, // trust only these options, do not read any babelrc config file
56
+ ast: true,
57
+ sourceMaps: true,
58
+ // sourceFileName: scriptPath,
59
+ plugins: [
60
+ [
61
+ babelPluginInlineWorkerImports,
62
+ {
63
+ readImportedScript,
64
+ },
65
+ ],
66
+ ],
102
67
  })
103
- const importedSourceAst = parse(importedScriptResult.code)
104
- return [...previous, ...importedSourceAst.program.body]
68
+ return [...previous, ...ast.program.body]
105
69
  }, [])
106
70
 
107
71
  calleePath.parentPath.replaceWithMultiple(nodes)
@@ -4,7 +4,7 @@ import {
4
4
  getJavaScriptSourceMappingUrl,
5
5
  setJavaScriptSourceMappingUrl,
6
6
  } from "@jsenv/core/src/internal/sourceMappingURLUtils.js"
7
- import { bundleWorker } from "@jsenv/core/src/internal/building/bundleWorker.js"
7
+ import { transformWorker } from "./transform_worker.js"
8
8
 
9
9
  export const parseJsRessource = async (
10
10
  jsRessource,
@@ -47,19 +47,18 @@ export const parseJsRessource = async (
47
47
  map = JSON.parse(String(sourcemapRessource.bufferBeforeBuild))
48
48
  }
49
49
 
50
- // in case this js asset is a worker, bundle it so that:
51
- // importScripts are inlined which is good for:
52
- // - not breaking things (otherwise we would have to copy imported files in the build directory)
53
- // - perf (one less http request)
54
- const mightBeAWorkerScript = !jsRessource.isInline
55
- if (mightBeAWorkerScript) {
56
- const workerScriptUrl = asOriginalUrl(jsUrl)
57
- const workerBundle = await bundleWorker({
58
- workerScriptUrl,
59
- workerScriptSourceMap: map,
50
+ // in case this js asset is a worker, we transform it so that
51
+ // importScripts() calls are inlined
52
+ // We could also parse each importScripts call and decide to inline
53
+ // or not. For now inlining/concatenation is forced
54
+ if (jsRessource.isWorker || jsRessource.isServiceWorker) {
55
+ const transformResult = await transformWorker({
56
+ url: asOriginalUrl(jsUrl),
57
+ code: String(jsRessource.bufferBeforeBuild),
58
+ map,
60
59
  })
61
- code = workerBundle.code
62
- map = workerBundle.map
60
+ code = transformResult.code
61
+ map = transformResult.map
63
62
  } else {
64
63
  code = jsString
65
64
  }
@@ -0,0 +1,55 @@
1
+ // we could inline a worker by doing
2
+ // var blob = new Blob(code, { type: 'text/javascript' })
3
+ // window.URL.createObjectURL(blob)
4
+
5
+ import { readFileSync } from "fs"
6
+ import { urlToFileSystemPath } from "@jsenv/filesystem"
7
+ import { createDetailedMessage } from "@jsenv/logger"
8
+
9
+ import { babelPluginInlineWorkerImports } from "./babel_plugin_inline_worker_imports.js"
10
+
11
+ export const transformWorker = async ({ url, code, map }) => {
12
+ const { transformSync } = await import("@babel/core")
13
+
14
+ const transformResult = transformSync(code, {
15
+ filename: urlToFileSystemPath(url),
16
+ configFile: false,
17
+ babelrc: false, // trust only these options, do not read any babelrc config file
18
+ ast: false,
19
+ inputSourceMap: map,
20
+ sourceMaps: true,
21
+ // sourceFileName: scriptPath,
22
+ plugins: [
23
+ [
24
+ babelPluginInlineWorkerImports,
25
+ {
26
+ readImportedScript: readWorkerFile,
27
+ },
28
+ ],
29
+ ],
30
+ })
31
+ code = transformResult.code
32
+ map = transformResult.map
33
+ return { code, map }
34
+ }
35
+
36
+ export const readWorkerFile = (url, importerUrl) => {
37
+ const filePath = urlToFileSystemPath(url)
38
+ try {
39
+ const code = String(readFileSync(filePath))
40
+ return code
41
+ } catch (e) {
42
+ if (e.code === "ENOENT") {
43
+ if (importerUrl) {
44
+ throw new Error(
45
+ createDetailedMessage(`no file found for an import in a worker.`, {
46
+ ["worker url"]: importerUrl,
47
+ ["imported url"]: url,
48
+ }),
49
+ )
50
+ }
51
+ throw new Error(`no worker file at ${url}`)
52
+ }
53
+ throw e
54
+ }
55
+ }
@@ -4,7 +4,8 @@ window.__resolveImportUrl__ = (url, baseUrl) => {
4
4
 
5
5
  if (importmapNode) {
6
6
  const importmap = JSON.parse(importmapNode.textContent)
7
- return new URL(importmap.imports[url], baseUrl)
7
+ const specifier = importmap.imports[url] || url
8
+ return new URL(specifier, baseUrl)
8
9
  }
9
10
 
10
11
  return new URL(url, baseUrl)
@@ -5,7 +5,7 @@ import {
5
5
  urlToParentUrl,
6
6
  urlToFilename,
7
7
  } from "@jsenv/filesystem"
8
- import { createLogger } from "@jsenv/logger"
8
+ import { createLogger, loggerToLevels } from "@jsenv/logger"
9
9
 
10
10
  import { setJavaScriptSourceMappingUrl } from "@jsenv/core/src/internal/sourceMappingURLUtils.js"
11
11
  import { racePromises } from "../promise_race.js"
@@ -143,6 +143,9 @@ export const createRessourceBuilder = (
143
143
  contentType,
144
144
  bufferBeforeBuild,
145
145
  })
146
+ if (!reference) {
147
+ return null
148
+ }
146
149
  await reference.ressource.getReadyPromise()
147
150
  return reference
148
151
  }
@@ -229,10 +232,18 @@ export const createRessourceBuilder = (
229
232
 
230
233
  let ressourceUrl
231
234
  let isExternal = false
235
+ let isWorker = false
236
+ let isServiceWorker = false
232
237
  if (typeof ressourceUrlResolution === "object") {
233
- if (ressourceUrlResolution.external) {
238
+ if (ressourceUrlResolution.isExternal) {
234
239
  isExternal = true
235
240
  }
241
+ if (ressourceUrlResolution.isWorker) {
242
+ isWorker = true
243
+ }
244
+ if (ressourceUrlResolution.isServiceWorker) {
245
+ isServiceWorker = true
246
+ }
236
247
  ressourceUrl = ressourceUrlResolution.url
237
248
  } else {
238
249
  ressourceUrl = ressourceUrlResolution
@@ -292,6 +303,8 @@ export const createRessourceBuilder = (
292
303
  isExternal,
293
304
  isInline,
294
305
  isPlaceholder,
306
+ isWorker,
307
+ isServiceWorker,
295
308
  fileNamePattern,
296
309
  urlVersioningDisabled,
297
310
  })
@@ -330,14 +343,16 @@ export const createRessourceBuilder = (
330
343
  } else {
331
344
  ressource.references.push(reference)
332
345
  const effects = ressource.applyReferenceEffects(reference, { isJsModule })
333
- logger.debug(
334
- formatFoundReference({
335
- reference,
336
- referenceEffects: effects,
337
- showReferenceSourceLocation,
338
- shortenUrl,
339
- }),
340
- )
346
+ if (loggerToLevels(logger).debug) {
347
+ logger.debug(
348
+ formatFoundReference({
349
+ reference,
350
+ referenceEffects: effects,
351
+ showReferenceSourceLocation,
352
+ shortenUrl,
353
+ }),
354
+ )
355
+ }
341
356
  }
342
357
 
343
358
  return reference
@@ -356,9 +371,11 @@ export const createRessourceBuilder = (
356
371
  isExternal = false,
357
372
  isInline = false,
358
373
  isPlaceholder = false,
374
+ isWorker = false,
375
+ isServiceWorker = false,
359
376
 
360
377
  fileNamePattern,
361
- urlVersioningDisabled = false,
378
+ urlVersioningDisabled = isServiceWorker,
362
379
  }) => {
363
380
  const ressource = {
364
381
  contentType,
@@ -373,6 +390,8 @@ export const createRessourceBuilder = (
373
390
  isInline,
374
391
  isExternal,
375
392
  isPlaceholder,
393
+ isWorker,
394
+ isServiceWorker,
376
395
 
377
396
  urlVersioningDisabled,
378
397
  fileNamePattern,
@@ -424,12 +443,13 @@ export const createRessourceBuilder = (
424
443
 
425
444
  const response = await urlFetcher.fetchUrl(ressource.url, {
426
445
  contentTypeExpected: ressource.firstStrongReference.contentTypeExpected,
427
- urlTrace: () =>
428
- createRessourceTrace({
446
+ urlTrace: () => {
447
+ return createRessourceTrace({
429
448
  ressource,
430
449
  createUrlSiteFromReference,
431
450
  findRessourceByUrl,
432
- }),
451
+ })
452
+ },
433
453
  })
434
454
  if (response.url !== ressource.url) {
435
455
  const urlBeforeRedirection = ressource.url
@@ -875,7 +895,7 @@ export const createRessourceBuilder = (
875
895
  ? String(referenceSource)
876
896
  : ""
877
897
 
878
- return {
898
+ const urlSite = {
879
899
  type:
880
900
  referenceRessource && referenceRessource.isJsModule
881
901
  ? "import"
@@ -885,6 +905,30 @@ export const createRessourceBuilder = (
885
905
  column: referenceColumn,
886
906
  source: referenceSourceAsString,
887
907
  }
908
+
909
+ if (!referenceRessource.isInline) {
910
+ return urlSite
911
+ }
912
+ const { firstStrongReference } = referenceRessource
913
+ if (!firstStrongReference) {
914
+ return urlSite
915
+ }
916
+ const htmlUrlSite = createUrlSiteFromReference(firstStrongReference)
917
+ // when the html node is injected there is no line in the source file to target
918
+ if (htmlUrlSite.line === undefined) {
919
+ return urlSite
920
+ }
921
+ const importerRessource = findRessourceByUrl(
922
+ firstStrongReference.referenceUrl,
923
+ )
924
+ if (!importerRessource || importerRessource.contentType !== "text/html") {
925
+ return urlSite
926
+ }
927
+ return {
928
+ ...htmlUrlSite,
929
+ line: htmlUrlSite.line + urlSite.line,
930
+ column: htmlUrlSite.column + urlSite.column,
931
+ }
888
932
  }
889
933
 
890
934
  const showReferenceSourceLocation = (reference) => {