UNPKG

@antdevx/vite-plugin-hmr-sync

Version:

A Vite plugin for synchronizing HMR across multiple workspaces in a monorepo setup.

229 lines (228 loc) 6.77 kB
import { exec as w } from "node:child_process"; import { readFileSync as O } from "fs"; import { resolve as v } from "path"; import N from "node:http"; import b from "node:https"; import { URL as _ } from "node:url"; const C = "/on-child-rebuild", S = { type: "full-reload", path: "*" }, h = "vite-plugin-notify-on-rebuild", y = "vite-plugin-listen-for-remote-rebuilds", I = "vite-plugin-listen-for-remote-rebuilds-error"; function g(e, t = !1) { const o = `[${h}][${e}]`; return { log: (r) => !t && console.log(`${o} ${r}`), info: (r) => !t && console.info(`${o} ${r}`), warn: (r) => !t && console.warn(`${o} ${r}`), error: (r, n) => !t && console.error(`${o} ${r}`, n) }; } function T(e) { const t = g(e.appName || "unknown"); return new Promise((o, r) => { t.log("Starting build..."); const { buildCommand: n } = e, i = `${n} ${process.cwd()}/dist/spa`; w(i, (a, d, s) => { if (a) { t.error(`Error during build: ${a.message}`), r(a); return; } s && t.warn(s.toString()), t.log(d.toString()), t.log("Build completed successfully!"), o(d); }); }); } function A(e) { const t = g(e.appName || "unknown"); return new Promise((o, r) => { t.log("Starting server..."); const { port: n, cache: i = "0", cors: a = !0 } = e, d = `quasar serve ${process.cwd()}/dist/spa ${n ? "--port " + n : ""} ${i ? "--cache " + i : ""} ${a ? "--cors" : ""}`, s = w(d, (l, c, f) => { if (l) return t.error(`Error starting server: ${l.message}`), r(l); f && t.warn(f.toString()), t.log(`Server started: ${c}`); }); s.stdout && s.stdout.on("data", (l) => { t.log(`Server log: ${l}`); }), s.stderr && s.stderr.on("data", (l) => { t.error(`Server error: ${l}`); }), o(s); }); } function P(e, t, o, r, n) { const { onRebuild: i, hotPayload: a = S, allowedApps: d, suppressLogs: s = !1 } = r, l = g("host", s); try { const c = t.headers.host ? `http://${t.headers.host}` : "http://localhost", u = new URL(t.url || "", c).searchParams.get("app") || "unknown"; if (Array.isArray(d) && !d.includes(u)) { s || l.warn(`[${n}] ⚠️ Rebuild from unlisted app "${u}" ignored.`), o.writeHead(403, { "Content-Type": "text/plain" }), o.end(`[${n}] App "${u}" not allowed`); return; } s || l.log(`🔁 [${n}] Received rebuild signal from "${u}"`), e.ws.send(a), o.writeHead(200, { "Content-Type": "text/plain" }), o.end(`[${n}] Reload triggered`), i == null || i(u, e); } catch (c) { s || l.error(`[${n}] ❌ Error handling request:`, c), o.writeHead(500, { "Content-Type": "text/plain" }), o.end(`[${n}] Internal error`); return; } } function q() { const e = v(process.cwd(), "nodemon.json"); try { const t = O(e, "utf-8"); return JSON.parse(t).hmrSync || {}; } catch { return console.warn("[vite-plugin-hmr-sync] Failed to read nodemon.json config"), {}; } } function L(e) { const t = typeof e == "string" ? { appName: e } : e; if (!t.appName) throw new Error("`appName` is required"); return { appName: t.appName, hostUrl: t.hostUrl || "http://localhost:5000", endpoint: t.endpoint || "/on-child-rebuild", method: t.method || "GET", notifyOnSuccessOnly: t.notifyOnSuccessOnly ?? !0, suppressLogs: t.suppressLogs ?? !1 }; } function B(e) { const { endpoint: t, hotPayload: o, allowedApps: r, onRebuild: n, suppressLogs: i } = e; return { hotPayload: o || S, endpoint: t || C, onRebuild: n, allowedApps: r || [], suppressLogs: i || !1 }; } function F(e) { const { port: t = "5000", cors: o = !0, cache: r = "0", notify: n = !0, hostUrl: i = "http://localhost:5000", appName: a = "my-app", buildCommand: d = "quasar build", serveCommand: s = "quasar serve" } = e; return { port: t, cors: o, cache: r, notify: n, hostUrl: i, appName: a, buildCommand: d, serveCommand: s }; } function R(e, t) { const { appName: o, hostUrl: r, endpoint: n, method: i, notifyOnSuccessOnly: a, suppressLogs: d } = e, s = g(o, d); if (a && t) { s.error("Build failed, skipping notification.", (t == null ? void 0 : t.message) || t); return; } const l = `${r}${n}?app=${encodeURIComponent(o)}`; let c; try { c = new _(l); } catch (p) { s.error(`Invalid URL: "${l}"`, p); return; } const f = c.protocol === "https:" ? b : N, u = { method: i.toUpperCase(), hostname: c.hostname, port: c.port || (c.protocol === "https:" ? 443 : 80), path: c.pathname + c.search, headers: { "User-Agent": `vite-plugin-notify-on-rebuild/${o}` } }; s.info(`🔔 Sending ${i.toUpperCase()} request to ${c.href}`); const $ = f.request(u, (p) => { let m = ""; p.on("data", (E) => { m += E; }), p.on("end", () => { p.statusCode && p.statusCode >= 200 && p.statusCode < 300 ? s.info(`✅ Host notified (${p.statusCode})`) : s.warn(`⚠️ Host responded with ${p.statusCode}. Response: ${m.slice(0, 200)}${m.length > 200 ? "..." : ""}`); }); }); $.on("error", (p) => s.error("Notification failed:", p)), $.end(); } const U = "1.1.1"; function j(e) { let t; try { t = L(e); } catch (o) { return g("unknown").error(`[${h}] ❌`, o), { name: I }; } return { api: { get options() { return t; }, version: U }, enforce: "post", name: h, buildEnd(o) { R(t, o); } }; } function z(e = {}) { const t = B(e), { hotPayload: o, endpoint: r } = t; return { api: { get options() { return t; }, version: U }, enforce: "post", name: y, configureServer(n) { n.middlewares.use(t.endpoint, (i, a) => { P( n, i, a, { ...e, hotPayload: o }, y ); }); } }; } async function M() { const e = q(), t = F(e), { appName: o, hostUrl: r } = t; await T(t), await A(t).then((n) => { var i; return (i = n.stdout) == null || i.on("data", (a) => { if (console.log(a.toString()), a.includes("Listening at") && e.notify) { console.log("Server is running, sending notification..."); const d = L({ appName: o, hostUrl: r || "http://localhost:5000" }); R(d); } }), console.log("Server started successfully!"), n; }); } export { F as createBuildAndServeContext, P as handleRemoteRebuildRequest, z as listenForRemoteRebuilds, B as normalizeListenOptions, L as normalizeNotifyOptions, j as notifyOnRebuild, q as readNodemonHmrSyncConfig, R as sendNotification, T as startBuild, M as startBuildAndServer, A as startServer };