@jsenv/core 27.0.0-alpha.54 → 27.0.0-alpha.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "27.0.0-alpha.54",
3
+ "version": "27.0.0-alpha.57",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -224,16 +224,6 @@ ${Object.keys(rawGraph.urlInfos).join("\n")}`,
224
224
  })
225
225
  })
226
226
  const addToBundlerIfAny = (rawUrlInfo) => {
227
- if (
228
- // entry point must be given to the bundler (rollup)
229
- // so that the bundler know it's an entry point, even if it has no dependency
230
- // this way the bundler can share code properly and avoid inlining an entry point
231
- // if it's used by an other entry point
232
- !rawUrlInfo.data.isEntryPoint &&
233
- rawUrlInfo.dependencies.size === 0
234
- ) {
235
- return
236
- }
237
227
  const bundler = bundlers[rawUrlInfo.type]
238
228
  if (bundler) {
239
229
  bundler.urlInfos.push(rawUrlInfo)
@@ -740,12 +730,12 @@ ${Object.keys(finalGraph.urlInfos).join("\n")}`,
740
730
  buildInlineContents[buildRelativeUrl] = urlInfo.content
741
731
  } else {
742
732
  buildFileContents[buildRelativeUrl] = urlInfo.content
733
+ const buildRelativeUrlWithoutVersioning = urlToRelativeUrl(
734
+ urlInfo.url,
735
+ buildDirectoryUrl,
736
+ )
737
+ buildManifest[buildRelativeUrlWithoutVersioning] = buildRelativeUrl
743
738
  }
744
- const buildRelativeUrlWithoutVersioning = urlToRelativeUrl(
745
- urlInfo.url,
746
- buildDirectoryUrl,
747
- )
748
- buildManifest[buildRelativeUrlWithoutVersioning] = buildRelativeUrl
749
739
  })
