@octanejs/tanstack-start 0.1.1 → 0.1.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/package.json +13 -8
- package/src/GenericHydrate.tsrx +396 -0
- package/src/GenericHydrate.tsrx.d.ts +5 -0
- package/src/Hydrate.tsrx +106 -0
- package/src/Hydrate.tsrx.d.ts +63 -0
- package/src/client-only-server-strip.js +461 -0
- package/src/hydration/generic.d.ts +18 -0
- package/src/hydration/generic.js +26 -0
- package/src/hydration/idle.d.ts +9 -0
- package/src/hydration/idle.js +10 -0
- package/src/hydration/load.tsrx +38 -0
- package/src/hydration/load.tsrx.d.ts +8 -0
- package/src/hydration/never.tsrx +71 -0
- package/src/hydration/never.tsrx.d.ts +6 -0
- package/src/hydration/visible.tsrx +123 -0
- package/src/hydration/visible.tsrx.d.ts +12 -0
- package/src/hydration.d.ts +20 -0
- package/src/hydration.js +8 -0
- package/src/index.d.ts +11 -0
- package/src/index.js +2 -0
- package/src/internal/router-generator/filesystem/physical/getRouteNodes.js +4 -6
- package/src/internal/router-generator/generator.js +3 -0
- package/src/internal/router-plugin/core/code-splitter/compilers.js +3 -6
- package/src/internal/router-plugin/core/config.d.ts +1 -3
- package/src/internal/router-plugin/core/router-code-splitter-plugin.js +6 -3
- package/src/internal/router-plugin/esbuild.d.ts +4 -10
- package/src/internal/router-plugin/vite.d.ts +4 -10
- package/src/internal/start-plugin-core/import-protection/analysis.js +13 -12
- package/src/internal/start-plugin-core/import-protection/constants.d.ts +0 -1
- package/src/internal/start-plugin-core/import-protection/constants.js +0 -3
- package/src/internal/start-plugin-core/schema.d.ts +4 -14
- package/src/internal/start-plugin-core/start-compiler/compiler.d.ts +1 -6
- package/src/internal/start-plugin-core/start-compiler/compiler.js +4 -4
- package/src/internal/start-plugin-core/start-compiler/utils.d.ts +7 -0
- package/src/internal/start-plugin-core/start-compiler/utils.js +7 -0
- package/src/internal/start-plugin-core/types.d.ts +1 -2
- package/src/internal/start-plugin-core/vite/import-protection-plugin/plugin.js +21 -21
- package/src/internal/start-plugin-core/vite/module-id.d.ts +6 -0
- package/src/internal/start-plugin-core/vite/module-id.js +23 -0
- package/src/internal/start-plugin-core/vite/schema.d.ts +3 -12
- package/src/internal/start-plugin-core/vite/start-compiler-plugin/plugin.js +9 -3
- package/src/plugin-vite.d.ts +9 -1
- package/src/plugin-vite.js +20 -1
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// visible hydration strategy — port of @tanstack/react-start-client's
|
|
2
|
+
// hydration/visible.tsx. Fully self-contained fast path (no shared gate
|
|
3
|
+
// registry): a per-instance promise gate resolved by an IntersectionObserver.
|
|
4
|
+
// `reactUse` feature-detection is dropped — octane's `use` always exists.
|
|
5
|
+
//
|
|
6
|
+
// OCTANE ADAPTATION: upstream's VisibleHydrate is bare-called as a method
|
|
7
|
+
// (`props.when._h(props)`) with the strategy as `this`, running its hooks on
|
|
8
|
+
// the caller's fiber. Octane's compiled components take the
|
|
9
|
+
// `(props, __s, __extra)` ABI and cannot be bare-called, so octane's `Hydrate`
|
|
10
|
+
// renders `_h` as a child component and VisibleHydrate derives its strategy
|
|
11
|
+
// from `props.when` instead of `this` (resolving a function-valued `when` per
|
|
12
|
+
// render, exactly as upstream's Hydrate does).
|
|
13
|
+
import { Suspense, use, useEffect, useRef, useState } from 'octane';
|
|
14
|
+
import type { OctaneNode } from 'octane';
|
|
15
|
+
import { isServer } from '@tanstack/router-core/isServer';
|
|
16
|
+
import type {
|
|
17
|
+
HydrationPrefetchStrategy,
|
|
18
|
+
VisibleHydrationOptions,
|
|
19
|
+
} from '@tanstack/start-client-core/hydration';
|
|
20
|
+
import type { HydrateProps, InternalHydrateProps, OctaneHydrationStrategy } from '../Hydrate.tsrx';
|
|
21
|
+
|
|
22
|
+
type VisibleGate = {
|
|
23
|
+
p: Promise<void>;
|
|
24
|
+
r: boolean;
|
|
25
|
+
s: () => void;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
function HydrationBoundary(props: { g: VisibleGate; o?: () => void; children?: OctaneNode }) {
|
|
29
|
+
const { g, o } = props;
|
|
30
|
+
|
|
31
|
+
if (!g.r) {
|
|
32
|
+
use(g.p);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
o?.();
|
|
37
|
+
}, [o]);
|
|
38
|
+
|
|
39
|
+
return props.children;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function VisibleHydrate(props: HydrateProps) @{
|
|
43
|
+
const when = props.when;
|
|
44
|
+
const strategy = (typeof when === 'function' ? when() : when) as OctaneHydrationStrategy<
|
|
45
|
+
'visible',
|
|
46
|
+
true
|
|
47
|
+
>;
|
|
48
|
+
const prefetchStrategy = props.prefetch;
|
|
49
|
+
const preload = (props as InternalHydrateProps).p;
|
|
50
|
+
const markerRef = useRef<HTMLDivElement | null>(null);
|
|
51
|
+
const [gate] = useState<VisibleGate>(() => {
|
|
52
|
+
let resolvePromise: () => void;
|
|
53
|
+
const nextGate: VisibleGate = {
|
|
54
|
+
p: new Promise<void>((resolve) => {
|
|
55
|
+
resolvePromise = resolve;
|
|
56
|
+
}),
|
|
57
|
+
r: false,
|
|
58
|
+
s: () => {
|
|
59
|
+
nextGate.r = true;
|
|
60
|
+
resolvePromise();
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
if (isServer ?? typeof window === 'undefined') {
|
|
64
|
+
nextGate.s();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return nextGate;
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
if (!preload || typeof prefetchStrategy === 'function') {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return prefetchStrategy?._s?.({
|
|
76
|
+
element: markerRef.current,
|
|
77
|
+
prefetch: preload,
|
|
78
|
+
});
|
|
79
|
+
}, [prefetchStrategy, preload]);
|
|
80
|
+
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (gate.r) return;
|
|
83
|
+
|
|
84
|
+
return strategy._s?.({
|
|
85
|
+
element: markerRef.current,
|
|
86
|
+
gate: gate as never,
|
|
87
|
+
});
|
|
88
|
+
}, [gate, strategy]);
|
|
89
|
+
|
|
90
|
+
<div ref={markerRef}>
|
|
91
|
+
<Suspense fallback={props.fallback}>
|
|
92
|
+
<HydrationBoundary g={gate} o={props.onHydrated}>{props.children}</HydrationBoundary>
|
|
93
|
+
</Suspense>
|
|
94
|
+
</div>
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
98
|
+
export function visible(
|
|
99
|
+
options?: VisibleHydrationOptions,
|
|
100
|
+
): OctaneHydrationStrategy<'visible', true> & HydrationPrefetchStrategy<'visible'> {
|
|
101
|
+
const rootMargin = options?.rootMargin ?? '600px';
|
|
102
|
+
const threshold = options?.threshold ?? 0;
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
_s: ({ element, gate, prefetch }) => {
|
|
106
|
+
const callback = prefetch || (gate as never as VisibleGate).s;
|
|
107
|
+
|
|
108
|
+
if (!element) {
|
|
109
|
+
callback();
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const observer = new IntersectionObserver((entries) => {
|
|
114
|
+
if (!entries[0]!.isIntersecting) return;
|
|
115
|
+
observer.disconnect();
|
|
116
|
+
callback();
|
|
117
|
+
}, { rootMargin, threshold });
|
|
118
|
+
observer.observe(element);
|
|
119
|
+
return () => observer.disconnect();
|
|
120
|
+
},
|
|
121
|
+
_h: VisibleHydrate,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { OctaneNode } from 'octane';
|
|
2
|
+
import type {
|
|
3
|
+
HydrationPrefetchStrategy,
|
|
4
|
+
VisibleHydrationOptions,
|
|
5
|
+
} from '@tanstack/start-client-core/hydration';
|
|
6
|
+
import type { HydrateProps, OctaneHydrationStrategy } from '../Hydrate.tsrx';
|
|
7
|
+
|
|
8
|
+
export declare function VisibleHydrate(props: HydrateProps): OctaneNode;
|
|
9
|
+
|
|
10
|
+
export declare function visible(
|
|
11
|
+
options?: VisibleHydrationOptions,
|
|
12
|
+
): OctaneHydrationStrategy<'visible', true> & HydrationPrefetchStrategy<'visible'>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export { condition, interaction, media } from './hydration/generic.js';
|
|
2
|
+
export { idle } from './hydration/idle.js';
|
|
3
|
+
export { load } from './hydration/load.tsrx';
|
|
4
|
+
export { never } from './hydration/never.tsrx';
|
|
5
|
+
export { visible } from './hydration/visible.tsrx';
|
|
6
|
+
export type {
|
|
7
|
+
HydrationCondition,
|
|
8
|
+
HydrationInteractionEvent,
|
|
9
|
+
HydrationInteractionEvents,
|
|
10
|
+
IdleHydrationOptions,
|
|
11
|
+
HydrationPrefetchContext,
|
|
12
|
+
HydrationPrefetchFunction,
|
|
13
|
+
HydrationPrefetchWhen,
|
|
14
|
+
HydrationPrefetchStrategy,
|
|
15
|
+
HydrationPrefetchWaitReason,
|
|
16
|
+
HydrationStrategyTypes,
|
|
17
|
+
HydrationWhen,
|
|
18
|
+
VisibleHydrationOptions,
|
|
19
|
+
} from '@tanstack/start-client-core/hydration';
|
|
20
|
+
export type { HydrationStrategy, OctaneHydrationStrategy } from './Hydrate.tsrx';
|
package/src/hydration.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// `@octanejs/tanstack-start/hydration` — port of @tanstack/react-start's
|
|
2
|
+
// hydration.ts subpath: the hydration strategy factories consumed by
|
|
3
|
+
// `<Hydrate when={...}>`.
|
|
4
|
+
export { condition, interaction, media } from './hydration/generic.js';
|
|
5
|
+
export { idle } from './hydration/idle.js';
|
|
6
|
+
export { load } from './hydration/load.tsrx';
|
|
7
|
+
export { never } from './hydration/never.tsrx';
|
|
8
|
+
export { visible } from './hydration/visible.tsrx';
|
package/src/index.d.ts
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
export { useServerFn } from './use-server-fn.js';
|
|
2
2
|
export * from '@tanstack/start-client-core';
|
|
3
|
+
export { Hydrate } from './Hydrate.tsrx';
|
|
4
|
+
export type {
|
|
5
|
+
HydrateOptions,
|
|
6
|
+
HydrateProps,
|
|
7
|
+
HydrationInteractionEvent,
|
|
8
|
+
HydrationInteractionEvents,
|
|
9
|
+
HydrationPrefetchStrategy,
|
|
10
|
+
HydrationStrategy,
|
|
11
|
+
HydrationWhen,
|
|
12
|
+
OctaneHydrationStrategy,
|
|
13
|
+
} from './Hydrate.tsrx';
|
|
3
14
|
export {
|
|
4
15
|
createClientOnlyFn,
|
|
5
16
|
createCsrfMiddleware,
|
package/src/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useServerFn } from './use-server-fn.js';
|
|
2
|
+
import { Hydrate } from './Hydrate.tsrx';
|
|
2
3
|
import {
|
|
3
4
|
createClientOnlyFn,
|
|
4
5
|
createCsrfMiddleware,
|
|
@@ -11,6 +12,7 @@ import {
|
|
|
11
12
|
|
|
12
13
|
export * from '@tanstack/start-client-core';
|
|
13
14
|
export {
|
|
15
|
+
Hydrate,
|
|
14
16
|
createClientOnlyFn,
|
|
15
17
|
createCsrfMiddleware,
|
|
16
18
|
createIsomorphicFn,
|
|
@@ -180,12 +180,10 @@ async function getRouteNodes(config, root, tokenRegexes) {
|
|
|
180
180
|
}
|
|
181
181
|
const lastOriginalSegment = originalRoutePath.split('/').filter(Boolean).pop() || '';
|
|
182
182
|
const indexTokenCandidate = unwrapBracketWrappedSegment(lastOriginalSegment);
|
|
183
|
-
if (
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
)
|
|
188
|
-
) {
|
|
183
|
+
if (!(
|
|
184
|
+
lastOriginalSegment !== indexTokenCandidate &&
|
|
185
|
+
indexTokenSegmentRegex.test(indexTokenCandidate)
|
|
186
|
+
)) {
|
|
189
187
|
const updatedRouteSegments = routePath.split('/').filter(Boolean);
|
|
190
188
|
const updatedLastRouteSegment =
|
|
191
189
|
updatedRouteSegments[updatedRouteSegments.length - 1] || '';
|
|
@@ -240,6 +240,9 @@ var Generator = class Generator {
|
|
|
240
240
|
} else {
|
|
241
241
|
const unrecoverableErrors = errArray.filter((e) => !isRerun(e));
|
|
242
242
|
this.runPromise = void 0;
|
|
243
|
+
if (process.env.OCTANE_DEBUG_GENERATOR) {
|
|
244
|
+
for (const e of unrecoverableErrors) console.error('[generator-debug]', e);
|
|
245
|
+
}
|
|
243
246
|
throw new Error(unrecoverableErrors.map((e) => e.message).join());
|
|
244
247
|
}
|
|
245
248
|
}
|
|
@@ -836,12 +836,9 @@ function detectCodeSplitGroupingsFromRoute(opts) {
|
|
|
836
836
|
programPath.traverse({
|
|
837
837
|
CallExpression(path) {
|
|
838
838
|
if (!t.isIdentifier(path.node.callee)) return;
|
|
839
|
-
if (
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
path.node.callee.name === 'createFileRoute'
|
|
843
|
-
)
|
|
844
|
-
)
|
|
839
|
+
if (!(
|
|
840
|
+
path.node.callee.name === 'createRoute' || path.node.callee.name === 'createFileRoute'
|
|
841
|
+
))
|
|
845
842
|
return;
|
|
846
843
|
function babelHandleSplittingGroups(routeOptions) {
|
|
847
844
|
if (t.isObjectExpression(routeOptions))
|
|
@@ -251,9 +251,7 @@ export declare const getConfig: (
|
|
|
251
251
|
tmpDir: string;
|
|
252
252
|
importRoutesUsingAbsolutePaths: boolean;
|
|
253
253
|
virtualRouteConfig?:
|
|
254
|
-
|
|
|
255
|
-
| import('@tanstack/virtual-file-routes').VirtualRootRoute
|
|
256
|
-
| undefined;
|
|
254
|
+
string | import('@tanstack/virtual-file-routes').VirtualRootRoute | undefined;
|
|
257
255
|
routeFilePrefix?: string | undefined;
|
|
258
256
|
routeFileIgnorePattern?: string | undefined;
|
|
259
257
|
pathParamsAllowedCharacters?: (':' | '$' | ';' | '@' | '&' | '=' | '+' | ',')[] | undefined;
|
|
@@ -34,7 +34,7 @@ function createRouterCodeSplitterPlugin(options = {}, routerPluginContext) {
|
|
|
34
34
|
if (typeof options === 'function') userConfig = options();
|
|
35
35
|
else userConfig = getConfig(options, ROOT);
|
|
36
36
|
}
|
|
37
|
-
|
|
37
|
+
let isProduction = process.env.NODE_ENV === 'production';
|
|
38
38
|
const sharedBindingsMap = /* @__PURE__ */ new Map();
|
|
39
39
|
const getGlobalCodeSplitGroupings = () => {
|
|
40
40
|
return userConfig.codeSplittingOptions?.defaultBehavior || defaultCodeSplitGroupings;
|
|
@@ -159,6 +159,7 @@ function createRouterCodeSplitterPlugin(options = {}, routerPluginContext) {
|
|
|
159
159
|
},
|
|
160
160
|
vite: {
|
|
161
161
|
configResolved(config) {
|
|
162
|
+
isProduction = config.command === 'build';
|
|
162
163
|
ROOT = config.root;
|
|
163
164
|
initUserConfig();
|
|
164
165
|
validateFrameworkPluginOrder({
|
|
@@ -173,11 +174,13 @@ function createRouterCodeSplitterPlugin(options = {}, routerPluginContext) {
|
|
|
173
174
|
return true;
|
|
174
175
|
},
|
|
175
176
|
},
|
|
176
|
-
rspack() {
|
|
177
|
+
rspack(compiler) {
|
|
178
|
+
isProduction = compiler.options.mode === 'production';
|
|
177
179
|
ROOT = process.cwd();
|
|
178
180
|
initUserConfig();
|
|
179
181
|
},
|
|
180
|
-
webpack() {
|
|
182
|
+
webpack(compiler) {
|
|
183
|
+
isProduction = compiler.options.mode === 'production';
|
|
181
184
|
ROOT = process.cwd();
|
|
182
185
|
initUserConfig();
|
|
183
186
|
},
|
|
@@ -68,14 +68,11 @@ declare const TanStackRouterEsbuild: (
|
|
|
68
68
|
tmpDir: string;
|
|
69
69
|
importRoutesUsingAbsolutePaths: boolean;
|
|
70
70
|
virtualRouteConfig?:
|
|
71
|
-
|
|
|
72
|
-
| import('@tanstack/virtual-file-routes').VirtualRootRoute
|
|
73
|
-
| undefined;
|
|
71
|
+
string | import('@tanstack/virtual-file-routes').VirtualRootRoute | undefined;
|
|
74
72
|
routeFilePrefix?: string | undefined;
|
|
75
73
|
routeFileIgnorePattern?: string | undefined;
|
|
76
74
|
pathParamsAllowedCharacters?:
|
|
77
|
-
|
|
78
|
-
| undefined;
|
|
75
|
+
(':' | '$' | ';' | '@' | '&' | '=' | '+' | ',')[] | undefined;
|
|
79
76
|
routeTreeFileFooter?: string[] | (() => Array<string>) | undefined;
|
|
80
77
|
autoCodeSplitting?: boolean | undefined;
|
|
81
78
|
customScaffolding?:
|
|
@@ -143,14 +140,11 @@ declare const tanstackRouter: (
|
|
|
143
140
|
tmpDir: string;
|
|
144
141
|
importRoutesUsingAbsolutePaths: boolean;
|
|
145
142
|
virtualRouteConfig?:
|
|
146
|
-
|
|
|
147
|
-
| import('@tanstack/virtual-file-routes').VirtualRootRoute
|
|
148
|
-
| undefined;
|
|
143
|
+
string | import('@tanstack/virtual-file-routes').VirtualRootRoute | undefined;
|
|
149
144
|
routeFilePrefix?: string | undefined;
|
|
150
145
|
routeFileIgnorePattern?: string | undefined;
|
|
151
146
|
pathParamsAllowedCharacters?:
|
|
152
|
-
|
|
153
|
-
| undefined;
|
|
147
|
+
(':' | '$' | ';' | '@' | '&' | '=' | '+' | ',')[] | undefined;
|
|
154
148
|
routeTreeFileFooter?: string[] | (() => Array<string>) | undefined;
|
|
155
149
|
autoCodeSplitting?: boolean | undefined;
|
|
156
150
|
customScaffolding?:
|
|
@@ -68,14 +68,11 @@ declare const tanstackRouter: (
|
|
|
68
68
|
tmpDir: string;
|
|
69
69
|
importRoutesUsingAbsolutePaths: boolean;
|
|
70
70
|
virtualRouteConfig?:
|
|
71
|
-
|
|
|
72
|
-
| import('@tanstack/virtual-file-routes').VirtualRootRoute
|
|
73
|
-
| undefined;
|
|
71
|
+
string | import('@tanstack/virtual-file-routes').VirtualRootRoute | undefined;
|
|
74
72
|
routeFilePrefix?: string | undefined;
|
|
75
73
|
routeFileIgnorePattern?: string | undefined;
|
|
76
74
|
pathParamsAllowedCharacters?:
|
|
77
|
-
|
|
78
|
-
| undefined;
|
|
75
|
+
(':' | '$' | ';' | '@' | '&' | '=' | '+' | ',')[] | undefined;
|
|
79
76
|
routeTreeFileFooter?: string[] | (() => Array<string>) | undefined;
|
|
80
77
|
autoCodeSplitting?: boolean | undefined;
|
|
81
78
|
customScaffolding?:
|
|
@@ -146,14 +143,11 @@ declare const TanStackRouterVite: (
|
|
|
146
143
|
tmpDir: string;
|
|
147
144
|
importRoutesUsingAbsolutePaths: boolean;
|
|
148
145
|
virtualRouteConfig?:
|
|
149
|
-
|
|
|
150
|
-
| import('@tanstack/virtual-file-routes').VirtualRootRoute
|
|
151
|
-
| undefined;
|
|
146
|
+
string | import('@tanstack/virtual-file-routes').VirtualRootRoute | undefined;
|
|
152
147
|
routeFilePrefix?: string | undefined;
|
|
153
148
|
routeFileIgnorePattern?: string | undefined;
|
|
154
149
|
pathParamsAllowedCharacters?:
|
|
155
|
-
|
|
156
|
-
| undefined;
|
|
150
|
+
(':' | '$' | ';' | '@' | '&' | '=' | '+' | ',')[] | undefined;
|
|
157
151
|
routeTreeFileFooter?: string[] | (() => Array<string>) | undefined;
|
|
158
152
|
autoCodeSplitting?: boolean | undefined;
|
|
159
153
|
customScaffolding?:
|
|
@@ -72,21 +72,22 @@ function collectIdentifiersFromPattern$1(pattern, add) {
|
|
|
72
72
|
function isValidExportName(name) {
|
|
73
73
|
if (name === 'default' || name.length === 0) return false;
|
|
74
74
|
const first = name.charCodeAt(0);
|
|
75
|
-
if (
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
if (!(
|
|
76
|
+
(first >= 65 && first <= 90) ||
|
|
77
|
+
(first >= 97 && first <= 122) ||
|
|
78
|
+
first === 95 ||
|
|
79
|
+
first === 36
|
|
80
|
+
))
|
|
78
81
|
return false;
|
|
79
82
|
for (let i = 1; i < name.length; i++) {
|
|
80
83
|
const ch = name.charCodeAt(i);
|
|
81
|
-
if (
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
)
|
|
89
|
-
)
|
|
84
|
+
if (!(
|
|
85
|
+
(ch >= 65 && ch <= 90) ||
|
|
86
|
+
(ch >= 97 && ch <= 122) ||
|
|
87
|
+
(ch >= 48 && ch <= 57) ||
|
|
88
|
+
ch === 95 ||
|
|
89
|
+
ch === 36
|
|
90
|
+
))
|
|
90
91
|
return false;
|
|
91
92
|
}
|
|
92
93
|
return true;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export declare const SERVER_FN_LOOKUP_QUERY = '?server-fn-module-lookup';
|
|
2
1
|
export declare const MOCK_MODULE_ID = 'tanstack-start-import-protection:mock';
|
|
3
2
|
export declare const MOCK_BUILD_PREFIX = 'tanstack-start-import-protection:mock:build:';
|
|
4
3
|
export declare const MOCK_EDGE_PREFIX = 'tanstack-start-import-protection:mock-edge:';
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { SERVER_FN_LOOKUP } from '../constants.js';
|
|
2
1
|
//#region src/import-protection/constants.ts
|
|
3
|
-
var SERVER_FN_LOOKUP_QUERY = `?${SERVER_FN_LOOKUP}`;
|
|
4
2
|
var MOCK_MODULE_ID = 'tanstack-start-import-protection:mock';
|
|
5
3
|
var MOCK_BUILD_PREFIX = 'tanstack-start-import-protection:mock:build:';
|
|
6
4
|
var MOCK_EDGE_PREFIX = 'tanstack-start-import-protection:mock-edge:';
|
|
@@ -34,6 +32,5 @@ export {
|
|
|
34
32
|
MOCK_EDGE_PREFIX,
|
|
35
33
|
MOCK_MODULE_ID,
|
|
36
34
|
MOCK_RUNTIME_PREFIX,
|
|
37
|
-
SERVER_FN_LOOKUP_QUERY,
|
|
38
35
|
VITE_BROWSER_VIRTUAL_PREFIX,
|
|
39
36
|
};
|
|
@@ -208,8 +208,7 @@ export declare function parseStartConfig(
|
|
|
208
208
|
base: string;
|
|
209
209
|
disableCsrfMiddlewareWarning: boolean;
|
|
210
210
|
generateFunctionId?:
|
|
211
|
-
|
|
212
|
-
| undefined;
|
|
211
|
+
((opts: { filename: string; functionName: string }) => string | undefined) | undefined;
|
|
213
212
|
};
|
|
214
213
|
pages: {
|
|
215
214
|
path: string;
|
|
@@ -218,14 +217,7 @@ export declare function parseStartConfig(
|
|
|
218
217
|
exclude?: boolean | undefined;
|
|
219
218
|
priority?: number | undefined;
|
|
220
219
|
changefreq?:
|
|
221
|
-
| '
|
|
222
|
-
| 'always'
|
|
223
|
-
| 'hourly'
|
|
224
|
-
| 'daily'
|
|
225
|
-
| 'weekly'
|
|
226
|
-
| 'monthly'
|
|
227
|
-
| 'yearly'
|
|
228
|
-
| undefined;
|
|
220
|
+
'never' | 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | undefined;
|
|
229
221
|
lastmod?: string | Date | undefined;
|
|
230
222
|
alternateRefs?:
|
|
231
223
|
| {
|
|
@@ -297,8 +289,7 @@ export declare function parseStartConfig(
|
|
|
297
289
|
retryCount?: number | undefined;
|
|
298
290
|
retryDelay?: number | undefined;
|
|
299
291
|
onSuccess?:
|
|
300
|
-
|
|
301
|
-
| undefined;
|
|
292
|
+
((result: { page: z.infer<typeof pageBaseSchema>; html: string }) => unknown) | undefined;
|
|
302
293
|
headers?: Record<string, string> | undefined;
|
|
303
294
|
})
|
|
304
295
|
| undefined;
|
|
@@ -333,8 +324,7 @@ export declare function parseStartConfig(
|
|
|
333
324
|
| undefined;
|
|
334
325
|
mockAccess?: 'error' | 'warn' | 'off' | undefined;
|
|
335
326
|
onViolation?:
|
|
336
|
-
|
|
337
|
-
| undefined;
|
|
327
|
+
((violation: unknown) => boolean | void | Promise<boolean | void>) | undefined;
|
|
338
328
|
include?: (string | RegExp)[] | undefined;
|
|
339
329
|
exclude?: (string | RegExp)[] | undefined;
|
|
340
330
|
client?:
|
|
@@ -12,12 +12,7 @@ type Binding = ModuleInfoBinding & {
|
|
|
12
12
|
};
|
|
13
13
|
type Kind = 'None' | `Root` | `Builder` | LookupKind;
|
|
14
14
|
export type BuiltInLookupKind =
|
|
15
|
-
| '
|
|
16
|
-
| 'Middleware'
|
|
17
|
-
| 'IsomorphicFn'
|
|
18
|
-
| 'ServerOnlyFn'
|
|
19
|
-
| 'ClientOnlyFn'
|
|
20
|
-
| 'ClientOnlyJSX';
|
|
15
|
+
'ServerFn' | 'Middleware' | 'IsomorphicFn' | 'ServerOnlyFn' | 'ClientOnlyFn' | 'ClientOnlyJSX';
|
|
21
16
|
export type ExternalLookupKind = `External:${string}`;
|
|
22
17
|
export type LookupKind = BuiltInLookupKind | ExternalLookupKind;
|
|
23
18
|
export declare function getExternalLookupKind(
|
|
@@ -850,7 +850,7 @@ var StartCompiler = class {
|
|
|
850
850
|
const binding = (await this.getModuleInfo(id)).bindings.get(ident);
|
|
851
851
|
if (!binding) return 'None';
|
|
852
852
|
if (binding.resolvedKind) return binding.resolvedKind;
|
|
853
|
-
const vKey = `${
|
|
853
|
+
const vKey = `${id}:${ident}`;
|
|
854
854
|
if (visited.has(vKey)) return 'None';
|
|
855
855
|
visited.add(vKey);
|
|
856
856
|
const resolvedKind = await this.resolveBindingKind(binding, id, visited);
|
|
@@ -904,7 +904,7 @@ var StartCompiler = class {
|
|
|
904
904
|
if (isBuildMode) this.getExportResolutionCache(moduleInfo.id).set(exportName, null);
|
|
905
905
|
}
|
|
906
906
|
async resolveBindingTarget(resolution, visited = /* @__PURE__ */ new Set()) {
|
|
907
|
-
const key = `${
|
|
907
|
+
const key = `${resolution.moduleInfo.id}:${resolution.localName}`;
|
|
908
908
|
if (visited.has(key)) return;
|
|
909
909
|
visited.add(key);
|
|
910
910
|
if (resolution.binding.type !== 'import') return resolution;
|
|
@@ -936,7 +936,7 @@ var StartCompiler = class {
|
|
|
936
936
|
const target = found ? ((await this.resolveBindingTarget(found)) ?? found) : void 0;
|
|
937
937
|
if (
|
|
938
938
|
target &&
|
|
939
|
-
|
|
939
|
+
resolved.moduleInfo.id === target.moduleInfo.id &&
|
|
940
940
|
resolved.localName === target.localName
|
|
941
941
|
)
|
|
942
942
|
return kind;
|
|
@@ -965,7 +965,7 @@ var StartCompiler = class {
|
|
|
965
965
|
return knownKind;
|
|
966
966
|
}
|
|
967
967
|
if (found.binding.resolvedKind) return found.binding.resolvedKind;
|
|
968
|
-
const vKey = `${
|
|
968
|
+
const vKey = `${found.moduleInfo.id}:${found.localName}`;
|
|
969
969
|
if (visited.has(vKey)) return 'None';
|
|
970
970
|
visited.add(vKey);
|
|
971
971
|
const resolvedKind = await this.resolveBindingKind(found.binding, found.moduleInfo.id, visited);
|
|
@@ -14,6 +14,13 @@ export declare function codeFrameError(
|
|
|
14
14
|
},
|
|
15
15
|
message: string,
|
|
16
16
|
): Error;
|
|
17
|
+
/**
|
|
18
|
+
* Converts a bundler module ID to its physical-file identity for diagnostics,
|
|
19
|
+
* filesystem matching, and file-based invalidation.
|
|
20
|
+
*
|
|
21
|
+
* Do not use this for IDs passed to resolve/load hooks or as module cache keys:
|
|
22
|
+
* virtual prefixes and queries can be part of the module's semantic identity.
|
|
23
|
+
*/
|
|
17
24
|
export declare function cleanId(id: string): string;
|
|
18
25
|
/**
|
|
19
26
|
* Strips a method call by replacing it with its callee object.
|
|
@@ -15,6 +15,13 @@ function codeFrameError(code, loc, message) {
|
|
|
15
15
|
);
|
|
16
16
|
return new Error(frame);
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Converts a bundler module ID to its physical-file identity for diagnostics,
|
|
20
|
+
* filesystem matching, and file-based invalidation.
|
|
21
|
+
*
|
|
22
|
+
* Do not use this for IDs passed to resolve/load hooks or as module cache keys:
|
|
23
|
+
* virtual prefixes and queries can be part of the module's semantic identity.
|
|
24
|
+
*/
|
|
18
25
|
function cleanId(id) {
|
|
19
26
|
if (id.startsWith('\0')) id = id.slice(1);
|
|
20
27
|
const queryIndex = id.indexOf('?');
|
|
@@ -22,8 +22,7 @@ export type SerializationAdapterByRuntime = Partial<
|
|
|
22
22
|
Record<SerializationRuntime, SerializationAdapterModuleRef>
|
|
23
23
|
>;
|
|
24
24
|
export type SerializationAdapterConfig =
|
|
25
|
-
|
|
|
26
|
-
| SerializationAdapterByRuntime;
|
|
25
|
+
SerializationAdapterModuleRef | SerializationAdapterByRuntime;
|
|
27
26
|
export type StartCompilerEnvironment = 'client' | 'server';
|
|
28
27
|
export interface StartCompilerImportTransformImport {
|
|
29
28
|
libName: string;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { VITE_ENVIRONMENT_NAMES } from '../../constants.js';
|
|
1
|
+
import { SERVER_FN_LOOKUP, TRANSFORM_ID_REGEX, VITE_ENVIRONMENT_NAMES } from '../../constants.js';
|
|
2
2
|
import { escapeRegExp, resolveViteId } from '../../utils.js';
|
|
3
3
|
import {
|
|
4
4
|
IMPORT_PROTECTION_DEBUG,
|
|
5
5
|
MOCK_BUILD_PREFIX,
|
|
6
|
-
SERVER_FN_LOOKUP_QUERY,
|
|
7
6
|
VITE_BROWSER_VIRTUAL_PREFIX,
|
|
8
7
|
} from '../../import-protection/constants.js';
|
|
9
8
|
import {
|
|
@@ -64,6 +63,7 @@ import {
|
|
|
64
63
|
resolveInternalVirtualModuleId,
|
|
65
64
|
resolvedMarkerVirtualModuleId,
|
|
66
65
|
} from './virtualModules.js';
|
|
66
|
+
import { hasIdQueryFlag } from '../module-id.js';
|
|
67
67
|
import { dirname, relative } from 'pathe';
|
|
68
68
|
import { writeFileSync } from 'node:fs';
|
|
69
69
|
import { normalizePath } from 'vite';
|
|
@@ -415,12 +415,10 @@ function importProtectionPlugin(opts) {
|
|
|
415
415
|
) {
|
|
416
416
|
const normalizedResolvedId = normalizeFilePath(resolvedId);
|
|
417
417
|
const markerKind = shared.fileMarkerKind.get(normalizedResolvedId);
|
|
418
|
-
if (
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
)
|
|
423
|
-
)
|
|
418
|
+
if (!(
|
|
419
|
+
(envType === 'client' && markerKind === 'server') ||
|
|
420
|
+
(envType === 'server' && markerKind === 'client')
|
|
421
|
+
))
|
|
424
422
|
return void 0;
|
|
425
423
|
return buildViolationInfo(
|
|
426
424
|
envName,
|
|
@@ -696,7 +694,7 @@ function importProtectionPlugin(opts) {
|
|
|
696
694
|
let merged = null;
|
|
697
695
|
if (keySet)
|
|
698
696
|
for (const k of keySet) {
|
|
699
|
-
if (k
|
|
697
|
+
if (hasIdQueryFlag(k, SERVER_FN_LOOKUP)) continue;
|
|
700
698
|
const imports = env.postTransformImports.get(k);
|
|
701
699
|
if (imports)
|
|
702
700
|
if (!merged) merged = new Set(imports);
|
|
@@ -723,7 +721,7 @@ function importProtectionPlugin(opts) {
|
|
|
723
721
|
let anyVariantCached = false;
|
|
724
722
|
if (keySet)
|
|
725
723
|
for (const k of keySet) {
|
|
726
|
-
if (k
|
|
724
|
+
if (hasIdQueryFlag(k, SERVER_FN_LOOKUP)) continue;
|
|
727
725
|
const imports = env.postTransformImports.get(k);
|
|
728
726
|
if (imports) {
|
|
729
727
|
anyVariantCached = true;
|
|
@@ -1081,21 +1079,19 @@ function importProtectionPlugin(opts) {
|
|
|
1081
1079
|
if (internalVirtualId) return internalVirtualId;
|
|
1082
1080
|
if (!importer) {
|
|
1083
1081
|
const normalizedSource = normalizeFilePath(source);
|
|
1084
|
-
if (
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
)
|
|
1091
|
-
)
|
|
1082
|
+
if (!(
|
|
1083
|
+
config.command === 'serve' &&
|
|
1084
|
+
config.bundledDev &&
|
|
1085
|
+
envType === 'client' &&
|
|
1086
|
+
isInsideDirectory(normalizedSource, config.srcDirectory)
|
|
1087
|
+
))
|
|
1092
1088
|
env.graph.addEntry(source);
|
|
1093
1089
|
await processPendingViolations(env, this.warn.bind(this));
|
|
1094
1090
|
return;
|
|
1095
1091
|
}
|
|
1096
1092
|
if (source.startsWith('\0') || source.startsWith('virtual:')) return;
|
|
1097
1093
|
const normalizedImporter = normalizeFilePath(importer);
|
|
1098
|
-
const isDirectLookup = importer
|
|
1094
|
+
const isDirectLookup = hasIdQueryFlag(importer, SERVER_FN_LOOKUP);
|
|
1099
1095
|
if (config.command === 'serve' && config.bundledDev && envType === 'client') {
|
|
1100
1096
|
if (
|
|
1101
1097
|
isInsideDirectory(normalizedImporter, normalizePath(`${config.srcDirectory}/routes`))
|
|
@@ -1389,7 +1385,11 @@ function importProtectionPlugin(opts) {
|
|
|
1389
1385
|
return environmentNames.has(env.name);
|
|
1390
1386
|
},
|
|
1391
1387
|
transform: {
|
|
1392
|
-
|
|
1388
|
+
// TRANSFORM_ID_REGEX includes .tsrx — the hand-rolled react-only
|
|
1389
|
+
// regex here silently skipped octane importers, so denied *.client.*
|
|
1390
|
+
// imports were never edge-rewritten/deferred and hard-errored at
|
|
1391
|
+
// resolve instead of tree-shake-verified like react's do.
|
|
1392
|
+
filter: { id: { include: [...TRANSFORM_ID_REGEX] } },
|
|
1393
1393
|
async handler(code, id) {
|
|
1394
1394
|
perf?.count('transform.calls');
|
|
1395
1395
|
const envName = this.environment.name;
|
|
@@ -1432,7 +1432,7 @@ function importProtectionPlugin(opts) {
|
|
|
1432
1432
|
}
|
|
1433
1433
|
const cacheKey = normalizePath(id);
|
|
1434
1434
|
const envState = getEnv(envName);
|
|
1435
|
-
const isServerFnLookup = id
|
|
1435
|
+
const isServerFnLookup = hasIdQueryFlag(id, SERVER_FN_LOOKUP);
|
|
1436
1436
|
if (isServerFnLookup) envState.serverFnLookupModules.add(file);
|
|
1437
1437
|
const result = {
|
|
1438
1438
|
code,
|