@jsenv/core 27.3.4 → 27.4.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.
@@ -1,183 +1,180 @@
1
1
  import { urlToRelativeUrl } from "@jsenv/urls"
2
- import { createCallbackList } from "@jsenv/abort"
3
-
4
- import { createSSEService } from "@jsenv/core/src/helpers/event_source/sse_service.js"
5
2
 
6
3
  export const jsenvPluginDevSSEServer = ({
7
- rootDirectoryUrl,
8
- urlGraph,
9
4
  clientFileChangeCallbackList,
10
5
  clientFilesPruneCallbackList,
11
6
  }) => {
12
- const serverEventCallbackList = createCallbackList()
13
- const sseService = createSSEService({ serverEventCallbackList })
14
-
15
- const notifyDeclined = ({ cause, reason, declinedBy }) => {
16
- serverEventCallbackList.notify({
17
- type: "reload",
18
- data: JSON.stringify({
19
- cause,
20
- type: "full",
21
- typeReason: reason,
22
- declinedBy,
23
- }),
24
- })
25
- }
26
- const notifyAccepted = ({ cause, reason, instructions }) => {
27
- serverEventCallbackList.notify({
28
- type: "reload",
29
- data: JSON.stringify({
30
- cause,
31
- type: "hot",
32
- typeReason: reason,
33
- hotInstructions: instructions,
34
- }),
35
- })
36
- }
37
- const propagateUpdate = (firstUrlInfo) => {
38
- const iterate = (urlInfo, trace) => {
39
- if (urlInfo.data.hotAcceptSelf) {
40
- return {
41
- accepted: true,
42
- reason:
43
- urlInfo === firstUrlInfo
44
- ? `file accepts hot reload`
45
- : `a dependent file accepts hot reload`,
46
- instructions: [
47
- {
48
- type: urlInfo.type,
49
- boundary: urlToRelativeUrl(urlInfo.url, rootDirectoryUrl),
50
- acceptedBy: urlToRelativeUrl(urlInfo.url, rootDirectoryUrl),
51
- },
52
- ],
53
- }
7
+ return {
8
+ name: "jsenv:sse_server",
9
+ appliesDuring: { dev: true },
10
+ registerServerEvents: (
11
+ { sendServerEvent },
12
+ { rootDirectoryUrl, urlGraph },
13
+ ) => {
14
+ const notifyDeclined = ({ cause, reason, declinedBy }) => {
15
+ sendServerEvent({
16
+ type: "reload",
17
+ data: {
18
+ cause,
19
+ type: "full",
20
+ typeReason: reason,
21
+ declinedBy,
22
+ },
23
+ })
54
24
  }
55
- const { dependents } = urlInfo
56
- const instructions = []
57
- for (const dependentUrl of dependents) {
58
- const dependentUrlInfo = urlGraph.getUrlInfo(dependentUrl)
59
- if (dependentUrlInfo.data.hotDecline) {
60
- return {
61
- declined: true,
62
- reason: `a dependent file declines hot reload`,
63
- declinedBy: dependentUrl,
25
+ const notifyAccepted = ({ cause, reason, instructions }) => {
26
+ sendServerEvent({
27
+ type: "reload",
28
+ data: {
29
+ cause,
30
+ type: "hot",
31
+ typeReason: reason,
32
+ hotInstructions: instructions,
33
+ },
34
+ })
35
+ }
36
+ const propagateUpdate = (firstUrlInfo) => {
37
+ const iterate = (urlInfo, seen) => {
38
+ if (urlInfo.data.hotAcceptSelf) {
39
+ return {
40
+ accepted: true,
41
+ reason:
42
+ urlInfo === firstUrlInfo
43
+ ? `file accepts hot reload`
44
+ : `a dependent file accepts hot reload`,
45
+ instructions: [
46
+ {
47
+ type: urlInfo.type,
48
+ boundary: urlToRelativeUrl(urlInfo.url, rootDirectoryUrl),
49
+ acceptedBy: urlToRelativeUrl(urlInfo.url, rootDirectoryUrl),
50
+ },
51
+ ],
52
+ }
53
+ }
54
+ const { dependents } = urlInfo
55
+ const instructions = []
56
+ for (const dependentUrl of dependents) {
57
+ const dependentUrlInfo = urlGraph.getUrlInfo(dependentUrl)
58
+ if (dependentUrlInfo.data.hotDecline) {
59
+ return {
60
+ declined: true,
61
+ reason: `a dependent file declines hot reload`,
62
+ declinedBy: dependentUrl,
63
+ }
64
+ }
65
+ const { hotAcceptDependencies = [] } = dependentUrlInfo.data
66
+ if (hotAcceptDependencies.includes(urlInfo.url)) {
67
+ instructions.push({
68
+ type: dependentUrlInfo.type,
69
+ boundary: urlToRelativeUrl(dependentUrl, rootDirectoryUrl),
70
+ acceptedBy: urlToRelativeUrl(urlInfo.url, rootDirectoryUrl),
71
+ })
72
+ continue
73
+ }
74
+ if (seen.includes(dependentUrl)) {
75
+ return {
76
+ declined: true,
77
+ reason: "circular dependency",
78
+ declinedBy: urlToRelativeUrl(dependentUrl, rootDirectoryUrl),
79
+ }
80
+ }
81
+ const dependentPropagationResult = iterate(dependentUrlInfo, [
82
+ ...seen,
83
+ dependentUrl,
84
+ ])
85
+ if (dependentPropagationResult.accepted) {
86
+ instructions.push(...dependentPropagationResult.instructions)
87
+ continue
88
+ }
89
+ if (
90
+ // declined explicitely by an other file, it must decline the whole update
91
+ dependentPropagationResult.declinedBy
92
+ ) {
93
+ return dependentPropagationResult
94
+ }
95
+ // declined by absence of boundary, we can keep searching
96
+ continue
97
+ }
98
+ if (instructions.length === 0) {
99
+ return {
100
+ declined: true,
101
+ reason: `there is no file accepting hot reload while propagating update`,
102
+ }
64
103
  }
65
- }
66
- const { hotAcceptDependencies = [] } = dependentUrlInfo.data
67
- if (hotAcceptDependencies.includes(urlInfo.url)) {
68
- instructions.push({
69
- type: dependentUrlInfo.type,
70
- boundary: urlToRelativeUrl(dependentUrl, rootDirectoryUrl),
71
- acceptedBy: urlToRelativeUrl(urlInfo.url, rootDirectoryUrl),
72
- })
73
- continue
74
- }
75
- if (trace.includes(dependentUrl)) {
76
104
  return {
77
- declined: true,
78
- reason: "circular dependency",
79
- declinedBy: urlToRelativeUrl(dependentUrl, rootDirectoryUrl),
105
+ accepted: true,
106
+ reason: `${instructions.length} dependent file(s) accepts hot reload`,
107
+ instructions,
80
108
  }
81
109
  }
82
- const dependentPropagationResult = iterate(dependentUrlInfo, [
83
- ...trace,
84
- dependentUrl,
85
- ])
86
- if (dependentPropagationResult.accepted) {
87
- instructions.push(...dependentPropagationResult.instructions)
88
- continue
89
- }
90
- if (
91
- // declined explicitely by an other file, it must decline the whole update
92
- dependentPropagationResult.declinedBy
93
- ) {
94
- return dependentPropagationResult
95
- }
96
- // declined by absence of boundary, we can keep searching
97
- continue
110
+ const seen = []
111
+ return iterate(firstUrlInfo, seen)
98
112
  }
99
- if (instructions.length === 0) {
100
- return {
101
- declined: true,
102
- reason: `there is no file accepting hot reload while propagating update`,
113
+ clientFileChangeCallbackList.push(({ url, event }) => {
114
+ const urlInfo = urlGraph.getUrlInfo(url)
115
+ // file not part of dependency graph
116
+ if (!urlInfo) {
117
+ return
118
+ }
119
+ const relativeUrl = urlToRelativeUrl(url, rootDirectoryUrl)
120
+ const hotUpdate = propagateUpdate(urlInfo)
121
+ if (hotUpdate.declined) {
122
+ notifyDeclined({
123
+ cause: `${relativeUrl} ${event}`,
124
+ reason: hotUpdate.reason,
125
+ declinedBy: hotUpdate.declinedBy,
126
+ })
127
+ } else {
128
+ notifyAccepted({
129
+ cause: `${relativeUrl} ${event}`,
130
+ reason: hotUpdate.reason,
131
+ instructions: hotUpdate.instructions,
132
+ })
103
133
  }
104
- }
105
- return {
106
- accepted: true,
107
- reason: `${instructions.length} dependent file(s) accepts hot reload`,
108
- instructions,
109
- }
110
- }
111
- const trace = []
112
- return iterate(firstUrlInfo, trace)
113
- }
114
- clientFileChangeCallbackList.push(({ url, event }) => {
115
- const urlInfo = urlGraph.getUrlInfo(url)
116
- // file not part of dependency graph
117
- if (!urlInfo) {
118
- return
119
- }
120
- const relativeUrl = urlToRelativeUrl(url, rootDirectoryUrl)
121
- const hotUpdate = propagateUpdate(urlInfo)
122
- if (hotUpdate.declined) {
123
- notifyDeclined({
124
- cause: `${relativeUrl} ${event}`,
125
- reason: hotUpdate.reason,
126
- declinedBy: hotUpdate.declinedBy,
127
- })
128
- } else {
129
- notifyAccepted({
130
- cause: `${relativeUrl} ${event}`,
131
- reason: hotUpdate.reason,
132
- instructions: hotUpdate.instructions,
133
- })
134
- }
135
- })
136
- clientFilesPruneCallbackList.push(({ prunedUrlInfos, firstUrlInfo }) => {
137
- const mainHotUpdate = propagateUpdate(firstUrlInfo)
138
- const cause = `following files are no longer referenced: ${prunedUrlInfos.map(
139
- (prunedUrlInfo) => urlToRelativeUrl(prunedUrlInfo.url, rootDirectoryUrl),
140
- )}`
141
- // now check if we can hot update the main ressource
142
- // then if we can hot update all dependencies
143
- if (mainHotUpdate.declined) {
144
- notifyDeclined({
145
- cause,
146
- reason: mainHotUpdate.reason,
147
- declinedBy: mainHotUpdate.declinedBy,
148
134
  })
149
- return
150
- }
151
- // main can hot update
152
- let i = 0
153
- const instructions = []
154
- while (i < prunedUrlInfos.length) {
155
- const prunedUrlInfo = prunedUrlInfos[i++]
156
- if (prunedUrlInfo.data.hotDecline) {
157
- notifyDeclined({
135
+ clientFilesPruneCallbackList.push(({ prunedUrlInfos, firstUrlInfo }) => {
136
+ const mainHotUpdate = propagateUpdate(firstUrlInfo)
137
+ const cause = `following files are no longer referenced: ${prunedUrlInfos.map(
138
+ (prunedUrlInfo) =>
139
+ urlToRelativeUrl(prunedUrlInfo.url, rootDirectoryUrl),
140
+ )}`
141
+ // now check if we can hot update the main ressource
142
+ // then if we can hot update all dependencies
143
+ if (mainHotUpdate.declined) {
144
+ notifyDeclined({
145
+ cause,
146
+ reason: mainHotUpdate.reason,
147
+ declinedBy: mainHotUpdate.declinedBy,
148
+ })
149
+ return
150
+ }
151
+ // main can hot update
152
+ let i = 0
153
+ const instructions = []
154
+ while (i < prunedUrlInfos.length) {
155
+ const prunedUrlInfo = prunedUrlInfos[i++]
156
+ if (prunedUrlInfo.data.hotDecline) {
157
+ notifyDeclined({
158
+ cause,
159
+ reason: `a pruned file declines hot reload`,
160
+ declinedBy: urlToRelativeUrl(prunedUrlInfo.url, rootDirectoryUrl),
161
+ })
162
+ return
163
+ }
164
+ instructions.push({
165
+ type: "prune",
166
+ boundary: urlToRelativeUrl(prunedUrlInfo.url, rootDirectoryUrl),
167
+ acceptedBy: urlToRelativeUrl(firstUrlInfo.url, rootDirectoryUrl),
168
+ })
169
+ }
170
+ notifyAccepted({
158
171
  cause,
159
- reason: `a pruned file declines hot reload`,
160
- declinedBy: urlToRelativeUrl(prunedUrlInfo.url, rootDirectoryUrl),
172
+ reason: mainHotUpdate.reason,
173
+ instructions,
161
174
  })
162
- return
163
- }
164
- instructions.push({
165
- type: "prune",
166
- boundary: urlToRelativeUrl(prunedUrlInfo.url, rootDirectoryUrl),
167
- acceptedBy: urlToRelativeUrl(firstUrlInfo.url, rootDirectoryUrl),
168
175
  })
169
- }
170
- notifyAccepted({
171
- cause,
172
- reason: mainHotUpdate.reason,
173
- instructions,
174
- })
175
- })
176
-
177
- return {
178
- name: "jsenv:sse_server",
179
- appliesDuring: { dev: true },
180
- serve: (request) => {
176
+ },
177
+ serve: (request, { rootDirectoryUrl, urlGraph }) => {
181
178
  if (request.ressource === "/__graph__") {
182
179
  const graphJson = JSON.stringify(urlGraph.toJSON(rootDirectoryUrl))
183
180
  return {
@@ -189,15 +186,7 @@ export const jsenvPluginDevSSEServer = ({
189
186
  body: graphJson,
190
187
  }
191
188
  }
192
- const { accept } = request.headers
193
- if (accept && accept.includes("text/event-stream")) {
194
- const room = sseService.getOrCreateSSERoom(request)
195
- return room.join(request)
196
- }
197
189
  return null
198
190
  },
199
- destroy: () => {
200
- sseService.destroy()
201
- },
202
191
  }
203
192
  }
@@ -3,8 +3,6 @@ import { jsenvPluginDevSSEClient } from "./dev_sse/jsenv_plugin_dev_sse_client.j
3
3
  import { jsenvPluginDevSSEServer } from "./dev_sse/jsenv_plugin_dev_sse_server.js"
4
4
 
5
5
  export const jsenvPluginAutoreload = ({
6
- rootDirectoryUrl,
7
- urlGraph,
8
6
  scenario,
9
7
  clientFileChangeCallbackList,
10
8
  clientFilesPruneCallbackList,
@@ -16,8 +14,6 @@ export const jsenvPluginAutoreload = ({
16
14
  jsenvPluginHmr(),
17
15
  jsenvPluginDevSSEClient(),
18
16
  jsenvPluginDevSSEServer({
19
- rootDirectoryUrl,
20
- urlGraph,
21
17
  clientFileChangeCallbackList,
22
18
  clientFilesPruneCallbackList,
23
19
  }),