 5eb6d62c9c
			
		
	
	5eb6d62c9c
	
	
	
		
			
			* web: Silence ESBuild warning. * web: Flesh out live reload. Tidy ESBuild. --------- Signed-off-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
		
			
				
	
	
		
			142 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			142 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import * as http from "http";
 | |
| import path from "path";
 | |
| 
 | |
| /**
 | |
|  * Serializes a custom event to a text stream.
 | |
|  * a
 | |
|  * @param {Event} event
 | |
|  * @returns {string}
 | |
|  */
 | |
| export function serializeCustomEventToStream(event) {
 | |
|     // @ts-ignore
 | |
|     const data = event.detail ?? {};
 | |
| 
 | |
|     const eventContent = [`event: ${event.type}`, `data: ${JSON.stringify(data)}`];
 | |
| 
 | |
|     return eventContent.join("\n") + "\n\n";
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Options for the build observer plugin.
 | |
|  *
 | |
|  * @typedef {Object} BuildObserverOptions
 | |
|  *
 | |
|  * @property {URL} serverURL
 | |
|  * @property {string} logPrefix
 | |
|  * @property {string} relativeRoot
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * Creates a plugin that listens for build events and sends them to a server-sent event stream.
 | |
|  *
 | |
|  * @param {BuildObserverOptions} options
 | |
|  * @returns {import('esbuild').Plugin}
 | |
|  */
 | |
| export function buildObserverPlugin({ serverURL, logPrefix, relativeRoot }) {
 | |
|     const timerLabel = `[${logPrefix}] Build`;
 | |
|     const endpoint = serverURL.pathname;
 | |
|     const dispatcher = new EventTarget();
 | |
| 
 | |
|     const eventServer = http.createServer((req, res) => {
 | |
|         res.setHeader("Access-Control-Allow-Origin", "*");
 | |
|         res.setHeader("Access-Control-Allow-Methods", "GET");
 | |
|         res.setHeader("Access-Control-Allow-Headers", "Content-Type");
 | |
| 
 | |
|         if (req.url !== endpoint) {
 | |
|             console.log(`🚫 Invalid request to ${req.url}`);
 | |
|             res.writeHead(404);
 | |
|             res.end();
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         console.log("🔌 Client connected");
 | |
| 
 | |
|         res.writeHead(200, {
 | |
|             "Content-Type": "text/event-stream",
 | |
|             "Cache-Control": "no-cache",
 | |
|             "Connection": "keep-alive",
 | |
|         });
 | |
| 
 | |
|         /**
 | |
|          * @param {Event} event
 | |
|          */
 | |
|         const listener = (event) => {
 | |
|             const body = serializeCustomEventToStream(event);
 | |
| 
 | |
|             res.write(body);
 | |
|         };
 | |
| 
 | |
|         dispatcher.addEventListener("esbuild:start", listener);
 | |
|         dispatcher.addEventListener("esbuild:error", listener);
 | |
|         dispatcher.addEventListener("esbuild:end", listener);
 | |
| 
 | |
|         req.on("close", () => {
 | |
|             console.log("🔌 Client disconnected");
 | |
| 
 | |
|             clearInterval(keepAliveInterval);
 | |
| 
 | |
|             dispatcher.removeEventListener("esbuild:start", listener);
 | |
|             dispatcher.removeEventListener("esbuild:error", listener);
 | |
|             dispatcher.removeEventListener("esbuild:end", listener);
 | |
|         });
 | |
| 
 | |
|         const keepAliveInterval = setInterval(() => {
 | |
|             console.timeStamp("🏓 Keep-alive");
 | |
| 
 | |
|             res.write("event: keep-alive\n\n");
 | |
|             res.write(serializeCustomEventToStream(new CustomEvent("esbuild:keep-alive")));
 | |
|         }, 15_000);
 | |
|     });
 | |
| 
 | |
|     return {
 | |
|         name: "build-watcher",
 | |
|         setup: (build) => {
 | |
|             eventServer.listen(parseInt(serverURL.port, 10), serverURL.hostname);
 | |
| 
 | |
|             build.onDispose(() => {
 | |
|                 eventServer.close();
 | |
|             });
 | |
| 
 | |
|             build.onStart(() => {
 | |
|                 console.time(timerLabel);
 | |
| 
 | |
|                 dispatcher.dispatchEvent(
 | |
|                     new CustomEvent("esbuild:start", {
 | |
|                         detail: new Date().toISOString(),
 | |
|                     }),
 | |
|                 );
 | |
|             });
 | |
| 
 | |
|             build.onEnd((buildResult) => {
 | |
|                 console.timeEnd(timerLabel);
 | |
| 
 | |
|                 if (!buildResult.errors.length) {
 | |
|                     dispatcher.dispatchEvent(
 | |
|                         new CustomEvent("esbuild:end", {
 | |
|                             detail: new Date().toISOString(),
 | |
|                         }),
 | |
|                     );
 | |
| 
 | |
|                     return;
 | |
|                 }
 | |
| 
 | |
|                 console.warn(`Build ended with ${buildResult.errors.length} errors`);
 | |
| 
 | |
|                 dispatcher.dispatchEvent(
 | |
|                     new CustomEvent("esbuild:error", {
 | |
|                         detail: buildResult.errors.map((error) => ({
 | |
|                             ...error,
 | |
|                             location: error.location
 | |
|                                 ? {
 | |
|                                       ...error.location,
 | |
|                                       file: path.resolve(relativeRoot, error.location.file),
 | |
|                                   }
 | |
|                                 : null,
 | |
|                         })),
 | |
|                     }),
 | |
|                 );
 | |
|             });
 | |
|         },
 | |
|     };
 | |
| }
 |