Skip to content

Commit

Permalink
Stream title updates/skip hydration
Browse files Browse the repository at this point in the history
  • Loading branch information
ryansolid committed Sep 11, 2024
1 parent 553935b commit 95f3af4
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 18 deletions.
1 change: 1 addition & 0 deletions packages/dom-expressions/src/client.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export function getHydrationKey(): string;
export function getNextElement(template?: HTMLTemplateElement): Element;
export function getNextMatch(start: Node, elementName: string): Element;
export function getNextMarker(start: Node): [Node, Array<Node>];
export function useTitle(title: string | (() => string)): void;
export function useAssets(fn: () => JSX.Element): void;
export function getAssets(): string;
export function HydrationScript(): JSX.Element;
Expand Down
14 changes: 7 additions & 7 deletions packages/dom-expressions/src/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -594,17 +594,17 @@ export function Hydration(props) {

const voidFn = () => undefined;

export function useTitle(source) {
effect(() => {
if (typeof source === 'function') source = source();
isHydrating() || (document.title = source);
});
}

// experimental
export const RequestContext = Symbol();

// deprecated
export function innerHTML(parent, content) {
!sharedConfig.context && (parent.innerHTML = content);
}

export function useTitle(source) {
effect(() => {
while (typeof source === 'function') source = source();
document.title = source;
});
}
12 changes: 9 additions & 3 deletions packages/dom-expressions/src/server.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export function ssrAttribute(key: string, value: any, isBoolean: boolean): strin
export function ssrHydrationKey(): string;
export function resolveSSRNode(node: any): string;
export function escape(html: string): string;
export function useTitle(title: string | (() => string)): void;
export function useAssets(fn: () => JSX.Element): void;
export function getAssets(): string;
export function getHydrationKey(): string;
Expand All @@ -74,13 +75,18 @@ export function getRequestEvent(): RequestEvent | undefined;

export function Hydration(props: { children?: JSX.Element }): JSX.Element;
export function NoHydration(props: { children?: JSX.Element }): JSX.Element;
export function Assets(props: { children?: JSX.Element }): JSX.Element;
export function untrack<T>(fn: () => T): T;

// deprecated
/** @deprecated Replaced by useAssets */
export function Assets(props: { children?: JSX.Element }): JSX.Element;

export type LegacyResults = {
write: (text: string) => void;
startWriting: () => void;
};

/** @deprecated Replaced by renderToStream */
export function pipeToWritable<T>(
fn: () => T,
writable: WritableStream,
Expand All @@ -90,6 +96,8 @@ export function pipeToWritable<T>(
onCompleteAll?: () => void;
}
): void;

/** @deprecated Replaced by renderToStream */
export function pipeToNodeWritable<T>(
fn: () => T,
writable: { write: (v: string) => void },
Expand All @@ -100,8 +108,6 @@ export function pipeToNodeWritable<T>(
}
): void;

export function untrack<T>(fn: () => T): T;

// client-only APIs

/** @deprecated not supported on the server side */
Expand Down
33 changes: 25 additions & 8 deletions packages/dom-expressions/src/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function renderToString(code, options = {}) {
nextRoot() {
return this.renderId + "i-" + this.roots++;
},
title: '',
title: ""
};
let html = root(d => {
setTimeout(d);
Expand Down Expand Up @@ -116,6 +116,9 @@ export function renderToStream(code, options = {}) {
};
const registry = new Map();
const writeTasks = () => {
if (context.title !== flushedTitle) {
tasks += `document.title="${(flushedTitle = context.title)}";`;
}
if (tasks.length && !completed && firstFlushed) {
buffer.write(`<script${nonce ? ` nonce="${nonce}"` : ""}>${tasks}</script>`);
tasks = "";
Expand All @@ -132,6 +135,7 @@ export function renderToStream(code, options = {}) {
let completed = false;
let shellCompleted = false;
let scriptFlushed = false;
let flushedTitle = "";
let timer = null;
let buffer = {
write(payload) {
Expand Down Expand Up @@ -217,7 +221,7 @@ export function renderToStream(code, options = {}) {
return firstFlushed;
};
},
title: '',
title: ""
};

let html = root(d => {
Expand All @@ -228,7 +232,7 @@ export function renderToStream(code, options = {}) {
if (shellCompleted) return;
sharedConfig.context = context;
context.noHydrate = true;
html = injectTitle(context.title, html);
html = injectTitle((flushedTitle = context.title), html);
html = injectAssets(context.assets, html);
if (tasks.length) html = injectScripts(html, tasks, nonce);
buffer.write(html);
Expand Down Expand Up @@ -603,7 +607,9 @@ export function getRequestEvent() {
: undefined;
}

// consider deprecating
/**
* @deprecated Replaced by useAssets
*/
export function Assets(props) {
useAssets(() => props.children);
}
Expand Down Expand Up @@ -700,14 +706,25 @@ export function ssrSpread(props, isSVG, skipChildren) {
}

export function useTitle(source) {
// TODO should we resolve this eagerly?
if (typeof source === "function") source = source();
sharedConfig.context.title = source;
}

function injectTitle(title, html) {
const result = resolveSSRNode(title);
// TODO should we put this after the head opening
return result ? html.replace(`</head>`, result + `</head>`) : html;
if (!title) return html;
const head = html.indexOf(`<head`);
if (head === -1) return html;
const headEnd = html.indexOf(`</head>`, head);
const titleStart = html.indexOf(`<title`, head);
if (titleStart > headEnd) return html;
if (titleStart > -1) {
return (
html.slice(0, titleStart) +
`<title>${title}</title>` +
html.slice(html.indexOf(`</title>`, titleStart) + 8)
);
}
return html.slice(0, headEnd) + `<title>${title}</title>` + html.slice(headEnd);
}

// client-only APIs
Expand Down

0 comments on commit 95f3af4

Please sign in to comment.