@veryfront/ext-bundler-esbuild 0.1.1047 → 0.1.1049

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -43,3 +43,14 @@ No factory options. The extension reads no environment variables and takes no co
43
43
  ## Lifecycle
44
44
 
45
45
  The factory's `teardown()` calls `EsbuildBundler.stop()` to release the esbuild service on shutdown.
46
+
47
+ All `EsbuildBundler` instances in a process share one module-level esbuild service and shutdown
48
+ barrier. Await `stop()` after bundler work, and dispose build contexts before stopping the service.
49
+
50
+ Use the Veryfront `Bundler` contract exclusively for asynchronous esbuild work. Starting the same
51
+ raw `esbuild` module outside this adapter makes its child process impossible to track retroactively.
52
+ The adapter rejects that mixed-ownership state and requires a process restart instead of reporting
53
+ an unverified shutdown as successful.
54
+
55
+ The service-child tracking matches the esbuild `0.28.1` process contract. Revalidate spawn capture,
56
+ plugin disposal ordering, and child-close tests before changing that version.
@@ -56,7 +56,7 @@ export let import_meta_ponyfill_esmodule = (Reflect.get(globalThis, Symbol.for("
56
56
  const resolveFunStr = String(importMeta.resolve);
57
57
  const shimWs = new WeakSet();
58
58
  //@ts-ignore
59
- const mainUrl = ("file:///" + process.argv[1].replace(/\\/g, "/"))
59
+ const mainUrl = ("file:///" + (process.argv[1] ?? "").replace(/\\/g, "/"))
60
60
  .replace(/\/{3,}/, "///");
61
61
  const commonShim = (importMeta) => {
62
62
  if (typeof importMeta.main !== "boolean") {
@@ -1,16 +1,10 @@
1
+ import type { BuildContext, BundleOptions, Bundler, BundleResult, TransformOptions, TransformResult } from "veryfront/extensions/bundler";
1
2
  /**
2
- * esbuild-backed implementation of the {@link Bundler} contract.
3
- *
4
- * Lazy-initializes the esbuild binary (including `deno compile` VFS
5
- * extraction) on first use. All options pass through to esbuild unchanged
6
- * because the {@link BundleOptions} shape was designed to be esbuild-compatible;
7
- * the only translation is converting {@link BundlerPlugin}s into esbuild
8
- * plugins via {@link toEsbuildPlugin}.
3
+ * esbuild-backed {@link Bundler} implementation.
9
4
  *
10
- * @module extensions/ext-bundler-esbuild/esbuild-bundler
5
+ * Every instance coordinates through one module-wide service lifecycle. Raw
6
+ * asynchronous esbuild calls must not share the same module in this process.
11
7
  */
12
- import type { BuildContext, BundleOptions, Bundler, BundleResult, TransformOptions, TransformResult } from "veryfront/extensions/bundler";
13
- /** esbuild-backed {@link Bundler} implementation. */
14
8
  export declare class EsbuildBundler implements Bundler {
15
9
  bundle(options: BundleOptions): Promise<BundleResult>;
16
10
  transform(options: TransformOptions): Promise<TransformResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"esbuild-bundler.d.ts","sourceRoot":"","sources":["../src/esbuild-bundler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EAEb,OAAO,EACP,YAAY,EAGZ,gBAAgB,EAChB,eAAe,EAChB,MAAM,8BAA8B,CAAC;AAoDtC,qDAAqD;AACrD,qBAAa,cAAe,YAAW,OAAO;IACtC,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAWrD,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAW9D,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAiBtD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAM5B"}
1
+ {"version":3,"file":"esbuild-bundler.d.ts","sourceRoot":"","sources":["../src/esbuild-bundler.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EAEb,OAAO,EACP,YAAY,EAGZ,gBAAgB,EAChB,eAAe,EAChB,MAAM,8BAA8B,CAAC;AAwTtC;;;;;GAKG;AACH,qBAAa,cAAe,YAAW,OAAO;IACtC,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAkBrD,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAa9D,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAiCtD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAiF5B"}
@@ -9,9 +9,28 @@
9
9
  *
10
10
  * @module extensions/ext-bundler-esbuild/esbuild-bundler
11
11
  */
12
+ import * as dntShim from "./_dnt.shims.js";
13
+ import { AsyncLocalStorage } from "node:async_hooks";
14
+ import { createRequire } from "node:module";
12
15
  import { ensureEsbuildBinary } from "./binary.js";
13
16
  import { toEsbuildPlugin } from "./plugin-adapter.js";
17
+ const ESBUILD_STOP_TIMEOUT_MS = 5_000;
18
+ const childProcess = createRequire(globalThis[Symbol.for("import-meta-ponyfill-esmodule")](import.meta).url)("node:child_process");
14
19
  let esbuildModule = null;
20
+ let esbuildService = null;
21
+ let esbuildOwnershipError = null;
22
+ let esbuildShutdownError = null;
23
+ let pluginDisposalError = null;
24
+ let esbuildStopPromise = null;
25
+ let activeOperationCount = 0;
26
+ let activeOperationsIdle = Promise.resolve();
27
+ let resolveActiveOperationsIdle = null;
28
+ const operationScopes = new AsyncLocalStorage();
29
+ function recordOwnershipError(cause) {
30
+ const message = "[ext-bundler-esbuild] Cannot own an esbuild service started outside the module-wide adapter; restart the process and use only the Bundler contract";
31
+ esbuildOwnershipError ??= new Error(message, cause === undefined ? undefined : { cause });
32
+ return esbuildOwnershipError;
33
+ }
15
34
  async function getEsbuild() {
16
35
  await ensureEsbuildBinary();
17
36
  if (esbuildModule)
@@ -19,6 +38,193 @@ async function getEsbuild() {
19
38
  esbuildModule = await import("esbuild");
20
39
  return esbuildModule;
21
40
  }
41
+ function beginOperation() {
42
+ if (activeOperationCount === 0) {
43
+ activeOperationsIdle = new Promise((resolve) => {
44
+ resolveActiveOperationsIdle = resolve;
45
+ });
46
+ }
47
+ activeOperationCount += 1;
48
+ }
49
+ function endOperation() {
50
+ activeOperationCount -= 1;
51
+ if (activeOperationCount !== 0)
52
+ return;
53
+ const resolve = resolveActiveOperationsIdle;
54
+ resolveActiveOperationsIdle = null;
55
+ activeOperationsIdle = Promise.resolve();
56
+ resolve?.();
57
+ }
58
+ function createPluginDisposalBarrier(scope) {
59
+ const callbacks = [];
60
+ let activated = false;
61
+ let holdingOperation = false;
62
+ const releaseIfSettled = () => {
63
+ if (!holdingOperation || callbacks.some((callback) => !callback.settled))
64
+ return;
65
+ holdingOperation = false;
66
+ scope.activeCount -= 1;
67
+ endOperation();
68
+ };
69
+ const settle = (callback) => {
70
+ if (callback.settled)
71
+ return;
72
+ callback.settled = true;
73
+ releaseIfSettled();
74
+ };
75
+ const fail = (callback, error) => {
76
+ if (!pluginDisposalError) {
77
+ pluginDisposalError = new Error("[ext-bundler-esbuild] Plugin disposal failed", { cause: error });
78
+ }
79
+ settle(callback);
80
+ };
81
+ return {
82
+ wrap(callback) {
83
+ const state = { started: false, settled: false };
84
+ callbacks.push(state);
85
+ return () => {
86
+ if (state.settled)
87
+ return;
88
+ state.started = true;
89
+ try {
90
+ const result = callback();
91
+ if (result !== null &&
92
+ (typeof result === "object" || typeof result === "function") &&
93
+ typeof result.then === "function") {
94
+ void Promise.resolve(result).then(() => settle(state), (error) => fail(state, error));
95
+ }
96
+ else {
97
+ settle(state);
98
+ }
99
+ }
100
+ catch (error) {
101
+ fail(state, error);
102
+ }
103
+ };
104
+ },
105
+ activate() {
106
+ if (activated)
107
+ return;
108
+ activated = true;
109
+ if (callbacks.length === 0 || callbacks.every((callback) => callback.settled))
110
+ return;
111
+ holdingOperation = true;
112
+ beginOperation();
113
+ scope.activeCount += 1;
114
+ // esbuild 0.28 schedules disposal callbacks with zero-delay timers
115
+ // before settling build/dispose. Queueing a sentinel after settlement
116
+ // identifies callbacks that setup failures left unscheduled. Callbacks
117
+ // that started async cleanup retain the operation until they settle.
118
+ dntShim.setTimeout(() => {
119
+ for (const callback of callbacks) {
120
+ if (!callback.started)
121
+ settle(callback);
122
+ }
123
+ releaseIfSettled();
124
+ }, 0);
125
+ },
126
+ };
127
+ }
128
+ async function runBundlerOperation(operation, preferredScope) {
129
+ if (esbuildOwnershipError)
130
+ throw esbuildOwnershipError;
131
+ if (esbuildShutdownError)
132
+ throw esbuildShutdownError;
133
+ const inheritedScope = operationScopes.getStore();
134
+ const isReentrant = inheritedScope !== undefined && inheritedScope.activeCount > 0;
135
+ if (!isReentrant) {
136
+ while (esbuildStopPromise)
137
+ await esbuildStopPromise;
138
+ }
139
+ // Admission is synchronous after the stop barrier check. This makes a stop
140
+ // exclusive without serializing independent operations. Work re-entered by
141
+ // an active plugin shares its live scope so shutdown cannot deadlock on it.
142
+ const scope = preferredScope ?? (isReentrant ? inheritedScope : { activeCount: 0 });
143
+ beginOperation();
144
+ scope.activeCount += 1;
145
+ try {
146
+ return await operationScopes.run(scope, () => operation(scope));
147
+ }
148
+ finally {
149
+ scope.activeCount -= 1;
150
+ endOperation();
151
+ }
152
+ }
153
+ function isEsbuildServiceSpawn(spawnArgs) {
154
+ const args = spawnArgs[1];
155
+ return Array.isArray(args) &&
156
+ args.some((arg) => typeof arg === "string" && arg.startsWith("--service=")) &&
157
+ args.includes("--ping");
158
+ }
159
+ function isLiveService(service) {
160
+ return !service.child.killed &&
161
+ service.child.exitCode === null &&
162
+ service.child.signalCode === null;
163
+ }
164
+ function invokeEsbuild(operation) {
165
+ const originalSpawn = childProcess.spawn;
166
+ let capturedService = null;
167
+ let result;
168
+ // esbuild does not expose its service child, and stop() resolves before that
169
+ // child closes. esbuild 0.28 starts it synchronously with --service and
170
+ // --ping, so keep interception to this operation and restore the shared
171
+ // binding with compare-and-swap.
172
+ const trackedSpawn = ((...spawnArgs) => {
173
+ const child = Reflect.apply(originalSpawn, childProcess, spawnArgs);
174
+ if (isEsbuildServiceSpawn(spawnArgs)) {
175
+ let resolveClosed = () => { };
176
+ const closed = new Promise((resolve) => {
177
+ resolveClosed = resolve;
178
+ });
179
+ const service = { child, closed, expectedClose: false };
180
+ child.once("close", () => {
181
+ if (!service.expectedClose)
182
+ recordOwnershipError();
183
+ resolveClosed();
184
+ if (esbuildService === service)
185
+ esbuildService = null;
186
+ });
187
+ capturedService = service;
188
+ esbuildService = service;
189
+ if (childProcess.spawn === trackedSpawn)
190
+ childProcess.spawn = originalSpawn;
191
+ }
192
+ return child;
193
+ });
194
+ childProcess.spawn = trackedSpawn;
195
+ try {
196
+ result = operation();
197
+ }
198
+ finally {
199
+ if (childProcess.spawn === trackedSpawn)
200
+ childProcess.spawn = originalSpawn;
201
+ }
202
+ const ownedService = capturedService ?? esbuildService;
203
+ if (!ownedService || !isLiveService(ownedService)) {
204
+ const ownershipError = recordOwnershipError();
205
+ return result.then(() => {
206
+ throw ownershipError;
207
+ }, (cause) => {
208
+ throw recordOwnershipError(cause);
209
+ });
210
+ }
211
+ return result;
212
+ }
213
+ async function waitForServiceClose(service) {
214
+ let timeoutId;
215
+ const timeout = new Promise((_resolve, reject) => {
216
+ timeoutId = dntShim.setTimeout(() => {
217
+ reject(new Error(`[ext-bundler-esbuild] Timed out after ${ESBUILD_STOP_TIMEOUT_MS}ms waiting for the esbuild service to close`));
218
+ }, ESBUILD_STOP_TIMEOUT_MS);
219
+ });
220
+ try {
221
+ await Promise.race([service.closed, timeout]);
222
+ }
223
+ finally {
224
+ if (timeoutId !== undefined)
225
+ clearTimeout(timeoutId);
226
+ }
227
+ }
22
228
  // deno-lint-ignore no-explicit-any
23
229
  function toMessage(m) {
24
230
  return {
@@ -42,57 +248,162 @@ function toOutput(f) {
42
248
  hash: f.hash,
43
249
  };
44
250
  }
45
- function mapOptions(options) {
251
+ function mapOptions(options, scope) {
46
252
  const { plugins, ...rest } = options;
47
253
  const mapped = { ...rest };
254
+ const pluginDisposals = createPluginDisposalBarrier(scope);
48
255
  if (plugins && plugins.length > 0) {
49
- mapped.plugins = plugins.map(toEsbuildPlugin);
256
+ const runInOperationScope = (callback) => operationScopes.run(scope, callback);
257
+ mapped.plugins = plugins.map((plugin) => toEsbuildPlugin(plugin, runInOperationScope, pluginDisposals.wrap));
50
258
  }
51
- return mapped;
259
+ return {
260
+ options: mapped,
261
+ activatePluginDisposals: pluginDisposals.activate,
262
+ };
52
263
  }
53
- /** esbuild-backed {@link Bundler} implementation. */
264
+ /**
265
+ * esbuild-backed {@link Bundler} implementation.
266
+ *
267
+ * Every instance coordinates through one module-wide service lifecycle. Raw
268
+ * asynchronous esbuild calls must not share the same module in this process.
269
+ */
54
270
  export class EsbuildBundler {
55
271
  async bundle(options) {
56
- const esbuild = await getEsbuild();
57
- const result = await esbuild.build(mapOptions(options));
58
- return {
59
- outputFiles: (result.outputFiles ?? []).map(toOutput),
60
- warnings: toMessages(result.warnings),
61
- errors: toMessages(result.errors),
62
- metafile: result.metafile,
63
- };
64
- }
65
- async transform(options) {
66
- const esbuild = await getEsbuild();
67
- const { code, ...rest } = options;
68
- const result = await esbuild.transform(code, rest);
69
- return {
70
- code: result.code,
71
- map: result.map,
72
- warnings: toMessages(result.warnings).map((m) => m.text),
73
- };
74
- }
75
- async context(options) {
76
- const esbuild = await getEsbuild();
77
- const ctx = await esbuild.context(mapOptions(options));
78
- return {
79
- rebuild: async () => {
80
- const result = await ctx.rebuild();
272
+ return runBundlerOperation(async (scope) => {
273
+ const esbuild = await getEsbuild();
274
+ const mapped = mapOptions(options, scope);
275
+ try {
276
+ const result = await invokeEsbuild(() => esbuild.build(mapped.options));
81
277
  return {
82
278
  outputFiles: (result.outputFiles ?? []).map(toOutput),
83
279
  warnings: toMessages(result.warnings),
84
280
  errors: toMessages(result.errors),
85
281
  metafile: result.metafile,
86
282
  };
87
- },
88
- dispose: () => ctx.dispose(),
89
- };
283
+ }
284
+ finally {
285
+ mapped.activatePluginDisposals();
286
+ }
287
+ });
288
+ }
289
+ async transform(options) {
290
+ return runBundlerOperation(async () => {
291
+ const esbuild = await getEsbuild();
292
+ const { code, ...rest } = options;
293
+ const result = await invokeEsbuild(() => esbuild.transform(code, rest));
294
+ return {
295
+ code: result.code,
296
+ map: result.map,
297
+ warnings: toMessages(result.warnings).map((m) => m.text),
298
+ };
299
+ });
300
+ }
301
+ async context(options) {
302
+ return runBundlerOperation(async (contextScope) => {
303
+ const esbuild = await getEsbuild();
304
+ const mapped = mapOptions(options, contextScope);
305
+ const ctx = await invokeEsbuild(() => esbuild.context(mapped.options)).catch((error) => {
306
+ mapped.activatePluginDisposals();
307
+ throw error;
308
+ });
309
+ return {
310
+ rebuild: () => runBundlerOperation(async () => {
311
+ const result = await ctx.rebuild();
312
+ return {
313
+ outputFiles: (result.outputFiles ?? []).map(toOutput),
314
+ warnings: toMessages(result.warnings),
315
+ errors: toMessages(result.errors),
316
+ metafile: result.metafile,
317
+ };
318
+ }, contextScope),
319
+ dispose: () => runBundlerOperation(async () => {
320
+ try {
321
+ await ctx.dispose();
322
+ }
323
+ finally {
324
+ mapped.activatePluginDisposals();
325
+ }
326
+ }, contextScope),
327
+ };
328
+ });
90
329
  }
91
330
  async stop() {
92
- const m = esbuildModule;
93
- if (!m)
331
+ if ((operationScopes.getStore()?.activeCount ?? 0) > 0) {
332
+ throw new Error("[ext-bundler-esbuild] Cannot stop the esbuild service from an active bundler operation");
333
+ }
334
+ if (esbuildStopPromise) {
335
+ await esbuildStopPromise;
94
336
  return;
95
- esbuildModule = null;
96
- await m.stop();
337
+ }
338
+ const stopping = (async () => {
339
+ await activeOperationsIdle;
340
+ const m = esbuildModule;
341
+ const trackedService = esbuildService;
342
+ if (trackedService && !trackedService.expectedClose && !isLiveService(trackedService)) {
343
+ recordOwnershipError();
344
+ }
345
+ const ownershipError = esbuildOwnershipError;
346
+ const disposalError = pluginDisposalError;
347
+ if (!m) {
348
+ if (ownershipError)
349
+ throw ownershipError;
350
+ if (esbuildShutdownError)
351
+ throw esbuildShutdownError;
352
+ if (disposalError) {
353
+ pluginDisposalError = null;
354
+ throw disposalError;
355
+ }
356
+ return;
357
+ }
358
+ const service = esbuildService ?? trackedService;
359
+ if (service) {
360
+ service.expectedClose = true;
361
+ service.child.ref();
362
+ }
363
+ try {
364
+ await m.stop();
365
+ if (service)
366
+ await waitForServiceClose(service);
367
+ }
368
+ catch (error) {
369
+ const shutdownError = error instanceof Error
370
+ ? error
371
+ : new Error("[ext-bundler-esbuild] Failed to stop the esbuild service", {
372
+ cause: error,
373
+ });
374
+ esbuildShutdownError = shutdownError;
375
+ if (service) {
376
+ void service.closed.then(() => {
377
+ if (esbuildShutdownError === shutdownError)
378
+ esbuildShutdownError = null;
379
+ });
380
+ }
381
+ throw shutdownError;
382
+ }
383
+ finally {
384
+ service?.child.unref();
385
+ }
386
+ if (ownershipError) {
387
+ throw new Error("[ext-bundler-esbuild] Cannot verify closure of an externally owned esbuild service; restart the process", { cause: ownershipError });
388
+ }
389
+ if (esbuildModule === m)
390
+ esbuildModule = null;
391
+ if (esbuildService === service)
392
+ esbuildService = null;
393
+ esbuildShutdownError = null;
394
+ if (disposalError) {
395
+ if (pluginDisposalError === disposalError)
396
+ pluginDisposalError = null;
397
+ throw disposalError;
398
+ }
399
+ })();
400
+ esbuildStopPromise = stopping;
401
+ try {
402
+ await stopping;
403
+ }
404
+ finally {
405
+ if (Object.is(esbuildStopPromise, stopping))
406
+ esbuildStopPromise = null;
407
+ }
97
408
  }
98
409
  }
@@ -9,6 +9,8 @@
9
9
  */
10
10
  import type { BundlerPlugin } from "veryfront/extensions/bundler";
11
11
  type EsbuildPlugin = any;
12
- export declare function toEsbuildPlugin(plugin: BundlerPlugin): EsbuildPlugin;
12
+ type PluginContextRunner = <T>(callback: () => T) => T;
13
+ type PluginDisposeWrapper = (callback: () => unknown) => () => void;
14
+ export declare function toEsbuildPlugin(plugin: BundlerPlugin, runInContext: PluginContextRunner, wrapDispose: PluginDisposeWrapper): EsbuildPlugin;
13
15
  export {};
14
16
  //# sourceMappingURL=plugin-adapter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-adapter.d.ts","sourceRoot":"","sources":["../src/plugin-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,aAAa,EAMd,MAAM,8BAA8B,CAAC;AAEtC,KAAK,aAAa,GAAG,GAAG,CAAC;AAEzB,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa,CA4CpE"}
1
+ {"version":3,"file":"plugin-adapter.d.ts","sourceRoot":"","sources":["../src/plugin-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,aAAa,EAMd,MAAM,8BAA8B,CAAC;AAEtC,KAAK,aAAa,GAAG,GAAG,CAAC;AAEzB,KAAK,mBAAmB,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;AACvD,KAAK,oBAAoB,GAAG,CAAC,QAAQ,EAAE,MAAM,OAAO,KAAK,MAAM,IAAI,CAAC;AAEpE,wBAAgB,eAAe,CAC7B,MAAM,EAAE,aAAa,EACrB,YAAY,EAAE,mBAAmB,EACjC,WAAW,EAAE,oBAAoB,GAChC,aAAa,CA8Cf"}
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * @module extensions/ext-bundler-esbuild/plugin-adapter
9
9
  */
10
- export function toEsbuildPlugin(plugin) {
10
+ export function toEsbuildPlugin(plugin, runInContext, wrapDispose) {
11
11
  return {
12
12
  name: plugin.name,
13
13
  // deno-lint-ignore no-explicit-any
@@ -15,7 +15,7 @@ export function toEsbuildPlugin(plugin) {
15
15
  const bridged = {
16
16
  onResolve(options, callback) {
17
17
  // deno-lint-ignore no-explicit-any
18
- build.onResolve(options, async (args) => {
18
+ build.onResolve(options, (args) => runInContext(async () => {
19
19
  const resolveArgs = {
20
20
  path: args.path,
21
21
  importer: args.importer,
@@ -28,11 +28,11 @@ export function toEsbuildPlugin(plugin) {
28
28
  if (result == null)
29
29
  return result ?? null;
30
30
  return result;
31
- });
31
+ }));
32
32
  },
33
33
  onLoad(options, callback) {
34
34
  // deno-lint-ignore no-explicit-any
35
- build.onLoad(options, async (args) => {
35
+ build.onLoad(options, (args) => runInContext(async () => {
36
36
  const loadArgs = {
37
37
  path: args.path,
38
38
  namespace: args.namespace,
@@ -43,13 +43,13 @@ export function toEsbuildPlugin(plugin) {
43
43
  if (result == null)
44
44
  return result ?? null;
45
45
  return result;
46
- });
46
+ }));
47
47
  },
48
48
  onDispose(callback) {
49
- build.onDispose(callback);
49
+ build.onDispose(wrapDispose(() => runInContext(callback)));
50
50
  },
51
51
  };
52
- plugin.setup(bridged);
52
+ return runInContext(() => plugin.setup(bridged));
53
53
  },
54
54
  };
55
55
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veryfront/ext-bundler-esbuild",
3
- "version": "0.1.1047",
3
+ "version": "0.1.1049",
4
4
  "description": "Veryfront first-party extension package for ext-bundler-esbuild",
5
5
  "keywords": [
6
6
  "veryfront",
@@ -50,7 +50,7 @@
50
50
  "esbuild": "0.28.1"
51
51
  },
52
52
  "peerDependencies": {
53
- "veryfront": "^0.1.1047"
53
+ "veryfront": "^0.1.1049"
54
54
  },
55
55
  "type": "module",
56
56
  "types": "./esm/index.d.ts",