@ttsc/unplugin 0.28.3 → 0.28.5
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 +70 -8
- package/lib/api.js +3 -0
- package/lib/api.js.map +1 -1
- package/lib/api.mjs +1 -0
- package/lib/api.mjs.map +1 -1
- package/lib/core/index.d.cts +17 -6
- package/lib/core/index.d.mts +17 -6
- package/lib/core/index.d.ts +17 -6
- package/lib/core/index.js +117 -21
- package/lib/core/index.js.map +1 -1
- package/lib/core/index.mjs +115 -21
- package/lib/core/index.mjs.map +1 -1
- package/lib/core/transform.d.cts +93 -25
- package/lib/core/transform.d.mts +93 -25
- package/lib/core/transform.d.ts +93 -25
- package/lib/core/transform.js +803 -121
- package/lib/core/transform.js.map +1 -1
- package/lib/core/transform.mjs +804 -122
- package/lib/core/transform.mjs.map +1 -1
- package/lib/core/tsconfigPaths.d.cts +61 -0
- package/lib/core/tsconfigPaths.d.mts +61 -0
- package/lib/core/tsconfigPaths.d.ts +61 -0
- package/lib/core/tsconfigPaths.js +190 -7
- package/lib/core/tsconfigPaths.js.map +1 -1
- package/lib/core/tsconfigPaths.mjs +188 -8
- package/lib/core/tsconfigPaths.mjs.map +1 -1
- package/lib/next.d.cts +27 -10
- package/lib/next.d.mts +27 -10
- package/lib/next.d.ts +27 -10
- package/lib/next.js +229 -8
- package/lib/next.js.map +1 -1
- package/lib/next.mjs +229 -8
- package/lib/next.mjs.map +1 -1
- package/lib/turbopack.d.cts +5 -4
- package/lib/turbopack.d.mts +5 -4
- package/lib/turbopack.d.ts +5 -4
- package/lib/turbopack.js +13 -7
- package/lib/turbopack.js.map +1 -1
- package/lib/turbopack.mjs +14 -8
- package/lib/turbopack.mjs.map +1 -1
- package/package.json +3 -3
- package/src/core/index.ts +122 -21
- package/src/core/transform.ts +1073 -132
- package/src/core/tsconfigPaths.ts +254 -8
- package/src/next.ts +262 -10
- package/src/turbopack.ts +13 -9
package/src/core/index.ts
CHANGED
|
@@ -20,9 +20,13 @@ import { createViteServeMissingInputWatch } from "./viteServe";
|
|
|
20
20
|
|
|
21
21
|
const name = "ttsc-unplugin";
|
|
22
22
|
/**
|
|
23
|
-
* Matches
|
|
24
|
-
*
|
|
25
|
-
*
|
|
23
|
+
* Matches the TypeScript source extensions the ttsc transform handles: `.ts`,
|
|
24
|
+
* `.tsx`, `.mts`, `.cts` and their `x` forms. JavaScript is deliberately not
|
|
25
|
+
* among them, so a `.js` module reaches no adapter's transform.
|
|
26
|
+
*
|
|
27
|
+
* Shared with the Bun adapter (`bun.ts`) and the standalone Turbopack loader
|
|
28
|
+
* (`turbopack.ts`) through {@link isTransformTarget}, so the filter is defined
|
|
29
|
+
* once and every adapter answers the same way.
|
|
26
30
|
*/
|
|
27
31
|
export const sourceFilePattern = /\.[cm]?tsx?$/;
|
|
28
32
|
/** Matches any path segment that is a `node_modules` directory (cross-platform). */
|
|
@@ -37,13 +41,15 @@ const virtualModulePattern = /\0/;
|
|
|
37
41
|
* Unplugin factory that wires the ttsc transform pipeline into any supported
|
|
38
42
|
* bundler (Vite, Rollup, Rolldown, webpack, Rspack, esbuild, Farm).
|
|
39
43
|
*
|
|
40
|
-
* The factory resolves raw options once, creates
|
|
41
|
-
* and captures Vite alias configuration via the
|
|
42
|
-
* that path aliases are forwarded to the
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
44
|
+
* The factory resolves raw options once, creates one transform cache for the
|
|
45
|
+
* whole plugin instance, and captures Vite alias configuration via the
|
|
46
|
+
* `vite.configResolved` hook so that path aliases are forwarded to the
|
|
47
|
+
* generated tsconfig overlay. A host with a real `buildStart` opens a delivery
|
|
48
|
+
* pass there and keeps its generation across passes; a watching Vite
|
|
49
|
+
* development server keeps persistent validation instead, because its one
|
|
50
|
+
* `buildStart` spans later HMR edits and so cannot mark a pass, while a dev
|
|
51
|
+
* server configured without a watcher takes the pass lifecycle with them,
|
|
52
|
+
* having declared it will observe no edit at all.
|
|
47
53
|
*/
|
|
48
54
|
const unpluginFactory: UnpluginFactory<
|
|
49
55
|
TtscUnpluginOptions | undefined,
|
|
@@ -55,11 +61,16 @@ const unpluginFactory: UnpluginFactory<
|
|
|
55
61
|
let aliases: unknown;
|
|
56
62
|
let viteCommand: string | undefined;
|
|
57
63
|
let viteWatching = true;
|
|
64
|
+
// Whether a build-mode session is driven by Rollup's watcher. `build.watch`
|
|
65
|
+
// is `null` for an ordinary build and an object under `--watch`, which is the
|
|
66
|
+
// axis the disposal boundary actually turns on: only a watching build repeats
|
|
67
|
+
// its build phase, and only a watching build ends at `closeWatcher`.
|
|
68
|
+
let viteBuildWatching = false;
|
|
58
69
|
// A restart can start the replacement plugin container before closing the
|
|
59
70
|
// old one, and Vite calls buildEnd even for a container that never started.
|
|
60
71
|
// Track the stable per-container PluginContext identity so that unstarted
|
|
61
72
|
// old containers cannot dispose a replacement's freshly initialized cache.
|
|
62
|
-
|
|
73
|
+
let viteBuildOwners = new WeakSet<object>();
|
|
63
74
|
let viteBuildLifecycles = 0;
|
|
64
75
|
|
|
65
76
|
return {
|
|
@@ -84,6 +95,13 @@ const unpluginFactory: UnpluginFactory<
|
|
|
84
95
|
// (samchon/ttsc#1246).
|
|
85
96
|
viteWatching =
|
|
86
97
|
(config as { server?: { watch?: unknown } }).server?.watch !== null;
|
|
98
|
+
// Read on the same principle as the line above, from the half of the
|
|
99
|
+
// config that governs a build rather than a server. The comparison is
|
|
100
|
+
// loose where the server's is strict because the two defaults differ:
|
|
101
|
+
// `server.watch` is an object unless explicitly `null`, while
|
|
102
|
+
// `build.watch` is absent or `null` unless `--watch` supplies one.
|
|
103
|
+
viteBuildWatching =
|
|
104
|
+
(config as { build?: { watch?: unknown } }).build?.watch != null;
|
|
87
105
|
},
|
|
88
106
|
// Vite serve funnels every transform-context `addWatchFile()` into the
|
|
89
107
|
// module's added-import graph (`_addedImports`), which import-analysis
|
|
@@ -94,18 +112,87 @@ const unpluginFactory: UnpluginFactory<
|
|
|
94
112
|
configureServer(server) {
|
|
95
113
|
missingInputs.attach(server);
|
|
96
114
|
},
|
|
97
|
-
// Vite calls buildEnd when the dev server
|
|
98
|
-
// poller and, once the last
|
|
99
|
-
// generation-owned filesystem
|
|
115
|
+
// Vite calls buildEnd when the dev server closes, and Rollup calls it at
|
|
116
|
+
// the end of every build phase; drop every poller and, once the last
|
|
117
|
+
// overlapping container has closed, every generation-owned filesystem
|
|
118
|
+
// tracker as well.
|
|
119
|
+
//
|
|
120
|
+
// Disposing here is right wherever the end of a build phase is also the
|
|
121
|
+
// end of the session: a dev server, and an ordinary one-shot build. It is
|
|
122
|
+
// wrong for a watching build, whose watcher repeats build phases, so it
|
|
123
|
+
// means "this pass ended" there — measured as
|
|
124
|
+
// `buildStart -> buildEnd -> ... -> buildStart -> buildEnd` across
|
|
125
|
+
// `vite build --watch` rebuilds. Disposing on that repeat discarded the
|
|
126
|
+
// generation once per rebuild independently of the `buildStart` clear, so
|
|
127
|
+
// fixing one of the two sites alone left this host recompiling the whole
|
|
128
|
+
// project per edit (samchon/ttsc#1301). The watching build hands its
|
|
129
|
+
// teardown to `closeWatcher` below instead.
|
|
100
130
|
buildEnd() {
|
|
101
131
|
missingInputs.dispose();
|
|
102
132
|
if (viteBuildOwners.delete(this)) {
|
|
103
133
|
viteBuildLifecycles -= 1;
|
|
104
134
|
}
|
|
105
|
-
if (
|
|
135
|
+
if (
|
|
136
|
+
viteBuildLifecycles === 0 &&
|
|
137
|
+
(viteCommand === "serve" || !viteBuildWatching)
|
|
138
|
+
) {
|
|
139
|
+
resetTtscTransformCache(transformCache);
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
// The watching build's real teardown, and the only hook in a
|
|
143
|
+
// `vite build --watch` trace that fires exactly once: buildEnd,
|
|
144
|
+
// writeBundle and closeBundle all repeat per rebuild there. A generation
|
|
145
|
+
// retained across passes owns directory watchers, so this is where they
|
|
146
|
+
// are released. Vite's dev server drives no Rollup watcher and an
|
|
147
|
+
// ordinary build closes its bundle instead, so neither reaches here;
|
|
148
|
+
// a host that fired both would simply reset twice, which is idempotent.
|
|
149
|
+
//
|
|
150
|
+
// The container bookkeeping is cleared with the cache, and the owner set
|
|
151
|
+
// is replaced rather than merely zeroed alongside it. A watcher closed
|
|
152
|
+
// mid-rebuild leaves a container still registered, and its later
|
|
153
|
+
// `buildEnd` would then decrement a counter that is already zero and
|
|
154
|
+
// strand it below zero, after which the disposal above could never fire
|
|
155
|
+
// again for this plugin instance.
|
|
156
|
+
closeWatcher() {
|
|
157
|
+
viteBuildOwners = new WeakSet<object>();
|
|
158
|
+
viteBuildLifecycles = 0;
|
|
159
|
+
resetTtscTransformCache(transformCache);
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
// Rollup and Rolldown carry none of the Vite block's hooks, so before this
|
|
164
|
+
// they had no disposal site at all. They get both halves of the same
|
|
165
|
+
// boundary: a watching session ends at `closeWatcher`, and a one-shot build
|
|
166
|
+
// ends when its build phase does. `this.meta.watchMode` separates the two
|
|
167
|
+
// there, the way `build.watch` does for Vite, so a one-shot build is not
|
|
168
|
+
// left without a site the way `vite build` was (samchon/ttsc#1301).
|
|
169
|
+
// unplugin merges each of these blocks only into its own adapter, so the
|
|
170
|
+
// Vite adapter never receives them.
|
|
171
|
+
//
|
|
172
|
+
// A `buildEnd` at the top level instead of inside a block would be a
|
|
173
|
+
// regression rather than a shorthand: unplugin forwards a top-level one to
|
|
174
|
+
// esbuild's `onEnd` and to webpack's and Rspack's `hooks.emit`, each of
|
|
175
|
+
// which repeats per rebuild, so those hosts would start discarding a valid
|
|
176
|
+
// generation on every edit, which is samchon/ttsc#1300 again.
|
|
177
|
+
rollup: {
|
|
178
|
+
buildEnd(this: { meta?: { watchMode?: boolean } }) {
|
|
179
|
+
if (this.meta?.watchMode !== true) {
|
|
180
|
+
resetTtscTransformCache(transformCache);
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
closeWatcher() {
|
|
184
|
+
resetTtscTransformCache(transformCache);
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
rolldown: {
|
|
188
|
+
buildEnd(this: { meta?: { watchMode?: boolean } }) {
|
|
189
|
+
if (this.meta?.watchMode !== true) {
|
|
106
190
|
resetTtscTransformCache(transformCache);
|
|
107
191
|
}
|
|
108
192
|
},
|
|
193
|
+
closeWatcher() {
|
|
194
|
+
resetTtscTransformCache(transformCache);
|
|
195
|
+
},
|
|
109
196
|
},
|
|
110
197
|
|
|
111
198
|
buildStart() {
|
|
@@ -120,14 +207,18 @@ const unpluginFactory: UnpluginFactory<
|
|
|
120
207
|
// no client is hot-updated. Validating each delivery there does not buy
|
|
121
208
|
// freshness, it buys incoherence — modules delivered before an edit and
|
|
122
209
|
// after it would come from two different compilations of one program —
|
|
123
|
-
// while costing a full derived-input proof per delivered module. The
|
|
124
|
-
//
|
|
125
|
-
//
|
|
210
|
+
// while costing a full derived-input proof per delivered module. The pass
|
|
211
|
+
// lifecycle settles each module's first delivery against the generation
|
|
212
|
+
// the session started from, exactly as a build does, and still
|
|
126
213
|
// revalidates a module this session already delivered. A one-shot suite
|
|
127
214
|
// configures precisely this server (`vitest --run` sets `server.watch =
|
|
128
215
|
// null`) and is the workload behind samchon/ttsc#970
|
|
129
216
|
// (samchon/ttsc#1260). The neighbouring watch-registration decision reads
|
|
130
217
|
// the same two properties for the same reason.
|
|
218
|
+
//
|
|
219
|
+
// Opening a pass no longer discards the generation, so the `else` branch
|
|
220
|
+
// is what every host with a repeating `buildStart` takes without paying a
|
|
221
|
+
// whole-project transform per rebuild (samchon/ttsc#1300).
|
|
131
222
|
if (viteCommand === "serve" && viteWatching) {
|
|
132
223
|
resetTtscTransformCache(transformCache);
|
|
133
224
|
} else {
|
|
@@ -211,6 +302,11 @@ export type {
|
|
|
211
302
|
TtscTransformHooks,
|
|
212
303
|
TtscWatchInputEvidence,
|
|
213
304
|
} from "./transform";
|
|
305
|
+
export type { ITtscProjectMembershipPolicy } from "./tsconfigPaths";
|
|
306
|
+
export {
|
|
307
|
+
mergeMembershipPolicyOverlay,
|
|
308
|
+
readProjectMembershipPolicy,
|
|
309
|
+
} from "./tsconfigPaths";
|
|
214
310
|
export {
|
|
215
311
|
beginTtscTransformBuild,
|
|
216
312
|
collectExternalInputHashes,
|
|
@@ -226,10 +322,15 @@ export {
|
|
|
226
322
|
export default unplugin;
|
|
227
323
|
|
|
228
324
|
/**
|
|
229
|
-
* Returns `true` when the module id refers to a real TypeScript
|
|
230
|
-
*
|
|
325
|
+
* Returns `true` when the module id refers to a real TypeScript source file
|
|
326
|
+
* that should be processed by the ttsc transform.
|
|
327
|
+
*
|
|
328
|
+
* TypeScript only. {@link sourceFilePattern} deliberately excludes JavaScript,
|
|
329
|
+
* so a `.js` module reaches no adapter's transform, and this docstring used to
|
|
330
|
+
* say otherwise while the pattern it is built from said the truth
|
|
331
|
+
* (samchon/ttsc#1309).
|
|
231
332
|
*
|
|
232
|
-
*
|
|
333
|
+
* Also excluded: virtual modules (NUL prefix), `.d.ts` declaration files, and
|
|
233
334
|
* anything inside `node_modules`.
|
|
234
335
|
*/
|
|
235
336
|
export function isTransformTarget(id: string): boolean {
|