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

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 (27) hide show
  1. package/main.js +1 -1
  2. package/package.json +7 -8
  3. package/src/build/build.js +29 -17
  4. package/src/build/start_build_server.js +176 -0
  5. package/src/dev/start_dev_server.js +9 -20
  6. package/src/execute/execute.js +9 -2
  7. package/src/omega/kitchen.js +7 -3
  8. package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/autoreload_preference.js +0 -0
  9. package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/event_source_client.js +2 -2
  10. package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/reload.js +0 -0
  11. package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/url_helpers.js +0 -0
  12. package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_client.js +41 -0
  13. package/src/{dev/plugins/autoreload/jsenv_plugin_autoreload.js → plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_server.js} +23 -174
  14. package/src/plugins/autoreload/jsenv_plugin_autoreload.js +25 -0
  15. package/src/plugins/autoreload/jsenv_plugin_hmr.js +35 -0
  16. package/src/{dev/plugins/autoreload → plugins/import_meta_hot}/babel_plugin_metadata_import_meta_hot.js +3 -4
  17. package/src/{dev/plugins/autoreload → plugins/import_meta_hot}/client/import_meta_hot.js +0 -0
  18. package/src/{dev/plugins/autoreload → plugins/import_meta_hot}/html_hot_dependencies.js +0 -0
  19. package/src/plugins/import_meta_hot/jsenv_plugin_import_meta_hot.js +98 -0
  20. package/src/plugins/minification/jsenv_plugin_minification.js +2 -1
  21. package/src/plugins/plugins.js +23 -0
  22. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js +13 -0
  23. package/src/test/execute_plan.js +6 -1
  24. package/src/test/execute_test_plan.js +4 -0
  25. package/src/dev/plugins/autoreload/client/event_source_connection.js +0 -195
  26. package/src/dev/plugins/autoreload/sse_service.js +0 -169
  27. package/src/preview/preview.js +0 -3
