@tanstack/start-plugin-core 1.167.35 → 1.169.0
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/dist/esm/import-protection/adapterUtils.d.ts +27 -0
- package/dist/esm/import-protection/adapterUtils.js +31 -0
- package/dist/esm/import-protection/adapterUtils.js.map +1 -0
- package/dist/esm/import-protection/analysis.d.ts +36 -0
- package/dist/esm/import-protection/analysis.js +407 -0
- package/dist/esm/import-protection/analysis.js.map +1 -0
- package/dist/esm/{import-protection-plugin → import-protection}/ast.js +1 -1
- package/dist/esm/import-protection/ast.js.map +1 -0
- package/dist/esm/import-protection/constants.d.ts +11 -0
- package/dist/esm/{import-protection-plugin → import-protection}/constants.js +7 -2
- package/dist/esm/import-protection/constants.js.map +1 -0
- package/dist/esm/{import-protection-plugin → import-protection}/defaults.js +1 -1
- package/dist/esm/import-protection/defaults.js.map +1 -0
- package/dist/esm/{import-protection-plugin → import-protection}/extensionlessAbsoluteIdResolver.js +2 -2
- package/dist/esm/import-protection/extensionlessAbsoluteIdResolver.js.map +1 -0
- package/dist/esm/{import-protection-plugin → import-protection}/matchers.js +1 -1
- package/dist/esm/import-protection/matchers.js.map +1 -0
- package/dist/esm/{import-protection-plugin/rewriteDeniedImports.d.ts → import-protection/rewrite.d.ts} +0 -4
- package/dist/esm/import-protection/rewrite.js +121 -0
- package/dist/esm/import-protection/rewrite.js.map +1 -0
- package/dist/esm/{import-protection-plugin → import-protection}/sourceLocation.d.ts +32 -3
- package/dist/esm/{import-protection-plugin → import-protection}/sourceLocation.js +65 -10
- package/dist/esm/import-protection/sourceLocation.js.map +1 -0
- package/dist/esm/{import-protection-plugin → import-protection}/trace.d.ts +0 -1
- package/dist/esm/{import-protection-plugin → import-protection}/trace.js +1 -1
- package/dist/esm/import-protection/trace.js.map +1 -0
- package/dist/esm/{import-protection-plugin → import-protection}/utils.d.ts +18 -1
- package/dist/esm/{import-protection-plugin → import-protection}/utils.js +13 -20
- package/dist/esm/import-protection/utils.js.map +1 -0
- package/dist/esm/import-protection/virtualModules.d.ts +25 -0
- package/dist/esm/{import-protection-plugin → import-protection}/virtualModules.js +5 -117
- package/dist/esm/import-protection/virtualModules.js.map +1 -0
- package/dist/esm/index.d.ts +1 -5
- package/dist/esm/index.js +2 -4
- package/dist/esm/post-build.d.ts +9 -0
- package/dist/esm/post-build.js +37 -0
- package/dist/esm/post-build.js.map +1 -0
- package/dist/esm/prerender.d.ts +11 -0
- package/dist/esm/prerender.js +159 -0
- package/dist/esm/prerender.js.map +1 -0
- package/dist/esm/rsbuild/dev-server.d.ts +21 -0
- package/dist/esm/rsbuild/dev-server.js +76 -0
- package/dist/esm/rsbuild/dev-server.js.map +1 -0
- package/dist/esm/rsbuild/import-protection.d.ts +10 -0
- package/dist/esm/rsbuild/import-protection.js +775 -0
- package/dist/esm/rsbuild/import-protection.js.map +1 -0
- package/dist/esm/rsbuild/index.d.ts +4 -0
- package/dist/esm/rsbuild/index.js +3 -0
- package/dist/esm/rsbuild/normalized-client-build.d.ts +18 -0
- package/dist/esm/rsbuild/normalized-client-build.js +207 -0
- package/dist/esm/rsbuild/normalized-client-build.js.map +1 -0
- package/dist/esm/rsbuild/planning.d.ts +52 -0
- package/dist/esm/rsbuild/planning.js +108 -0
- package/dist/esm/rsbuild/planning.js.map +1 -0
- package/dist/esm/rsbuild/plugin.d.ts +4 -0
- package/dist/esm/rsbuild/plugin.js +344 -0
- package/dist/esm/rsbuild/plugin.js.map +1 -0
- package/dist/esm/rsbuild/post-build.d.ts +6 -0
- package/dist/esm/rsbuild/post-build.js +57 -0
- package/dist/esm/rsbuild/post-build.js.map +1 -0
- package/dist/esm/rsbuild/schema.d.ts +3372 -0
- package/dist/esm/rsbuild/schema.js +12 -0
- package/dist/esm/rsbuild/schema.js.map +1 -0
- package/dist/esm/rsbuild/start-compiler-host.d.ts +20 -0
- package/dist/esm/rsbuild/start-compiler-host.js +150 -0
- package/dist/esm/rsbuild/start-compiler-host.js.map +1 -0
- package/dist/esm/rsbuild/start-router-plugin.d.ts +18 -0
- package/dist/esm/rsbuild/start-router-plugin.js +63 -0
- package/dist/esm/rsbuild/start-router-plugin.js.map +1 -0
- package/dist/esm/rsbuild/swc-rsc.d.ts +14 -0
- package/dist/esm/rsbuild/swc-rsc.js +93 -0
- package/dist/esm/rsbuild/swc-rsc.js.map +1 -0
- package/dist/esm/rsbuild/types.d.ts +17 -0
- package/dist/esm/rsbuild/types.js +0 -0
- package/dist/esm/rsbuild/virtual-modules.d.ts +53 -0
- package/dist/esm/rsbuild/virtual-modules.js +287 -0
- package/dist/esm/rsbuild/virtual-modules.js.map +1 -0
- package/dist/esm/schema.d.ts +43 -43
- package/dist/esm/start-compiler/compiler.d.ts +1 -1
- package/dist/esm/start-compiler/compiler.js +80 -9
- package/dist/esm/start-compiler/compiler.js.map +1 -1
- package/dist/esm/start-compiler/handleCreateServerFn.js +9 -0
- package/dist/esm/start-compiler/handleCreateServerFn.js.map +1 -1
- package/dist/esm/start-compiler/host.js +5 -1
- package/dist/esm/start-compiler/host.js.map +1 -1
- package/dist/esm/start-compiler/types.d.ts +1 -0
- package/dist/esm/utils.d.ts +1 -0
- package/dist/esm/utils.js +10 -1
- package/dist/esm/utils.js.map +1 -1
- package/dist/esm/{import-protection-plugin → vite/import-protection-plugin}/plugin.js +41 -92
- package/dist/esm/vite/import-protection-plugin/plugin.js.map +1 -0
- package/dist/esm/{import-protection-plugin → vite/import-protection-plugin}/types.d.ts +5 -5
- package/dist/esm/vite/import-protection-plugin/virtualModules.d.ts +8 -0
- package/dist/esm/vite/import-protection-plugin/virtualModules.js +49 -0
- package/dist/esm/vite/import-protection-plugin/virtualModules.js.map +1 -0
- package/dist/esm/vite/index.d.ts +5 -0
- package/dist/esm/vite/index.js +4 -0
- package/dist/esm/vite/plugin.js +1 -1
- package/dist/esm/vite/plugin.js.map +1 -1
- package/dist/esm/vite/post-server-build.js +14 -32
- package/dist/esm/vite/post-server-build.js.map +1 -1
- package/dist/esm/vite/prerender.d.ts +2 -2
- package/dist/esm/vite/prerender.js +17 -147
- package/dist/esm/vite/prerender.js.map +1 -1
- package/dist/esm/vite/schema.d.ts +23 -23
- package/dist/esm/vite/start-compiler-plugin/hot-update.d.ts +2 -0
- package/dist/esm/vite/start-compiler-plugin/hot-update.js +16 -0
- package/dist/esm/vite/start-compiler-plugin/hot-update.js.map +1 -0
- package/dist/esm/vite/start-compiler-plugin/module-specifier.js +9 -4
- package/dist/esm/vite/start-compiler-plugin/module-specifier.js.map +1 -1
- package/dist/esm/vite/start-compiler-plugin/plugin.js +86 -13
- package/dist/esm/vite/start-compiler-plugin/plugin.js.map +1 -1
- package/package.json +32 -4
- package/src/import-protection/INTERNALS.md +266 -0
- package/src/import-protection/adapterUtils.ts +94 -0
- package/src/import-protection/analysis.ts +853 -0
- package/src/{import-protection-plugin → import-protection}/constants.ts +7 -0
- package/src/import-protection/rewrite.ts +229 -0
- package/src/{import-protection-plugin → import-protection}/sourceLocation.ts +125 -9
- package/src/{import-protection-plugin → import-protection}/trace.ts +0 -1
- package/src/{import-protection-plugin → import-protection}/utils.ts +36 -21
- package/src/{import-protection-plugin → import-protection}/virtualModules.ts +30 -177
- package/src/index.ts +1 -8
- package/src/post-build.ts +64 -0
- package/src/prerender.ts +292 -0
- package/src/rsbuild/INTERNALS-import-protection.md +169 -0
- package/src/rsbuild/dev-server.ts +129 -0
- package/src/rsbuild/import-protection.ts +1599 -0
- package/src/rsbuild/index.ts +4 -0
- package/src/rsbuild/normalized-client-build.ts +346 -0
- package/src/rsbuild/planning.ts +234 -0
- package/src/rsbuild/plugin.ts +754 -0
- package/src/rsbuild/post-build.ts +96 -0
- package/src/rsbuild/schema.ts +31 -0
- package/src/rsbuild/start-compiler-host.ts +250 -0
- package/src/rsbuild/start-router-plugin.ts +86 -0
- package/src/rsbuild/swc-rsc.ts +166 -0
- package/src/rsbuild/types.ts +20 -0
- package/src/rsbuild/virtual-modules.ts +565 -0
- package/src/start-compiler/compiler.ts +153 -19
- package/src/start-compiler/handleCreateServerFn.ts +18 -0
- package/src/start-compiler/types.ts +1 -0
- package/src/utils.ts +14 -0
- package/src/vite/import-protection-plugin/INTERNALS.md +187 -0
- package/src/{import-protection-plugin → vite/import-protection-plugin}/plugin.ts +73 -158
- package/src/{import-protection-plugin → vite/import-protection-plugin}/types.ts +5 -5
- package/src/vite/import-protection-plugin/virtualModules.ts +122 -0
- package/src/vite/index.ts +8 -0
- package/src/vite/plugin.ts +1 -1
- package/src/vite/post-server-build.ts +14 -57
- package/src/vite/prerender.ts +19 -260
- package/src/vite/start-compiler-plugin/hot-update.ts +24 -0
- package/src/vite/start-compiler-plugin/module-specifier.ts +15 -5
- package/src/vite/start-compiler-plugin/plugin.ts +193 -18
- package/dist/esm/import-protection-plugin/ast.js.map +0 -1
- package/dist/esm/import-protection-plugin/constants.d.ts +0 -6
- package/dist/esm/import-protection-plugin/constants.js.map +0 -1
- package/dist/esm/import-protection-plugin/defaults.js.map +0 -1
- package/dist/esm/import-protection-plugin/extensionlessAbsoluteIdResolver.js.map +0 -1
- package/dist/esm/import-protection-plugin/matchers.js.map +0 -1
- package/dist/esm/import-protection-plugin/plugin.js.map +0 -1
- package/dist/esm/import-protection-plugin/postCompileUsage.d.ts +0 -13
- package/dist/esm/import-protection-plugin/postCompileUsage.js +0 -63
- package/dist/esm/import-protection-plugin/postCompileUsage.js.map +0 -1
- package/dist/esm/import-protection-plugin/rewriteDeniedImports.js +0 -205
- package/dist/esm/import-protection-plugin/rewriteDeniedImports.js.map +0 -1
- package/dist/esm/import-protection-plugin/sourceLocation.js.map +0 -1
- package/dist/esm/import-protection-plugin/trace.js.map +0 -1
- package/dist/esm/import-protection-plugin/utils.js.map +0 -1
- package/dist/esm/import-protection-plugin/virtualModules.d.ts +0 -78
- package/dist/esm/import-protection-plugin/virtualModules.js.map +0 -1
- package/dist/esm/start-compiler/load-module.d.ts +0 -14
- package/dist/esm/start-compiler/load-module.js +0 -18
- package/dist/esm/start-compiler/load-module.js.map +0 -1
- package/src/import-protection-plugin/INTERNALS.md +0 -700
- package/src/import-protection-plugin/postCompileUsage.ts +0 -100
- package/src/import-protection-plugin/rewriteDeniedImports.ts +0 -379
- package/src/start-compiler/load-module.ts +0 -31
- /package/dist/esm/{import-protection-plugin → import-protection}/ast.d.ts +0 -0
- /package/dist/esm/{import-protection-plugin → import-protection}/defaults.d.ts +0 -0
- /package/dist/esm/{import-protection-plugin → import-protection}/extensionlessAbsoluteIdResolver.d.ts +0 -0
- /package/dist/esm/{import-protection-plugin → import-protection}/matchers.d.ts +0 -0
- /package/dist/esm/{import-protection-plugin → vite/import-protection-plugin}/plugin.d.ts +0 -0
- /package/src/{import-protection-plugin → import-protection}/ast.ts +0 -0
- /package/src/{import-protection-plugin → import-protection}/defaults.ts +0 -0
- /package/src/{import-protection-plugin → import-protection}/extensionlessAbsoluteIdResolver.ts +0 -0
- /package/src/{import-protection-plugin → import-protection}/matchers.ts +0 -0
|
@@ -13,6 +13,7 @@ import { handleCreateMiddleware } from './handleCreateMiddleware'
|
|
|
13
13
|
import { handleCreateIsomorphicFn } from './handleCreateIsomorphicFn'
|
|
14
14
|
import { handleEnvOnlyFn } from './handleEnvOnly'
|
|
15
15
|
import { handleClientOnlyJSX } from './handleClientOnlyJSX'
|
|
16
|
+
import { cleanId } from './utils'
|
|
16
17
|
import type {
|
|
17
18
|
CompilationContext,
|
|
18
19
|
DevServerFnModuleSpecifierEncoder,
|
|
@@ -259,6 +260,19 @@ function isNestedDirectCallCandidate(node: t.CallExpression): boolean {
|
|
|
259
260
|
return calleeName !== undefined && DirectCallFactoryNames.has(calleeName)
|
|
260
261
|
}
|
|
261
262
|
|
|
263
|
+
function isSimpleDirectCallExpression(node: t.CallExpression): boolean {
|
|
264
|
+
return (
|
|
265
|
+
t.isIdentifier(node.callee) ||
|
|
266
|
+
(t.isMemberExpression(node.callee) &&
|
|
267
|
+
t.isIdentifier(node.callee.object) &&
|
|
268
|
+
t.isIdentifier(node.callee.property))
|
|
269
|
+
)
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function isTopLevelDirectCallCandidateNode(node: t.CallExpression): boolean {
|
|
273
|
+
return isSimpleDirectCallExpression(node)
|
|
274
|
+
}
|
|
275
|
+
|
|
262
276
|
/**
|
|
263
277
|
* Checks if a CallExpression path is a top-level direct-call candidate.
|
|
264
278
|
* Top-level means the call is the init of a VariableDeclarator at program level.
|
|
@@ -272,13 +286,7 @@ function isTopLevelDirectCallCandidate(
|
|
|
272
286
|
const node = path.node
|
|
273
287
|
|
|
274
288
|
// Must be a simple identifier call or namespace call
|
|
275
|
-
|
|
276
|
-
t.isIdentifier(node.callee) ||
|
|
277
|
-
(t.isMemberExpression(node.callee) &&
|
|
278
|
-
t.isIdentifier(node.callee.object) &&
|
|
279
|
-
t.isIdentifier(node.callee.property))
|
|
280
|
-
|
|
281
|
-
if (!isSimpleCall) {
|
|
289
|
+
if (!isSimpleDirectCallExpression(node)) {
|
|
282
290
|
return false
|
|
283
291
|
}
|
|
284
292
|
|
|
@@ -294,6 +302,12 @@ function isTopLevelDirectCallCandidate(
|
|
|
294
302
|
return t.isProgram(path.parentPath.parentPath?.parent)
|
|
295
303
|
}
|
|
296
304
|
|
|
305
|
+
function isDirectCallCandidateForKind(
|
|
306
|
+
kind: Exclude<LookupKind, 'ClientOnlyJSX'>,
|
|
307
|
+
): boolean {
|
|
308
|
+
return LookupSetup[kind].type === 'directCall'
|
|
309
|
+
}
|
|
310
|
+
|
|
297
311
|
export class StartCompiler {
|
|
298
312
|
private moduleCache = new Map<string, ModuleInfo>()
|
|
299
313
|
private initialized = false
|
|
@@ -530,7 +544,6 @@ export class StartCompiler {
|
|
|
530
544
|
|
|
531
545
|
/**
|
|
532
546
|
* Extracts bindings and exports from an already-parsed AST.
|
|
533
|
-
* This is the core logic shared by ingestModule and ingestModuleFromAst.
|
|
534
547
|
*/
|
|
535
548
|
private extractModuleInfo(
|
|
536
549
|
ast: ReturnType<typeof parseAst>,
|
|
@@ -642,10 +655,105 @@ export class StartCompiler {
|
|
|
642
655
|
}
|
|
643
656
|
|
|
644
657
|
public invalidateModule(id: string) {
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
658
|
+
const normalizedId = cleanId(id)
|
|
659
|
+
let hasCachedModule = false
|
|
660
|
+
|
|
661
|
+
for (const moduleId of Array.from(this.moduleCache.keys())) {
|
|
662
|
+
if (cleanId(moduleId) === normalizedId) {
|
|
663
|
+
this.moduleCache.delete(moduleId)
|
|
664
|
+
hasCachedModule = true
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// Root import metadata is synthetic compiler state and should survive HMR.
|
|
669
|
+
// The stale dev state lives in per-module resolvedKind memoization.
|
|
670
|
+
for (const [moduleId, moduleInfo] of this.moduleCache) {
|
|
671
|
+
if (this.knownRootImports.has(moduleId)) {
|
|
672
|
+
continue
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
for (const binding of moduleInfo.bindings.values()) {
|
|
676
|
+
binding.resolvedKind = undefined
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// Build-mode caches are cheap to rebuild and may point at removed entries.
|
|
681
|
+
this.resolveIdCache.clear()
|
|
682
|
+
this.exportResolutionCache.clear()
|
|
683
|
+
|
|
684
|
+
return hasCachedModule
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
public async getTransitiveImporters(id: string): Promise<Set<string>> {
|
|
688
|
+
const discoveredImporters = new Set<string>()
|
|
689
|
+
const pendingTargets = [cleanId(id)]
|
|
690
|
+
const visitedTargets = new Set<string>()
|
|
691
|
+
const resolveCache = new Map<string, Promise<string | null>>()
|
|
692
|
+
|
|
693
|
+
const resolveSource = (source: string, importer: string) => {
|
|
694
|
+
const cacheKey = `${importer}::${source}`
|
|
695
|
+
let resolved = resolveCache.get(cacheKey)
|
|
696
|
+
|
|
697
|
+
if (!resolved) {
|
|
698
|
+
resolved = this.resolveIdCached(source, importer)
|
|
699
|
+
resolveCache.set(cacheKey, resolved)
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
return resolved
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
while (pendingTargets.length > 0) {
|
|
706
|
+
const targetId = pendingTargets.pop()!
|
|
707
|
+
|
|
708
|
+
if (visitedTargets.has(targetId)) {
|
|
709
|
+
continue
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
visitedTargets.add(targetId)
|
|
713
|
+
|
|
714
|
+
const importerIds = await Promise.all(
|
|
715
|
+
Array.from(this.moduleCache.values()).map(async (moduleInfo) => {
|
|
716
|
+
if (this.knownRootImports.has(moduleInfo.id)) {
|
|
717
|
+
return null
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
const moduleId = cleanId(moduleInfo.id)
|
|
721
|
+
|
|
722
|
+
if (moduleId === targetId) {
|
|
723
|
+
return null
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
const importSources = new Set(moduleInfo.reExportAllSources)
|
|
727
|
+
|
|
728
|
+
for (const binding of moduleInfo.bindings.values()) {
|
|
729
|
+
if (binding.type === 'import') {
|
|
730
|
+
importSources.add(binding.source)
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
for (const source of importSources) {
|
|
735
|
+
const resolved = await resolveSource(source, moduleInfo.id)
|
|
736
|
+
|
|
737
|
+
if (resolved && cleanId(resolved) === targetId) {
|
|
738
|
+
return moduleId
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
return null
|
|
743
|
+
}),
|
|
744
|
+
)
|
|
745
|
+
|
|
746
|
+
for (const importerId of importerIds) {
|
|
747
|
+
if (!importerId || discoveredImporters.has(importerId)) {
|
|
748
|
+
continue
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
discoveredImporters.add(importerId)
|
|
752
|
+
pendingTargets.push(importerId)
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
return discoveredImporters
|
|
649
757
|
}
|
|
650
758
|
|
|
651
759
|
public async compile({
|
|
@@ -719,7 +827,10 @@ export class StartCompiler {
|
|
|
719
827
|
if (declarations) {
|
|
720
828
|
for (const decl of declarations) {
|
|
721
829
|
if (decl.init && t.isCallExpression(decl.init)) {
|
|
722
|
-
if (
|
|
830
|
+
if (
|
|
831
|
+
isMethodChainCandidate(decl.init, fileKinds) ||
|
|
832
|
+
isTopLevelDirectCallCandidateNode(decl.init)
|
|
833
|
+
) {
|
|
723
834
|
candidateIndices.push(i)
|
|
724
835
|
break // Only need to mark this statement once
|
|
725
836
|
}
|
|
@@ -760,6 +871,11 @@ export class StartCompiler {
|
|
|
760
871
|
// Method chain pattern
|
|
761
872
|
if (isMethodChainCandidate(node, fileKinds)) {
|
|
762
873
|
candidatePaths.push(path)
|
|
874
|
+
return
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
if (isTopLevelDirectCallCandidate(path)) {
|
|
878
|
+
candidatePaths.push(path)
|
|
763
879
|
}
|
|
764
880
|
},
|
|
765
881
|
})
|
|
@@ -792,11 +908,14 @@ export class StartCompiler {
|
|
|
792
908
|
return
|
|
793
909
|
}
|
|
794
910
|
|
|
911
|
+
if (isTopLevelDirectCallCandidate(path)) {
|
|
912
|
+
candidatePaths.push(path)
|
|
913
|
+
return
|
|
914
|
+
}
|
|
915
|
+
|
|
795
916
|
// Pattern 2: Direct call pattern
|
|
796
917
|
if (checkDirectCalls) {
|
|
797
|
-
if (
|
|
798
|
-
candidatePaths.push(path)
|
|
799
|
-
} else if (isNestedDirectCallCandidate(node)) {
|
|
918
|
+
if (isNestedDirectCallCandidate(node)) {
|
|
800
919
|
candidatePaths.push(path)
|
|
801
920
|
}
|
|
802
921
|
}
|
|
@@ -845,9 +964,23 @@ export class StartCompiler {
|
|
|
845
964
|
)
|
|
846
965
|
|
|
847
966
|
// Filter to valid candidates
|
|
848
|
-
const validCandidates = resolvedCandidates.filter(({ kind }) =>
|
|
849
|
-
|
|
850
|
-
|
|
967
|
+
const validCandidates = resolvedCandidates.filter(({ path, kind }) => {
|
|
968
|
+
if (
|
|
969
|
+
!this.validLookupKinds.has(kind as Exclude<LookupKind, 'ClientOnlyJSX'>)
|
|
970
|
+
) {
|
|
971
|
+
return false
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
if (
|
|
975
|
+
isLookupKind(kind) &&
|
|
976
|
+
kind !== 'ClientOnlyJSX' &&
|
|
977
|
+
!isMethodChainCandidate(path.node, fileKinds)
|
|
978
|
+
) {
|
|
979
|
+
return isDirectCallCandidateForKind(kind)
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
return true
|
|
983
|
+
}) as Array<{
|
|
851
984
|
path: babel.NodePath<t.CallExpression>
|
|
852
985
|
kind: Exclude<LookupKind, 'ClientOnlyJSX'>
|
|
853
986
|
}>
|
|
@@ -925,6 +1058,7 @@ export class StartCompiler {
|
|
|
925
1058
|
code,
|
|
926
1059
|
env: this.options.env,
|
|
927
1060
|
envName: this.options.envName,
|
|
1061
|
+
mode: this.mode,
|
|
928
1062
|
root: this.options.root,
|
|
929
1063
|
framework: this.options.framework,
|
|
930
1064
|
providerEnvName: this.options.providerEnvName,
|
|
@@ -7,6 +7,20 @@ import type { CompileStartFrameworkOptions } from '../types'
|
|
|
7
7
|
|
|
8
8
|
const TSS_SERVERFN_SPLIT_PARAM = 'tss-serverfn-split'
|
|
9
9
|
|
|
10
|
+
const providerHmrAcceptTemplate = babel.template.statements(
|
|
11
|
+
`
|
|
12
|
+
if (import.meta.hot) {
|
|
13
|
+
import.meta.hot.accept(() => {})
|
|
14
|
+
}
|
|
15
|
+
if (import.meta.webpackHot) {
|
|
16
|
+
import.meta.webpackHot.accept(() => {})
|
|
17
|
+
}
|
|
18
|
+
`,
|
|
19
|
+
{
|
|
20
|
+
placeholderPattern: false,
|
|
21
|
+
},
|
|
22
|
+
)
|
|
23
|
+
|
|
10
24
|
// ============================================================================
|
|
11
25
|
// Pre-compiled babel templates (compiled once at module load time)
|
|
12
26
|
// ============================================================================
|
|
@@ -414,6 +428,10 @@ export function handleCreateServerFn(
|
|
|
414
428
|
),
|
|
415
429
|
)
|
|
416
430
|
}
|
|
431
|
+
|
|
432
|
+
if (context.mode === 'dev') {
|
|
433
|
+
context.ast.program.body.push(...providerHmrAcceptTemplate())
|
|
434
|
+
}
|
|
417
435
|
}
|
|
418
436
|
|
|
419
437
|
// Notify about discovered functions (only for non-provider files)
|
|
@@ -12,6 +12,7 @@ export interface CompilationContext {
|
|
|
12
12
|
readonly id: string
|
|
13
13
|
readonly env: 'client' | 'server'
|
|
14
14
|
readonly envName: string
|
|
15
|
+
readonly mode: 'dev' | 'build'
|
|
15
16
|
readonly root: string
|
|
16
17
|
/** The framework being used (e.g., 'react', 'solid') */
|
|
17
18
|
readonly framework: CompileStartFrameworkOptions
|
package/src/utils.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
|
|
3
|
+
const isWindows: boolean =
|
|
4
|
+
typeof process !== 'undefined' && process.platform === 'win32'
|
|
5
|
+
const windowsSlashRE = /\\/g
|
|
6
|
+
|
|
1
7
|
/** Read `build.rollupOptions` or `build.rolldownOptions` from a build config. */
|
|
2
8
|
export function getBundlerOptions(build: any): any {
|
|
3
9
|
return build?.rolldownOptions ?? build?.rollupOptions
|
|
@@ -17,3 +23,11 @@ export function createLogger(prefix: string) {
|
|
|
17
23
|
error: (...args: any) => console.error(label, ...args),
|
|
18
24
|
}
|
|
19
25
|
}
|
|
26
|
+
|
|
27
|
+
function slash(path: string): string {
|
|
28
|
+
return path.replace(windowsSlashRE, '/')
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function normalizePath(id: string): string {
|
|
32
|
+
return path.posix.normalize(isWindows ? slash(id) : id)
|
|
33
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Vite Import Protection - Adapter Internals
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
|
|
5
|
+
This document covers the Vite-specific orchestration around the shared
|
|
6
|
+
import-protection core in `src/import-protection/INTERNALS.md`.
|
|
7
|
+
|
|
8
|
+
Vite owns:
|
|
9
|
+
|
|
10
|
+
- `resolveId`-first violation discovery
|
|
11
|
+
- dev/build deferral decisions tied to Vite lifecycle hooks
|
|
12
|
+
- the transform-cache plugin and post-transform graph bookkeeping
|
|
13
|
+
- Vite virtual-module id resolution and loading
|
|
14
|
+
- bundle-time survival checks in `generateBundle`
|
|
15
|
+
|
|
16
|
+
Shared AST analysis, rewrite logic, source extraction, mock export discovery,
|
|
17
|
+
usage lookup, source locations, and mock code generation are described in the
|
|
18
|
+
shared internals doc.
|
|
19
|
+
|
|
20
|
+
## Plugin Shape
|
|
21
|
+
|
|
22
|
+
`importProtectionPlugin()` returns two Vite plugins:
|
|
23
|
+
|
|
24
|
+
1. `tanstack-start-core:import-protection`
|
|
25
|
+
2. `tanstack-start-core:import-protection-transform-cache`
|
|
26
|
+
|
|
27
|
+
The first plugin owns resolve-time detection and reporting decisions. The
|
|
28
|
+
second plugin owns transformed-result caching, post-transform import graph
|
|
29
|
+
updates, self-denial transforms, and dev pending-violation verification.
|
|
30
|
+
|
|
31
|
+
## Why Vite Uses Two Plugins
|
|
32
|
+
|
|
33
|
+
Vite discovers many violations in `resolveId`, but accurate source locations and
|
|
34
|
+
post-transform graph truth require transformed code that only exists later.
|
|
35
|
+
|
|
36
|
+
So the adapter splits responsibilities:
|
|
37
|
+
|
|
38
|
+
- `resolveId`: detect, classify, defer/report, substitute mock ids where needed
|
|
39
|
+
- later transform hook: cache transformed code/maps, self-deny files, compute
|
|
40
|
+
post-transform imports, and process pending violations
|
|
41
|
+
|
|
42
|
+
## Vite State Model
|
|
43
|
+
|
|
44
|
+
Per environment, Vite keeps `EnvState` with:
|
|
45
|
+
|
|
46
|
+
- `graph`
|
|
47
|
+
- `mockExportsByImporter`
|
|
48
|
+
- `resolveCache`
|
|
49
|
+
- `resolveCacheByFile`
|
|
50
|
+
- `importLocCache`
|
|
51
|
+
- `seenViolations`
|
|
52
|
+
- `serverFnLookupModules`
|
|
53
|
+
- `transformResultCache`
|
|
54
|
+
- `transformResultKeysByFile`
|
|
55
|
+
- `transformResultProvider`
|
|
56
|
+
- `postTransformImports`
|
|
57
|
+
- `pendingViolations`
|
|
58
|
+
- `deferredBuildViolations`
|
|
59
|
+
|
|
60
|
+
Cross-environment shared state is intentionally small:
|
|
61
|
+
|
|
62
|
+
- `fileMarkerKind`
|
|
63
|
+
|
|
64
|
+
This is larger than the Rsbuild state model because Vite must bridge resolve-
|
|
65
|
+
time detection with later transform/bundle verification.
|
|
66
|
+
|
|
67
|
+
## Detection Flow
|
|
68
|
+
|
|
69
|
+
Vite is `resolveId`-driven.
|
|
70
|
+
|
|
71
|
+
That means the adapter may see violations before:
|
|
72
|
+
|
|
73
|
+
- the Start compiler removes safe-boundary imports
|
|
74
|
+
- tree-shaking removes false-positive edges
|
|
75
|
+
- transformed importer code is available
|
|
76
|
+
|
|
77
|
+
So Vite must decide whether to report immediately or defer.
|
|
78
|
+
|
|
79
|
+
## Deferral Policy
|
|
80
|
+
|
|
81
|
+
The shared helper is:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
shouldDefer = isBuild || isDevMock
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Adapter meaning:
|
|
88
|
+
|
|
89
|
+
- dev + error: report immediately with `ctx.error()`
|
|
90
|
+
- dev + mock: store `pendingViolations`, then verify later from post-transform
|
|
91
|
+
edges and reachability
|
|
92
|
+
- build + mock/error: store `deferredBuildViolations`, then verify in
|
|
93
|
+
`generateBundle`
|
|
94
|
+
|
|
95
|
+
This is the main adapter-specific state machine difference from Rsbuild.
|
|
96
|
+
|
|
97
|
+
## Dev Strategy
|
|
98
|
+
|
|
99
|
+
### Dev + Error
|
|
100
|
+
|
|
101
|
+
Vite throws immediately in `resolveId`.
|
|
102
|
+
|
|
103
|
+
This is intentionally aggressive and can still produce known barrel false
|
|
104
|
+
positives because there is no tree-shaking in the dev server.
|
|
105
|
+
|
|
106
|
+
Pre-transform resolve paths like `SERVER_FN_LOOKUP` are silenced in this mode
|
|
107
|
+
because there is no later deferred verification path.
|
|
108
|
+
|
|
109
|
+
### Dev + Mock
|
|
110
|
+
|
|
111
|
+
Vite defers all violations into `pendingViolations`.
|
|
112
|
+
|
|
113
|
+
Later, the transform-cache plugin:
|
|
114
|
+
|
|
115
|
+
1. caches transformed code and sourcemaps
|
|
116
|
+
2. resolves post-transform imports
|
|
117
|
+
3. records graph edges from transformed code
|
|
118
|
+
4. runs `processPendingViolations()`
|
|
119
|
+
|
|
120
|
+
Pending verification uses two checks:
|
|
121
|
+
|
|
122
|
+
1. edge survival after the Start compiler transform
|
|
123
|
+
2. graph reachability from entries using post-transform edges
|
|
124
|
+
|
|
125
|
+
This is how Vite suppresses many dev false positives without bundling.
|
|
126
|
+
|
|
127
|
+
## Build Strategy
|
|
128
|
+
|
|
129
|
+
Vite build uses mock-first, verify-later behavior.
|
|
130
|
+
|
|
131
|
+
At resolve time it substitutes mocks silently and records deferred violations.
|
|
132
|
+
At `generateBundle`, it checks whether each unique mock id survived tree-
|
|
133
|
+
shaking.
|
|
134
|
+
|
|
135
|
+
If the mock survived:
|
|
136
|
+
|
|
137
|
+
- error mode: fail the build
|
|
138
|
+
- mock mode: emit a warning
|
|
139
|
+
|
|
140
|
+
If the mock was removed, the violation is suppressed as a false positive.
|
|
141
|
+
|
|
142
|
+
## Self-Denial In Vite
|
|
143
|
+
|
|
144
|
+
For file-based violations, `resolveId` does not return a virtual mock id.
|
|
145
|
+
Instead it returns the physical file path, and the later transform-cache plugin
|
|
146
|
+
replaces the file contents with a mock module.
|
|
147
|
+
|
|
148
|
+
This Vite-specific choice exists for two reasons:
|
|
149
|
+
|
|
150
|
+
- avoid cross-environment cache contamination in shared resolver caches
|
|
151
|
+
- avoid cold-start export-resolution issues when importer AST data is not yet
|
|
152
|
+
available
|
|
153
|
+
|
|
154
|
+
## Vite Virtual Modules
|
|
155
|
+
|
|
156
|
+
The shared mock generators use abstract ids like:
|
|
157
|
+
|
|
158
|
+
- `\0tanstack-start-import-protection:mock`
|
|
159
|
+
- `\0tanstack-start-import-protection:mock-edge:...`
|
|
160
|
+
- `\0tanstack-start-import-protection:mock-runtime:...`
|
|
161
|
+
- `\0tanstack-start-import-protection:marker:*`
|
|
162
|
+
|
|
163
|
+
The Vite adapter adds:
|
|
164
|
+
|
|
165
|
+
- resolved Vite ids via `resolveViteId(...)`
|
|
166
|
+
- support for browser-prefixed ids via `__x00__`
|
|
167
|
+
- `loadResolvedVirtualModule()` for serving the generated code
|
|
168
|
+
|
|
169
|
+
This id transport is adapter-specific. The generated module contents are shared.
|
|
170
|
+
|
|
171
|
+
## Warm-Start Considerations
|
|
172
|
+
|
|
173
|
+
Vite can skip `resolveId` on warm cache hits, so the adapter maintains its own
|
|
174
|
+
graph and transform-result caches to recover enough information for traces and
|
|
175
|
+
pending-violation verification.
|
|
176
|
+
|
|
177
|
+
Special care is taken not to treat pre-transform lookup edges as authoritative
|
|
178
|
+
reachability edges.
|
|
179
|
+
|
|
180
|
+
## Practical Maintainer Rule
|
|
181
|
+
|
|
182
|
+
When changing Vite import protection, ask:
|
|
183
|
+
|
|
184
|
+
1. Is this really about Vite lifecycle timing or state?
|
|
185
|
+
2. If not, should it move into the shared import-protection core?
|
|
186
|
+
3. If yes, does it belong in resolve-time detection, transform-cache handling,
|
|
187
|
+
or bundle-time verification?
|