@jsenv/core 27.0.0-alpha.93 → 27.0.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "27.0.0-alpha.93",
3
+ "version": "27.0.0",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -61,7 +61,7 @@
61
61
  },
62
62
  "dependencies": {
63
63
  "@babel/plugin-proposal-dynamic-import": "7.16.7",
64
- "@babel/plugin-transform-modules-systemjs": "7.18.5",
64
+ "@babel/plugin-transform-modules-systemjs": "7.18.6",
65
65
  "@babel/plugin-transform-modules-umd": "7.18.0",
66
66
  "@c88/v8-coverage": "0.1.1",
67
67
  "@financial-times/polyfill-useragent-normaliser": "2.0.1",
@@ -71,13 +71,13 @@
71
71
  "@jsenv/importmap": "1.2.1",
72
72
  "@jsenv/integrity": "0.0.1",
73
73
  "@jsenv/node-esm-resolution": "0.1.0",
74
- "@jsenv/server": "12.7.3",
74
+ "@jsenv/server": "12.7.4",
75
75
  "@jsenv/uneval": "1.6.0",
76
76
  "@jsenv/url-meta": "7.0.0",
77
77
  "@jsenv/urls": "1.2.6",
78
78
  "@jsenv/utils": "2.0.1",
79
79
  "@jsenv/babel-plugins": "1.0.5",
80
- "@jsenv/log": "2.1.0",
80
+ "@jsenv/log": "3.0.2",
81
81
  "@jsenv/sourcemap": "1.0.1",
82
82
  "acorn-import-assertions": "1.8.0",
83
83
  "cuid": "2.1.8",
@@ -99,15 +99,15 @@
99
99
  "@babel/plugin-syntax-import-assertions": "7.17.12",
100
100
  "@jsenv/assert": "2.6.0",
101
101
  "@jsenv/eslint-config": "16.0.9",
102
- "@jsenv/file-size-impact": "13.0.0",
102
+ "@jsenv/file-size-impact": "13.0.1",
103
103
  "@jsenv/https-local": "2.1.0",
104
- "@jsenv/package-workspace": "0.3.0",
105
- "@jsenv/performance-impact": "3.0.0",
106
- "eslint": "8.18.0",
104
+ "@jsenv/package-workspace": "0.4.0",
105
+ "@jsenv/performance-impact": "3.0.1",
106
+ "eslint": "8.19.0",
107
107
  "eslint-plugin-html": "6.2.0",
108
108
  "eslint-plugin-import": "2.26.0",
109
109
  "eslint-plugin-react": "7.30.1",
110
- "playwright": "1.22.2",
110
+ "playwright": "1.23.1",
111
111
  "prettier": "2.7.1"
112
112
  }
