@bgub/fig-server 0.1.0-alpha.1 → 0.1.0-alpha.2
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/{shared-Bna74_aZ.js → image-preloads-BIFcrqm9.js} +40 -2
- package/dist/image-preloads-BIFcrqm9.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +68 -12
- package/dist/index.js.map +1 -1
- package/dist/payload.d.ts +1 -1
- package/dist/payload.js +22 -6
- package/dist/payload.js.map +1 -1
- package/dist/{types-CimwEFsf.d.ts → types-mrjoQDOc.d.ts} +6 -3
- package/package.json +3 -3
- package/dist/shared-Bna74_aZ.js.map +0 -1
|
@@ -118,6 +118,44 @@ function nonceAttribute(nonce) {
|
|
|
118
118
|
return nonce === void 0 ? "" : ` nonce="${escapeAttribute(nonce)}"`;
|
|
119
119
|
}
|
|
120
120
|
//#endregion
|
|
121
|
-
|
|
121
|
+
//#region src/image-preloads.ts
|
|
122
|
+
function imagePreloadFromHostProps(type, props, suppressed) {
|
|
123
|
+
if (suppressed || type.toLowerCase() !== "img") return null;
|
|
124
|
+
if (props.loading === "lazy" || props.fetchpriority === "low") return null;
|
|
125
|
+
const src = stringProp(props.src);
|
|
126
|
+
const srcset = stringProp(props.srcset);
|
|
127
|
+
if (props.src != null && typeof props.src !== "string" || props.srcset != null && typeof props.srcset !== "string" || !src && !srcset || isDataUrl(src) || isDataUrl(srcset)) return null;
|
|
128
|
+
return {
|
|
129
|
+
as: "image",
|
|
130
|
+
crossorigin: imageCrossorigin(props.crossorigin),
|
|
131
|
+
fetchpriority: imageFetchpriority(props.fetchpriority),
|
|
132
|
+
href: src || void 0,
|
|
133
|
+
imagesizes: srcset ? stringProp(props.sizes) : void 0,
|
|
134
|
+
imagesrcset: srcset || void 0,
|
|
135
|
+
kind: "preload",
|
|
136
|
+
referrerpolicy: stringProp(props.referrerpolicy),
|
|
137
|
+
type: stringProp(props.type)
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
function suppressesImagePreloads(type) {
|
|
141
|
+
const normalizedType = type.toLowerCase();
|
|
142
|
+
return normalizedType === "picture" || normalizedType === "noscript";
|
|
143
|
+
}
|
|
144
|
+
function stringProp(value) {
|
|
145
|
+
return typeof value === "string" ? value : void 0;
|
|
146
|
+
}
|
|
147
|
+
function isDataUrl(value) {
|
|
148
|
+
return value?.slice(0, 5).toLowerCase() === "data:";
|
|
149
|
+
}
|
|
150
|
+
function imageCrossorigin(value) {
|
|
151
|
+
if (typeof value !== "string") return void 0;
|
|
152
|
+
if (value === "anonymous" || value === "use-credentials" || value === "") return value;
|
|
153
|
+
return "";
|
|
154
|
+
}
|
|
155
|
+
function imageFetchpriority(value) {
|
|
156
|
+
return value === "high" || value === "auto" ? value : void 0;
|
|
157
|
+
}
|
|
158
|
+
//#endregion
|
|
159
|
+
export { componentStack as a, nonceAttribute as c, withContextValue as d, cloneContextValues as i, streamFlowBlocked as l, suppressesImagePreloads as n, createStaticDispatcher as o, STREAMED_METADATA_ATTRIBUTE as r, deferred as s, imagePreloadFromHostProps as t, streamHighWaterMark as u };
|
|
122
160
|
|
|
123
|
-
//# sourceMappingURL=
|
|
161
|
+
//# sourceMappingURL=image-preloads-BIFcrqm9.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-preloads-BIFcrqm9.js","names":[],"sources":["../src/shared.ts","../src/image-preloads.ts"],"sourcesContent":["import type {\n ActionStateAction,\n ActionStateRunner,\n DependencyList,\n EffectCallback,\n ExternalStoreSubscribe,\n FigContext,\n StateSetter,\n StartTransition,\n} from \"@bgub/fig\";\nimport type {\n DataResource,\n RenderDispatcher,\n StableEventCallerArgs,\n} from \"@bgub/fig/internal\";\nimport { escapeAttribute } from \"./escaping.ts\";\n\nexport type ContextValues = Map<FigContext<unknown>, unknown[]>;\n\nexport const STREAMED_METADATA_ATTRIBUTE = \"data-fig-streamed-metadata\";\n\nexport interface StackFrame {\n name: string;\n parent: StackFrame | null;\n}\n\ninterface StaticDispatcherOptions {\n contextValues: ContextValues;\n externalStoreError: string;\n preloadData<TArgs extends unknown[], TValue>(\n resource: DataResource<TArgs, TValue>,\n args: TArgs,\n ): void;\n readData<TArgs extends unknown[], TValue>(\n resource: DataResource<TArgs, TValue>,\n args: TArgs,\n ): TValue;\n readPromise<T>(promise: PromiseLike<T>): T;\n updateError: string;\n useId(): string;\n}\n\nfunction contextStack(\n values: ContextValues,\n context: FigContext<unknown>,\n): unknown[] {\n let stack = values.get(context);\n\n if (stack === undefined) {\n stack = [];\n values.set(context, stack);\n }\n\n return stack;\n}\n\nexport function withContextValue<T>(\n values: ContextValues,\n context: FigContext<unknown>,\n value: unknown,\n callback: () => T,\n): T {\n const stack = contextStack(values, context);\n stack.push(value);\n\n try {\n return callback();\n } finally {\n stack.pop();\n }\n}\n\nfunction readContextValue<T>(values: ContextValues, context: FigContext<T>): T {\n const stack = values.get(context as FigContext<unknown>);\n if (stack !== undefined && stack.length > 0) {\n return stack[stack.length - 1] as T;\n }\n\n return context.defaultValue;\n}\n\nexport interface Deferred<T> {\n promise: Promise<T>;\n reject: (reason: unknown) => void;\n resolve: (value: T) => void;\n}\n\nexport function deferred<T>(): Deferred<T> {\n let resolve: Deferred<T>[\"resolve\"] = () => undefined;\n let reject: Deferred<T>[\"reject\"] = () => undefined;\n const promise = new Promise<T>((innerResolve, innerReject) => {\n resolve = innerResolve;\n reject = innerReject;\n });\n return { promise, reject, resolve };\n}\n\nexport function cloneContextValues(values: ContextValues): ContextValues {\n const clone: ContextValues = new Map();\n for (const [context, stack] of values) clone.set(context, [...stack]);\n return clone;\n}\n\n// Encoded bytes a render result stream's internal queue holds before flushing\n// pauses (resumed by consumer pulls). Shared by the HTML and payload\n// renderers. Large enough that a healthy consumer never blocks a flush; small\n// enough to bound per-connection buffering when the consumer stalls.\n// Rendering itself never pauses — only writing to the stream does.\nconst DEFAULT_STREAM_HIGH_WATER_MARK = 65536;\n\n// 0 would deadlock: desiredSize never goes positive, and read requests alone\n// do not make it so. 1 byte is the honest pure-pull minimum.\nexport function streamHighWaterMark(option: number | undefined): number {\n return Math.max(1, option ?? DEFAULT_STREAM_HIGH_WATER_MARK);\n}\n\n// Blocked means the stream's internal queue is at or past its high-water\n// mark; completed work then waits un-enqueued until the consumer pulls.\n// desiredSize is null on an errored stream — never blocked, because fatal\n// paths close the request before any further writes.\nexport function streamFlowBlocked(\n controller: ReadableStreamDefaultController<Uint8Array> | null,\n): boolean {\n const desiredSize = controller?.desiredSize;\n return typeof desiredSize === \"number\" && desiredSize <= 0;\n}\n\nfunction resolveInitialState<S>(initialState: S | (() => S)): S {\n return typeof initialState === \"function\"\n ? (initialState as () => S)()\n : initialState;\n}\n\nexport function createStaticDispatcher(\n options: StaticDispatcherOptions,\n): RenderDispatcher {\n return {\n useState<S>(initialState: S | (() => S)): [S, StateSetter<S>] {\n const value = resolveInitialState(initialState);\n const setState: StateSetter<typeof value> = () => {\n throw new Error(options.updateError);\n };\n return [value, setState];\n },\n useActionState<S, Args extends unknown[]>(\n _action: ActionStateAction<S, Args>,\n initialState: S,\n ): [S, ActionStateRunner<Args>, boolean] {\n const runner: ActionStateRunner<Args> = () => {\n throw new Error(options.updateError);\n };\n return [initialState, runner, false];\n },\n useId(): string {\n return options.useId();\n },\n useDeferredValue<T>(\n value: T,\n _initialValue: T | undefined,\n _hasInitialValue: boolean,\n ): T {\n return value;\n },\n useMemo<T>(calculate: () => T, _deps: DependencyList): T {\n return calculate();\n },\n useTransition(): [boolean, StartTransition] {\n // Server transitions run synchronously to completion; the signal never\n // aborts (there is no supersede/unmount lifecycle during a request).\n const startTransition: StartTransition = (\n callback: (signal: AbortSignal) => void | PromiseLike<void>,\n ) => void callback(new AbortController().signal);\n return [false, startTransition];\n },\n useReactive(_effect: EffectCallback, _deps?: DependencyList): void {},\n useBeforePaint(_effect: EffectCallback, _deps?: DependencyList): void {},\n useBeforeLayout(_effect: EffectCallback, _deps?: DependencyList): void {},\n useSyncExternalStore<T>(\n _subscribe: ExternalStoreSubscribe,\n _getSnapshot: () => T,\n getServerSnapshot?: () => T,\n ): T {\n if (getServerSnapshot === undefined) {\n throw new Error(options.externalStoreError);\n }\n\n return getServerSnapshot();\n },\n useStableEvent<Args extends unknown[], Result>(\n _handler: (...args: Args) => Result,\n ): (...args: StableEventCallerArgs<Args>) => Result {\n return (..._args: StableEventCallerArgs<Args>): Result => {\n throw new Error(\"Stable events cannot be called during server render.\");\n };\n },\n readContext<T>(context: FigContext<T>): T {\n return readContextValue(options.contextValues, context);\n },\n readData<TArgs extends unknown[], TValue>(\n resource: DataResource<TArgs, TValue>,\n args: TArgs,\n ): TValue {\n return options.readData(resource, args);\n },\n preloadData<TArgs extends unknown[], TValue>(\n resource: DataResource<TArgs, TValue>,\n args: TArgs,\n ): void {\n options.preloadData(resource, args);\n },\n readPromise<T>(promise: PromiseLike<T>): T {\n return options.readPromise(promise);\n },\n };\n}\n\nexport function errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nexport function componentStack(stack: StackFrame | null): string {\n const frames: string[] = [];\n for (let frame = stack; frame !== null; frame = frame.parent) {\n frames.push(` at ${frame.name}`);\n }\n return frames.length === 0 ? \"\" : `\\n${frames.join(\"\\n\")}`;\n}\n\nexport function nonceAttribute(nonce: string | undefined): string {\n return nonce === undefined ? \"\" : ` nonce=\"${escapeAttribute(nonce)}\"`;\n}\n","import type { PreloadResource, Props } from \"@bgub/fig\";\n\nexport function imagePreloadFromHostProps(\n type: string,\n props: Props,\n suppressed: boolean,\n): PreloadResource | null {\n if (suppressed || type.toLowerCase() !== \"img\") return null;\n if (props.loading === \"lazy\" || props.fetchpriority === \"low\") return null;\n\n const src = stringProp(props.src);\n const srcset = stringProp(props.srcset);\n if (\n (props.src != null && typeof props.src !== \"string\") ||\n (props.srcset != null && typeof props.srcset !== \"string\") ||\n (!src && !srcset) ||\n isDataUrl(src) ||\n isDataUrl(srcset)\n ) {\n return null;\n }\n\n return {\n as: \"image\",\n crossorigin: imageCrossorigin(props.crossorigin),\n fetchpriority: imageFetchpriority(props.fetchpriority),\n href: src || undefined,\n imagesizes: srcset ? stringProp(props.sizes) : undefined,\n imagesrcset: srcset || undefined,\n kind: \"preload\",\n referrerpolicy: stringProp(props.referrerpolicy),\n type: stringProp(props.type),\n };\n}\n\nexport function suppressesImagePreloads(type: string): boolean {\n const normalizedType = type.toLowerCase();\n return normalizedType === \"picture\" || normalizedType === \"noscript\";\n}\n\nfunction stringProp(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction isDataUrl(value: string | undefined): boolean {\n return value?.slice(0, 5).toLowerCase() === \"data:\";\n}\n\nfunction imageCrossorigin(value: unknown): PreloadResource[\"crossorigin\"] {\n if (typeof value !== \"string\") return undefined;\n if (value === \"anonymous\" || value === \"use-credentials\" || value === \"\") {\n return value;\n }\n return \"\";\n}\n\nfunction imageFetchpriority(value: unknown): PreloadResource[\"fetchpriority\"] {\n return value === \"high\" || value === \"auto\" ? value : undefined;\n}\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as ServerPreloadHeaderOptions, c as ServerPrerenderResult, d as RenderTreeKind, f as RenderTreeNode, i as ServerFragmentRenderResult, l as ServerRenderOptions, n as ServerErrorInfo, o as ServerPreloadHeaderResource, p as createRenderTreeCollector, r as ServerErrorPayload, s as ServerPrerenderOptions, t as ServerDocumentRenderResult, u as RenderTreeCollector } from "./types-
|
|
1
|
+
import { a as ServerPreloadHeaderOptions, c as ServerPrerenderResult, d as RenderTreeKind, f as RenderTreeNode, i as ServerFragmentRenderResult, l as ServerRenderOptions, n as ServerErrorInfo, o as ServerPreloadHeaderResource, p as createRenderTreeCollector, r as ServerErrorPayload, s as ServerPrerenderOptions, t as ServerDocumentRenderResult, u as RenderTreeCollector } from "./types-mrjoQDOc.js";
|
|
2
2
|
import { FigNode } from "@bgub/fig";
|
|
3
3
|
//#region src/index.d.ts
|
|
4
4
|
declare function renderToStream(node: FigNode, options?: ServerRenderOptions): ServerFragmentRenderResult;
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { i as escapeText, n as escapeScriptJson, t as escapeAttribute } from "./escaping-DAot8sFu.js";
|
|
2
|
-
import { a as
|
|
2
|
+
import { a as componentStack, c as nonceAttribute, d as withContextValue, i as cloneContextValues, l as streamFlowBlocked, n as suppressesImagePreloads, o as createStaticDispatcher, r as STREAMED_METADATA_ATTRIBUTE, s as deferred, t as imagePreloadFromHostProps, u as streamHighWaterMark } from "./image-preloads-BIFcrqm9.js";
|
|
3
3
|
import { Fragment, createElement, isValidElement } from "@bgub/fig";
|
|
4
4
|
import { ACTIVITY_TEMPLATE_ATTRIBUTE, EARLY_EVENT_HANDLER_PROPERTY, EARLY_EVENT_QUEUE_PROPERTY, HYDRATION_SKIP_ATTRIBUTE, REPLAYABLE_EVENT_TYPES, SUSPENSE_CLIENT_MARKER, SUSPENSE_COMPLETED_MARKER, SUSPENSE_END_MARKER, SUSPENSE_MARKER_PREFIX, SUSPENSE_PENDING_PREFIX, TEXT_SEPARATOR_DATA, VIEW_TRANSITION_CLASS_ATTRIBUTE, VIEW_TRANSITION_NAME_ATTRIBUTE, VIEW_TRANSITION_PENDING_PROPERTY, VIEW_TRANSITION_TIMEOUT_MS, assetResourceFromHostProps, assetResourceHostAttributes, assetResourceKey, attachDataStore, collectChildren, createRendererDataStore, invalidChildError, isActivity, isAssets, isClientReference, isContext, isErrorBoundary, isFigAssetResource, isPortal, isSuspense, isThenable, isViewTransition, readThenable, setCurrentDataStore, setCurrentDispatcher } from "@bgub/fig/internal";
|
|
5
5
|
//#region src/html.ts
|
|
@@ -158,13 +158,13 @@ const DEFAULT_LENGTH = 2e3;
|
|
|
158
158
|
const HEX_ESCAPE = /^[0-9A-Fa-f]{2}$/;
|
|
159
159
|
const PARAMETER_TOKEN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
160
160
|
const URI_REFERENCE_PUNCTUATION = "-._~:/?#[]@!$&'()*+,;=";
|
|
161
|
-
function createPreloadHeaderEntries(resources) {
|
|
161
|
+
function createPreloadHeaderEntries(resources, isEarlyImage) {
|
|
162
162
|
const preconnects = [];
|
|
163
163
|
const criticalPreloads = [];
|
|
164
164
|
const stylesheets = [];
|
|
165
165
|
const remaining = [];
|
|
166
166
|
for (const resource of resources) {
|
|
167
|
-
if (resource
|
|
167
|
+
if (!isServerPreloadHeaderResource(resource)) continue;
|
|
168
168
|
const value = preloadHeaderValue(resource);
|
|
169
169
|
if (value === null) continue;
|
|
170
170
|
const entry = {
|
|
@@ -172,7 +172,7 @@ function createPreloadHeaderEntries(resources) {
|
|
|
172
172
|
value
|
|
173
173
|
};
|
|
174
174
|
if (resource.kind === "preconnect") preconnects.push(entry);
|
|
175
|
-
else if (resource.kind === "font" || resource.kind === "preload" && (resource.as === "font" || resource.as === "image" && resource.fetchpriority === "high")) criticalPreloads.push(entry);
|
|
175
|
+
else if (resource.kind === "font" || resource.kind === "preload" && (resource.as === "font" || resource.as === "image" && (resource.fetchpriority === "high" || isEarlyImage?.(resource) === true))) criticalPreloads.push(entry);
|
|
176
176
|
else if (resource.kind === "stylesheet") stylesheets.push(entry);
|
|
177
177
|
else remaining.push(entry);
|
|
178
178
|
}
|
|
@@ -213,7 +213,8 @@ function preloadHeaderValue(resource) {
|
|
|
213
213
|
["as", resource.as],
|
|
214
214
|
["crossorigin", resource.crossorigin],
|
|
215
215
|
["type", resource.type],
|
|
216
|
-
["fetchpriority", resource.fetchpriority]
|
|
216
|
+
["fetchpriority", resource.fetchpriority],
|
|
217
|
+
["referrerpolicy", resource.referrerpolicy]
|
|
217
218
|
]);
|
|
218
219
|
case "modulepreload": return serializeLink(resource.href, [
|
|
219
220
|
["rel", "modulepreload"],
|
|
@@ -231,6 +232,10 @@ function preloadHeaderValue(resource) {
|
|
|
231
232
|
case "preconnect": return serializeLink(resource.href, [["rel", "preconnect"], ["crossorigin", resource.crossorigin]]);
|
|
232
233
|
}
|
|
233
234
|
}
|
|
235
|
+
function isServerPreloadHeaderResource(resource) {
|
|
236
|
+
if (resource.kind === "script") return false;
|
|
237
|
+
return resource.kind !== "preload" || resource.href !== void 0 && (resource.as !== "image" || !resource.imagesrcset);
|
|
238
|
+
}
|
|
234
239
|
function serializeLink(target, parameters) {
|
|
235
240
|
const encodedTarget = encodeLinkTarget(target);
|
|
236
241
|
if (encodedTarget === null) return null;
|
|
@@ -292,6 +297,7 @@ function normalizedLength(value) {
|
|
|
292
297
|
//#region src/asset-registry.ts
|
|
293
298
|
var AssetResourceRegistry = class {
|
|
294
299
|
identifierPrefix;
|
|
300
|
+
earlyImageKeys = /* @__PURE__ */ new Set();
|
|
295
301
|
emittedResources = /* @__PURE__ */ new Set();
|
|
296
302
|
deliveryResources = /* @__PURE__ */ new Map();
|
|
297
303
|
metadataByOwner = /* @__PURE__ */ new Map();
|
|
@@ -304,6 +310,13 @@ var AssetResourceRegistry = class {
|
|
|
304
310
|
if (isMetadataResource(resource)) return;
|
|
305
311
|
this.canonical(resource);
|
|
306
312
|
}
|
|
313
|
+
registerAutomaticImage(resource) {
|
|
314
|
+
const { key, resource: current } = this.canonical(resource);
|
|
315
|
+
if (this.earlyImageKeys.size < 10 || current.kind === "preload" && current.as === "image" && current.fetchpriority === "high") this.earlyImageKeys.add(key);
|
|
316
|
+
}
|
|
317
|
+
isEarlyImage(resource) {
|
|
318
|
+
return this.earlyImageKeys.has(assetResourceKey(resource));
|
|
319
|
+
}
|
|
307
320
|
activateMetadata(owner, resources) {
|
|
308
321
|
const metadata = resources.filter(isMetadataResource);
|
|
309
322
|
if (metadata.length === 0) {
|
|
@@ -367,7 +380,7 @@ var AssetResourceRegistry = class {
|
|
|
367
380
|
return snapshot;
|
|
368
381
|
}
|
|
369
382
|
preloadHeaderEntries() {
|
|
370
|
-
return createPreloadHeaderEntries(this.deliveryResources.values());
|
|
383
|
+
return createPreloadHeaderEntries(this.deliveryResources.values(), (resource) => this.isEarlyImage(resource));
|
|
371
384
|
}
|
|
372
385
|
visibleMetadata() {
|
|
373
386
|
const visible = /* @__PURE__ */ new Map();
|
|
@@ -378,7 +391,15 @@ var AssetResourceRegistry = class {
|
|
|
378
391
|
const key = assetResourceKey(resource);
|
|
379
392
|
const current = this.deliveryResources.get(key);
|
|
380
393
|
if (current !== void 0) {
|
|
381
|
-
if (assetSignature(current) !== assetSignature(resource))
|
|
394
|
+
if (assetSignature(current) !== assetSignature(resource)) {
|
|
395
|
+
const promoted = promoteCompatibleImagePreload(current, resource);
|
|
396
|
+
if (promoted === null) throw new AssetResourceConflictError(key, current, resource);
|
|
397
|
+
this.deliveryResources.set(key, promoted);
|
|
398
|
+
return {
|
|
399
|
+
key,
|
|
400
|
+
resource: promoted
|
|
401
|
+
};
|
|
402
|
+
}
|
|
382
403
|
return {
|
|
383
404
|
key,
|
|
384
405
|
resource: current
|
|
@@ -475,9 +496,12 @@ function withNonce(sink, props) {
|
|
|
475
496
|
function assetSignature(resource) {
|
|
476
497
|
switch (resource.kind) {
|
|
477
498
|
case "stylesheet": return signature(resource.kind, resource.href, resource.media ?? "", resource.precedence ?? "", resource.crossorigin ?? "", resource.blocking ?? "reveal");
|
|
478
|
-
case "preload":
|
|
499
|
+
case "preload": {
|
|
500
|
+
const imagesrcset = resource.as === "image" ? resource.imagesrcset || void 0 : void 0;
|
|
501
|
+
return signature(resource.kind, imagesrcset === void 0 ? resource.href ?? "" : "", resource.as, resource.type ?? "", resource.crossorigin ?? "", resource.fetchpriority ?? "", imagesrcset ?? "", imagesrcset === void 0 ? "" : resource.imagesizes ?? "", resource.referrerpolicy ?? "");
|
|
502
|
+
}
|
|
479
503
|
case "modulepreload": return signature(resource.kind, resource.href, resource.crossorigin ?? "", resource.fetchpriority ?? "");
|
|
480
|
-
case "font": return signature("preload", resource.href, "font", resource.type, resource.crossorigin ?? "anonymous", resource.fetchpriority ?? "");
|
|
504
|
+
case "font": return signature("preload", resource.href, "font", resource.type, resource.crossorigin ?? "anonymous", resource.fetchpriority ?? "", "", "", "");
|
|
481
505
|
case "preconnect": return signature(resource.kind, resource.href, resource.crossorigin ?? "");
|
|
482
506
|
case "script": return signature(resource.kind, resource.src, resource.module === true, resource.async !== false, resource.defer === true, resource.crossorigin ?? "");
|
|
483
507
|
case "title": return signature(resource.kind, resource.value);
|
|
@@ -485,6 +509,20 @@ function assetSignature(resource) {
|
|
|
485
509
|
}
|
|
486
510
|
return unsupportedAssetResource(resource);
|
|
487
511
|
}
|
|
512
|
+
function promoteCompatibleImagePreload(current, incoming) {
|
|
513
|
+
if (current.kind !== "preload" || incoming.kind !== "preload" || current.as !== "image" || incoming.as !== "image" || assetSignature({
|
|
514
|
+
...current,
|
|
515
|
+
fetchpriority: incoming.fetchpriority
|
|
516
|
+
}) !== assetSignature(incoming)) return null;
|
|
517
|
+
const currentPriority = current.fetchpriority === "auto" ? void 0 : current.fetchpriority;
|
|
518
|
+
const incomingPriority = incoming.fetchpriority === "auto" ? void 0 : incoming.fetchpriority;
|
|
519
|
+
if (currentPriority === incomingPriority) return current;
|
|
520
|
+
if (currentPriority === "low" || incomingPriority === "low") return null;
|
|
521
|
+
return currentPriority === "high" ? current : {
|
|
522
|
+
...current,
|
|
523
|
+
fetchpriority: "high"
|
|
524
|
+
};
|
|
525
|
+
}
|
|
488
526
|
function unsupportedAssetResource(resource) {
|
|
489
527
|
throw new Error(`Unsupported asset resource kind: ${resource.kind}`);
|
|
490
528
|
}
|
|
@@ -771,20 +809,20 @@ function writeChunk(request, chunk, segment) {
|
|
|
771
809
|
}
|
|
772
810
|
if (request.document === null) return;
|
|
773
811
|
const metadata = request.headSnapshot ?? request.assetRegistry.headMetadataHtml(request.nonce);
|
|
774
|
-
const [beforeMetadata, afterMetadata] = partitionHeadAssets(segment.assetResources);
|
|
812
|
+
const [beforeMetadata, afterMetadata] = partitionHeadAssets(request, segment.assetResources);
|
|
775
813
|
const blockingIds = /* @__PURE__ */ new Set();
|
|
776
814
|
request.write(metadata.preamble);
|
|
777
815
|
flushAssetList(request, beforeMetadata, blockingIds);
|
|
778
816
|
request.write(metadata.metadata);
|
|
779
817
|
flushAssetList(request, afterMetadata, blockingIds);
|
|
780
818
|
}
|
|
781
|
-
function partitionHeadAssets(resources) {
|
|
819
|
+
function partitionHeadAssets(request, resources) {
|
|
782
820
|
const preconnects = [];
|
|
783
821
|
const criticalPreloads = [];
|
|
784
822
|
const stylesheets = [];
|
|
785
823
|
const afterMetadata = [];
|
|
786
824
|
for (const resource of resources) if (resource.kind === "preconnect") preconnects.push(resource);
|
|
787
|
-
else if (resource.kind === "font" || resource.kind === "preload" && (resource.as === "font" || resource.as === "image" && resource.fetchpriority === "high")) criticalPreloads.push(resource);
|
|
825
|
+
else if (resource.kind === "font" || resource.kind === "preload" && (resource.as === "font" || resource.as === "image" && (resource.fetchpriority === "high" || request.assetRegistry.isEarlyImage(resource)))) criticalPreloads.push(resource);
|
|
788
826
|
else if (resource.kind === "stylesheet") stylesheets.push(resource);
|
|
789
827
|
else afterMetadata.push(resource);
|
|
790
828
|
return [[
|
|
@@ -878,6 +916,7 @@ function createServerRenderRequest(node, options = {}, mode = {}) {
|
|
|
878
916
|
hiddenActivityId: null,
|
|
879
917
|
hostAncestors: [],
|
|
880
918
|
hostNamespace: "html",
|
|
919
|
+
imagePreloadsSuppressed: false,
|
|
881
920
|
idPath: "",
|
|
882
921
|
pendingLeadingNewline: false,
|
|
883
922
|
selectProps: null,
|
|
@@ -953,6 +992,7 @@ function forkScope(scope) {
|
|
|
953
992
|
hiddenActivityId: scope.hiddenActivityId,
|
|
954
993
|
hostAncestors: scope.hostAncestors,
|
|
955
994
|
hostNamespace: scope.hostNamespace,
|
|
995
|
+
imagePreloadsSuppressed: scope.imagePreloadsSuppressed,
|
|
956
996
|
idPath: scope.idPath,
|
|
957
997
|
pendingLeadingNewline: scope.pendingLeadingNewline,
|
|
958
998
|
selectProps: scope.selectProps,
|
|
@@ -1265,6 +1305,15 @@ function renderAssetValue(value, frame) {
|
|
|
1265
1305
|
frame.segment.assetResources.push(resource);
|
|
1266
1306
|
}
|
|
1267
1307
|
}
|
|
1308
|
+
function renderAutomaticImagePreload(resource, frame) {
|
|
1309
|
+
try {
|
|
1310
|
+
frame.request.assetRegistry.registerAutomaticImage(resource);
|
|
1311
|
+
} catch (error) {
|
|
1312
|
+
recordErrorStack(error, frame.stack);
|
|
1313
|
+
throw error;
|
|
1314
|
+
}
|
|
1315
|
+
frame.segment.assetResources.push(resource);
|
|
1316
|
+
}
|
|
1268
1317
|
function renderSuspense(props, frame) {
|
|
1269
1318
|
consumePendingLeadingNewline(frame);
|
|
1270
1319
|
const fallbackAbortableTasks = /* @__PURE__ */ new Set();
|
|
@@ -1360,6 +1409,10 @@ function renderHostElement(type, props, frame) {
|
|
|
1360
1409
|
if (isVoid && hasRenderableChild(props.children)) throw new Error(`Void element <${type}> cannot have children.`);
|
|
1361
1410
|
if (isVoid && unsafeHTML !== null) throw new Error(`Void element <${type}> cannot have unsafeHTML.`);
|
|
1362
1411
|
if (unsafeHTML !== null && hasRenderableChild(props.children)) throw new Error("Host elements cannot have both unsafeHTML and children.");
|
|
1412
|
+
if (namespace === "html") {
|
|
1413
|
+
const imagePreload = imagePreloadFromHostProps(type, props, frame.imagePreloadsSuppressed);
|
|
1414
|
+
if (imagePreload !== null) renderAutomaticImagePreload(imagePreload, frame);
|
|
1415
|
+
}
|
|
1363
1416
|
consumePendingLeadingNewline(frame);
|
|
1364
1417
|
const viewTransition = frame.viewTransition;
|
|
1365
1418
|
writeElementStart(type, viewTransition === null ? props : viewTransitionHostProps(props, viewTransition), frame.segment, frame.selectProps ?? {});
|
|
@@ -1385,9 +1438,11 @@ function renderHostElement(type, props, frame) {
|
|
|
1385
1438
|
if (namespace === "html" && type === "select") frame.selectProps = props;
|
|
1386
1439
|
const previousHostAncestors = frame.hostAncestors;
|
|
1387
1440
|
const previousHostNamespace = frame.hostNamespace;
|
|
1441
|
+
const previousImagePreloadsSuppressed = frame.imagePreloadsSuppressed;
|
|
1388
1442
|
const previousViewTransition = frame.viewTransition;
|
|
1389
1443
|
if (viewTransition !== null) frame.viewTransition = null;
|
|
1390
1444
|
frame.hostNamespace = childHostNamespace(type, namespace);
|
|
1445
|
+
frame.imagePreloadsSuppressed = previousImagePreloadsSuppressed || namespace === "html" && suppressesImagePreloads(type);
|
|
1391
1446
|
if (tracksLeadingNewline) frame.segment.chunks.push(leadingNewlineStartMarker);
|
|
1392
1447
|
try {
|
|
1393
1448
|
renderChildren(props.children, frame);
|
|
@@ -1395,6 +1450,7 @@ function renderHostElement(type, props, frame) {
|
|
|
1395
1450
|
frame.selectProps = previousSelectProps;
|
|
1396
1451
|
frame.hostAncestors = previousHostAncestors;
|
|
1397
1452
|
frame.hostNamespace = previousHostNamespace;
|
|
1453
|
+
frame.imagePreloadsSuppressed = previousImagePreloadsSuppressed;
|
|
1398
1454
|
frame.viewTransition = previousViewTransition;
|
|
1399
1455
|
frame.pendingLeadingNewline = previousPendingLeadingNewline;
|
|
1400
1456
|
}
|