@ttsc/unplugin 0.30.2 → 0.30.3
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/lib/bun.js +3 -16
- package/lib/bun.js.map +1 -1
- package/lib/bun.mjs +3 -16
- package/lib/bun.mjs.map +1 -1
- package/lib/core/esbuild.d.cts +4 -0
- package/lib/core/esbuild.d.mts +4 -0
- package/lib/core/esbuild.d.ts +4 -0
- package/lib/core/esbuild.js +110 -0
- package/lib/core/esbuild.js.map +1 -0
- package/lib/core/esbuild.mjs +108 -0
- package/lib/core/esbuild.mjs.map +1 -0
- package/lib/core/index.js +49 -89
- package/lib/core/index.js.map +1 -1
- package/lib/core/index.mjs +50 -90
- package/lib/core/index.mjs.map +1 -1
- package/lib/core/transform.d.cts +5 -3
- package/lib/core/transform.d.mts +5 -3
- package/lib/core/transform.d.ts +5 -3
- package/lib/core/transform.js +25 -25
- package/lib/core/transform.js.map +1 -1
- package/lib/core/transform.mjs +25 -25
- package/lib/core/transform.mjs.map +1 -1
- package/lib/core/viteServe.d.cts +16 -38
- package/lib/core/viteServe.d.mts +16 -38
- package/lib/core/viteServe.d.ts +16 -38
- package/lib/core/viteServe.js +234 -98
- package/lib/core/viteServe.js.map +1 -1
- package/lib/core/viteServe.mjs +235 -98
- package/lib/core/viteServe.mjs.map +1 -1
- package/package.json +4 -3
- package/src/bun.ts +2 -17
- package/src/core/esbuild.ts +127 -0
- package/src/core/index.ts +51 -100
- package/src/core/transform.ts +30 -28
- package/src/core/viteServe.ts +275 -164
package/src/core/index.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
1
|
import type { UnpluginFactory, UnpluginInstance } from "unplugin";
|
|
4
2
|
import { createUnplugin } from "unplugin";
|
|
5
3
|
|
|
4
|
+
import { createEsbuildOptions } from "./esbuild";
|
|
6
5
|
import type { TtscUnpluginOptions } from "./options";
|
|
7
6
|
import { resolveOptions } from "./options";
|
|
8
7
|
import { typescriptTransformSourcePattern } from "./sourceExtensions";
|
|
@@ -22,7 +21,7 @@ import {
|
|
|
22
21
|
transformTtsc,
|
|
23
22
|
watchInputEvidenceMatchesBaseline,
|
|
24
23
|
} from "./transform";
|
|
25
|
-
import {
|
|
24
|
+
import { createViteServeInputWatch } from "./viteServe";
|
|
26
25
|
|
|
27
26
|
const name = "ttsc-unplugin";
|
|
28
27
|
/**
|
|
@@ -60,10 +59,13 @@ const virtualModulePattern = /\0/;
|
|
|
60
59
|
const unpluginFactory: UnpluginFactory<
|
|
61
60
|
TtscUnpluginOptions | undefined,
|
|
62
61
|
false
|
|
63
|
-
> = (rawOptions = {}) => {
|
|
62
|
+
> = (rawOptions = {}, meta) => {
|
|
64
63
|
const options = resolveOptions(rawOptions);
|
|
64
|
+
if (meta.framework === "esbuild") {
|
|
65
|
+
return createEsbuildOptions(options, isTransformTarget);
|
|
66
|
+
}
|
|
65
67
|
const transformCache = createTtscTransformCache();
|
|
66
|
-
const
|
|
68
|
+
const serveInputs = createViteServeInputWatch();
|
|
67
69
|
let aliases: unknown;
|
|
68
70
|
let viteCommand: string | undefined;
|
|
69
71
|
let viteWatching = true;
|
|
@@ -78,13 +80,6 @@ const unpluginFactory: UnpluginFactory<
|
|
|
78
80
|
// old containers cannot dispose a replacement's freshly initialized cache.
|
|
79
81
|
let viteBuildOwners = new WeakSet<object>();
|
|
80
82
|
let viteBuildLifecycles = 0;
|
|
81
|
-
// esbuild schedules one-shot onDispose callbacks after it settles the build
|
|
82
|
-
// Promise. Acquire ownership only at onStart: plugin setup runs before build
|
|
83
|
-
// option validation, and a validation failure has no onDispose callback with
|
|
84
|
-
// which to release a setup-time owner. Once a build has actually started, the
|
|
85
|
-
// count keeps an older delayed callback from disposing its active generation.
|
|
86
|
-
const esbuildOwners = new WeakSet<object>();
|
|
87
|
-
let esbuildLifecycles = 0;
|
|
88
83
|
|
|
89
84
|
return {
|
|
90
85
|
name,
|
|
@@ -116,14 +111,11 @@ const unpluginFactory: UnpluginFactory<
|
|
|
116
111
|
viteBuildWatching =
|
|
117
112
|
(config as { build?: { watch?: unknown } }).build?.watch != null;
|
|
118
113
|
},
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
//
|
|
122
|
-
// hook can route watch inputs that do not exist yet — superseding
|
|
123
|
-
// resolution candidates above all — around that graph and still
|
|
124
|
-
// invalidate their importers when the path is created.
|
|
114
|
+
// Compiler dependencies belong to the filesystem watch graph. Vite's
|
|
115
|
+
// transform-context addWatchFile also inserts runtime imports, so none
|
|
116
|
+
// of those dependencies may use that channel during serve (#1368).
|
|
125
117
|
configureServer(server) {
|
|
126
|
-
|
|
118
|
+
serveInputs.attach(server);
|
|
127
119
|
},
|
|
128
120
|
// Vite calls buildEnd when the dev server closes, and Rollup calls it at
|
|
129
121
|
// the end of every build phase; drop every poller and, once the last
|
|
@@ -140,15 +132,15 @@ const unpluginFactory: UnpluginFactory<
|
|
|
140
132
|
// fixing one of the two sites alone left this host recompiling the whole
|
|
141
133
|
// project per edit (samchon/ttsc#1301). The watching build hands its
|
|
142
134
|
// teardown to `closeWatcher` below instead.
|
|
143
|
-
buildEnd() {
|
|
135
|
+
async buildEnd() {
|
|
144
136
|
if (viteBuildOwners.delete(this)) {
|
|
145
137
|
viteBuildLifecycles -= 1;
|
|
146
138
|
}
|
|
147
139
|
if (viteBuildLifecycles === 0) {
|
|
148
|
-
missingInputs.dispose();
|
|
149
140
|
if (viteCommand === "serve" || !viteBuildWatching) {
|
|
150
141
|
resetTtscTransformCache(transformCache);
|
|
151
142
|
}
|
|
143
|
+
await serveInputs.dispose();
|
|
152
144
|
}
|
|
153
145
|
},
|
|
154
146
|
// The watching build's real teardown, and the only hook in a
|
|
@@ -165,11 +157,11 @@ const unpluginFactory: UnpluginFactory<
|
|
|
165
157
|
// `buildEnd` would then decrement a counter that is already zero and
|
|
166
158
|
// strand it below zero, after which the disposal above could never fire
|
|
167
159
|
// again for this plugin instance.
|
|
168
|
-
closeWatcher() {
|
|
160
|
+
async closeWatcher() {
|
|
169
161
|
viteBuildOwners = new WeakSet<object>();
|
|
170
162
|
viteBuildLifecycles = 0;
|
|
171
|
-
missingInputs.dispose();
|
|
172
163
|
resetTtscTransformCache(transformCache);
|
|
164
|
+
await serveInputs.dispose();
|
|
173
165
|
},
|
|
174
166
|
},
|
|
175
167
|
|
|
@@ -221,26 +213,16 @@ const unpluginFactory: UnpluginFactory<
|
|
|
221
213
|
resetTtscTransformCache(transformCache);
|
|
222
214
|
});
|
|
223
215
|
},
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
}
|
|
232
|
-
build.onDispose(() => {
|
|
233
|
-
if (!esbuildOwners.delete(build)) {
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
esbuildLifecycles -= 1;
|
|
237
|
-
if (esbuildLifecycles === 0) {
|
|
238
|
-
resetTtscTransformCache(transformCache);
|
|
239
|
-
}
|
|
240
|
-
});
|
|
216
|
+
farm: {
|
|
217
|
+
// Farm calls buildStart only for the initial compilation. Every update
|
|
218
|
+
// opens a new pass so a failed verdict can recover, while an unchanged
|
|
219
|
+
// successful generation remains reusable across its module deliveries.
|
|
220
|
+
updateModules: {
|
|
221
|
+
executor() {
|
|
222
|
+
beginTtscTransformBuild(transformCache);
|
|
223
|
+
},
|
|
241
224
|
},
|
|
242
225
|
},
|
|
243
|
-
|
|
244
226
|
buildStart() {
|
|
245
227
|
if (viteCommand !== undefined && !viteBuildOwners.has(this as object)) {
|
|
246
228
|
viteBuildOwners.add(this as object);
|
|
@@ -283,65 +265,34 @@ const unpluginFactory: UnpluginFactory<
|
|
|
283
265
|
return undefined;
|
|
284
266
|
}
|
|
285
267
|
return transformTtsc(file, source, options, aliases, transformCache, {
|
|
286
|
-
//
|
|
287
|
-
//
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
// every cache hit revalidates it, and probing each input again
|
|
315
|
-
// costs one `existsSync` per input per delivered module.
|
|
316
|
-
const unavailable =
|
|
317
|
-
evidence?.unavailable ??
|
|
318
|
-
(evidence === undefined
|
|
319
|
-
? !fs.existsSync(watched)
|
|
320
|
-
? "missing"
|
|
321
|
-
: undefined
|
|
322
|
-
: evidence.missing
|
|
323
|
-
? "missing"
|
|
324
|
-
: undefined);
|
|
325
|
-
if (unavailable !== undefined) {
|
|
326
|
-
missingInputs.watch(
|
|
327
|
-
watched,
|
|
328
|
-
path.resolve(file),
|
|
329
|
-
unavailable === "not-file" ? "file" : "exists",
|
|
330
|
-
);
|
|
331
|
-
return;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
// A dev server configured without a watcher can never deliver a
|
|
335
|
-
// change event, so a registration here buys nothing, and it is not
|
|
336
|
-
// free: Vite's import analysis resolves every registered path like a
|
|
337
|
-
// real import of the transformed module, once per module. The
|
|
338
|
-
// adapter's own missing-input poll above stays active either way,
|
|
339
|
-
// because it never depended on Vite's watcher.
|
|
340
|
-
if (viteCommand === "serve" && !viteWatching) {
|
|
341
|
-
return;
|
|
342
|
-
}
|
|
343
|
-
this.addWatchFile(watched);
|
|
344
|
-
},
|
|
268
|
+
// A watcherless server has no invalidation channel and needs no
|
|
269
|
+
// watch-input derivation. Every other host keeps its native contract.
|
|
270
|
+
addWatchFiles:
|
|
271
|
+
viteCommand === "serve" && !viteWatching
|
|
272
|
+
? undefined
|
|
273
|
+
: (inputs, failed) => {
|
|
274
|
+
if (viteCommand === "serve") {
|
|
275
|
+
serveInputs.replace(file, inputs, failed);
|
|
276
|
+
} else {
|
|
277
|
+
const native = this.getNativeBuildContext?.();
|
|
278
|
+
for (const input of inputs) {
|
|
279
|
+
if (
|
|
280
|
+
native?.framework === "rspack" &&
|
|
281
|
+
native.loaderContext !== undefined
|
|
282
|
+
) {
|
|
283
|
+
// Compilation-level dependencies schedule a pass but do
|
|
284
|
+
// not invalidate Rspack's cached transformed modules.
|
|
285
|
+
if (input.evidence?.missing === true)
|
|
286
|
+
native.loaderContext.addMissingDependency(input.file);
|
|
287
|
+
else native.loaderContext.addDependency(input.file);
|
|
288
|
+
} else if (native?.framework === "farm") {
|
|
289
|
+
native.context.addWatchFile(file, input.file);
|
|
290
|
+
} else {
|
|
291
|
+
this.addWatchFile(input.file);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
},
|
|
345
296
|
// A module the plugin declared volatile depends on non-file inputs,
|
|
346
297
|
// which no file-dependency snapshot can represent; mark it
|
|
347
298
|
// uncacheable where the bundler exposes that control.
|
package/src/core/transform.ts
CHANGED
|
@@ -239,14 +239,13 @@ class TtscUnstableGenerationError extends TtscTerminalGenerationError {
|
|
|
239
239
|
/**
|
|
240
240
|
* A compile this pass already attempted, whose envelope failed outright.
|
|
241
241
|
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
* made a single broken save cost one compile per delivered module
|
|
242
|
+
* Native project diagnostics carry a structured failure envelope; setup and
|
|
243
|
+
* host failures can still arrive as opaque exceptions. Both settle the current
|
|
244
|
+
* attempt, so the adapter uses the delivery boundary it owns rather than
|
|
245
|
+
* guessing retryability from a diagnostic message. Inside a pass the answer is
|
|
246
|
+
* already settled, so every later module replays it instead of repeating a
|
|
247
|
+
* whole-project transform to reach the same verdict, which is what made a
|
|
248
|
+
* single broken save cost one compile per delivered module
|
|
250
249
|
* (samchon/ttsc#1303).
|
|
251
250
|
*
|
|
252
251
|
* The scope is exactly the pass. A host whose `buildStart` repeats drops the
|
|
@@ -811,10 +810,12 @@ export interface TtscTransformHooks {
|
|
|
811
810
|
addWatchFile?: (file: string, evidence?: TtscWatchInputEvidence) => void;
|
|
812
811
|
/**
|
|
813
812
|
* Batched form of {@link addWatchFile}. When supplied, the transform calls it
|
|
814
|
-
* once per delivered module and does not call `addWatchFile` for that
|
|
815
|
-
*
|
|
813
|
+
* once per delivered module and does not call `addWatchFile` for that module.
|
|
814
|
+
* `failed` marks a recovery batch: a failed compiler can omit inputs from its
|
|
815
|
+
* previous successful result, so replacing hosts should retain those
|
|
816
|
+
* spellings until the next successful delivery.
|
|
816
817
|
*/
|
|
817
|
-
addWatchFiles?: (inputs: readonly TtscWatchInput[]) => void;
|
|
818
|
+
addWatchFiles?: (inputs: readonly TtscWatchInput[], failed?: boolean) => void;
|
|
818
819
|
/**
|
|
819
820
|
* Invoked when the plugin declared the transformed file volatile (the
|
|
820
821
|
* envelope's `volatile` list): its output depends on non-file inputs that no
|
|
@@ -1947,11 +1948,11 @@ function collectDeclaredIdentities(
|
|
|
1947
1948
|
* invalidated, and the error stays on screen (samchon/ttsc#1312).
|
|
1948
1949
|
*
|
|
1949
1950
|
* A failure envelope can retain exact external input spellings from its graph
|
|
1950
|
-
* and host metadata
|
|
1951
|
-
*
|
|
1952
|
-
*
|
|
1953
|
-
*
|
|
1954
|
-
*
|
|
1951
|
+
* and host metadata, including missing resolution candidates on native
|
|
1952
|
+
* typecheck failures. For hosts that return no graph, structured diagnostics or
|
|
1953
|
+
* standard diagnostic lines provide only the paths they actually name. The cost
|
|
1954
|
+
* is paid only on a failure, and only until the next compile succeeds and
|
|
1955
|
+
* narrows the set back to the derived inputs.
|
|
1955
1956
|
*/
|
|
1956
1957
|
function notifyFailedGenerationInputs(
|
|
1957
1958
|
hooks: TtscTransformHooks | undefined,
|
|
@@ -2002,7 +2003,7 @@ function notifyFailedGenerationInputs(
|
|
|
2002
2003
|
}
|
|
2003
2004
|
}
|
|
2004
2005
|
if (addWatchFiles !== undefined) {
|
|
2005
|
-
addWatchFiles(inputs);
|
|
2006
|
+
addWatchFiles(inputs, true);
|
|
2006
2007
|
return;
|
|
2007
2008
|
}
|
|
2008
2009
|
for (const input of inputs) {
|
|
@@ -5006,7 +5007,9 @@ async function registerWindowsProjectMutationTracker(
|
|
|
5006
5007
|
});
|
|
5007
5008
|
broker.pendingRegistrations += 1;
|
|
5008
5009
|
broker.child.ref();
|
|
5009
|
-
|
|
5010
|
+
// Bun's IPC channel omits Node's Control.ref/unref methods. The child itself
|
|
5011
|
+
// still owns the outstanding acknowledgement on that runtime.
|
|
5012
|
+
broker.child.channel?.ref?.();
|
|
5010
5013
|
const id = broker.nextId++;
|
|
5011
5014
|
let resolveReady!: () => void;
|
|
5012
5015
|
const ready = new Promise<void>((resolve) => {
|
|
@@ -5071,7 +5074,7 @@ async function registerWindowsProjectMutationTracker(
|
|
|
5071
5074
|
// exit mid-build.
|
|
5072
5075
|
if (broker.pendingRegistrations === 0 && broker.pendingDrains === 0) {
|
|
5073
5076
|
broker.child.unref();
|
|
5074
|
-
broker.child.channel?.unref();
|
|
5077
|
+
broker.child.channel?.unref?.();
|
|
5075
5078
|
}
|
|
5076
5079
|
}
|
|
5077
5080
|
}
|
|
@@ -5199,7 +5202,7 @@ function startWindowsProjectMutationDrain(
|
|
|
5199
5202
|
broker.pendingDrains -= 1;
|
|
5200
5203
|
if (broker.pendingDrains === 0 && broker.pendingRegistrations === 0) {
|
|
5201
5204
|
broker.child.unref();
|
|
5202
|
-
broker.child.channel?.unref();
|
|
5205
|
+
broker.child.channel?.unref?.();
|
|
5203
5206
|
}
|
|
5204
5207
|
resolve();
|
|
5205
5208
|
};
|
|
@@ -5210,7 +5213,7 @@ function startWindowsProjectMutationDrain(
|
|
|
5210
5213
|
// process exits mid-build with nothing to report.
|
|
5211
5214
|
broker.pendingDrains += 1;
|
|
5212
5215
|
broker.child.ref();
|
|
5213
|
-
broker.child.channel?.ref();
|
|
5216
|
+
broker.child.channel?.ref?.();
|
|
5214
5217
|
const timer = setTimeout(release, WINDOWS_MUTATION_DRAIN_FALLBACK_MS);
|
|
5215
5218
|
broker.drains.set(id, release);
|
|
5216
5219
|
if (broker.child.send?.({ id, op: "drain" }) !== true) {
|
|
@@ -7858,13 +7861,12 @@ function formatUnknownError(error: unknown): string {
|
|
|
7858
7861
|
/**
|
|
7859
7862
|
* Remove terminal colour and cursor sequences from text the adapter surfaces.
|
|
7860
7863
|
*
|
|
7861
|
-
* An
|
|
7862
|
-
*
|
|
7863
|
-
*
|
|
7864
|
-
*
|
|
7865
|
-
*
|
|
7866
|
-
*
|
|
7867
|
-
* (samchon/ttsc#1312).
|
|
7864
|
+
* An opaque host exception can contain the host's own rendered output, colour
|
|
7865
|
+
* and all, with no structured diagnostics to format instead. What the adapter
|
|
7866
|
+
* hands back is not going to a terminal: it becomes the `Error` a bundler
|
|
7867
|
+
* reports, so it lands in a Vite overlay, a webpack error report or a CI
|
|
7868
|
+
* annotation, where the escapes render as literal noise around the file and
|
|
7869
|
+
* line the reader needs (samchon/ttsc#1312).
|
|
7868
7870
|
*
|
|
7869
7871
|
* The colour originates in the host's rendering rather than in anything this
|
|
7870
7872
|
* adapter configures, so this is the adapter-side repair, applied to every
|