@veryfront/ext-bundler-esbuild 0.1.1046 → 0.1.1048
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 +11 -0
- package/esm/_dnt.polyfills.js +1 -1
- package/esm/esbuild-bundler.d.ts +4 -10
- package/esm/esbuild-bundler.d.ts.map +1 -1
- package/esm/esbuild-bundler.js +347 -36
- package/esm/plugin-adapter.d.ts +3 -1
- package/esm/plugin-adapter.d.ts.map +1 -1
- package/esm/plugin-adapter.js +7 -7
- package/package.json +2 -2
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.
|
package/esm/_dnt.polyfills.js
CHANGED
|
@@ -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") {
|
package/esm/esbuild-bundler.d.ts
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
|
+
import type { BuildContext, BundleOptions, Bundler, BundleResult, TransformOptions, TransformResult } from "veryfront/extensions/bundler";
|
|
1
2
|
/**
|
|
2
|
-
* esbuild-backed
|
|
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
|
-
*
|
|
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":"
|
|
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"}
|
package/esm/esbuild-bundler.js
CHANGED
|
@@ -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
|
-
|
|
256
|
+
const runInOperationScope = (callback) => operationScopes.run(scope, callback);
|
|
257
|
+
mapped.plugins = plugins.map((plugin) => toEsbuildPlugin(plugin, runInOperationScope, pluginDisposals.wrap));
|
|
50
258
|
}
|
|
51
|
-
return
|
|
259
|
+
return {
|
|
260
|
+
options: mapped,
|
|
261
|
+
activatePluginDisposals: pluginDisposals.activate,
|
|
262
|
+
};
|
|
52
263
|
}
|
|
53
|
-
/**
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
-
|
|
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
|
-
|
|
93
|
-
|
|
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
|
-
|
|
96
|
-
|
|
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
|
}
|
package/esm/plugin-adapter.d.ts
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { BundlerPlugin } from "veryfront/extensions/bundler";
|
|
11
11
|
type EsbuildPlugin = any;
|
|
12
|
-
|
|
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,
|
|
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"}
|
package/esm/plugin-adapter.js
CHANGED
|
@@ -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 (
|
|
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 (
|
|
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.
|
|
3
|
+
"version": "0.1.1048",
|
|
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.
|
|
53
|
+
"veryfront": "^0.1.1048"
|
|
54
54
|
},
|
|
55
55
|
"type": "module",
|
|
56
56
|
"types": "./esm/index.d.ts",
|