@ttsc/unplugin 0.32.0 → 0.32.1
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/core/options/ResolvedTtscUnpluginOptions.d.cts +2 -0
- package/lib/core/options/ResolvedTtscUnpluginOptions.d.mts +2 -0
- package/lib/core/options/ResolvedTtscUnpluginOptions.d.ts +2 -0
- package/lib/core/options/TtscUnpluginOptions.d.cts +12 -2
- package/lib/core/options/TtscUnpluginOptions.d.mts +12 -2
- package/lib/core/options/TtscUnpluginOptions.d.ts +12 -2
- package/lib/core/options/resolveOptions.d.cts +4 -3
- package/lib/core/options/resolveOptions.d.mts +4 -3
- package/lib/core/options/resolveOptions.d.ts +4 -3
- package/lib/core/options/resolveOptions.js +5 -3
- package/lib/core/options/resolveOptions.js.map +1 -1
- package/lib/core/options/resolveOptions.mjs +5 -3
- package/lib/core/options/resolveOptions.mjs.map +1 -1
- package/lib/core/transform/TtscPrecompilation.d.cts +52 -0
- package/lib/core/transform/TtscPrecompilation.d.mts +52 -0
- package/lib/core/transform/TtscPrecompilation.d.ts +52 -0
- package/lib/core/transform/TtscPrecompilation.js +101 -0
- package/lib/core/transform/TtscPrecompilation.js.map +1 -0
- package/lib/core/transform/TtscPrecompilation.mjs +101 -0
- package/lib/core/transform/TtscPrecompilation.mjs.map +1 -0
- package/lib/core/transform/cache/selectCachedGenerationAction.d.cts +2 -0
- package/lib/core/transform/cache/selectCachedGenerationAction.d.mts +2 -0
- package/lib/core/transform/cache/selectCachedGenerationAction.d.ts +2 -0
- package/lib/core/transform/cache/selectCachedGenerationAction.js +1 -1
- package/lib/core/transform/cache/selectCachedGenerationAction.js.map +1 -1
- package/lib/core/transform/cache/selectCachedGenerationAction.mjs +1 -1
- package/lib/core/transform/cache/selectCachedGenerationAction.mjs.map +1 -1
- package/lib/core/transform/cache/withdrawTtscTransformGenerations.js +2 -0
- package/lib/core/transform/cache/withdrawTtscTransformGenerations.js.map +1 -1
- package/lib/core/transform/cache/withdrawTtscTransformGenerations.mjs +2 -0
- package/lib/core/transform/cache/withdrawTtscTransformGenerations.mjs.map +1 -1
- package/lib/core/transform/generation/captureTransformGeneration.d.cts +2 -0
- package/lib/core/transform/generation/captureTransformGeneration.d.mts +2 -0
- package/lib/core/transform/generation/captureTransformGeneration.d.ts +2 -0
- package/lib/core/transform/generation/captureTransformGeneration.js +7 -2
- package/lib/core/transform/generation/captureTransformGeneration.js.map +1 -1
- package/lib/core/transform/generation/captureTransformGeneration.mjs +7 -2
- package/lib/core/transform/generation/captureTransformGeneration.mjs.map +1 -1
- package/lib/core/transform/generation/transformProject.d.cts +2 -0
- package/lib/core/transform/generation/transformProject.d.mts +2 -0
- package/lib/core/transform/generation/transformProject.d.ts +2 -0
- package/lib/core/transform/generation/transformProject.js.map +1 -1
- package/lib/core/transform/generation/transformProject.mjs.map +1 -1
- package/lib/core/transform/transformTtsc.d.cts +8 -24
- package/lib/core/transform/transformTtsc.d.mts +8 -24
- package/lib/core/transform/transformTtsc.d.ts +8 -24
- package/lib/core/transform/transformTtsc.js +51 -31
- package/lib/core/transform/transformTtsc.js.map +1 -1
- package/lib/core/transform/transformTtsc.mjs +51 -31
- package/lib/core/transform/transformTtsc.mjs.map +1 -1
- package/lib/core/transform/validation/captureUniversalHostInputValidation.d.cts +1 -1
- package/lib/core/transform/validation/captureUniversalHostInputValidation.d.mts +1 -1
- package/lib/core/transform/validation/captureUniversalHostInputValidation.d.ts +1 -1
- package/lib/core/transform/validation/captureUniversalHostInputValidation.js +12 -4
- package/lib/core/transform/validation/captureUniversalHostInputValidation.js.map +1 -1
- package/lib/core/transform/validation/captureUniversalHostInputValidation.mjs +12 -4
- package/lib/core/transform/validation/captureUniversalHostInputValidation.mjs.map +1 -1
- package/lib/core/transform/validation/matchesCachedSource.d.cts +9 -2
- package/lib/core/transform/validation/matchesCachedSource.d.mts +9 -2
- package/lib/core/transform/validation/matchesCachedSource.d.ts +9 -2
- package/lib/core/transform/validation/matchesCachedSource.js +11 -3
- package/lib/core/transform/validation/matchesCachedSource.js.map +1 -1
- package/lib/core/transform/validation/matchesCachedSource.mjs +11 -3
- package/lib/core/transform/validation/matchesCachedSource.mjs.map +1 -1
- package/lib/core/transform/watch/TtscTransformHooks.d.cts +9 -0
- package/lib/core/transform/watch/TtscTransformHooks.d.mts +9 -0
- package/lib/core/transform/watch/TtscTransformHooks.d.ts +9 -0
- package/lib/core/unplugin.js +14 -0
- package/lib/core/unplugin.js.map +1 -1
- package/lib/core/unplugin.mjs +14 -0
- package/lib/core/unplugin.mjs.map +1 -1
- package/lib/core/vite/installViteDependencyScanPlugins.d.cts +46 -0
- package/lib/core/vite/installViteDependencyScanPlugins.d.mts +46 -0
- package/lib/core/vite/installViteDependencyScanPlugins.d.ts +46 -0
- package/lib/core/vite/installViteDependencyScanPlugins.js +186 -0
- package/lib/core/vite/installViteDependencyScanPlugins.js.map +1 -0
- package/lib/core/vite/installViteDependencyScanPlugins.mjs +184 -0
- package/lib/core/vite/installViteDependencyScanPlugins.mjs.map +1 -0
- package/package.json +5 -4
- package/src/core/options/ResolvedTtscUnpluginOptions.ts +3 -0
- package/src/core/options/TtscUnpluginOptions.ts +13 -2
- package/src/core/options/resolveOptions.ts +6 -3
- package/src/core/transform/TtscPrecompilation.ts +103 -0
- package/src/core/transform/cache/selectCachedGenerationAction.ts +3 -0
- package/src/core/transform/cache/withdrawTtscTransformGenerations.ts +2 -0
- package/src/core/transform/generation/captureTransformGeneration.ts +12 -2
- package/src/core/transform/generation/transformProject.ts +3 -0
- package/src/core/transform/transformTtsc.ts +81 -36
- package/src/core/transform/validation/captureUniversalHostInputValidation.ts +12 -4
- package/src/core/transform/validation/matchesCachedSource.ts +9 -2
- package/src/core/transform/watch/TtscTransformHooks.ts +10 -0
- package/src/core/unplugin.ts +32 -0
- package/src/core/vite/installViteDependencyScanPlugins.ts +219 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BuildOptions,
|
|
3
|
+
Plugin as EsbuildPlugin,
|
|
4
|
+
ResolveResult,
|
|
5
|
+
} from "esbuild";
|
|
6
|
+
import fs from "node:fs";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
|
|
9
|
+
import { typescriptTransformSourcePattern } from "../source/typescriptTransformSourcePattern";
|
|
10
|
+
import type { TtscTransformResult } from "../transform/TtscTransformResult";
|
|
11
|
+
import { inlineSourceMap } from "../transform/utils/inlineSourceMap";
|
|
12
|
+
import { isHostWrapperQuery } from "../transform/utils/isHostWrapperQuery";
|
|
13
|
+
import { stripQuery } from "../transform/utils/stripQuery";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Exposes imports introduced by ttsc plugins to Vite's dependency scanner.
|
|
17
|
+
*
|
|
18
|
+
* Vite scans files without its normal transform hooks. Its optimizer plugins
|
|
19
|
+
* are the supported connection: Rolldown transforms the scanner's loaded text,
|
|
20
|
+
* while esbuild scans transformed modules in a separate namespace and also
|
|
21
|
+
* imports each original through Vite's loader. That original graph preserves
|
|
22
|
+
* glob, JSX and user loaders; the transformed graph adds complete relative
|
|
23
|
+
* import chains without a second parser or artificial exports.
|
|
24
|
+
*
|
|
25
|
+
* Vite's esbuild scanner supplies stdin; dependency bundling supplies entry
|
|
26
|
+
* points. Only the scanner gets the extra original graph, because publishing
|
|
27
|
+
* that graph would execute untransformed code alongside transformed code.
|
|
28
|
+
* Bundling applies ordinary transforms after user loaders instead. Supplying
|
|
29
|
+
* both stdin and entryPoints is not a supported Vite optimizer configuration.
|
|
30
|
+
*
|
|
31
|
+
* The caller owns compilation, aliases, validation and cache lifetime. Each
|
|
32
|
+
* environment keeps its own optimizer settings and existing plugins. Disabled
|
|
33
|
+
* discovery is left alone, and repeated installation on one settings object
|
|
34
|
+
* within this call is suppressed.
|
|
35
|
+
*
|
|
36
|
+
* @evidence contracts/common.md#principled-implementation Official optimizer hooks and the host's Rolldown capability select the real backend. Esbuild's stdin scan parses transformed namespaces plus actual-loader originals, while entry-point dependency bundles receive ordinary transforms without duplicate runtime source.
|
|
37
|
+
* @evidence contracts/common.md#clear-and-simple-design One installer selects the host's resolved optimizer backend and delegates compilation to the adapter's existing transform owner.
|
|
38
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Uses published setup, input options, namespaces, load, resolve and transform APIs. Synthetic original-import edges belong only to the unpublished dependency scan, and no host method, global, package name or expected dependency is replaced or special-cased.
|
|
39
|
+
* @evidence contracts/common.md#meaningful-documentation Prose explains the missing transform phase, original-loader ownership, scan versus bundle behavior, caller-owned generation validity and environment-specific option preservation.
|
|
40
|
+
* @evidence contracts/portability.md#os-neutral-implementation Node reads native paths and derives their resolve directories; Vite's resolver retains workspace, alias and filesystem identity policy. No OS-name or case assumption is introduced.
|
|
41
|
+
* @evidence contracts/performance.md#efficient-algorithms Esbuild scans at most a transformed and an original graph node per reached TypeScript source, sharing host cycle detection and parsing. Each interception delegates native resolution once. Active equal requests yield to the next resolver while the initiating interception retains the transformed graph edge; compilation and validation retain their own costs.
|
|
42
|
+
* @evidence contracts/performance.md#reuse-equivalent-work Scanner deliveries use the caller's transform cache and proof rules. Existing optimizer plugin objects remain shared by identity. Each distinct backend settings object receives one Rolldown transform or one prepended esbuild scanner and one appended bundle transform per installation.
|
|
43
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources Settings retain plugin closures for their Vite configuration lifetime. Active resolution keys are removed in finally; module graph state belongs to the host's scanner context. No child build, module history or separate compiler cache is retained, and the caller releases generations at its existing Vite boundaries.
|
|
44
|
+
*/
|
|
45
|
+
export function installViteDependencyScanPlugins(
|
|
46
|
+
config: {
|
|
47
|
+
command: string;
|
|
48
|
+
optimizeDeps: {
|
|
49
|
+
disabled?: boolean | "build" | "dev";
|
|
50
|
+
noDiscovery?: boolean;
|
|
51
|
+
esbuildOptions?: BuildOptions;
|
|
52
|
+
rolldownOptions?: { plugins?: unknown };
|
|
53
|
+
};
|
|
54
|
+
environments?: Record<
|
|
55
|
+
string,
|
|
56
|
+
{ optimizeDeps?: typeof config.optimizeDeps }
|
|
57
|
+
>;
|
|
58
|
+
},
|
|
59
|
+
includes: (file: string) => boolean,
|
|
60
|
+
transform: (
|
|
61
|
+
source: string,
|
|
62
|
+
file: string,
|
|
63
|
+
) => Promise<TtscTransformResult | undefined>,
|
|
64
|
+
backend: "esbuild" | "rolldown",
|
|
65
|
+
): void {
|
|
66
|
+
if (config.command !== "serve") return;
|
|
67
|
+
const installed = new Set<object>();
|
|
68
|
+
const backends = new Set<object>();
|
|
69
|
+
for (const options of [
|
|
70
|
+
config.optimizeDeps,
|
|
71
|
+
...Object.values(config.environments ?? {}).map(
|
|
72
|
+
(environment) => environment.optimizeDeps,
|
|
73
|
+
),
|
|
74
|
+
]) {
|
|
75
|
+
if (
|
|
76
|
+
options === undefined ||
|
|
77
|
+
installed.has(options) ||
|
|
78
|
+
options.noDiscovery === true ||
|
|
79
|
+
options.disabled === true ||
|
|
80
|
+
options.disabled === "dev"
|
|
81
|
+
)
|
|
82
|
+
continue;
|
|
83
|
+
installed.add(options);
|
|
84
|
+
if (backend === "rolldown") {
|
|
85
|
+
options.rolldownOptions ??= {};
|
|
86
|
+
if (backends.has(options.rolldownOptions)) continue;
|
|
87
|
+
backends.add(options.rolldownOptions);
|
|
88
|
+
const existing = options.rolldownOptions.plugins;
|
|
89
|
+
options.rolldownOptions.plugins = [
|
|
90
|
+
...(existing === undefined ? [] : [existing]),
|
|
91
|
+
{
|
|
92
|
+
name: "ttsc-dependency-scan",
|
|
93
|
+
async transform(source: string, file: string) {
|
|
94
|
+
if (isHostWrapperQuery(file) || !includes(stripQuery(file))) return;
|
|
95
|
+
return transform(source, stripQuery(file));
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
];
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
options.esbuildOptions ??= {};
|
|
102
|
+
if (backends.has(options.esbuildOptions)) continue;
|
|
103
|
+
backends.add(options.esbuildOptions);
|
|
104
|
+
const plugin: EsbuildPlugin = {
|
|
105
|
+
name: "ttsc-dependency-scan",
|
|
106
|
+
setup(build) {
|
|
107
|
+
if (build.initialOptions.stdin === undefined) return;
|
|
108
|
+
const namespace = "ttsc-dependency-scan";
|
|
109
|
+
const originalPrefix = "ttsc-dependency-original:";
|
|
110
|
+
const resolving = new Set<string>();
|
|
111
|
+
build.onResolve(
|
|
112
|
+
{ filter: /^ttsc-dependency-original:/, namespace },
|
|
113
|
+
(imported) => ({
|
|
114
|
+
path: imported.path.slice(originalPrefix.length),
|
|
115
|
+
namespace: "file",
|
|
116
|
+
pluginData: imported.pluginData,
|
|
117
|
+
}),
|
|
118
|
+
);
|
|
119
|
+
build.onResolve({ filter: /.*/ }, async (imported) => {
|
|
120
|
+
if (
|
|
121
|
+
imported.namespace !== "file" &&
|
|
122
|
+
imported.namespace !== namespace &&
|
|
123
|
+
imported.namespace !== ""
|
|
124
|
+
)
|
|
125
|
+
return;
|
|
126
|
+
const key = JSON.stringify([
|
|
127
|
+
imported.namespace === namespace
|
|
128
|
+
? "file"
|
|
129
|
+
: imported.namespace || "file",
|
|
130
|
+
imported.path,
|
|
131
|
+
imported.importer,
|
|
132
|
+
imported.resolveDir,
|
|
133
|
+
imported.kind,
|
|
134
|
+
imported.with,
|
|
135
|
+
]);
|
|
136
|
+
// Equal active requests include both self recursion and concurrent
|
|
137
|
+
// duplicates. Their raw edges cannot remove the first request's
|
|
138
|
+
// transformed node, which still exposes the added dependency closure.
|
|
139
|
+
if (resolving.has(key)) return;
|
|
140
|
+
resolving.add(key);
|
|
141
|
+
let resolved: ResolveResult;
|
|
142
|
+
try {
|
|
143
|
+
resolved = await build.resolve(imported.path, {
|
|
144
|
+
importer: imported.importer,
|
|
145
|
+
resolveDir: imported.resolveDir,
|
|
146
|
+
namespace: "file",
|
|
147
|
+
kind: imported.kind,
|
|
148
|
+
pluginData: imported.pluginData,
|
|
149
|
+
with: imported.with,
|
|
150
|
+
});
|
|
151
|
+
} finally {
|
|
152
|
+
resolving.delete(key);
|
|
153
|
+
}
|
|
154
|
+
if (
|
|
155
|
+
resolved.errors.length !== 0 ||
|
|
156
|
+
resolved.external ||
|
|
157
|
+
resolved.namespace !== "file" ||
|
|
158
|
+
!includes(resolved.path) ||
|
|
159
|
+
isHostWrapperQuery(resolved.suffix)
|
|
160
|
+
)
|
|
161
|
+
return resolved;
|
|
162
|
+
const loader =
|
|
163
|
+
build.initialOptions.loader?.[path.extname(resolved.path)];
|
|
164
|
+
if (
|
|
165
|
+
loader !== undefined &&
|
|
166
|
+
!["js", "jsx", "ts", "tsx"].includes(loader)
|
|
167
|
+
)
|
|
168
|
+
return resolved;
|
|
169
|
+
return { ...resolved, namespace, pluginData: resolved };
|
|
170
|
+
});
|
|
171
|
+
build.onLoad(
|
|
172
|
+
{ filter: typescriptTransformSourcePattern, namespace },
|
|
173
|
+
async ({ path: file, pluginData }) => {
|
|
174
|
+
const resolved = pluginData as ResolveResult;
|
|
175
|
+
const source = await fs.promises.readFile(file, "utf8");
|
|
176
|
+
const transformed = await transform(source, file);
|
|
177
|
+
return {
|
|
178
|
+
contents: `${transformed?.code ?? source}\nimport ${JSON.stringify(originalPrefix + file)};\n`,
|
|
179
|
+
loader:
|
|
180
|
+
build.initialOptions.loader?.[path.extname(file)] ??
|
|
181
|
+
(file.endsWith(".tsx") ? "tsx" : "ts"),
|
|
182
|
+
resolveDir: path.dirname(file),
|
|
183
|
+
pluginData: resolved.pluginData,
|
|
184
|
+
};
|
|
185
|
+
},
|
|
186
|
+
);
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
const bundle: EsbuildPlugin = {
|
|
190
|
+
name: "ttsc-dependency-transform",
|
|
191
|
+
setup(build) {
|
|
192
|
+
if (build.initialOptions.stdin !== undefined) return;
|
|
193
|
+
build.onLoad(
|
|
194
|
+
{ filter: typescriptTransformSourcePattern, namespace: "file" },
|
|
195
|
+
async ({ path: file }) => {
|
|
196
|
+
if (!includes(file)) return;
|
|
197
|
+
const loader =
|
|
198
|
+
build.initialOptions.loader?.[path.extname(file)] ??
|
|
199
|
+
(file.endsWith(".tsx") ? "tsx" : "ts");
|
|
200
|
+
if (!["js", "jsx", "ts", "tsx"].includes(loader)) return;
|
|
201
|
+
const source = await fs.promises.readFile(file, "utf8");
|
|
202
|
+
const result = await transform(source, file);
|
|
203
|
+
if (result === undefined) return;
|
|
204
|
+
return {
|
|
205
|
+
contents: inlineSourceMap(result),
|
|
206
|
+
loader,
|
|
207
|
+
resolveDir: path.dirname(file),
|
|
208
|
+
};
|
|
209
|
+
},
|
|
210
|
+
);
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
options.esbuildOptions.plugins = [
|
|
214
|
+
plugin,
|
|
215
|
+
...(options.esbuildOptions.plugins ?? []),
|
|
216
|
+
bundle,
|
|
217
|
+
];
|
|
218
|
+
}
|
|
219
|
+
}
|