@@ -1,195 +0,0 @@
1
- export const createEventSourceConnection = (
2
- eventSourceUrl,
3
- events = {},
4
- { retryMaxAttempt = Infinity, retryAllocatedMs = Infinity, lastEventId } = {},
5
- ) => {
6
- const { EventSource } = window
7
- if (typeof EventSource !== "function") {
8
- return () => {}
9
- }
10
-
11
- const eventSourceOrigin = new URL(eventSourceUrl).origin
12
- Object.keys(events).forEach((eventName) => {
13
- const eventCallback = events[eventName]
14
- events[eventName] = (e) => {
15
- if (e.origin === eventSourceOrigin) {
16
- if (e.lastEventId) {
17
- lastEventId = e.lastEventId
18
- }
19
- eventCallback(e)
20
- }
21
- }
22
- })
23
-
24
- const status = {
25
- value: "default",
26
- goTo: (value) => {
27
- if (value === status.value) {
28
- return
29
- }
30
- status.value = value
31
- status.onchange()
32
- },
33
- onchange: () => {},
34
- }
35
- let _disconnect = () => {}
36
-
37
- const attemptConnection = (url) => {
38
- const eventSource = new EventSource(url, {
39
- withCredentials: true,
40
- })
41
- _disconnect = () => {
42
- if (status.value !== "connecting" && status.value !== "connected") {
43
- console.warn(
44
- `disconnect() ignored because connection is ${status.value}`,
45
- )
46
- return
47
- }
48
- eventSource.onerror = undefined
49
- eventSource.close()
50
- Object.keys(events).forEach((eventName) => {
51
- eventSource.removeEventListener(eventName, events[eventName])
52
- })
53
- status.goTo("disconnected")
54
- }
55
- let retryCount = 0
56
- let firstRetryMs = Date.now()
57
- eventSource.onerror = (errorEvent) => {
58
- if (errorEvent.target.readyState === EventSource.CONNECTING) {
59
- if (retryCount > retryMaxAttempt) {
60
- console.info(`could not connect after ${retryMaxAttempt} attempt`)
61
- _disconnect()
62
- return
63
- }
64
-
65
- if (retryCount === 0) {
66
- firstRetryMs = Date.now()
67
- } else {
68
- const allRetryDuration = Date.now() - firstRetryMs
69
- if (retryAllocatedMs && allRetryDuration > retryAllocatedMs) {
70
- console.info(
71
- `could not connect in less than ${retryAllocatedMs} ms`,
72
- )
73
- _disconnect()
74
- return
75
- }
76
- }
77
-
78
- retryCount++
79
- status.goTo("connecting")
80
- return
81
- }
82
-
83
- if (errorEvent.target.readyState === EventSource.CLOSED) {
84
- _disconnect()
85
- return
86
- }
87
- }
88
- eventSource.onopen = () => {
89
- status.goTo("connected")
90
- }
91
- Object.keys(events).forEach((eventName) => {
92
- eventSource.addEventListener(eventName, events[eventName])
93
- })
94
- if (!events.hasOwnProperty("welcome")) {
95
- eventSource.addEventListener("welcome", (e) => {
96
- if (e.origin === eventSourceOrigin && e.lastEventId) {
97
- lastEventId = e.lastEventId
98
- }
99
- })
100
- }
101
- status.goTo("connecting")
102
- }
103
-
104
- let connect = () => {
105
- attemptConnection(eventSourceUrl)
106
- connect = () => {
107
- attemptConnection(
108
- lastEventId
109
- ? addLastEventIdIntoUrlSearchParams(eventSourceUrl, lastEventId)
110
- : eventSourceUrl,
111
- )
112
- }
113
- }
114
-
115
- const removePageUnloadListener = listenPageUnload(() => {
116
- if (status.value === "connecting" || status.value === "connected") {
117
- _disconnect()
118
- }
119
- })
120
-
121
- const destroy = () => {
122
- removePageUnloadListener()
123
- _disconnect()
124
- }
125
-
126
- return {
127
- status,
128
- connect,
129
- disconnect: () => _disconnect(),
130
- destroy,
131
- }
132
- }
133
-
134
- const addLastEventIdIntoUrlSearchParams = (url, lastEventId) => {
135
- if (url.indexOf("?") === -1) {
136
- url += "?"
137
- } else {
138
- url += "&"
139
- }
140
- return `${url}last-event-id=${encodeURIComponent(lastEventId)}`
141
- }
142
-
143
- // const listenPageMightFreeze = (callback) => {
144
- // const removePageHideListener = listenEvent(window, "pagehide", (pageHideEvent) => {
145
- // if (pageHideEvent.persisted === true) {
146
- // callback(pageHideEvent)
147
- // }
148
- // })
149
- // return removePageHideListener
150
- // }
151
-
152
- // const listenPageFreeze = (callback) => {
153
- // const removeFreezeListener = listenEvent(document, "freeze", (freezeEvent) => {
154
- // callback(freezeEvent)
155
- // })
156
- // return removeFreezeListener
157
- // }
158
-
159
- // const listenPageIsRestored = (callback) => {
160
- // const removeResumeListener = listenEvent(document, "resume", (resumeEvent) => {
161
- // removePageshowListener()
162
- // callback(resumeEvent)
163
- // })
164
- // const removePageshowListener = listenEvent(window, "pageshow", (pageshowEvent) => {
165
- // if (pageshowEvent.persisted === true) {
166
- // removePageshowListener()
167
- // removeResumeListener()
168
- // callback(pageshowEvent)
169
- // }
170
- // })
171
- // return () => {
172
- // removeResumeListener()
173
- // removePageshowListener()
174
- // }
175
- // }
176
-
177
- const listenPageUnload = (callback) => {
178
- const removePageHideListener = listenEvent(
179
- window,
180
- "pagehide",
181
- (pageHideEvent) => {
182
- if (pageHideEvent.persisted !== true) {
183
- callback(pageHideEvent)
184
- }
185
- },
186
- )
187
- return removePageHideListener
188
- }
189
-
190
- const listenEvent = (emitter, event, callback) => {
191
- emitter.addEventListener(event, callback)
192
- return () => {
193
- emitter.removeEventListener(event, callback)
194
- }
195
- }
@@ -1,169 +0,0 @@
1
- import { createSSERoom } from "@jsenv/server"
2
- import { registerDirectoryLifecycle } from "@jsenv/filesystem"
3
- import {
4
- createCallbackList,
5
- createCallbackListNotifiedOnce,
6
- } from "@jsenv/abort"
7
-
8
- export const createSSEService = ({
9
- rootDirectoryUrl,
10
- autoreloadPatterns,
11
- onFileChange,
12
- hotUpdateCallbackList,
13
- cooldownBetweenFileEvents = 0,
14
- }) => {
15
- const destroyCallbackList = createCallbackListNotifiedOnce()
16
- const projectFileModified = createCallbackList()
17
- const projectFileRemoved = createCallbackList()
18
- const projectFileAdded = createCallbackList()
19
- const watchProjectFiles = (callback) => {
20
- const removeModifiedCallback = projectFileModified.add((relativeUrl) => {
21
- callback({
22
- event: "modified",
23
- relativeUrl,
24
- })
25
- })
26
- const removeRemovedCallback = projectFileRemoved.add((relativeUrl) => {
27
- callback({
28
- event: "removed",
29
- relativeUrl,
30
- })
31
- })
32
- const removeAddedCallback = projectFileRemoved.add((relativeUrl) => {
33
- callback({
34
- event: "added",
35
- relativeUrl,
36
- })
37
- })
38
- return () => {
39
- removeModifiedCallback()
40
- removeRemovedCallback()
41
- removeAddedCallback()
42
- }
43
- }
44
- // wait 100ms to actually start watching
45
- // otherwise server starting is delayed by the filesystem scan done in
46
- // registerDirectoryLifecycle
47
- const timeout = setTimeout(() => {
48
- const unregisterDirectoryLifecyle = registerDirectoryLifecycle(
49
- rootDirectoryUrl,
50
- {
51
- watchDescription: {
52
- ...autoreloadPatterns,
53
- ".jsenv/": false,
54
- },
55
- updated: ({ relativeUrl }) => {
56
- projectFileModified.notify(relativeUrl)
57
- },
58
- removed: ({ relativeUrl }) => {
59
- projectFileRemoved.notify(relativeUrl)
60
- },
61
- added: ({ relativeUrl }) => {
62
- projectFileAdded.notify(relativeUrl)
63
- },
64
- keepProcessAlive: false,
65
- recursive: true,
66
- },
67
- )
68
- destroyCallbackList.add(unregisterDirectoryLifecyle)
69
- }, 100)
70
- destroyCallbackList.add(() => {
71
- clearTimeout(timeout)
72
- })
73
-
74
- const cache = []
75
- const sseRoomLimit = 100
76
- const getOrCreateSSERoom = (request) => {
77
- const htmlFileRelativeUrl = request.ressource.slice(1)
78
- const cacheEntry = cache.find(
79
- (cacheEntryCandidate) =>
80
- cacheEntryCandidate.htmlFileRelativeUrl === htmlFileRelativeUrl,
81
- )
82
- if (cacheEntry) {
83
- return cacheEntry.sseRoom
84
- }
85
- const sseRoom = createSSERoom({
86
- retryDuration: 2000,
87
- historyLength: 100,
88
- welcomeEventEnabled: true,
89
- effect: () => {
90
- const removeHotUpdateCallback = hotUpdateCallbackList.add(
91
- (hotUpdate) => {
92
- if (hotUpdate.declined) {
93
- sseRoom.sendEvent({
94
- type: "reload",
95
- data: JSON.stringify({
96
- cause: hotUpdate.cause,
97
- type: "full",
98
- typeReason: hotUpdate.reason,
99
- declinedBy: hotUpdate.declinedBy,
100
- }),
101
- })
102
- } else {
103
- sseRoom.sendEvent({
104
- type: "reload",
105
- data: JSON.stringify({
106
- cause: hotUpdate.cause,
107
- type: "hot",
108
- typeReason: hotUpdate.reason,
109
- hotInstructions: hotUpdate.instructions,
110
- }),
111
- })
112
- }
113
- },
114
- )
115
- const stopWatching = watchProjectFiles(
116
- cooldownBetweenFileEvents
117
- ? guardTooFastSecondCall(onFileChange, cooldownBetweenFileEvents)
118
- : onFileChange,
119
- )
120
- return () => {
121
- removeHotUpdateCallback()
122
- stopWatching()
123
- }
124
- },
125
- })
126
-
127
- const removeSSECleanupCallback = destroyCallbackList.add(() => {
128
- removeSSECleanupCallback()
129
- sseRoom.close()
130
- })
131
- cache.push({
132
- htmlFileRelativeUrl,
133
- sseRoom,
134
- cleanup: () => {
135
- removeSSECleanupCallback()
136
- sseRoom.close()
137
- },
138
- })
139
- if (cache.length >= sseRoomLimit) {
140
- const firstCacheEntry = cache.shift()
141
- firstCacheEntry.cleanup()
142
- }
143
- return sseRoom
144
- }
145
-
146
- return {
147
- getOrCreateSSERoom,
148
- destroy: () => {
149
- destroyCallbackList.notify()
150
- },
151
- }
152
- }
153
-
154
- const guardTooFastSecondCall = (callback, cooldownBetweenFileEvents = 40) => {
155
- const previousCallMsMap = new Map()
156
- return ({ relativeUrl, event }) => {
157
- const previousCallMs = previousCallMsMap.get(relativeUrl)
158
- const nowMs = Date.now()
159
- if (previousCallMs) {
160
- const msEllapsed = nowMs - previousCallMs
161
- if (msEllapsed < cooldownBetweenFileEvents) {
162
- previousCallMsMap.delete(relativeUrl)
163
- return
164
- }
165
- }
166
- previousCallMsMap.set(relativeUrl, nowMs)
167
- callback({ relativeUrl, event })
168
- }
169
- }
@@ -1,3 +0,0 @@
1
- export const preview = () => {
2
- // TODO
3
- }