113
- }
113
+ }
@@ -988,7 +988,7 @@ const applyUrlVersioning = async ({
988
988
  // - ignored files:
989
989
  // we don't know their content
990
990
  // - unused files without reference
991
- // File updated such as style.css -> style.css.js or file.js->file.es5.js
991
+ // File updated such as style.css -> style.css.js or file.js->file.nomodule.js
992
992
  // Are used at some point just to be discarded later because they need to be converted
993
993
  // There is no need to version them and we could not because the file have been ignored
994
994
  // so their content is unknown
@@ -56,8 +56,8 @@ export const startBuildServer = async ({
56
56
  "./package.json": true,
57
57
  "./jsenv.config.mjs": true,
58
58
  },
59
+ buildServerAutoreload = false,
59
60
  buildServerMainFile = getCallerPosition().url,
60
- buildServerAutoreload = true,
61
61
  cooldownBetweenFileEvents,
62
62
  }) => {
63
63
  const logger = createLogger({ logLevel })
@@ -96,54 +96,56 @@ export const startBuildServer = async ({
96
96
  port = await findFreePort(port, { signal: operation.signal })
97
97
  }
98
98
 
99
- const reloadableWorker = createReloadableWorker(buildServerMainFile)
100
- if (buildServerAutoreload && reloadableWorker.isPrimary) {
101
- const buildServerFileChangeCallback = ({ relativeUrl, event }) => {
102
- const url = new URL(relativeUrl, rootDirectoryUrl).href
103
- if (buildServerAutoreload) {
99
+ let reloadableWorker
100
+ if (buildServerAutoreload) {
101
+ reloadableWorker = createReloadableWorker(buildServerMainFile)
102
+ if (reloadableWorker.isPrimary) {
103
+ const buildServerFileChangeCallback = ({ relativeUrl, event }) => {
104
+ const url = new URL(relativeUrl, rootDirectoryUrl).href
104
105
  logger.info(`file ${event} ${url} -> restarting server...`)
105
106
  reloadableWorker.reload()
106
107
  }
107
- }
108
- const stopWatchingBuildServerFiles = registerDirectoryLifecycle(
109
- rootDirectoryUrl,
110
- {
111
- watchPatterns: {
112
- [buildServerMainFile]: true,
113
- ...buildServerFiles,
114
- },
115
- cooldownBetweenFileEvents,
116
- keepProcessAlive: false,
117
- recursive: true,
118
- added: ({ relativeUrl }) => {
119
- buildServerFileChangeCallback({ relativeUrl, event: "added" })
120
- },
121
- updated: ({ relativeUrl }) => {
122
- buildServerFileChangeCallback({ relativeUrl, event: "modified" })
123
- },
124
- removed: ({ relativeUrl }) => {
125
- buildServerFileChangeCallback({ relativeUrl, event: "removed" })
108
+ const stopWatchingBuildServerFiles = registerDirectoryLifecycle(
109
+ rootDirectoryUrl,
110
+ {
111
+ watchPatterns: {
112
+ ...buildServerFiles,
113
+ [buildServerMainFile]: true,
114
+ ".jsenv/": false,
115
+ },
116
+ cooldownBetweenFileEvents,
117
+ keepProcessAlive: false,
118
+ recursive: true,
119
+ added: ({ relativeUrl }) => {
120
+ buildServerFileChangeCallback({ relativeUrl, event: "added" })
121
+ },
122
+ updated: ({ relativeUrl }) => {
123
+ buildServerFileChangeCallback({ relativeUrl, event: "modified" })
124
+ },
125
+ removed: ({ relativeUrl }) => {
126
+ buildServerFileChangeCallback({ relativeUrl, event: "removed" })
127
+ },
126
128
  },
127
- },
128
- )
129
- operation.addAbortCallback(() => {
130
- stopWatchingBuildServerFiles()
131
- reloadableWorker.terminate()
132
- })
133
- const worker = await reloadableWorker.load()
134
- const messagePromise = new Promise((resolve) => {
135
- worker.once("message", resolve)
136
- })
137
- await messagePromise
138
- // if (!keepProcessAlive) {
139
- // worker.unref()
140
- // }
141
- return {
142
- origin: `${protocol}://127.0.0.1:${port}`,
143
- stop: () => {
129
+ )
130
+ operation.addAbortCallback(() => {
144
131
  stopWatchingBuildServerFiles()
145
132
  reloadableWorker.terminate()
146
- },
133
+ })
134
+ const worker = await reloadableWorker.load()
135
+ const messagePromise = new Promise((resolve) => {
136
+ worker.once("message", resolve)
137
+ })
138
+ await messagePromise
139
+ // if (!keepProcessAlive) {
140
+ // worker.unref()
141
+ // }
142
+ return {
143
+ origin: `${protocol}://127.0.0.1:${port}`,
144
+ stop: () => {
145
+ stopWatchingBuildServerFiles()
146
+ reloadableWorker.terminate()
147
+ },
148
+ }
147
149
  }
148
150
  }
149
151
 
@@ -195,7 +197,7 @@ export const startBuildServer = async ({
195
197
  logger.info(`- ${server.origins[key]}`)
196
198
  })
197
199
  logger.info(``)
198
- if (reloadableWorker.isWorker) {
200
+ if (reloadableWorker && reloadableWorker.isWorker) {
199
201
  parentPort.postMessage(server.origin)
200
202
  }
201
203
  return {
@@ -4,53 +4,51 @@
4
4
  viewBox="0 0 430 430"
5
5
  enable-background="new 0 0 430 430"
6
6
  >
7
- <g>
8
- <g>
9
- <path
10
- id="j-letter"
11
- fill="#F7931E"
12
- d="M78.879,272.229c3.381-0.441,7.056-1.176,9.408-3.822c2.793-2.939,3.234-8.086,3.234-19.111v-63.064
7
+ <g id="letters">
8
+ <path
9
+ id="j"
10
+ fill="#F7931E"
11
+ d="M78.879,272.229c3.381-0.441,7.056-1.176,9.408-3.822c2.793-2.939,3.234-8.086,3.234-19.111v-63.064
13
12
  h19.404v66.74c0,16.023-3.381,23.52-9.555,28.371c-5.292,4.264-14.112,6.174-21.021,6.174L78.879,272.229z M111.072,167.121
14
13
  c0,6.174-4.41,10.438-10.143,10.438c-5.292,0-9.702-4.263-9.555-10.438c-0.147-6.468,4.41-10.437,9.849-10.437
15
14
  S111.072,160.653,111.072,167.121z"
16
- />
17
- <path
18
- id="s-letter"
19
- fill="#F7931E"
20
- d="M123.714,240.77c2.793,1.764,8.085,3.822,12.936,3.822c4.998,0,7.791-2.205,7.791-6.469
15
+ />
16
+ <path
17
+ id="s"
18
+ fill="#F7931E"
19
+ d="M123.714,240.77c2.793,1.764,8.085,3.822,12.936,3.822c4.998,0,7.791-2.205,7.791-6.469
21
20
  c0-3.675-2.058-6.027-8.379-9.702c-11.76-6.615-14.553-14.112-14.553-20.727c0-12.937,9.261-22.639,23.667-22.639
22
21
  c6.027,0,10.731,1.47,14.553,3.234l-3.381,14.112c-2.793-1.617-6.174-2.94-9.996-2.94c-4.851,0-7.203,2.94-7.203,6.174
23
22
  c0,3.234,1.617,4.998,8.379,8.967c10.584,6.027,14.553,13.524,14.553,21.756c0,14.699-10.584,22.639-25.432,22.639
24
23
  c-6.027,0-13.083-1.617-16.464-4.117L123.714,240.77z"
25
- />
26
- <path
27
- id="e-letter"
28
- fill="#F7931E"
29
- d="M204.414,223.57c0.148,21.756,8.674,26.461,16.906,26.461c4.852,0,8.967-1.176,11.76-2.793l1.764,8.379
24
+ />
25
+ <path
26
+ id="e"
27
+ fill="#F7931E"
28
+ d="M204.414,223.57c0.148,21.756,8.674,26.461,16.906,26.461c4.852,0,8.967-1.176,11.76-2.793l1.764,8.379
30
29
  c-3.969,2.205-9.996,3.381-15.582,3.381c-17.052,0-25.872-13.965-25.872-35.722c0-23.08,9.702-37.486,23.961-37.486
31
30
  c14.553,0,20.285,15.289,20.285,31.459c0,2.646,0,4.557-0.146,6.321H204.414z M226.76,215.191
32
31
  c0.293-14.259-5.145-20.581-10.584-20.581c-7.352,0-11.174,10.878-11.613,20.581H226.76z"
33
- />
34
- <path
35
- id="n-letter"
36
- fill="#F7931E"
37
- d="M249.836,205.342c0-8.379-0.441-12.643-0.588-18.375h9.85l0.588,8.526h0.293
32
+ />
33
+ <path
34
+ id="n"
35
+ fill="#F7931E"
36
+ d="M249.836,205.342c0-8.379-0.441-12.643-0.588-18.375h9.85l0.588,8.526h0.293
38
37
  c3.088-5.733,8.82-9.702,16.318-9.702c9.85,0,17.199,7.35,17.199,24.55v47.775h-11.318V212.25c0-8.379-1.617-16.905-9.85-16.905
39
38
  c-4.705,0-9.262,3.969-10.732,11.613c-0.293,1.764-0.439,3.969-0.439,6.321v44.835h-11.32V205.342z"
40
- />
41
- <path
42
- id="v-letter"
43
- fill="#F7931E"
44
- d="M313.783,186.966l8.967,39.985c1.029,4.851,2.205,11.172,3.088,17.346h0.441
39
+ />
40
+ <path
41
+ id="v"
42
+ fill="#F7931E"
43
+ d="M313.783,186.966l8.967,39.985c1.029,4.851,2.205,11.172,3.088,17.346h0.441
45
44
  c0.734-5.879,1.91-11.907,2.939-17.346l8.82-39.985h11.172l-18.523,71.149h-10.143l-18.521-71.149H313.783z"
46
- />
47
- </g>
48
- <g>
49
- <g>
50
- <path
51
- id="arc1"
52
- fill="#F7931E"
53
- d="M32.118,204.979c0,0,0.105,1.801,0.302,5.179c0.124,3.4,0.638,8.29,1.434,14.48
45
+ />
46
+ </g>
47
+ <g id="arcs">
48
+ <path
49
+ id="arc1"
50
+ fill="#F7931E"
51
+ d="M32.118,204.979c0,0,0.105,1.801,0.302,5.179c0.124,3.4,0.638,8.29,1.434,14.48
54
52
  c0.249,1.546,0.511,3.174,0.786,4.882c0.137,0.853,0.278,1.725,0.421,2.617c0.154,0.89,0.376,1.789,0.558,2.712
55
53
  c0.384,1.843,0.783,3.761,1.197,5.75c0.444,1.981,1.027,4.008,1.56,6.112c2.274,8.378,5.328,17.708,9.758,27.396
56
54
  c4.406,9.688,10.04,19.776,17.062,29.673c7.003,9.901,15.393,19.609,25.102,28.499c9.702,8.888,20.652,17.025,32.581,23.85
@@ -74,13 +72,11 @@
74
72
  c-12.467-7.743-23.632-16.999-33.41-26.861c-9.758-9.893-18.135-20.455-24.833-31.222c-6.743-10.739-11.988-21.536-15.97-31.794
75
73
  c-4.006-10.258-6.601-20.021-8.441-28.721c-1.917-8.698-2.688-16.429-3.245-22.764c-0.396-6.374-0.584-11.386-0.485-14.752
76
74
  c0.026-3.383,0.04-5.188,0.04-5.188c0.003-0.47,0.387-0.848,0.857-0.844C31.725,204.181,32.091,204.536,32.118,204.979z"
77
- />
78
- </g>
79
- <g>
80
- <path
81
- id="arc2"
82
- fill="#F7931E"
83
- d="M393.625,225.021c0,0-0.104-1.731-0.297-4.979c-0.049-0.812-0.103-1.718-0.162-2.716
75
+ />
76
+ <path
77
+ id="arc2"
78
+ fill="#F7931E"
79
+ d="M393.625,225.021c0,0-0.104-1.731-0.297-4.979c-0.049-0.812-0.103-1.718-0.162-2.716
84
80
  c-0.029-0.499-0.061-1.021-0.093-1.565c-0.059-0.538-0.119-1.097-0.182-1.679c-0.269-2.323-0.534-4.99-0.906-7.966
85
81
  c-0.241-1.486-0.496-3.051-0.763-4.693c-0.133-0.82-0.269-1.658-0.408-2.516c-0.126-0.859-0.286-1.731-0.487-2.616
86
82
  c-0.778-3.54-1.458-7.393-2.614-11.413c-0.266-1.009-0.537-2.034-0.812-3.075c-0.264-1.043-0.553-2.096-0.908-3.147
@@ -119,26 +115,26 @@
119
115
  c0.173,3.065,0.257,5.808,0.365,8.183c0.022,0.594,0.045,1.165,0.066,1.714c-0.006,0.545-0.01,1.068-0.015,1.567
120
116
  c-0.009,1-0.017,1.908-0.024,2.721c-0.029,3.252-0.045,4.987-0.045,4.987c-0.004,0.47-0.389,0.847-0.857,0.843
121
117
  C394.018,225.817,393.652,225.463,393.625,225.021z"
122
- />
123
- </g>
124
- <circle
125
- id="circle2"
126
- fill="#F7931E"
127
- stroke-width="9"
128
- stroke-miterlimit="10"
129
- cx="70.536"
130
- cy="110.694"
131
- r="36.011"
132
- />
133
- <circle
134
- id="circle1"
135
- fill="#F7931E"
136
- stroke-width="9"
137
- stroke-miterlimit="10"
138
- cx="362.721"
139
- cy="309.694"
140
- r="36.012"
141
- />
142
- </g>
118
+ />
119
+ </g>
120
+ <g id="circles">
121
+ <circle
122
+ id="circle2"
123
+ fill="#F7931E"
124
+ stroke-width="9"
125
+ stroke-miterlimit="10"
126
+ cx="70.536"
127
+ cy="110.694"
128
+ r="36.011"
129
+ />
130
+ <circle
131
+ id="circle1"
132
+ fill="#F7931E"
133
+ stroke-width="9"
134
+ stroke-miterlimit="10"
135
+ cx="362.721"
136
+ cy="309.694"
137
+ r="36.012"
138
+ />
143
139
  </g>
144
- </svg>
140
+ </svg>
@@ -31,19 +31,21 @@ export const startDevServer = async ({
31
31
  certificate,
32
32
  privateKey,
33
33
  keepProcessAlive = true,
34
+ serverPlugins,
35
+
34
36
  rootDirectoryUrl,
37
+ clientFiles = {
38
+ "./src/": true,
39
+ "./tests/": true,
40
+ },
35
41
  devServerFiles = {
36
42
  "./package.json": true,
37
43
  "./jsenv.config.mjs": true,
38
44
  },
45
+ clientAutoreload = true,
46
+ devServerAutoreload = false,
39
47
  devServerMainFile = getCallerPosition().url,
40
- devServerAutoreload = true,
41
- clientFiles = {
42
- "./src/": true,
43
- "./tests/": true,
44
- },
45
48
  cooldownBetweenFileEvents,
46
- clientAutoreload = true,
47
49
 
48
50
  sourcemaps = "inline",
49
51
  // default runtimeCompat assume dev server will be request by recent browsers
@@ -92,53 +94,57 @@ export const startDevServer = async ({
92
94
  port = await findFreePort(port, { signal: operation.signal })
93
95
  }
94
96
 
95
- const reloadableWorker = createReloadableWorker(devServerMainFile)
96
- if (devServerAutoreload && reloadableWorker.isPrimary) {
97
- const devServerFileChangeCallback = ({ relativeUrl, event }) => {
98
- const url = new URL(relativeUrl, rootDirectoryUrl).href
99
- logger.info(`file ${event} ${url} -> restarting server...`)
100
- reloadableWorker.reload()
101
- }
102
- const stopWatchingDevServerFiles = registerDirectoryLifecycle(
103
- rootDirectoryUrl,
104
- {
105
- watchPatterns: {
106
- [devServerMainFile]: true,
107
- ...devServerFiles,
108
- },
109
- cooldownBetweenFileEvents,
110
- keepProcessAlive: false,
111
- recursive: true,
112
- added: ({ relativeUrl }) => {
113
- devServerFileChangeCallback({ relativeUrl, event: "added" })
114
- },
115
- updated: ({ relativeUrl }) => {
116
- devServerFileChangeCallback({ relativeUrl, event: "modified" })
117
- },
118
- removed: ({ relativeUrl }) => {
119
- devServerFileChangeCallback({ relativeUrl, event: "removed" })
97
+ let reloadableWorker
98
+ if (devServerAutoreload) {
99
+ reloadableWorker = createReloadableWorker(devServerMainFile)
100
+ if (reloadableWorker.isPrimary) {
101
+ const devServerFileChangeCallback = ({ relativeUrl, event }) => {
102
+ const url = new URL(relativeUrl, rootDirectoryUrl).href
103
+ logger.info(`file ${event} ${url} -> restarting server...`)
104
+ reloadableWorker.reload()
105
+ }
106
+ const stopWatchingDevServerFiles = registerDirectoryLifecycle(
107
+ rootDirectoryUrl,
108
+ {
109
+ watchPatterns: {
110
+ ...devServerFiles.include,
111
+ [devServerMainFile]: true,
112
+ ".jsenv/": false,
113
+ },
114
+ cooldownBetweenFileEvents,
115
+ keepProcessAlive: false,
116
+ recursive: true,
117
+ added: ({ relativeUrl }) => {
118
+ devServerFileChangeCallback({ relativeUrl, event: "added" })
119
+ },
120
+ updated: ({ relativeUrl }) => {
121
+ devServerFileChangeCallback({ relativeUrl, event: "modified" })
122
+ },
123
+ removed: ({ relativeUrl }) => {
124
+ devServerFileChangeCallback({ relativeUrl, event: "removed" })
125
+ },
120
126
  },
121
- },
122
- )
123
- operation.addAbortCallback(() => {
124
- stopWatchingDevServerFiles()
125
- reloadableWorker.terminate()
126
- })
127
-
128
- const worker = await reloadableWorker.load()
129
- const messagePromise = new Promise((resolve) => {
130
- worker.once("message", resolve)
131
- })
132
- await messagePromise
133
- // if (!keepProcessAlive) {
134
- // worker.unref()
135
- // }
136
- return {
137
- origin: `${protocol}://127.0.0.1:${port}`,
138
- stop: () => {
127
+ )
128
+ operation.addAbortCallback(() => {
139
129
  stopWatchingDevServerFiles()
140
130
  reloadableWorker.terminate()
141
- },
131
+ })
132
+
133
+ const worker = await reloadableWorker.load()
134
+ const messagePromise = new Promise((resolve) => {
135
+ worker.once("message", resolve)
136
+ })
137
+ await messagePromise
138
+ // if (!keepProcessAlive) {
139
+ // worker.unref()
140
+ // }
141
+ return {
142
+ origin: `${protocol}://127.0.0.1:${port}`,
143
+ stop: () => {
144
+ stopWatchingDevServerFiles()
145
+ reloadableWorker.terminate()
146
+ },
147
+ }
142
148
  }
143
149
  }
144
150
 
@@ -155,7 +161,10 @@ export const startDevServer = async ({
155
161
  })
156
162
  }
157
163
  const stopWatchingClientFiles = registerDirectoryLifecycle(rootDirectoryUrl, {
158
- watchPatterns: clientFiles,
164
+ watchPatterns: {
165
+ ...clientFiles,
166
+ ".jsenv/": false,
167
+ },
159
168
  cooldownBetweenFileEvents,
160
169
  keepProcessAlive: false,
161
170
  recursive: true,
@@ -218,6 +227,7 @@ export const startDevServer = async ({
218
227
  urlGraph,
219
228
  kitchen,
220
229
  scenario: "dev",
230
+ serverPlugins,
221
231
  })
222
232
  startDevServerTask.done()
223
233
  logger.info(``)
@@ -230,7 +240,7 @@ export const startDevServer = async ({
230
240
  kitchen.pluginController.callHooks("destroy", {})
231
241
  }
232
242
  })
233
- if (reloadableWorker.isWorker) {
243
+ if (reloadableWorker && reloadableWorker.isWorker) {
234
244
  parentPort.postMessage(server.origin)
235
245
  }
236
246
  return {
@@ -64,6 +64,7 @@ export const createKitchen = ({
64
64
  return RUNTIME_COMPAT.isSupported(runtimeCompat, feature)
65
65
  },
66
66
  }
67
+ pluginController.callHooks("init", kitchenContext)
67
68
  const createReference = ({
68
69
  data = {},
69
70
  node,
@@ -61,7 +61,13 @@ export const createFileService = ({
61
61
  const urlInfo = urlGraph.reuseOrCreateUrlInfo(reference.url)
62
62
 
63
63
  const ifNoneMatch = request.headers["if-none-match"]
64
- if (ifNoneMatch && urlInfo.contentEtag === ifNoneMatch) {
64
+ if (
65
+ ifNoneMatch &&
66
+ urlInfo.contentEtag === ifNoneMatch &&
67
+ // - isValid is true by default
68
+ // - isValid can be overriden by plugins such as cjs_to_esm
69
+ urlInfo.isValid()
70
+ ) {
65
71
  return {
66
72
  status: 304,
67
73
  headers: {
@@ -83,6 +89,7 @@ export const createFileService = ({
83
89
  urlInfo.originalContent = null
84
90
  urlInfo.type = null
85
91
  urlInfo.subtype = null
92
+ urlInfo.dependsOnPackageJson = false
86
93
  urlInfo.timing = {}
87
94
  }
88
95
  const { runtimeName, runtimeVersion } = parseUserAgentHeader(
@@ -121,33 +121,48 @@ export const createUrlGraph = ({
121
121
  }
122
122
 
123
123
  if (clientFileChangeCallbackList) {
124
- const updateModifiedTimestamp = (urlInfo, modifiedTimestamp) => {
125
- const seen = []
126
- const iterate = (urlInfo) => {
127
- if (seen.includes(urlInfo.url)) {
128
- return
129
- }
130
- seen.push(urlInfo.url)
131
- urlInfo.modifiedTimestamp = modifiedTimestamp
132
- urlInfo.dependents.forEach((dependentUrl) => {
133
- const dependentUrlInfo = urlInfos[dependentUrl]
134
- const { hotAcceptDependencies = [] } = dependentUrlInfo.data
135
- if (!hotAcceptDependencies.includes(urlInfo.url)) {
136
- iterate(dependentUrlInfo)
137
- }
138
- })
139
- }
140
- iterate(urlInfo)
141
- }
142
124
  clientFileChangeCallbackList.push(({ url }) => {
143
125
  const urlInfo = urlInfos[url]
144
126
  if (urlInfo) {
145
- updateModifiedTimestamp(urlInfo, Date.now())
146
- urlInfo.contentEtag = null
127
+ considerModified(urlInfo, Date.now())
147
128
  }
148
129
  })
149
130
  }
150
131
 
132
+ const considerModified = (urlInfo, modifiedTimestamp = Date.now()) => {
133
+ const seen = []
134
+ const iterate = (urlInfo) => {
135
+ if (seen.includes(urlInfo.url)) {
136
+ return
137
+ }
138
+ seen.push(urlInfo.url)
139
+ urlInfo.modifiedTimestamp = modifiedTimestamp
140
+ urlInfo.contentEtag = undefined
141
+ urlInfo.dependents.forEach((dependentUrl) => {
142
+ const dependentUrlInfo = urlInfos[dependentUrl]
143
+ const { hotAcceptDependencies = [] } = dependentUrlInfo.data
144
+ if (!hotAcceptDependencies.includes(urlInfo.url)) {
145
+ iterate(dependentUrlInfo)
146
+ }
147
+ })
148
+ }
149
+ iterate(urlInfo)
150
+ }
151
+
152
+ const getRelatedUrlInfos = (url) => {
153
+ const urlInfosUntilNotInline = []
154
+ const parentUrlInfo = getUrlInfo(url)
155
+ if (parentUrlInfo) {
156
+ urlInfosUntilNotInline.push(parentUrlInfo)
157
+ if (parentUrlInfo.inlineUrlSite) {
158
+ urlInfosUntilNotInline.push(
159
+ ...getRelatedUrlInfos(parentUrlInfo.inlineUrlSite.url),
160
+ )
161
+ }
162
+ }
163
+ return urlInfosUntilNotInline
164
+ }
165
+
151
166
  return {
152
167
  urlInfos,
153
168
  reuseOrCreateUrlInfo,
@@ -156,6 +171,8 @@ export const createUrlGraph = ({
156
171
  inferReference,
157
172
  findDependent,
158
173
  updateReferences,
174
+ considerModified,
175
+ getRelatedUrlInfos,
159
176
 
160
177
  toJSON: (rootDirectoryUrl) => {
161
178
  const data = {}
@@ -176,6 +193,9 @@ export const createUrlGraph = ({
176
193
  const createUrlInfo = (url) => {
177
194
  return {
178
195
  modifiedTimestamp: 0,
196
+ contentEtag: null,
197
+ dependsOnPackageJson: false,
198
+ isValid,
179
199
  data: {}, // plugins can put whatever they want here
180
200
  references: [],
181
201
  dependencies: new Set(),
@@ -192,10 +212,12 @@ const createUrlInfo = (url) => {
192
212
  shouldHandle: undefined,
193
213
  originalContent: undefined,
194
214
  content: undefined,
195
- contentEtag: null,
215
+
196
216
  sourcemap: null,
197
217
  sourcemapReference: null,
198
218
  timing: {},
199
219
  headers: {},
200
220
  }
201
221
  }
222
+
223
+ const isValid = () => true