@jsenv/core 24.0.2 → 24.1.0-alpha.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/{LICENSE → license} +0 -0
- package/package.json +2 -3
- package/src/internal/compiling/compile-directory/getOrGenerateCompiledFile.js +1 -2
- package/src/internal/compiling/compile-directory/validateCache.js +5 -0
- package/src/internal/compiling/compileFile.js +84 -19
- package/src/internal/compiling/createCompiledFileService.js +6 -0
- package/src/internal/compiling/jsenvCompilerForHtml.js +113 -98
- package/src/internal/compiling/startCompileServer.js +5 -0
package/{LICENSE → license}
RENAMED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/core",
|
|
3
|
-
"version": "24.0.
|
|
3
|
+
"version": "24.1.0-alpha.0",
|
|
4
4
|
"description": "Tool to develop, test and build js projects",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -11,8 +11,7 @@
|
|
|
11
11
|
"node": ">=14.9.0"
|
|
12
12
|
},
|
|
13
13
|
"publishConfig": {
|
|
14
|
-
"access": "public"
|
|
15
|
-
"registry": "https://registry.npmjs.org"
|
|
14
|
+
"access": "public"
|
|
16
15
|
},
|
|
17
16
|
"type": "module",
|
|
18
17
|
"exports": {
|
|
@@ -127,8 +127,7 @@ const computeCompileReport = async ({
|
|
|
127
127
|
logger.warn(`WARNING: meta.sources is empty for ${compiledFileUrl}`)
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
const metaIsValid = cacheValidity.meta.isValid
|
|
131
|
-
|
|
130
|
+
const metaIsValid = cacheValidity.meta ? cacheValidity.meta.isValid : false
|
|
132
131
|
const [compileTiming, compileResult] = await timeFunction("compile", () =>
|
|
133
132
|
callCompile({
|
|
134
133
|
logger,
|
|
@@ -20,6 +20,11 @@ export const validateCache = async ({
|
|
|
20
20
|
}) => {
|
|
21
21
|
const validity = { isValid: true }
|
|
22
22
|
|
|
23
|
+
// disable cahce for html files so that we always parse the importmap file
|
|
24
|
+
if (compiledFileUrl.endsWith(".html")) {
|
|
25
|
+
return { isValid: false }
|
|
26
|
+
}
|
|
27
|
+
|
|
23
28
|
const metaJsonFileUrl = `${compiledFileUrl}__asset__meta.json`
|
|
24
29
|
const metaValidity = await validateMetaFile(metaJsonFileUrl)
|
|
25
30
|
mergeValidity(validity, "meta", metaValidity)
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
bufferToEtag,
|
|
6
6
|
urlIsInsideOf,
|
|
7
7
|
} from "@jsenv/filesystem"
|
|
8
|
+
import { normalizeImportMap, resolveImport } from "@jsenv/importmap"
|
|
8
9
|
import { convertFileSystemErrorToResponseProperties } from "@jsenv/server/src/internal/convertFileSystemErrorToResponseProperties.js"
|
|
9
10
|
|
|
10
11
|
import { getOrGenerateCompiledFile } from "./compile-directory/getOrGenerateCompiledFile.js"
|
|
@@ -19,6 +20,7 @@ export const compileFile = async ({
|
|
|
19
20
|
projectFileRequestedCallback = () => {},
|
|
20
21
|
request,
|
|
21
22
|
pushResponse,
|
|
23
|
+
importmapInfos,
|
|
22
24
|
compile,
|
|
23
25
|
compileCacheStrategy,
|
|
24
26
|
compileCacheSourcesValidation,
|
|
@@ -106,30 +108,34 @@ export const compileFile = async ({
|
|
|
106
108
|
)
|
|
107
109
|
})
|
|
108
110
|
|
|
109
|
-
if (
|
|
110
|
-
request.http2 &&
|
|
111
|
+
if (request.http2) {
|
|
111
112
|
// js resolution is special, we cannot just do resolveUrl of the import specifier
|
|
112
113
|
// because there can be importmap (bare specifier, import without extension, custom remapping, ...)
|
|
113
114
|
// And we would push 404 to the browser
|
|
114
115
|
// Until we implement import map resolution pushing ressource for js imports is disabled
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if (!urlIsInsideOf(dependencyUrl, request.origin)) {
|
|
121
|
-
// ignore external urls
|
|
122
|
-
return
|
|
123
|
-
}
|
|
124
|
-
if (dependencyUrl.startsWith("data:")) {
|
|
125
|
-
return
|
|
126
|
-
}
|
|
127
|
-
const dependencyRelativeUrl = urlToRelativeUrl(
|
|
128
|
-
dependencyUrl,
|
|
129
|
-
request.origin,
|
|
130
|
-
)
|
|
131
|
-
pushResponse({ path: `/${dependencyRelativeUrl}` })
|
|
116
|
+
const dependencyResolver = getDependencyResolver({
|
|
117
|
+
compileResult,
|
|
118
|
+
importmapInfos,
|
|
119
|
+
request,
|
|
120
|
+
projectDirectoryUrl,
|
|
132
121
|
})
|
|
122
|
+
if (dependencyResolver) {
|
|
123
|
+
compileResult.dependencies.forEach((dependency) => {
|
|
124
|
+
const dependencyUrl = dependencyResolver.resolve(dependency)
|
|
125
|
+
if (!urlIsInsideOf(dependencyUrl, request.origin)) {
|
|
126
|
+
// ignore external urls
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
if (dependencyUrl.startsWith("data:")) {
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
const dependencyRelativeUrl = urlToRelativeUrl(
|
|
133
|
+
dependencyUrl,
|
|
134
|
+
request.origin,
|
|
135
|
+
)
|
|
136
|
+
pushResponse({ path: `/${dependencyRelativeUrl}` })
|
|
137
|
+
})
|
|
138
|
+
}
|
|
133
139
|
}
|
|
134
140
|
|
|
135
141
|
// when a compiled version of the source file was just created or updated
|
|
@@ -229,3 +235,62 @@ export const compileFile = async ({
|
|
|
229
235
|
return convertFileSystemErrorToResponseProperties(error)
|
|
230
236
|
}
|
|
231
237
|
}
|
|
238
|
+
|
|
239
|
+
const getDependencyResolver = ({
|
|
240
|
+
compileResult,
|
|
241
|
+
importmapInfos,
|
|
242
|
+
request,
|
|
243
|
+
projectDirectoryUrl,
|
|
244
|
+
}) => {
|
|
245
|
+
const importmapKeys = Object.keys(importmapInfos)
|
|
246
|
+
const requestUrl = resolveUrl(request.ressource, request.origin)
|
|
247
|
+
|
|
248
|
+
if (
|
|
249
|
+
compileResult.contentType !== "application/javascript" ||
|
|
250
|
+
importmapKeys.length === 0
|
|
251
|
+
) {
|
|
252
|
+
return {
|
|
253
|
+
type: "url_resolution",
|
|
254
|
+
resolve: (dependency) => {
|
|
255
|
+
const dependencyUrl = resolveUrl(dependency, requestUrl)
|
|
256
|
+
return dependencyUrl
|
|
257
|
+
},
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const firstImportmapInfo = importmapInfos[importmapKeys[0]]
|
|
262
|
+
if (!firstImportmapInfo.text) {
|
|
263
|
+
return null
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (
|
|
267
|
+
// we are aware only of 1 importmap
|
|
268
|
+
importmapKeys.length === 1 ||
|
|
269
|
+
// all importmaps are the same
|
|
270
|
+
importmapKeys.slice(1).every(({ url }) => url === firstImportmapInfo.url)
|
|
271
|
+
) {
|
|
272
|
+
const importMapBaseUrl = resolveUrl(
|
|
273
|
+
urlToRelativeUrl(firstImportmapInfo.url, projectDirectoryUrl),
|
|
274
|
+
`${request.origin}/`,
|
|
275
|
+
)
|
|
276
|
+
const importMap = normalizeImportMap(
|
|
277
|
+
JSON.parse(firstImportmapInfo.text),
|
|
278
|
+
importMapBaseUrl,
|
|
279
|
+
)
|
|
280
|
+
return {
|
|
281
|
+
type: "importmap_resolution",
|
|
282
|
+
resolve: (dependency) => {
|
|
283
|
+
const dependencyUrl = resolveImport({
|
|
284
|
+
specifier: dependency,
|
|
285
|
+
importer: requestUrl,
|
|
286
|
+
importMap,
|
|
287
|
+
})
|
|
288
|
+
return dependencyUrl
|
|
289
|
+
},
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// there is more than 2 importmaps, we cannot know which one to pick
|
|
294
|
+
// (not supposed ot happen because during dev you usually use a single importmap)
|
|
295
|
+
return null
|
|
296
|
+
}
|
|
@@ -80,6 +80,8 @@ export const createCompiledFileService = ({
|
|
|
80
80
|
projectDirectoryUrl,
|
|
81
81
|
)
|
|
82
82
|
|
|
83
|
+
const importmapInfos = {}
|
|
84
|
+
|
|
83
85
|
return (request, { pushResponse, redirectRequest }) => {
|
|
84
86
|
const { origin, ressource } = request
|
|
85
87
|
// we use "ressourceToPathname" to remove eventual query param from the url
|
|
@@ -167,6 +169,7 @@ export const createCompiledFileService = ({
|
|
|
167
169
|
projectFileRequestedCallback,
|
|
168
170
|
request,
|
|
169
171
|
pushResponse,
|
|
172
|
+
importmapInfos,
|
|
170
173
|
compile: ({ code }) => {
|
|
171
174
|
return compiler({
|
|
172
175
|
logger,
|
|
@@ -195,6 +198,9 @@ export const createCompiledFileService = ({
|
|
|
195
198
|
sourcemapMethod,
|
|
196
199
|
sourcemapExcludeSources,
|
|
197
200
|
jsenvToolbarInjection,
|
|
201
|
+
onHtmlImportmapInfo: ({ htmlUrl, importmapInfo }) => {
|
|
202
|
+
importmapInfos[htmlUrl] = importmapInfo
|
|
203
|
+
},
|
|
198
204
|
})
|
|
199
205
|
},
|
|
200
206
|
})
|
|
@@ -50,6 +50,7 @@ export const compileHtml = async ({
|
|
|
50
50
|
|
|
51
51
|
jsenvScriptInjection = true,
|
|
52
52
|
jsenvToolbarInjection,
|
|
53
|
+
onHtmlImportmapInfo,
|
|
53
54
|
}) => {
|
|
54
55
|
const jsenvBrowserBuildUrlRelativeToProject = urlToRelativeUrl(
|
|
55
56
|
jsenvBrowserSystemFileInfo.jsenvBuildUrl,
|
|
@@ -86,55 +87,127 @@ export const compileHtml = async ({
|
|
|
86
87
|
],
|
|
87
88
|
})
|
|
88
89
|
|
|
90
|
+
let sources = []
|
|
91
|
+
let sourcesContent = []
|
|
89
92
|
const { scripts } = parseHtmlAstRessources(htmlAst)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
let hasImportmap = false
|
|
93
|
-
const inlineScriptsContentMap = {}
|
|
94
|
-
const importmapsToInline = []
|
|
93
|
+
let importmapInfo = null
|
|
95
94
|
scripts.forEach((script) => {
|
|
96
95
|
const typeAttribute = getHtmlNodeAttributeByName(script, "type")
|
|
97
|
-
const srcAttribute = getHtmlNodeAttributeByName(script, "src")
|
|
98
|
-
|
|
99
|
-
// importmap
|
|
100
96
|
if (typeAttribute && typeAttribute.value === "importmap") {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
97
|
+
if (importmapInfo) {
|
|
98
|
+
console.error("HTML file must contain max 1 importmap")
|
|
99
|
+
} else {
|
|
100
|
+
const srcAttribute = getHtmlNodeAttributeByName(script, "src")
|
|
101
|
+
const src = srcAttribute ? srcAttribute.value : ""
|
|
102
|
+
if (src) {
|
|
103
|
+
importmapInfo = {
|
|
104
|
+
script,
|
|
105
|
+
url: resolveUrl(src, url),
|
|
106
|
+
loadAsText: async () => {
|
|
107
|
+
const importMapResponse = await fetchUrl(importmapInfo.url)
|
|
108
|
+
if (importMapResponse.status !== 200) {
|
|
109
|
+
logger.warn(
|
|
110
|
+
createDetailedMessage(
|
|
111
|
+
importMapResponse.status === 404
|
|
112
|
+
? `importmap script file cannot be found.`
|
|
113
|
+
: `importmap script file unexpected response status (${importMapResponse.status}).`,
|
|
114
|
+
{
|
|
115
|
+
"importmap url": importmapInfo.url,
|
|
116
|
+
"html url": url,
|
|
117
|
+
},
|
|
118
|
+
),
|
|
119
|
+
)
|
|
120
|
+
return "{}"
|
|
121
|
+
}
|
|
122
|
+
const importmapAsText = await importMapResponse.text()
|
|
123
|
+
sources.push(importmapInfo.url)
|
|
124
|
+
sourcesContent.push(importmapAsText)
|
|
125
|
+
|
|
126
|
+
const importMapMoved = moveImportMap(
|
|
127
|
+
JSON.parse(importmapAsText),
|
|
128
|
+
importmapInfo.url,
|
|
129
|
+
url,
|
|
130
|
+
)
|
|
131
|
+
const compiledImportmapAsText = JSON.stringify(
|
|
132
|
+
importMapMoved,
|
|
133
|
+
null,
|
|
134
|
+
" ",
|
|
135
|
+
)
|
|
136
|
+
return compiledImportmapAsText
|
|
137
|
+
},
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
importmapInfo = {
|
|
141
|
+
script,
|
|
142
|
+
url: compiledUrl,
|
|
143
|
+
loadAsText: () => getHtmlNodeTextNode(script).value,
|
|
144
|
+
}
|
|
107
145
|
}
|
|
108
|
-
|
|
109
|
-
// we force inline because browsers supporting importmap supports only when they are inline
|
|
110
|
-
importmapsToInline.push({
|
|
111
|
-
script,
|
|
112
|
-
src: srcAttribute.value,
|
|
113
|
-
})
|
|
114
|
-
return
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const defaultImportMap = getDefaultImportMap({
|
|
118
|
-
importMapFileUrl: compiledUrl,
|
|
119
|
-
projectDirectoryUrl,
|
|
120
|
-
compileDirectoryRelativeUrl: `${outDirectoryRelativeUrl}${compileId}/`,
|
|
121
|
-
})
|
|
122
|
-
const inlineImportMap = JSON.parse(getHtmlNodeTextNode(script).value)
|
|
123
|
-
const mappings = composeTwoImportMaps(defaultImportMap, inlineImportMap)
|
|
124
|
-
if (moduleOutFormat === "systemjs") {
|
|
125
|
-
typeAttribute.value = "jsenv-importmap"
|
|
126
146
|
}
|
|
127
|
-
setHtmlNodeText(script, JSON.stringify(mappings, null, " "))
|
|
128
|
-
return
|
|
129
147
|
}
|
|
148
|
+
})
|
|
149
|
+
if (importmapInfo) {
|
|
150
|
+
const htmlImportMap = JSON.parse(await importmapInfo.loadAsText())
|
|
151
|
+
const importMapFromJsenv = getDefaultImportMap({
|
|
152
|
+
importMapFileUrl: compiledUrl,
|
|
153
|
+
projectDirectoryUrl,
|
|
154
|
+
compileDirectoryRelativeUrl: `${outDirectoryRelativeUrl}${compileId}/`,
|
|
155
|
+
})
|
|
156
|
+
const mappings = composeTwoImportMaps(importMapFromJsenv, htmlImportMap)
|
|
157
|
+
const importmapAsText = JSON.stringify(mappings, null, " ")
|
|
158
|
+
replaceHtmlNode(
|
|
159
|
+
importmapInfo.script,
|
|
160
|
+
`<script type="${
|
|
161
|
+
moduleOutFormat === "systemjs" ? "jsenv-importmap" : "importmap"
|
|
162
|
+
}">${importmapAsText}</script>`,
|
|
163
|
+
{
|
|
164
|
+
attributesToIgnore: ["src"],
|
|
165
|
+
},
|
|
166
|
+
)
|
|
167
|
+
importmapInfo.inlinedFrom = importmapInfo.url
|
|
168
|
+
importmapInfo.url = compiledUrl
|
|
169
|
+
importmapInfo.text = importmapAsText
|
|
170
|
+
} else {
|
|
171
|
+
// inject a default importmap
|
|
172
|
+
const defaultImportMap = getDefaultImportMap({
|
|
173
|
+
importMapFileUrl: compiledUrl,
|
|
174
|
+
projectDirectoryUrl,
|
|
175
|
+
compileDirectoryRelativeUrl: `${outDirectoryRelativeUrl}${compileId}/`,
|
|
176
|
+
})
|
|
177
|
+
const importmapAsText = JSON.stringify(defaultImportMap, null, " ")
|
|
178
|
+
manipulateHtmlAst(htmlAst, {
|
|
179
|
+
scriptInjections: [
|
|
180
|
+
{
|
|
181
|
+
type:
|
|
182
|
+
moduleOutFormat === "systemjs" ? "jsenv-importmap" : "importmap",
|
|
183
|
+
// in case there is no importmap, force the presence
|
|
184
|
+
// so that '@jsenv/core/' are still remapped
|
|
185
|
+
text: importmapAsText,
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
})
|
|
189
|
+
importmapInfo = {
|
|
190
|
+
url: compiledUrl,
|
|
191
|
+
text: importmapAsText,
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
onHtmlImportmapInfo({
|
|
195
|
+
htmlUrl: url,
|
|
196
|
+
importmapInfo,
|
|
197
|
+
})
|
|
130
198
|
|
|
199
|
+
const htmlDependencies = collectHtmlDependenciesFromAst(htmlAst)
|
|
200
|
+
const inlineScriptsContentMap = {}
|
|
201
|
+
scripts.forEach((script) => {
|
|
202
|
+
const typeAttribute = getHtmlNodeAttributeByName(script, "type")
|
|
203
|
+
const srcAttribute = getHtmlNodeAttributeByName(script, "src")
|
|
204
|
+
const src = srcAttribute ? srcAttribute.value : ""
|
|
131
205
|
// remote module script
|
|
132
|
-
if (typeAttribute && typeAttribute.value === "module" &&
|
|
206
|
+
if (typeAttribute && typeAttribute.value === "module" && src) {
|
|
133
207
|
if (moduleOutFormat === "systemjs") {
|
|
134
208
|
removeHtmlNodeAttribute(script, typeAttribute)
|
|
135
209
|
}
|
|
136
210
|
removeHtmlNodeAttribute(script, srcAttribute)
|
|
137
|
-
const src = srcAttribute.value
|
|
138
211
|
const jsenvMethod =
|
|
139
212
|
moduleOutFormat === "systemjs"
|
|
140
213
|
? "executeFileUsingSystemJs"
|
|
@@ -174,66 +247,6 @@ export const compileHtml = async ({
|
|
|
174
247
|
return
|
|
175
248
|
}
|
|
176
249
|
})
|
|
177
|
-
|
|
178
|
-
if (hasImportmap === false) {
|
|
179
|
-
const defaultImportMap = getDefaultImportMap({
|
|
180
|
-
importMapFileUrl: compiledUrl,
|
|
181
|
-
projectDirectoryUrl,
|
|
182
|
-
compileDirectoryRelativeUrl: `${outDirectoryRelativeUrl}${compileId}/`,
|
|
183
|
-
})
|
|
184
|
-
manipulateHtmlAst(htmlAst, {
|
|
185
|
-
scriptInjections: [
|
|
186
|
-
{
|
|
187
|
-
type:
|
|
188
|
-
moduleOutFormat === "systemjs" ? "jsenv-importmap" : "importmap",
|
|
189
|
-
// in case there is no importmap, force the presence
|
|
190
|
-
// so that '@jsenv/core/' are still remapped
|
|
191
|
-
text: JSON.stringify(defaultImportMap, null, " "),
|
|
192
|
-
},
|
|
193
|
-
],
|
|
194
|
-
})
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
await Promise.all(
|
|
198
|
-
importmapsToInline.map(async ({ script, src }) => {
|
|
199
|
-
const importMapUrl = resolveUrl(src, url)
|
|
200
|
-
const importMapResponse = await fetchUrl(importMapUrl)
|
|
201
|
-
if (importMapResponse.status !== 200) {
|
|
202
|
-
logger.warn(
|
|
203
|
-
createDetailedMessage(
|
|
204
|
-
importMapResponse.status === 404
|
|
205
|
-
? `Cannot inline importmap script because file cannot be found.`
|
|
206
|
-
: `Cannot inline importmap script due to unexpected response status (${importMapResponse.status}).`,
|
|
207
|
-
{
|
|
208
|
-
"importmap script src": src,
|
|
209
|
-
"importmap url": importMapUrl,
|
|
210
|
-
"html url": url,
|
|
211
|
-
},
|
|
212
|
-
),
|
|
213
|
-
)
|
|
214
|
-
return
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
const importMapContent = await importMapResponse.json()
|
|
218
|
-
const importMapInlined = moveImportMap(
|
|
219
|
-
importMapContent,
|
|
220
|
-
importMapUrl,
|
|
221
|
-
url,
|
|
222
|
-
)
|
|
223
|
-
replaceHtmlNode(
|
|
224
|
-
script,
|
|
225
|
-
`<script type="importmap">${JSON.stringify(
|
|
226
|
-
importMapInlined,
|
|
227
|
-
null,
|
|
228
|
-
" ",
|
|
229
|
-
)}</script>`,
|
|
230
|
-
{
|
|
231
|
-
attributesToIgnore: ["src"],
|
|
232
|
-
},
|
|
233
|
-
)
|
|
234
|
-
}),
|
|
235
|
-
)
|
|
236
|
-
|
|
237
250
|
const htmlAfterTransformation = stringifyHtmlAst(htmlAst)
|
|
238
251
|
|
|
239
252
|
let assets = []
|
|
@@ -303,12 +316,14 @@ export const compileHtml = async ({
|
|
|
303
316
|
}
|
|
304
317
|
}),
|
|
305
318
|
)
|
|
319
|
+
sources.push(url)
|
|
320
|
+
sourcesContent.push(code)
|
|
306
321
|
|
|
307
322
|
return {
|
|
308
323
|
contentType: "text/html",
|
|
309
324
|
compiledSource: htmlAfterTransformation,
|
|
310
|
-
sources
|
|
311
|
-
sourcesContent
|
|
325
|
+
sources,
|
|
326
|
+
sourcesContent,
|
|
312
327
|
assets,
|
|
313
328
|
assetsContent,
|
|
314
329
|
dependencies: htmlDependencies.map(({ specifier }) => {
|
|
@@ -583,6 +583,9 @@ const setupServerSentEventsForLivereload = ({
|
|
|
583
583
|
const projectFileAdded = createCallbackList()
|
|
584
584
|
|
|
585
585
|
const projectFileRequestedCallback = (relativeUrl, request) => {
|
|
586
|
+
if (relativeUrl[0] === "/") {
|
|
587
|
+
relativeUrl = relativeUrl.slice(1)
|
|
588
|
+
}
|
|
586
589
|
const url = `${projectDirectoryUrl}${relativeUrl}`
|
|
587
590
|
|
|
588
591
|
if (
|
|
@@ -669,6 +672,7 @@ const setupServerSentEventsForLivereload = ({
|
|
|
669
672
|
return
|
|
670
673
|
}
|
|
671
674
|
|
|
675
|
+
livereloadLogger.debug(`${rootRelativeUrl} requested -> start tracking it`)
|
|
672
676
|
// when a file is requested, always rebuild its dependency in case it has changed
|
|
673
677
|
// since the last time it was requested
|
|
674
678
|
startTrackingRoot(rootRelativeUrl)
|
|
@@ -699,6 +703,7 @@ const setupServerSentEventsForLivereload = ({
|
|
|
699
703
|
const removeRootRemovedCallback = projectFileRemoved.add((relativeUrl) => {
|
|
700
704
|
if (relativeUrl === rootRelativeUrl) {
|
|
701
705
|
stopTrackingRoot(rootRelativeUrl)
|
|
706
|
+
livereloadLogger.debug(`${rootRelativeUrl} removed -> stop tracking it`)
|
|
702
707
|
}
|
|
703
708
|
})
|
|
704
709
|
addStopTrackingCalback(rootRelativeUrl, removeRootRemovedCallback)
|