Files
tibi-svelte-starter/scripts/esbuild-wrapper.js
T

168 lines
5.6 KiB
JavaScript

const esbuild = require("esbuild")
const fs = require("fs")
const http = require("http")
const path = require("path")
const config = require(process.cwd() + (process.argv?.length > 3 ? "/" + process.argv[3] : "/esbuild.config.js"))
const { watch } = require("chokidar")
function log(str, clear) {
if (clear && process.stdout.cursorTo && process.stdout.clearScreenDown) {
process.stdout.cursorTo(0, 0)
process.stdout.clearScreenDown()
}
console.log("\x1b[36m%s\x1b[0m", str)
}
let buildResults
let ctx
function cleanChunks() {
const outdir = config.options.outdir
if (!outdir) return
const chunksDir = path.join(outdir, "chunks")
if (fs.existsSync(chunksDir)) {
fs.rmSync(chunksDir, { recursive: true })
}
}
async function build(catchError) {
if (config.writeBuildInfo) {
config.writeBuildInfo()
}
cleanChunks()
if (!ctx) ctx = await esbuild.context(config.options)
log((buildResults ? "re" : "") + "building...")
const timerStart = Date.now()
try {
buildResults = await ctx.rebuild()
if (config.options.metafile) {
fs.writeFileSync(
(config.options.outfile ? path.dirname(config.options.outfile) : config.options.outdir) + "/meta.json",
JSON.stringify(buildResults.metafile, null, 4)
)
}
} catch (e) {
console.log(e)
if (!catchError) throw e
}
const timerEnd = Date.now()
log(`built in ${timerEnd - timerStart}ms.`)
}
let bs
switch (process.argv?.length > 2 ? process.argv[2] : "build") {
case "serve":
console.log("\x1b[36m%s\x1b[0mserving...")
esbuild.context(config.options).then(function (_ctx) {
_ctx.serve(config.serve).catch((err) => {
console.error(err)
process.exit(1)
})
})
break
case "start":
bs = require("browser-sync")
bs.init(config.browserSync)
case "watch":
// config.options.incremental = true
build(true).then(() => {
if (bs) {
bs.reload()
}
})
// Trigger tibi-server project reload for api/ changes
const apiDir = path.resolve("api") + "/"
let reloadInFlight = false
let reloadQueued = false
function reloadTibi() {
if (!config.tibiReloadUrl || !config.adminToken) {
log("tibi-server reload: missing URL or token (running in mock mode?)")
return
}
if (reloadInFlight) {
reloadQueued = true
log("tibi-server reload: already in flight, queuing another...")
return
}
reloadInFlight = true
const parts = new URL(config.tibiReloadUrl)
const opts = {
hostname: parts.hostname,
port: parts.port,
path: parts.pathname,
method: "POST",
headers: { Authorization: "Bearer " + config.adminToken },
timeout: 5000,
}
let body = ""
const finishReload = () => {
reloadInFlight = false
if (reloadQueued) {
reloadQueued = false
log("tibi-server reload: executing queued reload...")
reloadTibi()
}
}
const req = http.request(opts, (res) => {
res.on("data", (chunk) => (body += chunk))
res.on("end", () => {
if (res.statusCode === 200) {
log("tibi-server reloaded ✓")
} else {
console.error(
"\x1b[33mtibi-server reload: HTTP " + res.statusCode + " — " + body.trim() + "\x1b[0m"
)
}
finishReload()
})
})
req.on("error", (e) => {
console.error("\x1b[33mtibi-server reload failed: " + e.message + "\x1b[0m")
finishReload()
})
req.end()
}
const { path: watchPaths, ignored: watchIgnored, ...watchRest } = config.watch
const watcher = watch(watchPaths, { ignored: watchIgnored, ...watchRest })
log("watching files...")
const DEBOUNCE_MS = 200
let frontendTimer, apiTimer
watcher.on("change", function (changedPath) {
log(`${changedPath} changed`, true)
if (changedPath.startsWith(apiDir)) {
clearTimeout(apiTimer)
apiTimer = setTimeout(() => {
log("api/ change detected → reloading tibi-server...")
reloadTibi()
}, DEBOUNCE_MS)
} else {
clearTimeout(frontendTimer)
frontendTimer = setTimeout(() => {
build(true).then(() => {
if (bs) {
bs.reload()
}
})
}, DEBOUNCE_MS)
}
})
break
default:
if (config.writeBuildInfo) {
config.writeBuildInfo()
}
cleanChunks()
esbuild.build(config.options).then(function (buildResults) {
if (config.options.metafile) {
fs.writeFileSync(
(config.options.outfile ? path.dirname(config.options.outfile) : config.options.outdir) +
"/meta.json",
JSON.stringify(buildResults.metafile, null, 4)
)
}
})
}