(content, inlineContents = false, options = {})
| 380 | } |
| 381 | |
| 382 | augmentContentWithNotifier(content, inlineContents = false, options = {}) { |
| 383 | let { integrityHash, scriptContents } = options; |
| 384 | if(!scriptContents) { |
| 385 | scriptContents = this.#getFileContents("./client/reload-client.js"); |
| 386 | } |
| 387 | if(!integrityHash) { |
| 388 | integrityHash = ssri.fromData(scriptContents); |
| 389 | } |
| 390 | |
| 391 | let searchParams = new URLSearchParams(); |
| 392 | if(this.options.reloadPort) { |
| 393 | searchParams.set("reloadPort", this.options.reloadPort); |
| 394 | } |
| 395 | |
| 396 | let searchParamsStr = searchParams.size > 0 ? `?${searchParams.toString()}` : ""; |
| 397 | |
| 398 | // This isn’t super necessary because it’s a local file, but it’s included anyway |
| 399 | let script = `<script type="module" integrity="${integrityHash}"${inlineContents ? `>${scriptContents}` : ` src="/${this.options.injectedScriptsFolder}/reload-client.js${searchParamsStr}">`}</script>`; |
| 400 | |
| 401 | if (content.includes("</head>")) { |
| 402 | return content.replace("</head>", `${script}</head>`); |
| 403 | } |
| 404 | |
| 405 | // If the HTML document contains an importmap, insert the module script after the importmap element |
| 406 | let importMapRegEx = /<script type=\\?importmap\\?[^>]*>(\n|.)*?<\/script>/gmi; |
| 407 | let importMapMatch = content.match(importMapRegEx)?.[0]; |
| 408 | |
| 409 | if (importMapMatch) { |
| 410 | return content.replace(importMapMatch, `${importMapMatch}${script}`); |
| 411 | } |
| 412 | |
| 413 | // <title> is the only *required* element in an HTML document |
| 414 | if (content.includes("</title>")) { |
| 415 | return content.replace("</title>", `</title>${script}`); |
| 416 | } |
| 417 | |
| 418 | // If you’ve reached this section, your HTML is invalid! |
| 419 | // We want to be super forgiving here, because folks might be in-progress editing the document! |
| 420 | if (content.includes("</body>")) { |
| 421 | return content.replace("</body>", `${script}</body>`); |
| 422 | } |
| 423 | if (content.includes("</html>")) { |
| 424 | return content.replace("</html>", `${script}</html>`); |
| 425 | } |
| 426 | if (content.includes("<!doctype html>")) { |
| 427 | return content.replace("<!doctype html>", `<!doctype html>${script}`); |
| 428 | } |
| 429 | |
| 430 | // Notably, works without content at all!! |
| 431 | return (content || "") + script; |
| 432 | } |
| 433 | |
| 434 | getFileContentType(filepath, res) { |
| 435 | let contentType = res.getHeader("Content-Type"); |
no test coverage detected