Skip to content

Commit 530de88

Browse files
committed
avoid the need for set_nonce dance
1 parent f060159 commit 530de88

File tree

5 files changed

+33
-35
lines changed

5 files changed

+33
-35
lines changed

packages/kit/src/runtime/server/page/data_serializer.js

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,9 @@ import {
1818
export function server_data_serializer(event, event_state, options) {
1919
let promise_id = 1;
2020

21-
const { iterator, add } = create_async_iterator();
21+
const iterator = create_async_iterator();
2222
const global = get_global_name(options);
2323

24-
/** @type {(nonce: string) => void} */
25-
let set_nonce;
26-
const nonce = /** @type {Promise<string>} */ new Promise((r) => (set_nonce = r));
27-
2824
/** @param {any} thing */
2925
function replacer(thing) {
3026
if (typeof thing?.then === 'function') {
@@ -56,11 +52,11 @@ export function server_data_serializer(event, event_state, options) {
5652
str = devalue.uneval([, error], replacer);
5753
}
5854

59-
return `<script${await nonce}>${global}.resolve(${id}, ${str.includes('app.decode') ? `(app) => ${str}` : `() => ${str}`})</script>\n`;
55+
return `${global}.resolve(${id}, ${str.includes('app.decode') ? `(app) => ${str}` : `() => ${str}`})`;
6056
}
6157
);
6258

63-
add(promise);
59+
iterator.add(promise);
6460

6561
return `${global}.defer(${id})`;
6662
} else {
@@ -96,15 +92,13 @@ export function server_data_serializer(event, event_state, options) {
9692
},
9793

9894
get_data(csp) {
99-
set_nonce(csp.script_needs_nonce ? ` nonce="${csp.nonce}"` : '');
95+
const open = `<script${csp.script_needs_nonce ? ` nonce="${csp.nonce}"` : ''}>`;
96+
const close = `</script>\n`;
97+
10098
return {
10199
data: `[${strings.join(',')}]`,
102-
chunks: promise_id > 1 ? iterator : null
100+
chunks: promise_id > 1 ? iterator.iterate((str) => open + str + close) : null
103101
};
104-
},
105-
106-
discard() {
107-
set_nonce('');
108102
}
109103
};
110104
}
@@ -120,7 +114,7 @@ export function server_data_serializer(event, event_state, options) {
120114
export function server_data_serializer_json(event, event_state, options) {
121115
let promise_id = 1;
122116

123-
const { iterator, add } = create_async_iterator();
117+
const iterator = create_async_iterator();
124118

125119
const reducers = {
126120
...Object.fromEntries(
@@ -166,7 +160,7 @@ export function server_data_serializer_json(event, event_state, options) {
166160
}
167161
);
168162

169-
add(promise);
163+
iterator.add(promise);
170164

171165
return id;
172166
}
@@ -201,7 +195,7 @@ export function server_data_serializer_json(event, event_state, options) {
201195
get_data() {
202196
return {
203197
data: `{"type":"data","nodes":[${strings.join(',')}]}\n`,
204-
chunks: promise_id > 1 ? iterator : null
198+
chunks: promise_id > 1 ? iterator.iterate() : null
205199
};
206200
}
207201
};

packages/kit/src/runtime/server/page/index.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,9 +281,6 @@ export async function render_page(
281281
const layouts = compact(branch.slice(0, j + 1));
282282
const nodes = new PageNodes(layouts.map((layout) => layout.node));
283283

284-
// prevent memory leak by resolving the `nonce` promise of the unused data_serializer
285-
data_serializer.discard();
286-
287284
return await render_response({
288285
event,
289286
event_state,

packages/kit/src/runtime/server/page/types.d.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ export interface Cookie {
4545
export type ServerDataSerializer = {
4646
add_node(i: number, node: ServerDataNode | null): void;
4747
get_data(csp: Csp): { data: string; chunks: AsyncIterable<string> | null };
48-
discard(): void;
4948
};
5049

5150
export type ServerDataSerializerJson = {

packages/kit/src/utils/streaming.js

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ function defer() {
1616

1717
/**
1818
* Create an async iterator and a function to push values into it
19+
* @template T
1920
* @returns {{
20-
* iterator: AsyncIterable<any>;
21-
* add: (promise: Promise<any>) => void;
21+
* iterate: (transform?: (input: T) => T) => AsyncIterable<T>;
22+
* add: (promise: Promise<T>) => void;
2223
* }}
2324
*/
2425
export function create_async_iterator() {
@@ -27,16 +28,23 @@ export function create_async_iterator() {
2728
const deferred = [defer()];
2829

2930
return {
30-
iterator: {
31-
[Symbol.asyncIterator]() {
32-
return {
33-
next: async () => {
34-
const next = await deferred[0].promise;
35-
if (!next.done) deferred.shift();
36-
return next;
37-
}
38-
};
39-
}
31+
iterate: (transform = (x) => x) => {
32+
return {
33+
[Symbol.asyncIterator]() {
34+
return {
35+
next: async () => {
36+
const next = await deferred[0].promise;
37+
38+
if (!next.done) {
39+
deferred.shift();
40+
return { value: transform(next.value), done: false };
41+
}
42+
43+
return next;
44+
}
45+
};
46+
}
47+
};
4048
},
4149
add: (promise) => {
4250
count += 1;

packages/kit/src/utils/streaming.spec.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ import { expect, test } from 'vitest';
22
import { create_async_iterator } from './streaming.js';
33

44
test('works with fast consecutive promise resolutions', async () => {
5-
const { iterator, add } = create_async_iterator();
5+
const { iterate, add } = create_async_iterator();
66

77
add(Promise.resolve(1));
88
add(Promise.resolve(2));
99

1010
const actual = [];
11-
for await (const value of iterator) {
11+
for await (const value of iterate((n) => n * 10)) {
1212
actual.push(value);
1313
}
1414

15-
expect(actual).toEqual([1, 2]);
15+
expect(actual).toEqual([10, 20]);
1616
});

0 commit comments

Comments
 (0)