vinext 1.0.1 → 1.1.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/README.md +72 -1
- package/dist/build/app-page-static-eligibility.d.ts +15 -0
- package/dist/build/app-page-static-eligibility.js +82 -0
- package/dist/build/prerender-paths.js +3 -78
- package/dist/build/prerender.js +33 -8
- package/dist/build/server-manifest.d.ts +7 -0
- package/dist/build/server-manifest.js +11 -1
- package/dist/cache/cache-adapters-virtual.d.ts +7 -1
- package/dist/cache/cache-adapters-virtual.js +3 -3
- package/dist/client/navigation-runtime.d.ts +11 -0
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/config/config-matchers.js +3 -1
- package/dist/config/next-config.d.ts +7 -0
- package/dist/config/next-config.js +18 -3
- package/dist/entries/app-rsc-entry.d.ts +2 -0
- package/dist/entries/app-rsc-entry.js +64 -43
- package/dist/index.d.ts +4 -1
- package/dist/index.js +59 -30
- package/dist/plugins/cache-flight-codec.d.ts +19 -0
- package/dist/plugins/cache-flight-codec.js +68 -0
- package/dist/plugins/commonjs-esm-facade.d.ts +35 -0
- package/dist/plugins/commonjs-esm-facade.js +80 -0
- package/dist/plugins/fonts.d.ts +8 -11
- package/dist/plugins/fonts.js +71 -34
- package/dist/routing/file-matcher.d.ts +1 -0
- package/dist/routing/file-matcher.js +1 -1
- package/dist/server/api-handler.js +17 -7
- package/dist/server/app-browser-entry.js +11 -7
- package/dist/server/app-browser-history-controller.d.ts +2 -0
- package/dist/server/app-browser-history-controller.js +8 -0
- package/dist/server/app-browser-interception-context.js +26 -2
- package/dist/server/app-browser-navigation-controller.d.ts +7 -1
- package/dist/server/app-browser-navigation-controller.js +93 -10
- package/dist/server/app-fallback-renderer.d.ts +2 -0
- package/dist/server/app-fallback-renderer.js +1 -0
- package/dist/server/app-history-state.d.ts +3 -0
- package/dist/server/app-history-state.js +7 -0
- package/dist/server/app-middleware.js +2 -1
- package/dist/server/app-optimistic-routing.js +1 -1
- package/dist/server/app-page-boundary-render.d.ts +5 -0
- package/dist/server/app-page-boundary-render.js +6 -4
- package/dist/server/app-page-cache-finalizer.d.ts +11 -0
- package/dist/server/app-page-cache-finalizer.js +41 -7
- package/dist/server/app-page-cache-render.d.ts +18 -0
- package/dist/server/app-page-cache-render.js +63 -43
- package/dist/server/app-page-cache.d.ts +5 -0
- package/dist/server/app-page-cache.js +27 -7
- package/dist/server/app-page-dispatch.d.ts +9 -1
- package/dist/server/app-page-dispatch.js +47 -30
- package/dist/server/app-page-element-builder.d.ts +7 -0
- package/dist/server/app-page-element-builder.js +27 -42
- package/dist/server/app-page-execution.d.ts +15 -12
- package/dist/server/app-page-execution.js +30 -40
- package/dist/server/app-page-head.d.ts +5 -0
- package/dist/server/app-page-head.js +9 -3
- package/dist/server/app-page-probe.d.ts +0 -109
- package/dist/server/app-page-probe.js +3 -136
- package/dist/server/app-page-render-identity.d.ts +0 -1
- package/dist/server/app-page-render-identity.js +1 -1
- package/dist/server/app-page-render-observation.js +2 -2
- package/dist/server/app-page-render.d.ts +13 -5
- package/dist/server/app-page-render.js +219 -119
- package/dist/server/app-page-request.d.ts +0 -1
- package/dist/server/app-page-request.js +1 -2
- package/dist/server/app-page-response.d.ts +4 -3
- package/dist/server/app-page-response.js +4 -3
- package/dist/server/app-page-route-wiring.d.ts +17 -5
- package/dist/server/app-page-route-wiring.js +55 -33
- package/dist/server/app-page-rsc-render-status.d.ts +48 -0
- package/dist/server/app-page-rsc-render-status.js +54 -0
- package/dist/server/app-page-stream.d.ts +15 -8
- package/dist/server/app-page-stream.js +6 -0
- package/dist/server/app-request-stage-dispatch.js +1 -1
- package/dist/server/app-request-stage-independent-entry.js +4 -4
- package/dist/server/app-response-header-provenance.d.ts +2 -0
- package/dist/server/app-response-header-provenance.js +10 -4
- package/dist/server/app-route-handler-dispatch.js +1 -1
- package/dist/server/app-router-entry.js +3 -3
- package/dist/server/app-rsc-handler.d.ts +4 -0
- package/dist/server/app-rsc-handler.js +212 -96
- package/dist/server/app-rsc-request-normalization.d.ts +3 -1
- package/dist/server/app-rsc-request-normalization.js +4 -2
- package/dist/server/app-rsc-response-stage.d.ts +1 -1
- package/dist/server/app-rsc-response-stage.js +6 -4
- package/dist/server/app-rsc-route-matching.d.ts +9 -1
- package/dist/server/app-rsc-route-matching.js +36 -19
- package/dist/server/app-server-action-execution.js +1 -1
- package/dist/server/app-ssr-entry.d.ts +3 -2
- package/dist/server/app-ssr-entry.js +6 -4
- package/dist/server/app-ssr-stream.d.ts +6 -1
- package/dist/server/app-ssr-stream.js +34 -15
- package/dist/server/app-worker-stages.d.ts +2 -2
- package/dist/server/app-worker-stages.js +3 -3
- package/dist/server/cacheability-request.js +9 -5
- package/dist/server/config-headers.js +2 -0
- package/dist/server/dev-server.js +12 -2
- package/dist/server/headers.d.ts +14 -0
- package/dist/server/headers.js +15 -1
- package/dist/server/image-optimization.d.ts +16 -0
- package/dist/server/image-optimization.js +26 -6
- package/dist/server/isr-cache.js +2 -2
- package/dist/server/middleware-matcher-pattern.js +8 -4
- package/dist/server/middleware-response-headers.js +2 -0
- package/dist/server/multi-stage.d.ts +8 -0
- package/dist/server/navigation-planner.js +1 -1
- package/dist/server/node-response-signal.d.ts +16 -0
- package/dist/server/node-response-signal.js +26 -0
- package/dist/server/open-redirect.d.ts +47 -0
- package/dist/server/open-redirect.js +74 -1
- package/dist/server/pages-page-handler.js +21 -4
- package/dist/server/pages-request-stage-entry.js +8 -4
- package/dist/server/prod-server.d.ts +8 -7
- package/dist/server/prod-server.js +153 -69
- package/dist/server/request-pipeline.d.ts +20 -8
- package/dist/server/request-pipeline.js +21 -7
- package/dist/server/response-compression.d.ts +43 -0
- package/dist/server/response-compression.js +111 -0
- package/dist/server/seed-cache.js +10 -7
- package/dist/server/socket-error-backstop.d.ts +14 -0
- package/dist/server/socket-error-backstop.js +27 -4
- package/dist/shims/cache-adapter-instantiate.d.ts +50 -0
- package/dist/shims/cache-adapter-instantiate.js +118 -0
- package/dist/shims/cache-callable-runtime.d.ts +2 -40
- package/dist/shims/cache-callable-runtime.js +50 -168
- package/dist/shims/cache-flight-arguments.d.ts +22 -0
- package/dist/shims/cache-flight-arguments.js +56 -0
- package/dist/shims/cache-request-state.d.ts +15 -0
- package/dist/shims/cache-request-state.js +31 -8
- package/dist/shims/cache-runtime.d.ts +6 -19
- package/dist/shims/cache-runtime.js +165 -225
- package/dist/shims/cache.d.ts +2 -2
- package/dist/shims/cache.js +5 -4
- package/dist/shims/cacheability-classification.d.ts +7 -0
- package/dist/shims/error-boundary-navigation.d.ts +7 -0
- package/dist/shims/error-boundary-navigation.js +19 -1
- package/dist/shims/error-boundary.d.ts +10 -10
- package/dist/shims/error-boundary.js +26 -7
- package/dist/shims/fetch-cache.d.ts +6 -0
- package/dist/shims/fetch-cache.js +19 -1
- package/dist/shims/form.js +1 -1
- package/dist/shims/headers.d.ts +13 -0
- package/dist/shims/headers.js +47 -4
- package/dist/shims/internal/app-page-props-cache-key.d.ts +5 -2
- package/dist/shims/internal/app-page-props-cache-key.js +24 -15
- package/dist/shims/internal/headers-state.d.ts +0 -1
- package/dist/shims/metadata.js +3 -3
- package/dist/shims/navigation-errors.d.ts +6 -0
- package/dist/shims/navigation-errors.js +11 -1
- package/dist/shims/navigation.d.ts +7 -0
- package/dist/shims/navigation.js +14 -4
- package/dist/shims/request-context.d.ts +9 -0
- package/dist/shims/thenable-params.d.ts +4 -0
- package/dist/shims/thenable-params.js +25 -3
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/utils/mdx-scan.d.ts +5 -0
- package/dist/utils/mdx-scan.js +8 -1
- package/dist/utils/regex-safety.d.ts +10 -0
- package/dist/utils/regex-safety.js +70 -18
- package/package.json +3 -3
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { parseAst } from "vite";
|
|
2
|
+
import MagicString from "magic-string";
|
|
3
|
+
//#region src/plugins/commonjs-esm-facade.ts
|
|
4
|
+
const EXPORT_FACADE_START = "/* [vite-plugin-commonjs] export-statement-S */";
|
|
5
|
+
const EXPORT_FACADE_END = "/* [vite-plugin-commonjs] export-statement-E */";
|
|
6
|
+
const EXPORT_KEYWORD_RE = /\bexport\b(?!-)/;
|
|
7
|
+
/** Whether `code` has a top-level ESM export statement. */
|
|
8
|
+
function hasEsmExports(code) {
|
|
9
|
+
if (!EXPORT_KEYWORD_RE.test(code)) return false;
|
|
10
|
+
let ast;
|
|
11
|
+
try {
|
|
12
|
+
ast = parseAst(code);
|
|
13
|
+
} catch {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
return ast.body.some((statement) => statement.type === "ExportNamedDeclaration" || statement.type === "ExportDefaultDeclaration" || statement.type === "ExportAllDeclaration");
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Removes the export facade vite-plugin-commonjs appended to `output` when the
|
|
20
|
+
* module it transformed is ESM. Returns `undefined` when there is nothing to
|
|
21
|
+
* remove.
|
|
22
|
+
*
|
|
23
|
+
* Next.js treats a module with ESM syntax as ESM: `require()` still works, but
|
|
24
|
+
* `module` / `exports` never become its exports. The plugin's analyzer is not
|
|
25
|
+
* scope-aware, so for bundled ESM that inlines CommonJS wrappers
|
|
26
|
+
* (`__commonJS((exports, module) => …)`) it exports the wrappers' assignments
|
|
27
|
+
* too, which duplicates the module's own exports. Its `require()` rewrite and
|
|
28
|
+
* its local `module` / `exports` polyfill stay, so free CommonJS assignments
|
|
29
|
+
* still run without becoming exports.
|
|
30
|
+
*
|
|
31
|
+
* Besides the facade, the plugin only prepends imports and its polyfill and
|
|
32
|
+
* rewrites `require()` calls, so the module's own top-level exports are still
|
|
33
|
+
* in `output`. Classifying the output rather than rereading the source keeps
|
|
34
|
+
* the decision tied to the exact code the plugin transformed.
|
|
35
|
+
*
|
|
36
|
+
* The facade is appended after the module's code (only dynamic-require
|
|
37
|
+
* runtimes, which have no source mappings, may follow it), so removing it
|
|
38
|
+
* leaves the plugin's source map valid.
|
|
39
|
+
*/
|
|
40
|
+
function stripEsmCommonJsExportFacade(output) {
|
|
41
|
+
const facade = findEsmCommonJsExportFacade(output);
|
|
42
|
+
return facade && output.slice(0, facade[0]) + output.slice(facade[1]);
|
|
43
|
+
}
|
|
44
|
+
/** The `[start, end)` range of the facade {@link stripEsmCommonJsExportFacade} removes. */
|
|
45
|
+
function findEsmCommonJsExportFacade(output) {
|
|
46
|
+
const start = output.lastIndexOf(EXPORT_FACADE_START);
|
|
47
|
+
if (start === -1) return void 0;
|
|
48
|
+
const end = output.indexOf(EXPORT_FACADE_END, start);
|
|
49
|
+
if (end === -1) return void 0;
|
|
50
|
+
const facadeEnd = end + 47;
|
|
51
|
+
return hasEsmExports(output.slice(0, start) + output.slice(facadeEnd)) ? [start, facadeEnd] : void 0;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Applies {@link stripEsmCommonJsExportFacade} in the client dependency
|
|
55
|
+
* optimizer's Rolldown builds (scan and pre-bundle). vite-plugin-commonjs's
|
|
56
|
+
* pre-bundle plugin loads and converts files there without vinext's transform
|
|
57
|
+
* wrapper, so its output reaches this hook as the loaded code. That code is
|
|
58
|
+
* the optimizer's source, so the removal needs its own map for anything the
|
|
59
|
+
* plugin appended after the facade.
|
|
60
|
+
*/
|
|
61
|
+
const commonJsEsmFacadeOptimizeDepsPlugin = {
|
|
62
|
+
name: "vinext:commonjs-esm-facade:optimize-deps",
|
|
63
|
+
transform: {
|
|
64
|
+
filter: { code: { include: EXPORT_FACADE_START } },
|
|
65
|
+
handler(code, id) {
|
|
66
|
+
const facade = findEsmCommonJsExportFacade(code);
|
|
67
|
+
if (!facade) return null;
|
|
68
|
+
const output = new MagicString(code).remove(facade[0], facade[1]);
|
|
69
|
+
return {
|
|
70
|
+
code: output.toString(),
|
|
71
|
+
map: output.generateMap({
|
|
72
|
+
source: id,
|
|
73
|
+
hires: "boundary"
|
|
74
|
+
})
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
//#endregion
|
|
80
|
+
export { commonJsEsmFacadeOptimizeDepsPlugin, stripEsmCommonJsExportFacade };
|
package/dist/plugins/fonts.d.ts
CHANGED
|
@@ -3,9 +3,10 @@ import { Plugin } from "vite";
|
|
|
3
3
|
export declare const VIRTUAL_GOOGLE_FONTS = "virtual:vinext-google-fonts";
|
|
4
4
|
export declare const RESOLVED_VIRTUAL_GOOGLE_FONTS: string;
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* Point the `@font-face { src: url(...) }` references of cached Google Fonts
|
|
7
|
+
* CSS at the served URL the plugin's `writeBundle` hook copies the font
|
|
8
|
+
* files to (and the dev middleware serves them from), by replacing
|
|
9
|
+
* `CACHED_FONT_DIR_TOKEN` with `/<assetsDir>/_vinext_fonts`.
|
|
9
10
|
*
|
|
10
11
|
* This is called once per transform, before the CSS string is embedded in
|
|
11
12
|
* the bundle as `_vinext.font.selfHostedCSS`. Every downstream consumer reads
|
|
@@ -14,9 +15,9 @@ export declare const RESOLVED_VIRTUAL_GOOGLE_FONTS: string;
|
|
|
14
15
|
* in `shims/font-google-base.ts`), and the HTTP `Link:` response header
|
|
15
16
|
* (via `buildAppPageFontLinkHeader` in `server/app-page-execution.ts`).
|
|
16
17
|
*
|
|
17
|
-
*
|
|
18
|
-
* (
|
|
19
|
-
*
|
|
18
|
+
* The token is substituted with plain split/join: it is a fixed string
|
|
19
|
+
* vinext wrote itself, so nothing about the checkout's path (spaces, quotes,
|
|
20
|
+
* parentheses, regex metacharacters, Windows separators) is parsed here.
|
|
20
21
|
*
|
|
21
22
|
* `assetsDir` must match whatever Vite has resolved for
|
|
22
23
|
* `build.assetsDir` on the client environment — otherwise the embedded
|
|
@@ -26,12 +27,8 @@ export declare const RESOLVED_VIRTUAL_GOOGLE_FONTS: string;
|
|
|
26
27
|
* passes the resolved value through from plugin state. The default is
|
|
27
28
|
* kept only so the exported helper can be driven directly from unit
|
|
28
29
|
* tests without synthesizing a full plugin context.
|
|
29
|
-
*
|
|
30
|
-
* Uses split/join rather than regex because `cacheDir` is an absolute
|
|
31
|
-
* filesystem path that may contain regex metacharacters on unusual
|
|
32
|
-
* filesystems.
|
|
33
30
|
*/
|
|
34
|
-
export declare function _rewriteCachedFontCssToServedUrls(css: string,
|
|
31
|
+
export declare function _rewriteCachedFontCssToServedUrls(css: string, assetsDir?: string): string;
|
|
35
32
|
/**
|
|
36
33
|
* Safely parse a static JS object literal string into a plain object.
|
|
37
34
|
* Uses Vite's parseAst (Rollup/acorn) so no code is ever evaluated.
|
package/dist/plugins/fonts.js
CHANGED
|
@@ -43,15 +43,15 @@ const GOOGLE_FONT_UTILITY_EXPORTS = /* @__PURE__ */ new Set([
|
|
|
43
43
|
/**
|
|
44
44
|
* Served URL prefix for self-hosted Google Font files.
|
|
45
45
|
*
|
|
46
|
-
* `fetchAndCacheFont()` downloads
|
|
46
|
+
* `fetchAndCacheFont()` downloads font files into `<root>/.vinext/fonts/`
|
|
47
47
|
* and writes an `@font-face` CSS snippet whose `src: url(...)` references
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
48
|
+
* name each file relative to that cache directory, behind
|
|
49
|
+
* `CACHED_FONT_DIR_TOKEN`. Before the CSS is embedded in the bundle as
|
|
50
|
+
* `_vinext.font.selfHostedCSS`, `_rewriteCachedFontCssToServedUrls()`
|
|
51
|
+
* replaces the token with this URL prefix, and the matching `writeBundle`
|
|
52
|
+
* hook in `createGoogleFontsPlugin` copies the font files into
|
|
53
|
+
* `<clientOutDir>/<assetsDir>/_vinext_fonts/` so the URL actually resolves
|
|
54
|
+
* against the origin at request time.
|
|
55
55
|
*
|
|
56
56
|
* The leading `_` keeps the namespace distinct from Vite's content-hashed
|
|
57
57
|
* asset names (which are emitted flat into `<assetsDir>/`) and from any
|
|
@@ -59,6 +59,25 @@ const GOOGLE_FONT_UTILITY_EXPORTS = /* @__PURE__ */ new Set([
|
|
|
59
59
|
*/
|
|
60
60
|
const VINEXT_FONT_URL_NAMESPACE = "_vinext_fonts";
|
|
61
61
|
const MAX_GOOGLE_FONTS_ERROR_BODY_LENGTH = 500;
|
|
62
|
+
/**
|
|
63
|
+
* Stands in for the font cache directory in every `url()` of a cached
|
|
64
|
+
* stylesheet, so the file on disk holds no absolute path and reads the same
|
|
65
|
+
* wherever the checkout's `.vinext/` ends up: a moved or copied project, a
|
|
66
|
+
* CI cache restored into another workspace, or a Docker build that copies
|
|
67
|
+
* in a host's `.vinext/`. Next.js has no such cache (its Google font loader
|
|
68
|
+
* keeps fetched CSS in memory and emits `/_next/static/media` URLs), so the
|
|
69
|
+
* parity target is output that does not depend on where the cache was
|
|
70
|
+
* written.
|
|
71
|
+
*/
|
|
72
|
+
const CACHED_FONT_DIR_TOKEN = "__VINEXT_FONT_CACHE_DIR__";
|
|
73
|
+
/**
|
|
74
|
+
* Cached stylesheet whose `url()` references use `CACHED_FONT_DIR_TOKEN`.
|
|
75
|
+
* The suffix ties the cache to that format: a `style.css` written by an
|
|
76
|
+
* earlier vinext holds the writing checkout's absolute paths, which would
|
|
77
|
+
* 404 once embedded, so it is never read and the font is fetched again.
|
|
78
|
+
* Change the suffix whenever the cached CSS format changes.
|
|
79
|
+
*/
|
|
80
|
+
const CACHED_FONT_CSS_FILE = "style-q7f3kd.css";
|
|
62
81
|
function formatGoogleFontsErrorBody(body) {
|
|
63
82
|
const trimmed = body.trim();
|
|
64
83
|
if (!trimmed) return "(empty response body)";
|
|
@@ -67,9 +86,10 @@ function formatGoogleFontsErrorBody(body) {
|
|
|
67
86
|
return `${trimmed.slice(0, MAX_GOOGLE_FONTS_ERROR_BODY_LENGTH)}\n... (truncated ${omitted} characters)`;
|
|
68
87
|
}
|
|
69
88
|
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
89
|
+
* Point the `@font-face { src: url(...) }` references of cached Google Fonts
|
|
90
|
+
* CSS at the served URL the plugin's `writeBundle` hook copies the font
|
|
91
|
+
* files to (and the dev middleware serves them from), by replacing
|
|
92
|
+
* `CACHED_FONT_DIR_TOKEN` with `/<assetsDir>/_vinext_fonts`.
|
|
73
93
|
*
|
|
74
94
|
* This is called once per transform, before the CSS string is embedded in
|
|
75
95
|
* the bundle as `_vinext.font.selfHostedCSS`. Every downstream consumer reads
|
|
@@ -78,9 +98,9 @@ function formatGoogleFontsErrorBody(body) {
|
|
|
78
98
|
* in `shims/font-google-base.ts`), and the HTTP `Link:` response header
|
|
79
99
|
* (via `buildAppPageFontLinkHeader` in `server/app-page-execution.ts`).
|
|
80
100
|
*
|
|
81
|
-
*
|
|
82
|
-
* (
|
|
83
|
-
*
|
|
101
|
+
* The token is substituted with plain split/join: it is a fixed string
|
|
102
|
+
* vinext wrote itself, so nothing about the checkout's path (spaces, quotes,
|
|
103
|
+
* parentheses, regex metacharacters, Windows separators) is parsed here.
|
|
84
104
|
*
|
|
85
105
|
* `assetsDir` must match whatever Vite has resolved for
|
|
86
106
|
* `build.assetsDir` on the client environment — otherwise the embedded
|
|
@@ -90,16 +110,9 @@ function formatGoogleFontsErrorBody(body) {
|
|
|
90
110
|
* passes the resolved value through from plugin state. The default is
|
|
91
111
|
* kept only so the exported helper can be driven directly from unit
|
|
92
112
|
* tests without synthesizing a full plugin context.
|
|
93
|
-
*
|
|
94
|
-
* Uses split/join rather than regex because `cacheDir` is an absolute
|
|
95
|
-
* filesystem path that may contain regex metacharacters on unusual
|
|
96
|
-
* filesystems.
|
|
97
113
|
*/
|
|
98
|
-
function _rewriteCachedFontCssToServedUrls(css,
|
|
99
|
-
|
|
100
|
-
if (!normalizedCacheDir || !css.includes(normalizedCacheDir)) return css;
|
|
101
|
-
const prefix = assetsDir || DEFAULT_ASSETS_DIR;
|
|
102
|
-
return css.split(normalizedCacheDir).join(`/${prefix}/${VINEXT_FONT_URL_NAMESPACE}`);
|
|
114
|
+
function _rewriteCachedFontCssToServedUrls(css, assetsDir = DEFAULT_ASSETS_DIR) {
|
|
115
|
+
return css.split(CACHED_FONT_DIR_TOKEN).join(`/${assetsDir || DEFAULT_ASSETS_DIR}/${VINEXT_FONT_URL_NAMESPACE}`);
|
|
103
116
|
}
|
|
104
117
|
/**
|
|
105
118
|
* Default `build.assetsDir` — matches vinext's resolved default in
|
|
@@ -274,24 +287,49 @@ function propertyNameToGoogleFontFamily(prop) {
|
|
|
274
287
|
}
|
|
275
288
|
/**
|
|
276
289
|
* Fetch Google Fonts CSS, download .woff2 files, cache locally, and return
|
|
277
|
-
* @font-face CSS
|
|
290
|
+
* @font-face CSS whose `url()` references use `CACHED_FONT_DIR_TOKEN`.
|
|
278
291
|
*
|
|
279
292
|
* Cache dir structure: .vinext/fonts/<family-hash>/
|
|
280
|
-
* - style
|
|
293
|
+
* - style-<suffix>.css (the rewritten @font-face CSS, see `CACHED_FONT_CSS_FILE`)
|
|
281
294
|
* - *.woff2 (downloaded font files)
|
|
282
295
|
*/
|
|
283
296
|
async function fetchAndCacheFont(cssUrl, family, cacheDir) {
|
|
284
297
|
const { createHash } = await import("node:crypto");
|
|
285
298
|
const urlHash = createHash("md5").update(cssUrl).digest("hex").slice(0, 12);
|
|
286
|
-
const
|
|
287
|
-
const
|
|
299
|
+
const fontDirName = `${family.toLowerCase().replace(/\s+/g, "-")}-${urlHash}`;
|
|
300
|
+
const fontDir = path.join(cacheDir, fontDirName);
|
|
301
|
+
const cachedCSSPath = path.join(fontDir, CACHED_FONT_CSS_FILE);
|
|
288
302
|
if (fs.existsSync(cachedCSSPath)) return fs.readFileSync(cachedCSSPath, "utf-8");
|
|
303
|
+
const css = await downloadGoogleFont(cssUrl, family, fontDir, fontDirName);
|
|
304
|
+
try {
|
|
305
|
+
writeFileAtomically(cachedCSSPath, css);
|
|
306
|
+
} catch {}
|
|
307
|
+
return css;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Write-then-rename, so a write that fails midway never leaves a partial
|
|
311
|
+
* file for a later build to trust: both font files and the stylesheet are
|
|
312
|
+
* reused as soon as they exist.
|
|
313
|
+
*/
|
|
314
|
+
function writeFileAtomically(filePath, data) {
|
|
315
|
+
const tempPath = `${filePath}.${process.pid}.tmp`;
|
|
316
|
+
try {
|
|
317
|
+
fs.writeFileSync(tempPath, data);
|
|
318
|
+
fs.renameSync(tempPath, filePath);
|
|
319
|
+
} catch (err) {
|
|
320
|
+
fs.rmSync(tempPath, { force: true });
|
|
321
|
+
throw err;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
async function downloadGoogleFont(cssUrl, family, fontDir, fontDirName) {
|
|
325
|
+
const { createHash } = await import("node:crypto");
|
|
289
326
|
const cssResponse = await fetch(cssUrl, { headers: { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" } });
|
|
290
327
|
if (!cssResponse.ok) {
|
|
291
328
|
const body = await cssResponse.text().catch(() => "");
|
|
292
329
|
throw new GoogleFontsHttpError(cssUrl, cssResponse.status, body);
|
|
293
330
|
}
|
|
294
331
|
let css = await cssResponse.text();
|
|
332
|
+
if (!css.trim()) throw new Error(`Google Fonts returned an empty stylesheet: ${cssUrl}`);
|
|
295
333
|
const urlRe = /url\((https:\/\/fonts\.gstatic\.com\/[^)]+)\)/g;
|
|
296
334
|
const urls = /* @__PURE__ */ new Map();
|
|
297
335
|
let urlMatch;
|
|
@@ -308,14 +346,13 @@ async function fetchAndCacheFont(cssUrl, family, cacheDir) {
|
|
|
308
346
|
const filePath = path.join(fontDir, filename);
|
|
309
347
|
if (!fs.existsSync(filePath)) {
|
|
310
348
|
const fontResponse = await fetch(fontUrl);
|
|
311
|
-
if (fontResponse.ok) {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
349
|
+
if (!fontResponse.ok) throw new Error(`Font file download failed with HTTP ${fontResponse.status}: ${fontUrl}`);
|
|
350
|
+
const buffer = Buffer.from(await fontResponse.arrayBuffer());
|
|
351
|
+
if (buffer.byteLength === 0) throw new Error(`Font file download returned an empty body: ${fontUrl}`);
|
|
352
|
+
writeFileAtomically(filePath, buffer);
|
|
315
353
|
}
|
|
316
|
-
css = css.split(fontUrl).join(
|
|
354
|
+
css = css.split(fontUrl).join(`${CACHED_FONT_DIR_TOKEN}/${fontDirName}/${filename}`);
|
|
317
355
|
}
|
|
318
|
-
fs.writeFileSync(cachedCSSPath, css);
|
|
319
356
|
return css;
|
|
320
357
|
}
|
|
321
358
|
/**
|
|
@@ -546,7 +583,7 @@ function createGoogleFontsPlugin(fontGoogleShimPath, shimsDir) {
|
|
|
546
583
|
if (err instanceof GoogleFontsHttpError) throw new Error(`[vinext:google-fonts] ${id}: Google Fonts returned HTTP ${err.status} for ${err.url}.\n${formatGoogleFontsErrorBody(err.responseBody)}`);
|
|
547
584
|
return;
|
|
548
585
|
}
|
|
549
|
-
const servedCSS = _rewriteCachedFontCssToServedUrls(localCSS,
|
|
586
|
+
const servedCSS = _rewriteCachedFontCssToServedUrls(localCSS, transformAssetsDir);
|
|
550
587
|
const preloadUrls = findFontFilesInCss(servedCSS, validated.preload ? validated.subsets : void 0).filter((file) => file.preloadFontFile).map((file) => file.googleFontFileUrl);
|
|
551
588
|
const fallbackMetrics = validated.adjustFontFallback === false ? void 0 : getFallbackFontOverrideMetrics(family);
|
|
552
589
|
const adjustedFallbackCSS = fallbackMetrics ? buildFallbackFontFace(family, fallbackMetrics) : void 0;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
//#region src/routing/file-matcher.d.ts
|
|
2
|
+
export declare const DEFAULT_PAGE_EXTENSIONS: readonly ["tsx", "ts", "jsx", "js"];
|
|
2
3
|
export declare function normalizePageExtensions(pageExtensions?: readonly string[] | null): string[];
|
|
3
4
|
export type ValidFileMatcher = {
|
|
4
5
|
extensions: string[];
|
|
@@ -152,4 +152,4 @@ async function* scanWithExtensions(stem, cwd, extensions, exclude) {
|
|
|
152
152
|
})) yield toSlash(file);
|
|
153
153
|
}
|
|
154
154
|
//#endregion
|
|
155
|
-
export { buildViteResolveExtensions, createValidFileMatcher, findFileWithExtensions, findFileWithExts, normalizePageExtensions, normalizeViteResolveExtensions, scanWithExtensions };
|
|
155
|
+
export { DEFAULT_PAGE_EXTENSIONS, buildViteResolveExtensions, createValidFileMatcher, findFileWithExtensions, findFileWithExts, normalizePageExtensions, normalizeViteResolveExtensions, scanWithExtensions };
|
|
@@ -11,6 +11,7 @@ import { resolveRequestHost, resolveRequestProtocol } from "./proxy-trust.js";
|
|
|
11
11
|
import { performOnDemandRevalidate } from "./pages-revalidate.js";
|
|
12
12
|
import { attachPagesPreviewApi, attachPagesRequestCookies } from "./pages-node-compat.js";
|
|
13
13
|
import { finalizeEdgeApiResponse, isEdgeApiRuntime } from "./edge-api-runtime.js";
|
|
14
|
+
import { signalFromNodeResponse } from "./node-response-signal.js";
|
|
14
15
|
import { Buffer } from "node:buffer";
|
|
15
16
|
import { decode } from "node:querystring";
|
|
16
17
|
//#region src/server/api-handler.ts
|
|
@@ -89,7 +90,7 @@ function readEdgeRequestBody(req) {
|
|
|
89
90
|
req.on("error", (error) => controller.error(error));
|
|
90
91
|
} });
|
|
91
92
|
}
|
|
92
|
-
function createEdgeApiRequest(req, url, params, nextConfig) {
|
|
93
|
+
function createEdgeApiRequest(req, res, url, params, nextConfig) {
|
|
93
94
|
const headers = new Headers();
|
|
94
95
|
for (const [name, value] of Object.entries(req.headers)) {
|
|
95
96
|
if (name.startsWith(":")) continue;
|
|
@@ -103,10 +104,12 @@ function createEdgeApiRequest(req, url, params, nextConfig) {
|
|
|
103
104
|
if (basePath && !hasBasePath(requestUrl.pathname, basePath)) requestUrl.pathname = `${basePath}${requestUrl.pathname}`;
|
|
104
105
|
const query = mergeRouteParamsIntoQuery(parseQueryString(url), params);
|
|
105
106
|
requestUrl.search = urlQueryToSearchParams(query).toString();
|
|
106
|
-
const
|
|
107
|
+
const signal = signalFromNodeResponse(res);
|
|
108
|
+
const body = signal.aborted ? void 0 : readEdgeRequestBody(req);
|
|
107
109
|
const init = {
|
|
108
110
|
headers,
|
|
109
|
-
method: req.method
|
|
111
|
+
method: req.method,
|
|
112
|
+
signal
|
|
110
113
|
};
|
|
111
114
|
if (body) {
|
|
112
115
|
init.body = body;
|
|
@@ -138,12 +141,17 @@ function waitForWritableDrain(res) {
|
|
|
138
141
|
res.once("close", onClose);
|
|
139
142
|
});
|
|
140
143
|
}
|
|
141
|
-
async function writeEdgeApiResponseBody(res, body) {
|
|
144
|
+
async function writeEdgeApiResponseBody(res, body, signal) {
|
|
142
145
|
if (!body) {
|
|
143
146
|
res.end();
|
|
144
147
|
return;
|
|
145
148
|
}
|
|
146
149
|
const reader = body.getReader();
|
|
150
|
+
const cancel = () => {
|
|
151
|
+
reader.cancel(signal.reason).catch(() => {});
|
|
152
|
+
};
|
|
153
|
+
if (signal.aborted) cancel();
|
|
154
|
+
else signal.addEventListener("abort", cancel, { once: true });
|
|
147
155
|
try {
|
|
148
156
|
while (true) {
|
|
149
157
|
const result = await reader.read();
|
|
@@ -151,11 +159,13 @@ async function writeEdgeApiResponseBody(res, body) {
|
|
|
151
159
|
if (result.value.byteLength === 0) continue;
|
|
152
160
|
if (!res.write(Buffer.from(result.value))) await waitForWritableDrain(res);
|
|
153
161
|
}
|
|
154
|
-
res.end();
|
|
162
|
+
if (!signal.aborted) res.end();
|
|
155
163
|
} catch (error) {
|
|
164
|
+
if (signal.aborted) return;
|
|
156
165
|
res.destroy(error instanceof Error ? error : new Error(String(error)));
|
|
157
166
|
throw error;
|
|
158
167
|
} finally {
|
|
168
|
+
signal.removeEventListener("abort", cancel);
|
|
159
169
|
reader.releaseLock();
|
|
160
170
|
}
|
|
161
171
|
}
|
|
@@ -224,7 +234,7 @@ async function handleApiRoute(runner, req, res, url, apiRoutes, nextConfig) {
|
|
|
224
234
|
try {
|
|
225
235
|
const apiModule = await importModule(runner, route.filePath);
|
|
226
236
|
if (isEdgeApiRouteModule(apiModule)) {
|
|
227
|
-
const nextRequest = new NextRequest(createEdgeApiRequest(req, url, params, nextConfig), nextConfig ? { nextConfig: {
|
|
237
|
+
const nextRequest = new NextRequest(createEdgeApiRequest(req, res, url, params, nextConfig), nextConfig ? { nextConfig: {
|
|
228
238
|
basePath: nextConfig.basePath,
|
|
229
239
|
i18n: nextConfig.i18n ?? void 0,
|
|
230
240
|
trailingSlash: nextConfig.trailingSlash
|
|
@@ -239,7 +249,7 @@ async function handleApiRoute(runner, req, res, url, apiRoutes, nextConfig) {
|
|
|
239
249
|
if (name !== "set-cookie") res.setHeader(name, value);
|
|
240
250
|
});
|
|
241
251
|
if (setCookieHeaders.length) res.setHeader("set-cookie", setCookieHeaders);
|
|
242
|
-
await writeEdgeApiResponseBody(res, response.body);
|
|
252
|
+
await writeEdgeApiResponseBody(res, response.body, nextRequest.signal);
|
|
243
253
|
return true;
|
|
244
254
|
}
|
|
245
255
|
const handler = apiModule.default;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { splitPathnameForRouteMatch } from "../routing/utils.js";
|
|
2
2
|
import { addBasePathToPathname, stripBasePath } from "../utils/base-path.js";
|
|
3
3
|
import { VINEXT_CLIENT_REUSE_MANIFEST_HEADER, VINEXT_PARAMS_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, VINEXT_RSC_REDIRECT_HEADER, VINEXT_RSC_REDIRECT_TYPE_HEADER } from "./headers.js";
|
|
4
|
-
import { AppElementsWire } from "./app-elements-wire.js";
|
|
5
|
-
import { getMountedSlotIdsHeader, resolveVisitedResponseInterceptionContext } from "./app-elements.js";
|
|
6
4
|
import { AppRouterContext } from "../shims/internal/app-router-context.js";
|
|
7
5
|
import { matchRoutePattern } from "../routing/route-pattern.js";
|
|
8
6
|
import { installWindowNext, setWindowNextInternalSourcePage } from "../client/window-next.js";
|
|
9
7
|
import { retryScrollTo, scrollToHashTargetOnNextFrame } from "../shims/hash-scroll.js";
|
|
8
|
+
import { AppElementsWire } from "./app-elements-wire.js";
|
|
9
|
+
import { getMountedSlotIdsHeader, resolveVisitedResponseInterceptionContext } from "./app-elements.js";
|
|
10
10
|
import { getBfcacheIdMapContext, getNavigationContext, setNavigationContext } from "../shims/navigation-context-state.js";
|
|
11
11
|
import { decodeRedirectError, isRedirectError } from "../shims/navigation-errors.js";
|
|
12
12
|
import DefaultGlobalError from "../shims/default-global-error.js";
|
|
@@ -362,22 +362,22 @@ function createActionInitiationSnapshot() {
|
|
|
362
362
|
}
|
|
363
363
|
function createNavigationCommitEffect(options) {
|
|
364
364
|
const { activeRoutePaths, bfcacheIds, href, historyUpdateMode, navId, params, previousNextUrl, targetHistoryIndex } = options;
|
|
365
|
-
return () => {
|
|
365
|
+
return ({ keepCurrentUrl, releaseSnapshot }) => {
|
|
366
366
|
if (!browserNavigationController.isCurrentNavigation(navId)) {
|
|
367
|
-
commitClientNavigationState(void 0, { releaseSnapshot
|
|
367
|
+
commitClientNavigationState(void 0, { releaseSnapshot });
|
|
368
368
|
return;
|
|
369
369
|
}
|
|
370
370
|
historyController.commitNavigationHistory({
|
|
371
371
|
activeRoutePaths,
|
|
372
372
|
bfcacheIds,
|
|
373
373
|
href,
|
|
374
|
-
historyUpdateMode,
|
|
374
|
+
historyUpdateMode: keepCurrentUrl ? void 0 : historyUpdateMode,
|
|
375
375
|
previousNextUrl,
|
|
376
376
|
stageClientParams: () => stageClientParams(params),
|
|
377
377
|
targetHistoryIndex
|
|
378
378
|
});
|
|
379
379
|
clearAppNavigationFailureTarget(href);
|
|
380
|
-
commitClientNavigationState(navId);
|
|
380
|
+
commitClientNavigationState(navId, { releaseSnapshot });
|
|
381
381
|
};
|
|
382
382
|
}
|
|
383
383
|
async function renderNavigationPayload(options) {
|
|
@@ -1505,7 +1505,11 @@ function bootstrapHydration(rscStream, devErrorOverlay, initialRscBootstrap) {
|
|
|
1505
1505
|
},
|
|
1506
1506
|
preparePrefetchResponse: (response) => decodeAppElementsPromise(createFromFetch(Promise.resolve(response))),
|
|
1507
1507
|
claimCurrentHistoryTreeSnapshot: (historyUpdateMode, previousHistoryState) => historyController.claimCurrentHistoryTreeSnapshot(historyUpdateMode, previousHistoryState),
|
|
1508
|
-
commitAppOwnedHistoryStateWrite: (historyUpdateMode, previousHistoryState) => historyController.commitAppOwnedHistoryStateWrite(historyUpdateMode, previousHistoryState)
|
|
1508
|
+
commitAppOwnedHistoryStateWrite: (historyUpdateMode, previousHistoryState) => historyController.commitAppOwnedHistoryStateWrite(historyUpdateMode, previousHistoryState),
|
|
1509
|
+
discardPendingNavigation: () => {
|
|
1510
|
+
if (browserNavigationController.discardPendingNavigation(historyController.readCurrentTreeSnapshot())) navigationAbortCoordinator.abortActive();
|
|
1511
|
+
},
|
|
1512
|
+
flushCommittingNavigationUrl: () => browserNavigationController.flushCommittingNavigationUrl()
|
|
1509
1513
|
});
|
|
1510
1514
|
const handlePopstate = createPopstateRestoreHandler({
|
|
1511
1515
|
getActiveNavigationId: browserNavigationController.getActiveNavigationId.bind(browserNavigationController),
|
|
@@ -79,6 +79,8 @@ export declare class AppBrowserHistoryController {
|
|
|
79
79
|
beginCacheInvalidationGuard(): () => void;
|
|
80
80
|
invalidateRestorableClientState(): void;
|
|
81
81
|
rememberHistoryStateSnapshot(state: AppRouterState): void;
|
|
82
|
+
/** The router state of the most recently committed render, if any. */
|
|
83
|
+
readCurrentTreeSnapshot(): AppRouterState | null;
|
|
82
84
|
isCurrentExternalHistoryTree(historyState: unknown): boolean;
|
|
83
85
|
/** Records the raw/hash history entry that now claims the live tree. */
|
|
84
86
|
claimCurrentHistoryTreeSnapshot(historyUpdateMode: HistoryUpdateMode, previousHistoryState: unknown): void;
|
|
@@ -96,6 +96,9 @@ var AppBrowserHistoryController = class {
|
|
|
96
96
|
this.#treeSnapshotIdPendingFreshState = historyTreeSnapshotId !== null && this.#treeSnapshots.has(historyTreeSnapshotId) ? historyTreeSnapshotId : null;
|
|
97
97
|
}
|
|
98
98
|
rememberHistoryStateSnapshot(state) {
|
|
99
|
+
const previousState = this.readCurrentTreeSnapshot();
|
|
100
|
+
const previousOperation = previousState?.activeOperation;
|
|
101
|
+
if (previousState && previousOperation?.navigationCommitKind === "detached" && state.activeOperation?.navigationCommitKind === "authoritative" && state.activeOperation.navigationId === previousOperation.navigationId) this.#restorableClientState.replaceHistoryStateSnapshots(previousState, state);
|
|
99
102
|
this.#restorableClientState.rememberHistoryStateSnapshot({
|
|
100
103
|
historyIndex: this.#currentHistoryTraversalIndex,
|
|
101
104
|
state
|
|
@@ -109,6 +112,11 @@ var AppBrowserHistoryController = class {
|
|
|
109
112
|
if (previousTreeSnapshotId !== null && previousTreeSnapshotId !== treeSnapshotId && !this.#treeSnapshotClaimCounts.has(previousTreeSnapshotId)) this.#treeSnapshots.delete(previousTreeSnapshotId);
|
|
110
113
|
if (historyTreeSnapshotId !== treeSnapshotId) this.#replaceHistoryState(createHistoryStateWithTreeSnapshotId(this.#readHistoryState(), treeSnapshotId));
|
|
111
114
|
}
|
|
115
|
+
/** The router state of the most recently committed render, if any. */
|
|
116
|
+
readCurrentTreeSnapshot() {
|
|
117
|
+
if (this.#currentTreeSnapshotId === null) return null;
|
|
118
|
+
return this.#treeSnapshots.get(this.#currentTreeSnapshotId) ?? null;
|
|
119
|
+
}
|
|
112
120
|
isCurrentExternalHistoryTree(historyState) {
|
|
113
121
|
const treeSnapshotId = readHistoryStateTreeSnapshotId(historyState);
|
|
114
122
|
return treeSnapshotId !== null && treeSnapshotId === this.#currentTreeSnapshotId;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { splitPathnameForRouteMatch } from "../routing/utils.js";
|
|
1
|
+
import { normalizePathnameForRouteMatch, splitPathnameForRouteMatch } from "../routing/utils.js";
|
|
2
2
|
import { stripBasePath } from "../utils/base-path.js";
|
|
3
|
+
import { normalizePath } from "./normalize-path.js";
|
|
3
4
|
import { matchRoutePattern, matchRoutePatternPrefix, matchRoutePatternWithOptionalDynamicSegments } from "../routing/route-pattern.js";
|
|
4
5
|
//#region src/server/app-browser-interception-context.ts
|
|
5
6
|
/**
|
|
@@ -37,9 +38,32 @@ function resolveMiddlewareRewriteNavigationInterceptionContext(options) {
|
|
|
37
38
|
for (const interception of options.routeManifest.segmentGraph.interceptions.values()) {
|
|
38
39
|
if (!matchRoutePatternWithOptionalDynamicSegments(targetParts, interception.targetPatternParts)) continue;
|
|
39
40
|
if (matchRoutePatternPrefix(sourceParts, interception.sourcePatternParts)) return currentPathname;
|
|
40
|
-
if (currentMatchedPathname !== null && matchedSourceParts !== null && matchRoutePatternPrefix(matchedSourceParts, interception.sourcePatternParts)) return currentMatchedPathname;
|
|
41
|
+
if (currentMatchedPathname !== null && matchedSourceParts !== null && matchRoutePatternPrefix(matchedSourceParts, interception.sourcePatternParts)) return encodeMatchedPathname(currentMatchedPathname);
|
|
41
42
|
}
|
|
42
43
|
return null;
|
|
43
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* The matched route pathname is the matched URL decoded once per segment, with
|
|
47
|
+
* path delimiters (and literal `%2F`-style text) re-escaped. The server matches
|
|
48
|
+
* the context on its raw segments, so undo that: keep the escaped delimiters and
|
|
49
|
+
* encode every other `%`, then let the URL parser encode the rest (`café`
|
|
50
|
+
* becomes `caf%C3%A9`). An escaped ASCII character comes back unescaped (`%61`
|
|
51
|
+
* as `a`), like Next.js's `Next-Url`, which it builds from the router tree's
|
|
52
|
+
* canonical params; both spellings match the same params. `%252F` is
|
|
53
|
+
* ambiguous, since both a literal `%2F` and a literal `%252F` produce it. That
|
|
54
|
+
* case, and a result that does not reproduce the same matched pathname because
|
|
55
|
+
* the URL parser changed it (stripping a control character, say), navigate
|
|
56
|
+
* without interception instead of naming a different source.
|
|
57
|
+
*/
|
|
58
|
+
function encodeMatchedPathname(pathname) {
|
|
59
|
+
if (/%25(?:2f|23|3f|5c)/i.test(pathname)) return null;
|
|
60
|
+
let encoded;
|
|
61
|
+
try {
|
|
62
|
+
encoded = new URL(pathname.replace(/%(?!(?:25)?(?:2f|23|3f|5c))/gi, "%25"), "http://n").pathname;
|
|
63
|
+
} catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
return normalizePath(normalizePathnameForRouteMatch(encoded)) === pathname ? encoded : null;
|
|
67
|
+
}
|
|
44
68
|
//#endregion
|
|
45
69
|
export { resolveManifestNavigationInterceptionContext, resolveMiddlewareRewriteNavigationInterceptionContext };
|
|
@@ -17,7 +17,10 @@ export type PendingBrowserRouterState = {
|
|
|
17
17
|
};
|
|
18
18
|
export type NavigationPayloadOutcome = "committed" | "no-commit" | "hard-navigate";
|
|
19
19
|
type HardNavigationMode = "assign" | "replace";
|
|
20
|
-
type BrowserNavigationCommitEffect = (
|
|
20
|
+
type BrowserNavigationCommitEffect = (options: {
|
|
21
|
+
keepCurrentUrl: boolean;
|
|
22
|
+
releaseSnapshot: boolean;
|
|
23
|
+
}) => void;
|
|
21
24
|
type BrowserNavigationCommitEffectFactory = (options: {
|
|
22
25
|
activeRoutePaths: readonly string[];
|
|
23
26
|
bfcacheIds: Readonly<Record<string, string>>;
|
|
@@ -78,6 +81,8 @@ type BrowserNavigationController = {
|
|
|
78
81
|
attachBrowserRouterState(setter: Dispatch<AppRouterState | Promise<AppRouterState>>, stateRef: BrowserRouterStateRef): () => void;
|
|
79
82
|
beginPendingBrowserRouterState(): PendingBrowserRouterState;
|
|
80
83
|
finalizeNavigation(navId: number, pending: PendingBrowserRouterState | null | undefined): void;
|
|
84
|
+
discardPendingNavigation(visibleState: AppRouterState | null): boolean;
|
|
85
|
+
flushCommittingNavigationUrl(): void;
|
|
81
86
|
restoreHistorySnapshotVisibleState(options: {
|
|
82
87
|
restoreCopiedExternalHistoryEntry?: boolean;
|
|
83
88
|
beforeCommit?: () => void;
|
|
@@ -100,6 +105,7 @@ type BrowserNavigationController = {
|
|
|
100
105
|
* navigation would otherwise be lost.
|
|
101
106
|
*/
|
|
102
107
|
drainPrePaintEffects(renderId: number): void;
|
|
108
|
+
beginNavigationRenderCommit(renderId: number): void;
|
|
103
109
|
commitNavigationRender(renderId: number): void;
|
|
104
110
|
clearCommittedNavigationFailureTargets(renderId: number): void;
|
|
105
111
|
NavigationCommitSignal(this: void, { renderId, children }: {
|