750
740
  if (writeOnFileSystem) {
751
741
  if (buildDirectoryClean) {
@@ -68,6 +68,7 @@ export const startBuildServer = async ({
68
68
  buildDirectoryUrl = assertAndNormalizeDirectoryUrl(buildDirectoryUrl)
69
69
 
70
70
  const reloadableProcess = await initReloadableProcess({
71
+ signal,
71
72
  handleSIGINT,
72
73
  ...(buildServerAutoreload
73
74
  ? {
@@ -192,10 +192,7 @@ export const createKitchen = ({
192
192
  Object.keys(returnValue).forEach((key) => {
193
193
  referenceUrlObject.searchParams.set(key, returnValue[key])
194
194
  })
195
- reference.generatedUrl = referenceUrlObject.href.replace(
196
- /[=](?=&|$)/g,
197
- "",
198
- )
195
+ reference.generatedUrl = normalizeUrl(referenceUrlObject.href)
199
196
  },
200
197
  )
201
198
  const returnValue = pluginController.callHooksUntil(
@@ -654,8 +651,6 @@ export const createKitchen = ({
654
651
  const prepareEntryPoint = (params) => {
655
652
  const entryReference = createReference(params)
656
653
  const entryUrlInfo = resolveReference(entryReference)
657
- // I should likely delete urlInfo.sourcemap
658
- // otherwise it is reused when page is reloaded
659
654
  return [entryReference, entryUrlInfo]
660
655
  }
661
656
 
@@ -20,6 +20,11 @@ export const createFileService = ({
20
20
  urlGraph,
21
21
  scenario,
22
22
  }
23
+ const augmentResponseContext = {
24
+ rootDirectoryUrl,
25
+ urlGraph,
26
+ scenario,
27
+ }
23
28
 
24
29
  const getResponse = async (request) => {
25
30
  // serve file inside ".jsenv" directory
@@ -58,9 +63,19 @@ export const createFileService = ({
58
63
  reference.parentUrl,
59
64
  )
60
65
  try {
61
- // urlInfo objects are reused, they must be "reset" before cooking then again
62
- if (!urlInfo.isInline && !urlInfo.type === "sourcemap") {
63
- urlGraph.resetUrlInfo(urlInfo)
66
+ // urlInfo objects are reused, they must be "reset" before cooking them again
67
+ if (
68
+ urlInfo.contentEtag &&
69
+ !urlInfo.isInline &&
70
+ urlInfo.type !== "sourcemap"
71
+ ) {
72
+ urlInfo.sourcemap = null
73
+ urlInfo.sourcemapReference = null
74
+ urlInfo.content = null
75
+ urlInfo.originalContent = null
76
+ urlInfo.type = null
77
+ urlInfo.subtype = null
78
+ urlInfo.timing = {}
64
79
  }
65
80
  const { runtimeName, runtimeVersion } = parseUserAgentHeader(
66
81
  request.headers["user-agent"],
@@ -92,7 +107,7 @@ export const createFileService = ({
92
107
  kitchen.pluginController.callHooks(
93
108
  "augmentResponse",
94
109
  { reference, urlInfo },
95
- {},
110
+ augmentResponseContext,
96
111
  (returnValue) => {
97
112
  response = composeTwoResponses(response, returnValue)
98
113
  },
@@ -15,16 +15,6 @@ export const createUrlGraph = ({
15
15
  }
16
16
  }
17
17
  }
18
- const resetUrlInfo = (urlInfo) => {
19
- urlInfo.sourcemap = null
20
- urlInfo.sourcemapReference = null
21
- urlInfo.content = null
22
- urlInfo.originalContent = null
23
- urlInfo.type = null
24
- urlInfo.subtype = null
25
- urlInfo.data = {}
26
- urlInfo.timing = {}
27
- }
28
18
 
29
19
  const reuseOrCreateUrlInfo = (url) => {
30
20
  const existingUrlInfo = urlInfos[url]
@@ -160,7 +150,6 @@ export const createUrlGraph = ({
160
150
  reuseOrCreateUrlInfo,
161
151
  getUrlInfo,
162
152
  deleteUrlInfo,
163
- resetUrlInfo,
164
153
  inferReference,
165
154
  findDependent,
166
155
  updateReferences,
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  isFileSystemPath,
3
3
  normalizeStructuredMetaMap,
4
+ urlIsInsideOf,
4
5
  urlToMeta,
5
6
  } from "@jsenv/filesystem"
6
7
  import { createDetailedMessage } from "@jsenv/logger"
@@ -8,6 +9,12 @@ import { createDetailedMessage } from "@jsenv/logger"
8
9
  import { applyRollupPlugins } from "@jsenv/utils/js_ast/apply_rollup_plugins.js"
9
10
  import { sourcemapConverter } from "@jsenv/utils/sourcemap/sourcemap_converter.js"
10
11
  import { fileUrlConverter } from "@jsenv/core/src/omega/file_url_converter.js"
12
+ import { babelHelperNameFromUrl } from "@jsenv/babel-plugins"
13
+
14
+ const jsenvBabelPluginDirectoryUrl = new URL(
15
+ "../../transpilation/babel/",
16
+ import.meta.url,
17
+ ).href
11
18
 
12
19
  export const bundleJsModule = async ({
13
20
  jsModuleUrlInfos,
@@ -216,6 +223,23 @@ const rollupPluginJsenv = ({
216
223
  const name = nameFromUrlInfo || `${chunkInfo.name}.js`
217
224
  return insideJs ? `js/${name}` : `${name}`
218
225
  },
226
+ manualChunks: (id) => {
227
+ const fileUrl = fileUrlConverter.asFileUrl(id)
228
+ if (
229
+ fileUrl.endsWith(
230
+ "babel-plugin-transform-async-to-promises/helpers.mjs",
231
+ )
232
+ ) {
233
+ return "babel_helpers"
234
+ }
235
+ if (babelHelperNameFromUrl(fileUrl)) {
236
+ return "babel_helpers"
237
+ }
238
+ if (urlIsInsideOf(fileUrl, jsenvBabelPluginDirectoryUrl)) {
239
+ return "babel_helpers"
240
+ }
241
+ return null
242
+ },
219
243
  // https://rollupjs.org/guide/en/#outputpaths
220
244
  // paths: (id) => {
221
245
  // return id
@@ -0,0 +1,34 @@
1
+ export const jsenvPluginCacheControl = () => {
2
+ return {
3
+ name: "jsenv:cache_control",
4
+ appliesDuring: {
5
+ dev: true,
6
+ test: true,
7
+ },
8
+ augmentResponse: ({ reference }, context) => {
9
+ if (context.scenario === "dev") {
10
+ // During dev, all files are put into browser cache for 1 hour because:
11
+ // 1: Browser cache is a temporary directory created by playwright
12
+ // 2: We assume source files won't be modified while tests are running
13
+ return {
14
+ headers: {
15
+ "cache-control": `private,max-age=3600,immutable`,
16
+ },
17
+ }
18
+ }
19
+ if (
20
+ reference.searchParams.has("v") &&
21
+ !reference.searchParams.has("hmr")
22
+ ) {
23
+ return {
24
+ headers: {
25
+ "cache-control": `private,max-age=${SECONDS_IN_30_DAYS},immutable`,
26
+ },
27
+ }
28
+ }
29
+ return null
30
+ },
31
+ }
32
+ }
33
+
34
+ const SECONDS_IN_30_DAYS = 60 * 60 * 24 * 30
@@ -17,6 +17,7 @@ import { jsenvPluginBundling } from "./bundling/jsenv_plugin_bundling.js"
17
17
  import { jsenvPluginMinification } from "./minification/jsenv_plugin_minification.js"
18
18
  import { jsenvPluginImportMetaHot } from "./import_meta_hot/jsenv_plugin_import_meta_hot.js"
19
19
  import { jsenvPluginAutoreload } from "./autoreload/jsenv_plugin_autoreload.js"
20
+ import { jsenvPluginCacheControl } from "./cache_control/jsenv_plugin_cache_control.js"
20
21
 
21
22
  export const getCorePlugins = ({
22
23
  rootDirectoryUrl,
@@ -68,7 +69,6 @@ export const getCorePlugins = ({
68
69
  jsenvPluginInjectGlobals(injectedGlobals),
69
70
  jsenvPluginCommonJsGlobals(),
70
71
  jsenvPluginImportMetaScenarios(),
71
- // jsenvPluginWorkers(),
72
72
 
73
73
  jsenvPluginBundling(bundling),
74
74
  jsenvPluginMinification(minification),
@@ -87,5 +87,6 @@ export const getCorePlugins = ({
87
87
  }),
88
88
  ]
89
89
  : []),
90
+ jsenvPluginCacheControl(),
90
91
  ]
91
92
  }
@@ -785,22 +785,88 @@
785
785
  (function () {
786
786
  // worker or service worker
787
787
  if (typeof WorkerGlobalScope === 'function' && self instanceof WorkerGlobalScope) {
788
- // auto import first register
789
- var messageEvents = []
790
- var messageCallback = (event) => {
791
- messageEvents.push(event)
788
+ /*
789
+ * SystemJs loads X files before executing the worker/service worker main file
790
+ * It mean events dispatched during this phase could be missed
791
+ * A warning like the one below is displayed in chrome devtools:
792
+ * "Event handler of 'install' event must be added on the initial evaluation of worker script"
793
+ * To fix that code below listen for these events early and redispatch them later
794
+ * once the worker file is executed (the listeners are installed)
795
+ */
796
+ var firstRegisterCallbacks = []
797
+ var isServiceWorker = typeof self.skipWaiting === 'function'
798
+ if (isServiceWorker) {
799
+ // for service worker there is more events to listen
800
+ // and, to get rid of the warning, we override self.addEventListener
801
+ var eventsToCatch = ['message', 'install', 'activate', 'fetch']
802
+ var eventCallbackProxies = {}
803
+ var firstRegisterPromise = new Promise((resolve) => {
804
+ firstRegisterCallbacks.push(resolve)
805
+ })
806
+ eventsToCatch.forEach(function(eventName) {
807
+ var eventsToDispatch = []
808
+ var eventCallback = function (event) {
809
+ const eventCallbackProxy = eventCallbackProxies[event.type]
810
+ if (eventCallbackProxy) {
811
+ eventCallbackProxy(event)
812
+ }
813
+ else {
814
+ eventsToDispatch.push(event)
815
+ event.waitUntil(firstRegisterPromise)
816
+ }
817
+ }
818
+ self.addEventListener(eventName, eventCallback)
819
+ firstRegisterCallbacks.push(function() {
820
+ if (eventsToDispatch.length) {
821
+ const eventCallbackProxy = eventCallbackProxies[eventsToDispatch[0].type]
822
+ if (eventCallbackProxy) {
823
+ eventsToDispatch.forEach(function (event) {
824
+ eventCallbackProxy(event)
825
+ })
826
+ }
827
+ eventsToDispatch.length = 0
828
+ }
829
+ })
830
+ })
831
+
832
+ var addEventListener = self.addEventListener
833
+ self.addEventListener = function (eventName, callback, options) {
834
+ if (eventsToCatch.indexOf(eventName) > -1) {
835
+ eventCallbackProxies[eventName] = callback
836
+ return
837
+ }
838
+ return addEventListener.call(self, eventName, callback, options)
839
+ }
840
+ }
841
+ else {
842
+ var eventsToCatch = ['message']
843
+ eventsToCatch.forEach(function (eventName) {
844
+ var eventQueue = []
845
+ var eventCallback = (event) => {
846
+ eventQueue.push(event)
847
+ }
848
+ self.addEventListener(eventName, eventCallback)
849
+ firstRegisterCallbacks.push(function() {
850
+ self.removeEventListener(eventName, eventCallback)
851
+ eventQueue.forEach(function (event) {
852
+ self.dispatchEvent(event)
853
+ })
854
+ eventQueue.length = 0
855
+ })
856
+ })
792
857
  }
793
- self.addEventListener('message', messageCallback)
858
+
859
+
860
+ // auto import first register
794
861
  var register = System.register;
795
862
  System.register = function(deps, declare) {
796
863
  System.register = register;
797
864
  System.registerRegistry[self.location.href] = [deps, declare];
798
865
  return System.import(self.location.href).then((result) => {
799
- self.removeEventListener('message', messageCallback)
800
- messageEvents.forEach((messageEvent) => {
801
- self.dispatchEvent(messageEvent)
866
+ firstRegisterCallbacks.forEach(firstRegisterCallback => {
867
+ firstRegisterCallback()
802
868
  })
803
- messageEvents = null
869
+ firstRegisterCallbacks.length = 0
804
870
  return result
805
871
  })
806
872
  }
@@ -1,7 +1,12 @@
1
1
  import { getBabelHelperFileUrl, requireBabelPlugin } from "@jsenv/babel-plugins"
2
2
  import { babelPluginCompatMap } from "./babel_plugins_compatibility.js"
3
3
 
4
- export const getBaseBabelPluginStructure = ({ url, isSupported }) => {
4
+ export const getBaseBabelPluginStructure = ({
5
+ url,
6
+ isSupported,
7
+ // isJsModule,
8
+ // getImportSpecifier,
9
+ }) => {
5
10
  const isBabelPluginNeeded = (babelPluginName) => {
6
11
  return !isSupported(babelPluginCompatMap[babelPluginName])
7
12
  }
@@ -35,6 +40,12 @@ export const getBaseBabelPluginStructure = ({ url, isSupported }) => {
35
40
  requireBabelPlugin("babel-plugin-transform-async-to-promises"),
36
41
  {
37
42
  topLevelAwait: "ignore", // will be handled by "jsenv:top_level_await" plugin
43
+ externalHelpers: false,
44
+ // enable once https://github.com/rpetrich/babel-plugin-transform-async-to-promises/pull/83
45
+ // externalHelpers: isJsModule,
46
+ // externalHelpersPath: isJsModule ? getImportSpecifier(
47
+ // "babel-plugin-transform-async-to-promises/helpers.mjs",
48
+ // ) : null
38
49
  },
39
50
  ]
40
51
  }
@@ -33,27 +33,29 @@ export const jsenvPluginBabel = ({ getCustomBabelPlugins } = {}) => {
33
33
  )
34
34
  }
35
35
 
36
- const { referenceUtils } = context
37
36
  const isSupported = (feature) =>
38
37
  RUNTIME_COMPAT.isSupported(clientRuntimeCompat, feature)
38
+ const getImportSpecifier = (clientFileUrl) => {
39
+ const [reference] = context.referenceUtils.inject({
40
+ type: "js_import_export",
41
+ expectedType: "js_module",
42
+ specifier: clientFileUrl,
43
+ })
44
+ return JSON.parse(reference.generatedSpecifier)
45
+ }
46
+
39
47
  const babelPluginStructure = getBaseBabelPluginStructure({
40
48
  url: urlInfo.url,
41
49
  isSupported,
42
50
  isWorkerContext,
51
+ isJsModule,
52
+ getImportSpecifier,
43
53
  })
44
54
  if (getCustomBabelPlugins) {
45
55
  Object.assign(babelPluginStructure, getCustomBabelPlugins(context))
46
56
  }
47
57
 
48
58
  if (isJsModule) {
49
- const getImportSpecifier = (clientFileUrl) => {
50
- const [reference] = referenceUtils.inject({
51
- type: "js_import_export",
52
- expectedType: "js_module",
53
- specifier: clientFileUrl,
54
- })
55
- return JSON.parse(reference.generatedSpecifier)
56
- }
57
59
  if (!isSupported("global_this")) {
58
60
  babelPluginStructure["global-this-as-jsenv-import"] = [
59
61
  babelPluginGlobalThisAsJsenvImport,
@@ -24,6 +24,16 @@ export const jsenvPluginTopLevelAwait = () => {
24
24
  // Maybe we could pass target: "es6" when we support arrow function
25
25
  // https://github.com/rpetrich/babel-plugin-transform-async-to-promises/blob/92755ff8c943c97596523e586b5fa515c2e99326/async-to-promises.ts#L55
26
26
  topLevelAwait: "simple",
27
+ // enable once https://github.com/rpetrich/babel-plugin-transform-async-to-promises/pull/83
28
+ // externalHelpers: true,
29
+ // externalHelpersPath: JSON.parse(
30
+ // context.referenceUtils.inject({
31
+ // type: "js_import_export",
32
+ // expectedType: "js_module",
33
+ // specifier:
34
+ // "babel-plugin-transform-async-to-promises/helpers.mjs",
35
+ // })[0],
36
+ // ),
27
37
  },
28
38
  ],
29
39
  ],
@@ -1,7 +1,7 @@
1
- export const jsenvPluginUrlVersion = ({ longTermCache = true } = {}) => {
1
+ export const jsenvPluginUrlVersion = () => {
2
2
  return {
3
3
  name: "jsenv:url_version",
4
- appliesDuring: "*", // maybe only during dev?
4
+ appliesDuring: "*",
5
5
  redirectUrl: (reference) => {
6
6
  // "v" search param goal is to enable long-term cache
7
7
  // for server response headers
@@ -24,24 +24,5 @@ export const jsenvPluginUrlVersion = ({ longTermCache = true } = {}) => {
24
24
  v: reference.data.version,
25
25
  }
26
26
  },
27
- augmentResponse: ({ reference }) => {
28
- if (!longTermCache) {
29
- return null
30
- }
31
- if (!reference.searchParams.has("v")) {
32
- return null
33
- }
34
- if (reference.searchParams.has("hmr")) {
35
- return null
36
- }
37
- // When url is versioned put it in browser cache for 30 days
38
- return {
39
- headers: {
40
- "cache-control": `private,max-age=${SECONDS_IN_30_DAYS},immutable`,
41
- },
42
- }
43
- },
44
27
  }
45
28
  }
46
-
47
- const SECONDS_IN_30_DAYS = 60 * 60 * 24 * 30