@jsenv/core 28.1.1 → 28.2.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 (51) hide show
  1. package/dist/js/script_type_module_supervisor.js +8 -13
  2. package/dist/js/supervisor.js +702 -534
  3. package/dist/main.js +13275 -13164
  4. package/package.json +5 -5
  5. package/readme.md +3 -3
  6. package/src/build/build.js +960 -712
  7. package/src/build/inject_global_version_mappings.js +5 -20
  8. package/src/build/start_build_server.js +2 -2
  9. package/src/dev/start_dev_server.js +3 -2
  10. package/src/execute/run.js +1 -1
  11. package/src/execute/runtimes/browsers/from_playwright.js +1 -1
  12. package/src/omega/compat/runtime_compat.js +9 -6
  13. package/src/omega/errors.js +3 -0
  14. package/src/omega/fetched_content_compliance.js +2 -2
  15. package/src/omega/kitchen.js +189 -145
  16. package/src/omega/server/file_service.js +104 -71
  17. package/src/omega/url_graph/url_graph_loader.js +77 -0
  18. package/src/omega/url_graph/url_info_transformations.js +12 -15
  19. package/src/omega/url_graph.js +115 -101
  20. package/src/plugins/autoreload/jsenv_plugin_autoreload_client.js +1 -0
  21. package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +34 -36
  22. package/src/plugins/autoreload/jsenv_plugin_hmr.js +3 -2
  23. package/src/plugins/bundling/js_module/{bundle_js_module.js → bundle_js_modules.js} +51 -14
  24. package/src/plugins/bundling/jsenv_plugin_bundling.js +2 -2
  25. package/src/plugins/import_meta_hot/jsenv_plugin_import_meta_hot.js +11 -0
  26. package/src/plugins/inline/jsenv_plugin_html_inline_content.js +73 -62
  27. package/src/plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +77 -89
  28. package/src/plugins/plugin_controller.js +26 -22
  29. package/src/plugins/server_events/jsenv_plugin_server_events_client_injection.js +1 -0
  30. package/src/plugins/supervisor/client/script_type_module_supervisor.js +7 -9
  31. package/src/plugins/supervisor/client/supervisor.js +125 -96
  32. package/src/plugins/supervisor/jsenv_plugin_supervisor.js +2 -4
  33. package/src/plugins/toolbar/client/execution/toolbar_execution.js +1 -1
  34. package/src/plugins/transpilation/as_js_classic/async-to-promises.js +16 -0
  35. package/src/plugins/transpilation/as_js_classic/convert_js_module_to_js_classic.js +85 -0
  36. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js +48 -190
  37. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_conversion.js +102 -0
  38. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_html.js +161 -240
  39. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_library.js +84 -0
  40. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_workers.js +19 -12
  41. package/src/plugins/transpilation/babel/jsenv_plugin_babel.js +1 -24
  42. package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +82 -52
  43. package/src/plugins/transpilation/jsenv_plugin_transpilation.js +12 -13
  44. package/src/plugins/url_analysis/html/html_urls.js +91 -34
  45. package/src/plugins/url_analysis/js/js_urls.js +5 -4
  46. package/src/plugins/url_resolution/jsenv_plugin_url_resolution.js +1 -0
  47. package/src/test/execute_plan.js +3 -8
  48. package/src/test/execute_test_plan.js +1 -1
  49. package/src/build/inject_service_worker_urls.js +0 -78
  50. package/src/build/resync_resource_hints.js +0 -112
  51. package/src/omega/url_graph/url_graph_load.js +0 -74
