UNPKG

@applicvision/js-toolbox

Version:

A collection of tools for modern JavaScript development

100 lines (81 loc) 2.74 kB
import style from '@applicvision/js-toolbox/style' import fs from "node:fs" import path from "node:path" import http, { OutgoingMessage } from "node:http" import https from "node:https" const clientScriptPath = new URL('./client.js', import.meta.url) /** * @param {{port: number, certificate?: string, paths: string[], ignorePatterns: string[]}} options */ export function createServer(options) { let running = false function logState() { if (!running) return console.clear() console.log('==== Autoreload server ====') console.log() console.log('Watching for changes in:', options.paths.map(path => style.bold(path)).join(', ')) if (options.ignorePatterns.length) { console.log('Ignoring files including:', options.ignorePatterns.map(path => style.bold(path)).join(', ')) } console.log() if (attachedClients.size == 0) { const url = `${options.certificate ? 'https' : 'http'}://localhost:${options.port}/autoreload.js` console.log(`Welcome to auto reload. In your web app, include ${style.underline(url)} to get started.`) } else { console.log('Connected clients:', attachedClients.size) } } /** @type {Set<OutgoingMessage>} */ const attachedClients = new Set() const { certificate = process.env.JS_TOOLBOX_CERT } = options const server = certificate ? https.createServer({ key: fs.readFileSync(path.resolve(certificate, 'key.pem')), cert: fs.readFileSync(path.resolve(certificate, 'cert.pem')) }) : http.createServer() server.on('request', async (request, response) => { const path = request.url if (path == '/autoreload.js') { response.writeHead(200, { 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/javascript' }) return fs.createReadStream(clientScriptPath).pipe(response) } if (path == '/stream') { response.writeHead(200, { 'content-type': 'text/event-stream', 'Access-Control-Allow-Origin': '*', }) attachedClients.add(response) response.write(`event: welcome\ndata: ${Date.now()}\n\n`) response.on('close', () => { attachedClients.delete(response) logState() }) return logState() } response.end(`Welcome to auto reload. In your web app, import ${certificate ? 'https' : 'http'}://${request.headers.host}/autoreload.js to get started.`) }) return { start(port) { running = true return new Promise(resolve => server.listen(port, () => { logState() resolve() })) }, notifyClients(filename) { attachedClients.forEach(stream => { stream.write(`event: filechange\ndata: ${filename}\n\n`) }) }, stop() { running = false attachedClients.forEach(stream => { stream.end(`event: stop\ndata: ${Date.now()}\n\n`) }) server.close() } } }