UNPKG

tiddlywiki-plugin-dev

Version:

[![](https://img.shields.io/badge/Join-TiddlyWiki_CN-blue)](https://github.com/tiddly-gittly)

176 lines (175 loc) 5.75 kB
import path from "path"; import tw from "tiddlywiki"; import chokidar from "chokidar"; import { rebuild } from "./packup.js"; import { createDevRefreshHandler } from "./dev-refresh.js"; import { createNotifyServer } from "./dev-ws-server.js"; import { buildWatchIgnored } from "./dev-ignored.js"; import { createWikiPortResolver } from "./dev-port.js"; import { buildListenArgs } from "./dev-listen-args.js"; import { renderDevWebListenerScript } from "./devweb-listener-template.js"; import { closeServerForRestart } from "./dev-server-close.js"; import { tiddlywiki } from "./utils.js"; const runDev = async (wiki, src, configs) => { const { lan, writeWiki, excludeFilter } = configs; const { attachToHttpServer, closeAllClients, notifyRefresh, setBuildGeneration, onSaveBusyChange } = await createNotifyServer(); let detachWs; const watchRoots = Array.from( new Set([src, wiki].map((target) => path.resolve(target))) ); let buildGeneration = 0; const nextGeneration = () => buildGeneration; let saveBusy = false; let deferredPaths; onSaveBusyChange((busy) => { saveBusy = busy; if (busy) { console.log( "[Modern.TiddlyDev] [save] Browser is writing files — deferring server restarts" ); } else { console.log( "[Modern.TiddlyDev] [save] Browser write finished — flushing deferred changes" ); const paths = deferredPaths; deferredPaths = void 0; if (paths && paths.length > 0) { console.log( `[Modern.TiddlyDev] [save] ${paths.length} file(s) changed during save` ); triggerRefresh(); } } }); const scannerPreload = writeWiki ? [] : [{ title: "$:/config/SyncFilter", text: "" }]; const $tw1 = tiddlywiki(scannerPreload, wiki); let twServer; const resolveStableWikiPort = createWikiPortResolver(lan); const watcher = chokidar.watch(watchRoots, { ignoreInitial: true, followSymlinks: true, ignored: buildWatchIgnored($tw1, src, wiki), awaitWriteFinish: { stabilityThreshold: 1e3, pollInterval: 100 } }); const reportRefreshError = (error, changedPaths) => { const changed = changedPaths.filter(Boolean); const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString(); console.error( changed.length > 0 ? `[${timestamp}] [refresh] Compilation failed for: ${changed.join(", ")}` : `[${timestamp}] [refresh] Compilation failed during initial build.` ); console.error("Waiting for the next change to retry..."); console.error(error); }; const startWikiServer = async (wikiRuntime, changedPaths, generation) => { const $tw = wikiRuntime.runtime; let resolve; let settled = false; const finish = (started) => { if (!settled) { settled = true; resolve(started); } }; const wait = new Promise((_resolve) => resolve = _resolve); $tw.hooks.addHook( "th-server-command-post-start", (_listenCommand, newTwServer) => { const onServerError = (error) => { reportRefreshError(error, changedPaths); finish(false); }; newTwServer.once("error", onServerError); newTwServer.once("listening", () => { detachWs?.(); detachWs = attachToHttpServer(newTwServer); setBuildGeneration(generation); finish(true); }); twServer = newTwServer; } ); const serve = async () => { const port = await resolveStableWikiPort(); $tw.boot.argv = buildListenArgs({ wikiPath: wiki, port, lan, writeWiki }); $tw.boot.boot(); }; const startServer = () => { serve().catch((error) => { reportRefreshError(error, changedPaths); finish(false); }); }; if (twServer) { closeServerForRestart(twServer, { closeWsClients: closeAllClients, onClosed: startServer }); } else { startServer(); } return wait; }; const refresh = createDevRefreshHandler({ renderListenerScript: renderDevWebListenerScript, nextGeneration, writeWiki, rebuildPlugins: async (changedPaths) => { $tw1.wiki.deleteTiddler("$:/Modern.TiddlyDev/devWebsocket/listener"); const plugins = await rebuild($tw1, src, changedPaths, true, excludeFilter); buildGeneration++; return plugins; }, createWiki: () => { const $tw = tw.TiddlyWiki(); return { runtime: $tw, preloadTiddler: (tiddler) => $tw.preloadTiddler(tiddler), preloadTiddlerArray: (tiddlers) => $tw.preloadTiddlerArray(tiddlers), appendExtraPlugins: (plugins) => { $tw.boot.extraPlugins = [ ...$tw.boot.extraPlugins ?? [], ...plugins ]; } }; }, startServer: startWikiServer, notifyRefresh, reportError: reportRefreshError }); const triggerRefresh = (changedPath) => { if (saveBusy) { if (changedPath) { if (!deferredPaths) deferredPaths = []; deferredPaths.push(changedPath); } return; } const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString(); if (changedPath) { console.log( `[${timestamp}] [watch] File changed: ${changedPath}` ); } refresh(changedPath).catch((error) => reportRefreshError(error, [])); }; watcher.on("error", (error) => reportRefreshError(error, [])); watcher.on("ready", () => triggerRefresh()); watcher.on("add", triggerRefresh); watcher.on("addDir", triggerRefresh); watcher.on("change", triggerRefresh); watcher.on("unlink", triggerRefresh); watcher.on("unlinkDir", triggerRefresh); }; export { runDev };