@@ -7,27 +7,17 @@ window.__supervisor__ = (() => {
7
7
  reportError: notImplemented,
8
8
  superviseScript: notImplemented,
9
9
  reloadSupervisedScript: notImplemented,
10
- collectScriptResults: notImplemented,
11
- getScriptExecutionResults: () => {
12
- // wait for page to load before collecting script execution results
13
- const htmlReadyPromise = new Promise((resolve) => {
14
- if (document.readyState === "complete") {
15
- resolve()
16
- return
17
- }
18
- const loadCallback = () => {
19
- window.removeEventListener("load", loadCallback)
20
- resolve()
21
- }
22
- window.addEventListener("load", loadCallback)
23
- })
24
- return htmlReadyPromise.then(() => {
25
- return supervisor.collectScriptResults()
26
- })
27
- },
10
+ getDocumentExecutionResult: notImplemented,
28
11
  executionResults,
29
12
  }
30
13
 
14
+ let navigationStartTime
15
+ try {
16
+ navigationStartTime = window.performance.timing.navigationStart
17
+ } catch (e) {
18
+ navigationStartTime = Date.now()
19
+ }
20
+
31
21
  supervisor.setupReportException = ({
32
22
  rootDirectoryUrl,
33
23
  errorNotification,
@@ -715,7 +705,6 @@ window.__supervisor__ = (() => {
715
705
  supervisor.setup = ({
716
706
  rootDirectoryUrl,
717
707
  logs,
718
- measurePerf,
719
708
  errorOverlay,
720
709
  errorBaseUrl,
721
710
  openInEditor,
@@ -728,8 +717,35 @@ window.__supervisor__ = (() => {
728
717
  })
729
718
 
730
719
  const supervisedScripts = []
731
- const executionPromises = []
732
- supervisor.createExecution = ({ type, src, async, execute }) => {
720
+ const pendingPromises = []
721
+ // respect execution order
722
+ // - wait for classic scripts to be done (non async)
723
+ // - wait module script previous execution (non async)
724
+ // see https://gist.github.com/jakub-g/385ee6b41085303a53ad92c7c8afd7a6#typemodule-vs-non-module-typetextjavascript-vs-script-nomodule
725
+ const executionQueue = []
726
+ let executing = false
727
+ const addToExecutionQueue = async (execution) => {
728
+ if (execution.async) {
729
+ execution.start()
730
+ return
731
+ }
732
+ if (executing) {
733
+ executionQueue.push(execution)
734
+ return
735
+ }
736
+ startThenDequeue(execution)
737
+ }
738
+ const startThenDequeue = async (execution) => {
739
+ executing = true
740
+ const promise = execution.start()
741
+ await promise
742
+ executing = false
743
+ if (executionQueue.length) {
744
+ const nextExecution = executionQueue.shift()
745
+ startThenDequeue(nextExecution)
746
+ }
747
+ }
748
+ supervisor.addExecution = ({ type, src, async, execute }) => {
733
749
  const execution = {
734
750
  type,
735
751
  src,
@@ -743,86 +759,103 @@ window.__supervisor__ = (() => {
743
759
  return superviseExecution(execution, { isReload: true })
744
760
  }
745
761
  supervisedScripts.push(execution)
746
- return execution
762
+ return addToExecutionQueue(execution)
747
763
  }
748
764
  const superviseExecution = async (execution, { isReload }) => {
749
765
  if (logs) {
750
766
  console.group(`[jsenv] loading ${execution.type} ${execution.src}`)
751
767
  }
752
- if (measurePerf) {
753
- performance.mark(`execution_start`)
754
- }
755
768
  const executionResult = {
756
769
  status: "pending",
770
+ loadDuration: null,
771
+ executionDuration: null,
772
+ duration: null,
757
773
  exception: null,
758
774
  namespace: null,
759
775
  coverage: null,
760
776
  }
761
777
  executionResults[execution.src] = executionResult
762
- let resolveExecutionPromise
763
- const promise = new Promise((resolve) => {
764
- resolveExecutionPromise = () => {
765
- const index = executionPromises.indexOf(promise)
766
- if (index > -1) {
767
- executionPromises.splice(index, 1)
768
- }
769
- resolve()
778
+
779
+ const monitorScriptLoad = () => {
780
+ const loadStartTime = Date.now()
781
+ let resolveScriptLoadPromise
782
+ const scriptLoadPromise = new Promise((resolve) => {
783
+ resolveScriptLoadPromise = resolve
784
+ })
785
+ pendingPromises.push(scriptLoadPromise)
786
+ return () => {
787
+ const loadEndTime = Date.now()
788
+ executionResult.loadDuration = loadEndTime - loadStartTime
789
+ resolveScriptLoadPromise()
770
790
  }
771
- })
772
- promise.execution = execution
773
- executionPromises.push(promise)
791
+ }
792
+ const monitorScriptExecution = () => {
793
+ const executionStartTime = Date.now()
794
+ let resolveExecutionPromise
795
+ const executionPromise = new Promise((resolve) => {
796
+ resolveExecutionPromise = resolve
797
+ })
798
+ pendingPromises.push(executionPromise)
799
+ return () => {
800
+ executionResult.coverage = window.__coverage__
801
+ executionResult.executionDuration = Date.now() - executionStartTime
802
+ executionResult.duration =
803
+ executionResult.loadDuration + executionResult.executionDuration
804
+ resolveExecutionPromise()
805
+ }
806
+ }
807
+
808
+ const onError = (e) => {
809
+ executionResult.status = "errored"
810
+ const exception = supervisor.createException({ reason: e })
811
+ if (exception.needsReport) {
812
+ supervisor.reportException(exception)
813
+ }
814
+ executionResult.exception = exception
815
+ }
816
+
817
+ const scriptLoadDone = monitorScriptLoad()
774
818
  try {
775
819
  const result = await execution.execute({ isReload })
776
- if (measurePerf) {
777
- performance.measure(`execution`, `execution_start`)
778
- }
779
- executionResult.status = "completed"
780
- executionResult.namespace = result
781
- executionResult.coverage = window.__coverage__
782
820
  if (logs) {
783
821
  console.log(`${execution.type} load ended`)
784
822
  console.groupEnd()
785
823
  }
786
- resolveExecutionPromise()
787
- } catch (e) {
788
- if (measurePerf) {
789
- performance.measure(`execution`, `execution_start`)
790
- }
791
- executionResult.status = "errored"
792
- const exception = supervisor.createException({
793
- reason: e,
794
- })
795
- if (exception.needsReport) {
796
- supervisor.reportException(exception)
824
+ executionResult.status = "loaded"
825
+ scriptLoadDone()
826
+
827
+ const scriptExecutionDone = monitorScriptExecution()
828
+ if (execution.type === "js_classic") {
829
+ executionResult.status = "completed"
830
+ scriptExecutionDone()
831
+ } else if (execution.type === "js_module") {
832
+ result.executionPromise.then(
833
+ (namespace) => {
834
+ executionResult.status = "completed"
835
+ executionResult.namespace = namespace
836
+ scriptExecutionDone()
837
+ },
838
+ (e) => {
839
+ onError(e)
840
+ scriptExecutionDone()
841
+ },
842
+ )
797
843
  }
798
- executionResult.exception = exception
799
- executionResult.coverage = window.__coverage__
844
+ } catch (e) {
800
845
  if (logs) {
801
846
  console.groupEnd()
802
847
  }
803
- resolveExecutionPromise()
848
+ onError(e)
849
+ scriptLoadDone()
804
850
  }
805
851
  }
806
852
 
807
- // respect execution order
808
- // - wait for classic scripts to be done (non async)
809
- // - wait module script previous execution (non async)
810
- // see https://gist.github.com/jakub-g/385ee6b41085303a53ad92c7c8afd7a6#typemodule-vs-non-module-typetextjavascript-vs-script-nomodule
811
- supervisor.getPreviousExecutionDonePromise = async () => {
812
- const previousNonAsyncExecutions = executionPromises.filter(
813
- (promise) => !promise.execution.async,
814
- )
815
- await Promise.all(previousNonAsyncExecutions)
816
- }
817
853
  supervisor.superviseScript = async ({ src, async }) => {
818
854
  const { currentScript } = document
819
855
  const parentNode = currentScript.parentNode
820
- if (!async) {
821
- await supervisor.getPreviousExecutionDonePromise()
822
- }
823
856
  let nodeToReplace
824
857
  let currentScriptClone
825
- const execution = supervisor.createExecution({
858
+ return supervisor.addExecution({
826
859
  src,
827
860
  type: "js_classic",
828
861
  async,
@@ -872,7 +905,6 @@ window.__supervisor__ = (() => {
872
905
  }
873
906
  },
874
907
  })
875
- return execution.start()
876
908
  }
877
909
  supervisor.reloadSupervisedScript = ({ type, src }) => {
878
910
  const supervisedScript = supervisedScripts.find(
@@ -890,43 +922,40 @@ window.__supervisor__ = (() => {
890
922
  supervisedScript.reload()
891
923
  }
892
924
  }
893
- supervisor.collectScriptResults = async () => {
925
+ supervisor.getDocumentExecutionResult = async () => {
894
926
  // just to be super safe and ensure any <script type="module"> got a chance to execute
895
- const scriptTypeModuleLoaded = new Promise((resolve) => {
896
- const scriptTypeModule = document.createElement("script")
897
- scriptTypeModule.type = "module"
898
- scriptTypeModule.innerText =
899
- "window.__supervisor__.scriptModuleCallback()"
900
- window.__supervisor__.scriptModuleCallback = () => {
901
- scriptTypeModule.parentNode.removeChild(scriptTypeModule)
927
+ const documentReadyPromise = new Promise((resolve) => {
928
+ if (document.readyState === "complete") {
929
+ resolve()
930
+ return
931
+ }
932
+ const loadCallback = () => {
933
+ window.removeEventListener("load", loadCallback)
902
934
  resolve()
903
935
  }
904
- document.body.appendChild(scriptTypeModule)
936
+ window.addEventListener("load", loadCallback)
905
937
  })
906
- await scriptTypeModuleLoaded
907
-
908
- const waitPendingExecutions = async () => {
909
- if (executionPromises.length) {
910
- await Promise.all(executionPromises)
911
- await waitPendingExecutions()
938
+ await documentReadyPromise
939
+ const waitScriptExecutions = async () => {
940
+ const numberOfPromises = pendingPromises.length
941
+ await Promise.all(pendingPromises)
942
+ // new scripts added while the other where executing
943
+ // (should happen only on webkit where
944
+ // script might be added after window load event)
945
+ await new Promise((resolve) => setTimeout(resolve))
946
+ if (pendingPromises.length > numberOfPromises) {
947
+ await waitScriptExecutions()
912
948
  }
913
949
  }
914
- await waitPendingExecutions()
950
+ await waitScriptExecutions()
951
+
915
952
  return {
916
953
  status: "completed",
917
954
  executionResults,
918
- startTime: getNavigationStartTime(),
955
+ startTime: navigationStartTime,
919
956
  endTime: Date.now(),
920
957
  }
921
958
  }
922
-
923
- const getNavigationStartTime = () => {
924
- try {
925
- return window.performance.timing.navigationStart
926
- } catch (e) {
927
- return Date.now()
928
- }
929
- }
930
959
  }
931
960
 
932
961
  return supervisor
@@ -70,10 +70,8 @@ export const jsenvPluginSupervisor = ({
70
70
  openInEditor = true,
71
71
  errorBaseUrl,
72
72
  }) => {
73
- const supervisorFileUrl = new URL(
74
- "./client/supervisor.js?js_classic",
75
- import.meta.url,
76
- ).href
73
+ const supervisorFileUrl = new URL("./client/supervisor.js", import.meta.url)
74
+ .href
77
75
  const scriptTypeModuleSupervisorFileUrl = new URL(
78
76
  "./client/script_type_module_supervisor.js",
79
77
  import.meta.url,
@@ -9,7 +9,7 @@ export const renderExecutionInToolbar = async () => {
9
9
  removeForceHideElement(document.querySelector("#execution-indicator"))
10
10
 
11
11
  const { status, startTime, endTime } =
12
- await window.parent.__supervisor__.getScriptExecutionResults()
12
+ await window.parent.__supervisor__.getDocumentExecutionResult()
13
13
  const execution = { status, startTime, endTime }
14
14
  applyExecutionIndicator(execution)
15
15
  const executionStorageKey = window.location.href
@@ -12,6 +12,7 @@ const defaultConfigValues = {
12
12
  minify: false,
13
13
  target: "es5",
14
14
  topLevelAwait: "disabled",
15
+ asyncAwait: true,
15
16
  };
16
17
  function readConfigKey(config, key) {
17
18
  if (Object.hasOwnProperty.call(config, key)) {
@@ -3649,6 +3650,9 @@ function default_1({ types, traverse, transformFromAst, version, }) {
3649
3650
  },
3650
3651
  },
3651
3652
  FunctionDeclaration(path) {
3653
+ if (!readConfigKey(this.opts, 'asyncAwait')) {
3654
+ return
3655
+ }
3652
3656
  const node = path.node;
3653
3657
  if (node.async) {
3654
3658
  const expression = types.functionExpression(undefined, node.params, node.body, node.generator, node.async);
@@ -3680,6 +3684,9 @@ function default_1({ types, traverse, transformFromAst, version, }) {
3680
3684
  }
3681
3685
  },
3682
3686
  ArrowFunctionExpression(path) {
3687
+ if (!readConfigKey(this.opts, 'asyncAwait')) {
3688
+ return
3689
+ }
3683
3690
  const node = path.node;
3684
3691
  if (node.async) {
3685
3692
  rewriteThisExpressions(path, path.getFunctionParent() || path.scope.getProgramParent().path);
@@ -3691,6 +3698,9 @@ function default_1({ types, traverse, transformFromAst, version, }) {
3691
3698
  }
3692
3699
  },
3693
3700
  FunctionExpression(path) {
3701
+ if (!readConfigKey(this.opts, 'asyncAwait')) {
3702
+ return
3703
+ }
3694
3704
  if (path.node.async) {
3695
3705
  const id = path.node.id;
3696
3706
  if (path.parentPath.isExportDefaultDeclaration() && id !== null && id !== undefined) {
@@ -3773,6 +3783,9 @@ function default_1({ types, traverse, transformFromAst, version, }) {
3773
3783
  }
3774
3784
  },
3775
3785
  ClassMethod(path) {
3786
+ if (!readConfigKey(this.opts, 'asyncAwait')) {
3787
+ return
3788
+ }
3776
3789
  if (path.node.async) {
3777
3790
  const body = path.get("body");
3778
3791
  if (path.node.kind === "method") {
@@ -3832,6 +3845,9 @@ function default_1({ types, traverse, transformFromAst, version, }) {
3832
3845
  }
3833
3846
  },
3834
3847
  ObjectMethod(path) {
3848
+ if (!readConfigKey(this.opts, 'asyncAwait')) {
3849
+ return
3850
+ }
3835
3851
  if (path.node.async) {
3836
3852
  if (path.node.kind === "method") {
3837
3853
  path.replaceWith(types.objectProperty(path.node.key, types.functionExpression(undefined, path.node.params, path.node.body, path.node.generator, path.node.async), path.node.computed, false, path.node.decorators));
@@ -0,0 +1,85 @@
1
+ import { readFileSync } from "@jsenv/filesystem"
2
+ import { createMagicSource, composeTwoSourcemaps } from "@jsenv/sourcemap"
3
+ import { applyBabelPlugins } from "@jsenv/ast"
4
+
5
+ import { requireFromJsenv } from "@jsenv/core/src/require_from_jsenv.js"
6
+ import { requireBabelPlugin } from "../babel/require_babel_plugin.js"
7
+ import { babelPluginTransformImportMetaUrl } from "./helpers/babel_plugin_transform_import_meta_url.js"
8
+
9
+ // import { jsenvPluginAsJsClassicLibrary } from "./jsenv_plugin_as_js_classic_library.js"
10
+ // because of https://github.com/rpetrich/babel-plugin-transform-async-to-promises/issues/84
11
+ import customAsyncToPromises from "./async-to-promises.js"
12
+
13
+ export const convertJsModuleToJsClassic = async ({
14
+ systemJsInjection,
15
+ systemJsClientFileUrl,
16
+ urlInfo,
17
+ jsModuleUrlInfo,
18
+ }) => {
19
+ const jsClassicFormat =
20
+ // in general html file are entry points, but js can be entry point when:
21
+ // - passed in entryPoints to build
22
+ // - is used by web worker
23
+ // - the reference contains ?entry_point
24
+ // When js is entry point there can be no HTML to inject systemjs
25
+ // and systemjs must be injected into the js file
26
+ urlInfo.isEntryPoint &&
27
+ // if it's an entry point without dependency (it does not use import)
28
+ // then we can use UMD, otherwise we have to use systemjs
29
+ // because it is imported by systemjs
30
+ !jsModuleUrlInfo.data.usesImport
31
+ ? "umd"
32
+ : "system"
33
+ urlInfo.data.jsClassicFormat = jsClassicFormat
34
+ const { code, map } = await applyBabelPlugins({
35
+ babelPlugins: [
36
+ ...(jsClassicFormat === "system"
37
+ ? [
38
+ // proposal-dynamic-import required with systemjs for babel8:
39
+ // https://github.com/babel/babel/issues/10746
40
+ requireFromJsenv("@babel/plugin-proposal-dynamic-import"),
41
+ requireFromJsenv("@babel/plugin-transform-modules-systemjs"),
42
+ [
43
+ customAsyncToPromises,
44
+ {
45
+ asyncAwait: false, // already handled + we might not needs it at all
46
+ topLevelAwait: "return",
47
+ },
48
+ ],
49
+ ]
50
+ : [
51
+ [
52
+ requireBabelPlugin("babel-plugin-transform-async-to-promises"),
53
+ {
54
+ asyncAwait: false, // already handled + we might not needs it at all
55
+ topLevelAwait: "simple",
56
+ },
57
+ ],
58
+ babelPluginTransformImportMetaUrl,
59
+ requireFromJsenv("@babel/plugin-transform-modules-umd"),
60
+ ]),
61
+ ],
62
+ urlInfo: jsModuleUrlInfo,
63
+ })
64
+ let sourcemap = jsModuleUrlInfo.sourcemap
65
+ sourcemap = await composeTwoSourcemaps(sourcemap, map)
66
+ if (
67
+ systemJsInjection &&
68
+ jsClassicFormat === "system" &&
69
+ urlInfo.isEntryPoint
70
+ ) {
71
+ const magicSource = createMagicSource(code)
72
+ const systemjsCode = readFileSync(systemJsClientFileUrl, { as: "string" })
73
+ magicSource.prepend(`${systemjsCode}\n\n`)
74
+ const magicResult = magicSource.toContentAndSourcemap()
75
+ sourcemap = await composeTwoSourcemaps(sourcemap, magicResult.sourcemap)
76
+ return {
77
+ content: magicResult.content,
78
+ sourcemap,
79
+ }
80
+ }
81
+ return {
82
+ content: code,
83
+ sourcemap,
84
+ }
85
+ }