watch-Cixa7HbR.mjs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. import { n as __toESM, t as require_binding } from "./binding-s-V_wTpj.mjs";
  2. import { o as logMultipleWatcherOption } from "./logs-D80CXhvg.mjs";
  3. import { v as LOG_LEVEL_WARN } from "./bindingify-input-options-DYpBf1OG.mjs";
  4. import { t as arraify } from "./misc-DJYbNKZX.mjs";
  5. import { n as createBundlerOptions, u as PluginDriver } from "./rolldown-build-DtGk-m96.mjs";
  6. import { t as aggregateBindingErrorsIntoJsError } from "./error-w0u7biK-.mjs";
  7. //#region ../../node_modules/.pnpm/signal-exit@4.1.0/node_modules/signal-exit/dist/mjs/signals.js
  8. /**
  9. * This is not the set of all possible signals.
  10. *
  11. * It IS, however, the set of all signals that trigger
  12. * an exit on either Linux or BSD systems. Linux is a
  13. * superset of the signal names supported on BSD, and
  14. * the unknown signals just fail to register, so we can
  15. * catch that easily enough.
  16. *
  17. * Windows signals are a different set, since there are
  18. * signals that terminate Windows processes, but don't
  19. * terminate (or don't even exist) on Posix systems.
  20. *
  21. * Don't bother with SIGKILL. It's uncatchable, which
  22. * means that we can't fire any callbacks anyway.
  23. *
  24. * If a user does happen to register a handler on a non-
  25. * fatal signal like SIGWINCH or something, and then
  26. * exit, it'll end up firing `process.emit('exit')`, so
  27. * the handler will be fired anyway.
  28. *
  29. * SIGBUS, SIGFPE, SIGSEGV and SIGILL, when not raised
  30. * artificially, inherently leave the process in a
  31. * state from which it is not safe to try and enter JS
  32. * listeners.
  33. */
  34. const signals = [];
  35. signals.push("SIGHUP", "SIGINT", "SIGTERM");
  36. if (process.platform !== "win32") signals.push("SIGALRM", "SIGABRT", "SIGVTALRM", "SIGXCPU", "SIGXFSZ", "SIGUSR2", "SIGTRAP", "SIGSYS", "SIGQUIT", "SIGIOT");
  37. if (process.platform === "linux") signals.push("SIGIO", "SIGPOLL", "SIGPWR", "SIGSTKFLT");
  38. //#endregion
  39. //#region ../../node_modules/.pnpm/signal-exit@4.1.0/node_modules/signal-exit/dist/mjs/index.js
  40. const processOk = (process) => !!process && typeof process === "object" && typeof process.removeListener === "function" && typeof process.emit === "function" && typeof process.reallyExit === "function" && typeof process.listeners === "function" && typeof process.kill === "function" && typeof process.pid === "number" && typeof process.on === "function";
  41. const kExitEmitter = Symbol.for("signal-exit emitter");
  42. const global = globalThis;
  43. const ObjectDefineProperty = Object.defineProperty.bind(Object);
  44. var Emitter = class {
  45. emitted = {
  46. afterExit: false,
  47. exit: false
  48. };
  49. listeners = {
  50. afterExit: [],
  51. exit: []
  52. };
  53. count = 0;
  54. id = Math.random();
  55. constructor() {
  56. if (global[kExitEmitter]) return global[kExitEmitter];
  57. ObjectDefineProperty(global, kExitEmitter, {
  58. value: this,
  59. writable: false,
  60. enumerable: false,
  61. configurable: false
  62. });
  63. }
  64. on(ev, fn) {
  65. this.listeners[ev].push(fn);
  66. }
  67. removeListener(ev, fn) {
  68. const list = this.listeners[ev];
  69. const i = list.indexOf(fn);
  70. /* c8 ignore start */
  71. if (i === -1) return;
  72. /* c8 ignore stop */
  73. if (i === 0 && list.length === 1) list.length = 0;
  74. else list.splice(i, 1);
  75. }
  76. emit(ev, code, signal) {
  77. if (this.emitted[ev]) return false;
  78. this.emitted[ev] = true;
  79. let ret = false;
  80. for (const fn of this.listeners[ev]) ret = fn(code, signal) === true || ret;
  81. if (ev === "exit") ret = this.emit("afterExit", code, signal) || ret;
  82. return ret;
  83. }
  84. };
  85. var SignalExitBase = class {};
  86. const signalExitWrap = (handler) => {
  87. return {
  88. onExit(cb, opts) {
  89. return handler.onExit(cb, opts);
  90. },
  91. load() {
  92. return handler.load();
  93. },
  94. unload() {
  95. return handler.unload();
  96. }
  97. };
  98. };
  99. var SignalExitFallback = class extends SignalExitBase {
  100. onExit() {
  101. return () => {};
  102. }
  103. load() {}
  104. unload() {}
  105. };
  106. var SignalExit = class extends SignalExitBase {
  107. /* c8 ignore start */
  108. #hupSig = process$1.platform === "win32" ? "SIGINT" : "SIGHUP";
  109. /* c8 ignore stop */
  110. #emitter = new Emitter();
  111. #process;
  112. #originalProcessEmit;
  113. #originalProcessReallyExit;
  114. #sigListeners = {};
  115. #loaded = false;
  116. constructor(process) {
  117. super();
  118. this.#process = process;
  119. this.#sigListeners = {};
  120. for (const sig of signals) this.#sigListeners[sig] = () => {
  121. const listeners = this.#process.listeners(sig);
  122. let { count } = this.#emitter;
  123. /* c8 ignore start */
  124. const p = process;
  125. if (typeof p.__signal_exit_emitter__ === "object" && typeof p.__signal_exit_emitter__.count === "number") count += p.__signal_exit_emitter__.count;
  126. /* c8 ignore stop */
  127. if (listeners.length === count) {
  128. this.unload();
  129. const ret = this.#emitter.emit("exit", null, sig);
  130. /* c8 ignore start */
  131. const s = sig === "SIGHUP" ? this.#hupSig : sig;
  132. if (!ret) process.kill(process.pid, s);
  133. }
  134. };
  135. this.#originalProcessReallyExit = process.reallyExit;
  136. this.#originalProcessEmit = process.emit;
  137. }
  138. onExit(cb, opts) {
  139. /* c8 ignore start */
  140. if (!processOk(this.#process)) return () => {};
  141. /* c8 ignore stop */
  142. if (this.#loaded === false) this.load();
  143. const ev = opts?.alwaysLast ? "afterExit" : "exit";
  144. this.#emitter.on(ev, cb);
  145. return () => {
  146. this.#emitter.removeListener(ev, cb);
  147. if (this.#emitter.listeners["exit"].length === 0 && this.#emitter.listeners["afterExit"].length === 0) this.unload();
  148. };
  149. }
  150. load() {
  151. if (this.#loaded) return;
  152. this.#loaded = true;
  153. this.#emitter.count += 1;
  154. for (const sig of signals) try {
  155. const fn = this.#sigListeners[sig];
  156. if (fn) this.#process.on(sig, fn);
  157. } catch (_) {}
  158. this.#process.emit = (ev, ...a) => {
  159. return this.#processEmit(ev, ...a);
  160. };
  161. this.#process.reallyExit = (code) => {
  162. return this.#processReallyExit(code);
  163. };
  164. }
  165. unload() {
  166. if (!this.#loaded) return;
  167. this.#loaded = false;
  168. signals.forEach((sig) => {
  169. const listener = this.#sigListeners[sig];
  170. /* c8 ignore start */
  171. if (!listener) throw new Error("Listener not defined for signal: " + sig);
  172. /* c8 ignore stop */
  173. try {
  174. this.#process.removeListener(sig, listener);
  175. } catch (_) {}
  176. /* c8 ignore stop */
  177. });
  178. this.#process.emit = this.#originalProcessEmit;
  179. this.#process.reallyExit = this.#originalProcessReallyExit;
  180. this.#emitter.count -= 1;
  181. }
  182. #processReallyExit(code) {
  183. /* c8 ignore start */
  184. if (!processOk(this.#process)) return 0;
  185. this.#process.exitCode = code || 0;
  186. /* c8 ignore stop */
  187. this.#emitter.emit("exit", this.#process.exitCode, null);
  188. return this.#originalProcessReallyExit.call(this.#process, this.#process.exitCode);
  189. }
  190. #processEmit(ev, ...args) {
  191. const og = this.#originalProcessEmit;
  192. if (ev === "exit" && processOk(this.#process)) {
  193. if (typeof args[0] === "number") this.#process.exitCode = args[0];
  194. /* c8 ignore start */
  195. const ret = og.call(this.#process, ev, ...args);
  196. /* c8 ignore start */
  197. this.#emitter.emit("exit", this.#process.exitCode, null);
  198. /* c8 ignore stop */
  199. return ret;
  200. } else return og.call(this.#process, ev, ...args);
  201. }
  202. };
  203. const process$1 = globalThis.process;
  204. const { onExit: onExit$1, load, unload } = signalExitWrap(processOk(process$1) ? new SignalExit(process$1) : new SignalExitFallback());
  205. //#endregion
  206. //#region src/utils/signal-exit.ts
  207. function onExit(...args) {
  208. if (typeof process === "object" && process.versions.webcontainer) {
  209. process.on("exit", (code) => {
  210. args[0](code, null);
  211. });
  212. return;
  213. }
  214. onExit$1(...args);
  215. }
  216. //#endregion
  217. //#region src/api/watch/watch-emitter.ts
  218. var WatcherEmitter = class {
  219. listeners = /* @__PURE__ */ new Map();
  220. on(event, listener) {
  221. const listeners = this.listeners.get(event);
  222. if (listeners) listeners.push(listener);
  223. else this.listeners.set(event, [listener]);
  224. return this;
  225. }
  226. off(event, listener) {
  227. const listeners = this.listeners.get(event);
  228. if (listeners) {
  229. const index = listeners.indexOf(listener);
  230. if (index !== -1) listeners.splice(index, 1);
  231. }
  232. return this;
  233. }
  234. clear(event) {
  235. this.listeners.delete(event);
  236. }
  237. /** Async emit — sequential dispatch so side effects from earlier handlers
  238. * (e.g. `event.result.close()` triggering `closeBundle`) are visible to later handlers. */
  239. async emit(event, ...args) {
  240. const handlers = this.listeners.get(event);
  241. if (handlers?.length) for (const h of handlers) await h(...args);
  242. }
  243. async close() {}
  244. };
  245. //#endregion
  246. //#region src/api/watch/watcher.ts
  247. var import_binding = /* @__PURE__ */ __toESM(require_binding(), 1);
  248. function createEventCallback(emitter) {
  249. return async (event) => {
  250. switch (event.eventKind()) {
  251. case "event": {
  252. const code = event.bundleEventKind();
  253. if (code === "BUNDLE_END") {
  254. const { duration, output, result } = event.bundleEndData();
  255. await emitter.emit("event", {
  256. code: "BUNDLE_END",
  257. duration,
  258. output: [output],
  259. result
  260. });
  261. } else if (code === "ERROR") {
  262. const data = event.bundleErrorData();
  263. await emitter.emit("event", {
  264. code: "ERROR",
  265. error: aggregateBindingErrorsIntoJsError(data.error),
  266. result: data.result
  267. });
  268. } else await emitter.emit("event", { code });
  269. break;
  270. }
  271. case "change": {
  272. const { path, kind } = event.watchChangeData();
  273. await emitter.emit("change", path, { event: kind });
  274. break;
  275. }
  276. case "restart":
  277. await emitter.emit("restart");
  278. break;
  279. case "close":
  280. await emitter.emit("close");
  281. break;
  282. }
  283. };
  284. }
  285. var Watcher = class {
  286. closed;
  287. inner;
  288. emitter;
  289. stopWorkers;
  290. constructor(emitter, inner, stopWorkers) {
  291. this.closed = false;
  292. this.inner = inner;
  293. this.emitter = emitter;
  294. const originClose = emitter.close.bind(emitter);
  295. emitter.close = async () => {
  296. await this.close();
  297. originClose();
  298. };
  299. this.stopWorkers = stopWorkers;
  300. process.nextTick(() => this.run());
  301. }
  302. async close() {
  303. if (this.closed) return;
  304. this.closed = true;
  305. for (const stop of this.stopWorkers) await stop?.();
  306. await this.inner.close();
  307. (0, import_binding.shutdownAsyncRuntime)();
  308. }
  309. async run() {
  310. await this.inner.run();
  311. this.inner.waitForClose();
  312. }
  313. };
  314. async function createWatcher(emitter, input) {
  315. const options = arraify(input);
  316. const bundlerOptions = await Promise.all(options.map((option) => arraify(option.output || {}).map(async (output) => {
  317. return createBundlerOptions(await PluginDriver.callOptionsHook(option, true), output, true);
  318. })).flat());
  319. warnMultiplePollingOptions(bundlerOptions);
  320. const callback = createEventCallback(emitter);
  321. new Watcher(emitter, new import_binding.BindingWatcher(bundlerOptions.map((option) => option.bundlerOptions), callback), bundlerOptions.map((option) => option.stopWorkers));
  322. }
  323. function warnMultiplePollingOptions(bundlerOptions) {
  324. let found = false;
  325. for (const option of bundlerOptions) {
  326. const watch = option.inputOptions.watch;
  327. const watcher = watch && typeof watch === "object" ? watch.watcher ?? watch.notify : void 0;
  328. if (watcher && (watcher.usePolling != null || watcher.pollInterval != null)) {
  329. if (found) {
  330. option.onLog(LOG_LEVEL_WARN, logMultipleWatcherOption());
  331. return;
  332. }
  333. found = true;
  334. }
  335. }
  336. }
  337. //#endregion
  338. //#region src/api/watch/index.ts
  339. /**
  340. * The API compatible with Rollup's `watch` function.
  341. *
  342. * This function will rebuild the bundle when it detects that the individual modules have changed on disk.
  343. *
  344. * Note that when using this function, it is your responsibility to call `event.result.close()` in response to the `BUNDLE_END` event to avoid resource leaks.
  345. *
  346. * @param input The watch options object or the list of them.
  347. * @returns A watcher object.
  348. *
  349. * @example
  350. * ```js
  351. * import { watch } from 'rolldown';
  352. *
  353. * const watcher = watch({ /* ... *\/ });
  354. * watcher.on('event', (event) => {
  355. * if (event.code === 'BUNDLE_END') {
  356. * console.log(event.duration);
  357. * event.result.close();
  358. * }
  359. * });
  360. *
  361. * // Stop watching
  362. * watcher.close();
  363. * ```
  364. *
  365. * @experimental
  366. * @category Programmatic APIs
  367. */
  368. function watch(input) {
  369. const emitter = new WatcherEmitter();
  370. createWatcher(emitter, input);
  371. return emitter;
  372. }
  373. //#endregion
  374. export { onExit as n, watch as t };