@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
|
@@ -1,100 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
MARKER_PREFIX,
|
|
3
|
+
MOCK_BUILD_PREFIX,
|
|
4
|
+
MOCK_EDGE_PREFIX,
|
|
5
|
+
MOCK_MODULE_ID,
|
|
6
|
+
MOCK_RUNTIME_PREFIX,
|
|
7
|
+
} from './constants'
|
|
8
|
+
import { isValidExportName } from './analysis'
|
|
4
9
|
import { CLIENT_ENV_SUGGESTIONS } from './trace'
|
|
5
|
-
import { VITE_BROWSER_VIRTUAL_PREFIX } from './constants'
|
|
6
10
|
import { relativizePath } from './utils'
|
|
7
11
|
import type { ViolationInfo } from './trace'
|
|
8
12
|
|
|
9
|
-
export const MOCK_MODULE_ID = 'tanstack-start-import-protection:mock'
|
|
10
|
-
const RESOLVED_MOCK_MODULE_ID = resolveViteId(MOCK_MODULE_ID)
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Per-violation mock prefix used in build+error mode.
|
|
14
|
-
* Each deferred violation gets a unique ID so we can check which ones
|
|
15
|
-
* survived tree-shaking in `generateBundle`.
|
|
16
|
-
*/
|
|
17
|
-
export const MOCK_BUILD_PREFIX = 'tanstack-start-import-protection:mock:build:'
|
|
18
|
-
const RESOLVED_MOCK_BUILD_PREFIX = resolveViteId(MOCK_BUILD_PREFIX)
|
|
19
|
-
|
|
20
|
-
export const MOCK_EDGE_PREFIX = 'tanstack-start-import-protection:mock-edge:'
|
|
21
|
-
const RESOLVED_MOCK_EDGE_PREFIX = resolveViteId(MOCK_EDGE_PREFIX)
|
|
22
|
-
|
|
23
|
-
export const MOCK_RUNTIME_PREFIX =
|
|
24
|
-
'tanstack-start-import-protection:mock-runtime:'
|
|
25
|
-
const RESOLVED_MOCK_RUNTIME_PREFIX = resolveViteId(MOCK_RUNTIME_PREFIX)
|
|
26
|
-
|
|
27
|
-
const MARKER_PREFIX = 'tanstack-start-import-protection:marker:'
|
|
28
|
-
const RESOLVED_MARKER_PREFIX = resolveViteId(MARKER_PREFIX)
|
|
29
|
-
|
|
30
|
-
const RESOLVED_MARKER_SERVER_ONLY = resolveViteId(`${MARKER_PREFIX}server-only`)
|
|
31
|
-
const RESOLVED_MARKER_CLIENT_ONLY = resolveViteId(`${MARKER_PREFIX}client-only`)
|
|
32
|
-
|
|
33
|
-
export function resolvedMarkerVirtualModuleId(
|
|
34
|
-
kind: 'server' | 'client',
|
|
35
|
-
): string {
|
|
36
|
-
return kind === 'server'
|
|
37
|
-
? RESOLVED_MARKER_SERVER_ONLY
|
|
38
|
-
: RESOLVED_MARKER_CLIENT_ONLY
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Convenience list for plugin `load` filters/handlers.
|
|
43
|
-
*
|
|
44
|
-
* Vite/Rollup call `load(id)` with the *resolved* virtual id (prefixed by `\0`).
|
|
45
|
-
* `resolveId(source)` sees the *unresolved* id/prefix (without `\0`).
|
|
46
|
-
*/
|
|
47
|
-
export function getResolvedVirtualModuleMatchers(): ReadonlyArray<string> {
|
|
48
|
-
return RESOLVED_VIRTUAL_MODULE_MATCHERS
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const RESOLVED_VIRTUAL_MODULE_MATCHERS = [
|
|
52
|
-
RESOLVED_MOCK_MODULE_ID,
|
|
53
|
-
RESOLVED_MOCK_BUILD_PREFIX,
|
|
54
|
-
RESOLVED_MOCK_EDGE_PREFIX,
|
|
55
|
-
RESOLVED_MOCK_RUNTIME_PREFIX,
|
|
56
|
-
RESOLVED_MARKER_PREFIX,
|
|
57
|
-
] as const
|
|
58
|
-
|
|
59
|
-
const RESOLVE_PREFIX_PAIRS = [
|
|
60
|
-
[MOCK_EDGE_PREFIX, RESOLVED_MOCK_EDGE_PREFIX],
|
|
61
|
-
[MOCK_RUNTIME_PREFIX, RESOLVED_MOCK_RUNTIME_PREFIX],
|
|
62
|
-
[MOCK_BUILD_PREFIX, RESOLVED_MOCK_BUILD_PREFIX],
|
|
63
|
-
[MARKER_PREFIX, RESOLVED_MARKER_PREFIX],
|
|
64
|
-
] as const
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Resolve import-protection's internal virtual module IDs.
|
|
68
|
-
*
|
|
69
|
-
* `resolveId(source)` sees *unresolved* ids/prefixes (no `\0`).
|
|
70
|
-
* Returning a resolved id (with `\0`) ensures Vite/Rollup route it to `load`.
|
|
71
|
-
*/
|
|
72
|
-
export function resolveInternalVirtualModuleId(
|
|
73
|
-
source: string,
|
|
74
|
-
): string | undefined {
|
|
75
|
-
if (source.startsWith(VITE_BROWSER_VIRTUAL_PREFIX)) {
|
|
76
|
-
return resolveInternalVirtualModuleId(
|
|
77
|
-
`\0${source.slice(VITE_BROWSER_VIRTUAL_PREFIX.length)}`,
|
|
78
|
-
)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (source === MOCK_MODULE_ID || source === RESOLVED_MOCK_MODULE_ID) {
|
|
82
|
-
return RESOLVED_MOCK_MODULE_ID
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
for (const [unresolvedPrefix, resolvedPrefix] of RESOLVE_PREFIX_PAIRS) {
|
|
86
|
-
if (source.startsWith(unresolvedPrefix)) {
|
|
87
|
-
return resolveViteId(source)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (source.startsWith(resolvedPrefix)) {
|
|
91
|
-
return source
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return undefined
|
|
96
|
-
}
|
|
97
|
-
|
|
98
13
|
function toBase64Url(input: string): string {
|
|
99
14
|
return Buffer.from(input, 'utf8').toString('base64url')
|
|
100
15
|
}
|
|
@@ -105,10 +20,6 @@ function fromBase64Url(input: string): string {
|
|
|
105
20
|
|
|
106
21
|
type MockAccessMode = 'error' | 'warn' | 'off'
|
|
107
22
|
|
|
108
|
-
/**
|
|
109
|
-
* Compact runtime suggestion text for browser console, derived from
|
|
110
|
-
* {@link CLIENT_ENV_SUGGESTIONS} so there's a single source of truth.
|
|
111
|
-
*/
|
|
112
23
|
export const RUNTIME_SUGGESTION_TEXT =
|
|
113
24
|
'Fix: ' +
|
|
114
25
|
CLIENT_ENV_SUGGESTIONS.join('. ') +
|
|
@@ -120,7 +31,7 @@ export function mockRuntimeModuleIdFromViolation(
|
|
|
120
31
|
root: string,
|
|
121
32
|
): string {
|
|
122
33
|
if (mode === 'off') return MOCK_MODULE_ID
|
|
123
|
-
if (info.env !==
|
|
34
|
+
if (info.env !== 'client') return MOCK_MODULE_ID
|
|
124
35
|
|
|
125
36
|
const rel = (p: string) => relativizePath(p, root)
|
|
126
37
|
const trace = info.trace.map((s) => {
|
|
@@ -136,6 +47,7 @@ export function mockRuntimeModuleIdFromViolation(
|
|
|
136
47
|
trace,
|
|
137
48
|
mode,
|
|
138
49
|
}
|
|
50
|
+
|
|
139
51
|
return `${MOCK_RUNTIME_PREFIX}${toBase64Url(JSON.stringify(payload))}`
|
|
140
52
|
}
|
|
141
53
|
|
|
@@ -147,17 +59,6 @@ export function makeMockEdgeModuleId(
|
|
|
147
59
|
return `${MOCK_EDGE_PREFIX}${toBase64Url(JSON.stringify(payload))}`
|
|
148
60
|
}
|
|
149
61
|
|
|
150
|
-
/**
|
|
151
|
-
* Generate a recursive Proxy-based mock module.
|
|
152
|
-
*
|
|
153
|
-
* When `diagnostics` is provided, the generated code includes a `__report`
|
|
154
|
-
* function that logs runtime warnings/errors when the mock is actually used
|
|
155
|
-
* (property access for primitive coercion, calls, construction, sets).
|
|
156
|
-
*
|
|
157
|
-
* When `diagnostics` is omitted, the mock is completely silent — suitable
|
|
158
|
-
* for base mock modules (e.g. `MOCK_MODULE_ID` or per-violation build mocks)
|
|
159
|
-
* that are consumed by mock-edge modules providing explicit named exports.
|
|
160
|
-
*/
|
|
161
62
|
function generateMockCode(diagnostics?: {
|
|
162
63
|
meta: {
|
|
163
64
|
env: string
|
|
@@ -203,7 +104,6 @@ function __report(action, accessPath) {
|
|
|
203
104
|
`
|
|
204
105
|
: ''
|
|
205
106
|
|
|
206
|
-
// Diagnostic-only traps for primitive coercion, set
|
|
207
107
|
const diagGetTraps = hasDiag
|
|
208
108
|
? `
|
|
209
109
|
if (prop === Symbol.toPrimitive) {
|
|
@@ -276,19 +176,10 @@ export function loadSilentMockModule(): { code: string } {
|
|
|
276
176
|
return { code: generateMockCode() }
|
|
277
177
|
}
|
|
278
178
|
|
|
279
|
-
/**
|
|
280
|
-
* Filter export names to valid, non-default names.
|
|
281
|
-
*/
|
|
282
179
|
function filterExportNames(exports: ReadonlyArray<string>): Array<string> {
|
|
283
180
|
return exports.filter((n) => n.length > 0 && n !== 'default')
|
|
284
181
|
}
|
|
285
182
|
|
|
286
|
-
/**
|
|
287
|
-
* Generate ESM export lines that re-export named properties from `mock`.
|
|
288
|
-
*
|
|
289
|
-
* Produces `export const foo = mock.foo;` for valid identifiers and
|
|
290
|
-
* string-keyed re-exports for non-identifier names.
|
|
291
|
-
*/
|
|
292
183
|
function generateExportLines(names: ReadonlyArray<string>): Array<string> {
|
|
293
184
|
const lines: Array<string> = []
|
|
294
185
|
const stringExports: Array<{ alias: string; name: string }> = []
|
|
@@ -314,17 +205,6 @@ function generateExportLines(names: ReadonlyArray<string>): Array<string> {
|
|
|
314
205
|
return lines
|
|
315
206
|
}
|
|
316
207
|
|
|
317
|
-
/**
|
|
318
|
-
* Generate a self-contained mock module with explicit named exports.
|
|
319
|
-
*
|
|
320
|
-
* Used by the transform hook's "self-denial" check: when a denied file
|
|
321
|
-
* (e.g. `.server.ts` in the client environment) is transformed, its entire
|
|
322
|
-
* content is replaced with this mock module. This avoids returning virtual
|
|
323
|
-
* module IDs from `resolveId`, which prevents cross-environment cache
|
|
324
|
-
* contamination from third-party resolver plugins.
|
|
325
|
-
*
|
|
326
|
-
* The generated code is side-effect-free and tree-shakeable.
|
|
327
|
-
*/
|
|
328
208
|
export function generateSelfContainedMockModule(exportNames: Array<string>): {
|
|
329
209
|
code: string
|
|
330
210
|
} {
|
|
@@ -338,18 +218,6 @@ ${exportLines.join('\n')}
|
|
|
338
218
|
}
|
|
339
219
|
}
|
|
340
220
|
|
|
341
|
-
/**
|
|
342
|
-
* Generate a dev-mode mock module for self-denial transforms.
|
|
343
|
-
*
|
|
344
|
-
* Similar to `loadMockEdgeModule` but takes export names and a runtime ID
|
|
345
|
-
* directly (instead of parsing them from a base64url-encoded payload).
|
|
346
|
-
* Used by the transform hook when a denied file (e.g. `.server.ts` in
|
|
347
|
-
* the client environment) is replaced in dev mode.
|
|
348
|
-
*
|
|
349
|
-
* The generated module imports mock-runtime for runtime diagnostics
|
|
350
|
-
* (error/warn on property access) and re-exports explicit named exports
|
|
351
|
-
* so that `import { foo } from './denied.server'` works.
|
|
352
|
-
*/
|
|
353
221
|
export function generateDevSelfDenialModule(
|
|
354
222
|
exportNames: Array<string>,
|
|
355
223
|
runtimeId: string,
|
|
@@ -367,18 +235,18 @@ export default mock;
|
|
|
367
235
|
|
|
368
236
|
export function loadMockEdgeModule(encodedPayload: string): { code: string } {
|
|
369
237
|
let payload: { exports?: Array<string>; runtimeId?: string }
|
|
238
|
+
|
|
370
239
|
try {
|
|
371
240
|
payload = JSON.parse(fromBase64Url(encodedPayload)) as typeof payload
|
|
372
241
|
} catch {
|
|
373
242
|
payload = { exports: [] }
|
|
374
243
|
}
|
|
375
|
-
const names = filterExportNames(payload.exports ?? [])
|
|
376
244
|
|
|
377
|
-
const
|
|
245
|
+
const names = filterExportNames(payload.exports ?? [])
|
|
246
|
+
const runtimeId =
|
|
378
247
|
typeof payload.runtimeId === 'string' && payload.runtimeId.length > 0
|
|
379
248
|
? payload.runtimeId
|
|
380
249
|
: MOCK_MODULE_ID
|
|
381
|
-
|
|
382
250
|
const exportLines = generateExportLines(names)
|
|
383
251
|
|
|
384
252
|
return {
|
|
@@ -399,6 +267,7 @@ export function loadMockRuntimeModule(encodedPayload: string): {
|
|
|
399
267
|
specifier?: string
|
|
400
268
|
trace?: Array<unknown>
|
|
401
269
|
}
|
|
270
|
+
|
|
402
271
|
try {
|
|
403
272
|
payload = JSON.parse(fromBase64Url(encodedPayload)) as typeof payload
|
|
404
273
|
} catch {
|
|
@@ -408,14 +277,17 @@ export function loadMockRuntimeModule(encodedPayload: string): {
|
|
|
408
277
|
const mode: 'error' | 'warn' | 'off' =
|
|
409
278
|
payload.mode === 'warn' || payload.mode === 'off' ? payload.mode : 'error'
|
|
410
279
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
280
|
+
return {
|
|
281
|
+
code: generateMockCode({
|
|
282
|
+
meta: {
|
|
283
|
+
env: String(payload.env ?? ''),
|
|
284
|
+
importer: String(payload.importer ?? ''),
|
|
285
|
+
specifier: String(payload.specifier ?? ''),
|
|
286
|
+
trace: Array.isArray(payload.trace) ? payload.trace : [],
|
|
287
|
+
},
|
|
288
|
+
mode,
|
|
289
|
+
}),
|
|
416
290
|
}
|
|
417
|
-
|
|
418
|
-
return { code: generateMockCode({ meta, mode }) }
|
|
419
291
|
}
|
|
420
292
|
|
|
421
293
|
const MARKER_MODULE_RESULT = { code: 'export {}' } as const
|
|
@@ -424,29 +296,10 @@ export function loadMarkerModule(): { code: string } {
|
|
|
424
296
|
return MARKER_MODULE_RESULT
|
|
425
297
|
}
|
|
426
298
|
|
|
427
|
-
export
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
// Per-violation build mock modules — same silent mock code
|
|
435
|
-
if (id.startsWith(RESOLVED_MOCK_BUILD_PREFIX)) {
|
|
436
|
-
return loadSilentMockModule()
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
if (id.startsWith(RESOLVED_MOCK_EDGE_PREFIX)) {
|
|
440
|
-
return loadMockEdgeModule(id.slice(RESOLVED_MOCK_EDGE_PREFIX.length))
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
if (id.startsWith(RESOLVED_MOCK_RUNTIME_PREFIX)) {
|
|
444
|
-
return loadMockRuntimeModule(id.slice(RESOLVED_MOCK_RUNTIME_PREFIX.length))
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
if (id.startsWith(RESOLVED_MARKER_PREFIX)) {
|
|
448
|
-
return loadMarkerModule()
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
return undefined
|
|
299
|
+
export {
|
|
300
|
+
MARKER_PREFIX,
|
|
301
|
+
MOCK_BUILD_PREFIX,
|
|
302
|
+
MOCK_EDGE_PREFIX,
|
|
303
|
+
MOCK_MODULE_ID,
|
|
304
|
+
MOCK_RUNTIME_PREFIX,
|
|
452
305
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
1
|
export type { TanStackStartInputConfig } from './schema'
|
|
2
2
|
export type { TanStackStartCoreOptions } from './types'
|
|
3
|
-
export
|
|
4
|
-
TanStackStartVitePluginCoreOptions,
|
|
5
|
-
ViteRscForwardSsrResolverStrategy,
|
|
6
|
-
} from './vite/types'
|
|
7
|
-
export type { TanStackStartViteInputConfig } from './vite/schema'
|
|
8
|
-
export { START_ENVIRONMENT_NAMES, VITE_ENVIRONMENT_NAMES } from './constants'
|
|
9
|
-
export { createVirtualModule } from './vite/createVirtualModule'
|
|
10
|
-
export { tanStackStartVite } from './vite/plugin'
|
|
3
|
+
export { START_ENVIRONMENT_NAMES } from './constants'
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { HEADERS } from '@tanstack/start-server-core'
|
|
2
|
+
import { buildSitemap } from './build-sitemap'
|
|
3
|
+
import type { TanStackStartOutputConfig } from './schema'
|
|
4
|
+
|
|
5
|
+
export interface StartPostBuildAdapter {
|
|
6
|
+
getClientOutputDirectory: () => string
|
|
7
|
+
prerender: (startConfig: TanStackStartOutputConfig) => Promise<void>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function postBuild({
|
|
11
|
+
startConfig,
|
|
12
|
+
adapter,
|
|
13
|
+
}: {
|
|
14
|
+
startConfig: TanStackStartOutputConfig
|
|
15
|
+
adapter: StartPostBuildAdapter
|
|
16
|
+
}) {
|
|
17
|
+
if (startConfig.prerender?.enabled !== false) {
|
|
18
|
+
startConfig.prerender = {
|
|
19
|
+
...startConfig.prerender,
|
|
20
|
+
enabled:
|
|
21
|
+
startConfig.prerender?.enabled ??
|
|
22
|
+
startConfig.pages.some((d) =>
|
|
23
|
+
typeof d === 'string' ? false : !!d.prerender?.enabled,
|
|
24
|
+
),
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (startConfig.spa?.enabled) {
|
|
29
|
+
startConfig.prerender = {
|
|
30
|
+
...startConfig.prerender,
|
|
31
|
+
enabled: true,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const maskUrl = new URL(startConfig.spa.maskPath, 'http://localhost')
|
|
35
|
+
if (maskUrl.origin !== 'http://localhost') {
|
|
36
|
+
throw new Error('spa.maskPath must be a path (no protocol/host)')
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
startConfig.pages.push({
|
|
40
|
+
path: maskUrl.toString().replace('http://localhost', ''),
|
|
41
|
+
prerender: {
|
|
42
|
+
...startConfig.spa.prerender,
|
|
43
|
+
headers: {
|
|
44
|
+
...startConfig.spa.prerender.headers,
|
|
45
|
+
[HEADERS.TSS_SHELL]: 'true',
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
sitemap: {
|
|
49
|
+
exclude: true,
|
|
50
|
+
},
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (startConfig.prerender.enabled) {
|
|
55
|
+
await adapter.prerender(startConfig)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (startConfig.sitemap?.enabled) {
|
|
59
|
+
buildSitemap({
|
|
60
|
+
startConfig,
|
|
61
|
+
publicDir: adapter.getClientOutputDirectory(),
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
}
|
package/src/prerender.ts
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { promises as fsp } from 'node:fs'
|
|
2
|
+
import os from 'node:os'
|
|
3
|
+
import path from 'pathe'
|
|
4
|
+
import { joinURL, withBase, withTrailingSlash, withoutBase } from 'ufo'
|
|
5
|
+
import { createLogger } from './utils'
|
|
6
|
+
import { Queue } from './queue'
|
|
7
|
+
import type { Page, TanStackStartOutputConfig } from './schema'
|
|
8
|
+
|
|
9
|
+
const DEFAULT_RETRY_DELAY = 500
|
|
10
|
+
|
|
11
|
+
export interface PrerenderHandler {
|
|
12
|
+
getClientOutputDirectory: () => string
|
|
13
|
+
request: (path: string, options?: RequestInit) => Promise<Response>
|
|
14
|
+
close?: () => Promise<void>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function prerender({
|
|
18
|
+
startConfig,
|
|
19
|
+
handler,
|
|
20
|
+
}: {
|
|
21
|
+
startConfig: TanStackStartOutputConfig
|
|
22
|
+
handler: PrerenderHandler
|
|
23
|
+
}) {
|
|
24
|
+
const logger = createLogger('prerender')
|
|
25
|
+
logger.info('Prerendering pages...')
|
|
26
|
+
|
|
27
|
+
if (startConfig.prerender?.enabled) {
|
|
28
|
+
let pages = startConfig.pages.length ? startConfig.pages : [{ path: '/' }]
|
|
29
|
+
|
|
30
|
+
if (startConfig.prerender.autoStaticPathsDiscovery ?? true) {
|
|
31
|
+
const pagesMap = new Map(pages.map((item) => [item.path, item]))
|
|
32
|
+
const discoveredPages = globalThis.TSS_PRERENDABLE_PATHS || []
|
|
33
|
+
|
|
34
|
+
for (const page of discoveredPages) {
|
|
35
|
+
if (!pagesMap.has(page.path)) {
|
|
36
|
+
pagesMap.set(page.path, page)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
pages = Array.from(pagesMap.values())
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
startConfig.pages = pages
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const routerBasePath = joinURL('/', startConfig.router.basepath ?? '')
|
|
47
|
+
const routerBaseUrl = new URL(routerBasePath, 'http://localhost')
|
|
48
|
+
|
|
49
|
+
startConfig.pages = validateAndNormalizePrerenderPages(
|
|
50
|
+
startConfig.pages,
|
|
51
|
+
routerBaseUrl,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
const pages = await prerenderPages({
|
|
56
|
+
outputDir: handler.getClientOutputDirectory(),
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
logger.info(`Prerendered ${pages.length} pages:`)
|
|
60
|
+
pages.forEach((page) => {
|
|
61
|
+
logger.info(`- ${page}`)
|
|
62
|
+
})
|
|
63
|
+
} catch (error) {
|
|
64
|
+
logger.error(error)
|
|
65
|
+
throw error
|
|
66
|
+
} finally {
|
|
67
|
+
await handler.close?.()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function extractLinks(html: string): Array<string> {
|
|
71
|
+
const linkRegex = /<a[^>]+href=["']([^"']+)["'][^>]*>/g
|
|
72
|
+
const links: Array<string> = []
|
|
73
|
+
let match: RegExpExecArray | null
|
|
74
|
+
|
|
75
|
+
while ((match = linkRegex.exec(html)) !== null) {
|
|
76
|
+
const href = match[1]
|
|
77
|
+
if (href && (href.startsWith('/') || href.startsWith('./'))) {
|
|
78
|
+
links.push(href)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return links
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function prerenderPages({ outputDir }: { outputDir: string }) {
|
|
86
|
+
const seen = new Set<string>()
|
|
87
|
+
const prerendered = new Set<string>()
|
|
88
|
+
const retriesByPath = new Map<string, number>()
|
|
89
|
+
const concurrency = startConfig.prerender?.concurrency ?? os.cpus().length
|
|
90
|
+
logger.info(`Concurrency: ${concurrency}`)
|
|
91
|
+
const queue = new Queue({ concurrency })
|
|
92
|
+
const routerBasePath = joinURL('/', startConfig.router.basepath ?? '')
|
|
93
|
+
const routerBaseUrl = new URL(routerBasePath, 'http://localhost')
|
|
94
|
+
|
|
95
|
+
startConfig.pages = validateAndNormalizePrerenderPages(
|
|
96
|
+
startConfig.pages,
|
|
97
|
+
routerBaseUrl,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
startConfig.pages.forEach((page) => addCrawlPageTask(page))
|
|
101
|
+
|
|
102
|
+
if (queue.isSettled()) {
|
|
103
|
+
logger.info('No pages matched prerender filter; skipping.')
|
|
104
|
+
return Array.from(prerendered)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
await queue.start()
|
|
108
|
+
|
|
109
|
+
return Array.from(prerendered)
|
|
110
|
+
|
|
111
|
+
function addCrawlPageTask(page: Page) {
|
|
112
|
+
if (seen.has(page.path)) return
|
|
113
|
+
|
|
114
|
+
seen.add(page.path)
|
|
115
|
+
|
|
116
|
+
if (page.fromCrawl) {
|
|
117
|
+
startConfig.pages.push(page)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (!(page.prerender?.enabled ?? true)) return
|
|
121
|
+
|
|
122
|
+
if (
|
|
123
|
+
startConfig.prerender?.filter &&
|
|
124
|
+
!startConfig.prerender.filter(page)
|
|
125
|
+
) {
|
|
126
|
+
return
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const prerenderOptions = {
|
|
130
|
+
...startConfig.prerender,
|
|
131
|
+
...page.prerender,
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
queue.add(async () => {
|
|
135
|
+
logger.info(`Crawling: ${page.path}`)
|
|
136
|
+
const retries = retriesByPath.get(page.path) || 0
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
const res = await requestWithRedirects(
|
|
140
|
+
withTrailingSlash(withBase(page.path, routerBasePath)),
|
|
141
|
+
{
|
|
142
|
+
headers: {
|
|
143
|
+
...(prerenderOptions.headers ?? {}),
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
prerenderOptions.maxRedirects,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
if (!res.ok) {
|
|
150
|
+
if (isRedirectResponse(res)) {
|
|
151
|
+
logger.warn(`Max redirects reached for ${page.path}`)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
throw new Error(`Failed to fetch ${page.path}: ${res.statusText}`, {
|
|
155
|
+
cause: res,
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const cleanPagePath = (
|
|
160
|
+
prerenderOptions.outputPath || page.path
|
|
161
|
+
).split(/[?#]/)[0]!
|
|
162
|
+
|
|
163
|
+
const contentType = res.headers.get('content-type') || ''
|
|
164
|
+
const isImplicitHTML =
|
|
165
|
+
!cleanPagePath.endsWith('.html') && contentType.includes('html')
|
|
166
|
+
|
|
167
|
+
const routeWithIndex = cleanPagePath.endsWith('/')
|
|
168
|
+
? cleanPagePath + 'index'
|
|
169
|
+
: cleanPagePath
|
|
170
|
+
|
|
171
|
+
const isSpaShell =
|
|
172
|
+
startConfig.spa?.prerender.outputPath === cleanPagePath
|
|
173
|
+
|
|
174
|
+
let htmlPath: string
|
|
175
|
+
if (isSpaShell) {
|
|
176
|
+
htmlPath = cleanPagePath + '.html'
|
|
177
|
+
} else if (
|
|
178
|
+
cleanPagePath.endsWith('/') ||
|
|
179
|
+
(prerenderOptions.autoSubfolderIndex ?? true)
|
|
180
|
+
) {
|
|
181
|
+
htmlPath = joinURL(cleanPagePath, 'index.html')
|
|
182
|
+
} else {
|
|
183
|
+
htmlPath = cleanPagePath + '.html'
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const filename = withoutBase(
|
|
187
|
+
isImplicitHTML ? htmlPath : routeWithIndex,
|
|
188
|
+
routerBasePath,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
const html = await res.text()
|
|
192
|
+
const filepath = path.join(outputDir, filename)
|
|
193
|
+
|
|
194
|
+
await fsp.mkdir(path.dirname(filepath), {
|
|
195
|
+
recursive: true,
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
await fsp.writeFile(filepath, html)
|
|
199
|
+
|
|
200
|
+
prerendered.add(page.path)
|
|
201
|
+
|
|
202
|
+
const newPage = await prerenderOptions.onSuccess?.({ page, html })
|
|
203
|
+
|
|
204
|
+
if (newPage) {
|
|
205
|
+
Object.assign(page, newPage)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (prerenderOptions.crawlLinks ?? true) {
|
|
209
|
+
const links = extractLinks(html)
|
|
210
|
+
for (const link of links) {
|
|
211
|
+
addCrawlPageTask({ path: link, fromCrawl: true })
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
} catch (error) {
|
|
215
|
+
if (retries < (prerenderOptions.retryCount ?? 0)) {
|
|
216
|
+
const retryDelay = normalizeRetryDelay(prerenderOptions.retryDelay)
|
|
217
|
+
logger.warn(
|
|
218
|
+
`Encountered error, retrying: ${page.path} in ${retryDelay}ms`,
|
|
219
|
+
)
|
|
220
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelay))
|
|
221
|
+
retriesByPath.set(page.path, retries + 1)
|
|
222
|
+
addCrawlPageTask(page)
|
|
223
|
+
} else if (prerenderOptions.failOnError ?? true) {
|
|
224
|
+
throw error
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
})
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function normalizeRetryDelay(value: number | undefined): number {
|
|
232
|
+
const retryDelay = Number(value)
|
|
233
|
+
|
|
234
|
+
if (!Number.isFinite(retryDelay) || retryDelay < 0) {
|
|
235
|
+
return DEFAULT_RETRY_DELAY
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return Math.trunc(retryDelay)
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
async function requestWithRedirects(
|
|
242
|
+
path: string,
|
|
243
|
+
options?: RequestInit,
|
|
244
|
+
maxRedirects: number = 5,
|
|
245
|
+
): Promise<Response> {
|
|
246
|
+
const response = await handler.request(path, options)
|
|
247
|
+
|
|
248
|
+
if (isRedirectResponse(response) && maxRedirects > 0) {
|
|
249
|
+
const location = response.headers.get('location')!
|
|
250
|
+
|
|
251
|
+
if (location.startsWith('http://localhost') || location.startsWith('/')) {
|
|
252
|
+
const nextPath = location.replace('http://localhost', '')
|
|
253
|
+
return requestWithRedirects(nextPath, options, maxRedirects - 1)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
logger.warn(`Skipping redirect to external location: ${location}`)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return response
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function isRedirectResponse(res: Response) {
|
|
264
|
+
return res.status >= 300 && res.status < 400 && res.headers.get('location')
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export function validateAndNormalizePrerenderPages(
|
|
268
|
+
pages: Array<Page>,
|
|
269
|
+
routerBaseUrl: URL,
|
|
270
|
+
): Array<Page> {
|
|
271
|
+
return pages.map((page) => {
|
|
272
|
+
let url: URL
|
|
273
|
+
try {
|
|
274
|
+
url = new URL(page.path, routerBaseUrl)
|
|
275
|
+
} catch (err) {
|
|
276
|
+
throw new Error(`prerender page path must be relative: ${page.path}`, {
|
|
277
|
+
cause: err,
|
|
278
|
+
})
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (url.origin !== 'http://localhost') {
|
|
282
|
+
throw new Error(`prerender page path must be relative: ${page.path}`)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const decodedPathname = decodeURIComponent(url.pathname)
|
|
286
|
+
|
|
287
|
+
return {
|
|
288
|
+
...page,
|
|
289
|
+
path: decodedPathname + url.search + url.hash,
|
|
290
|
+
}
|
|
291
|
+
})
|
|
292
|
+
}
|