Skip to content

Commit 4c8363e

Browse files
committed
fix handle promise resolution in createResource with improved inspection
1 parent 0af2c2b commit 4c8363e

File tree

2 files changed

+53
-6
lines changed

2 files changed

+53
-6
lines changed

.changeset/happy-sites-count.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"solid-js": patch
3+
---
4+
5+
- Handle promise resolution in `createResource` with improved inspection and serialization logic
6+
- Fixed the issue with promise return value in Synchronous Functions in SSR.

packages/solid/src/server/rendering.ts

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
useContext
1414
} from "./reactive.js";
1515
import type { JSX } from "../jsx.js";
16+
import { inspect } from "util";
1617

1718
export type Component<P = {}> = (props: P) => JSX.Element;
1819
export type VoidProps<P = {}> = P & { children?: never };
@@ -435,7 +436,6 @@ export function createResource<T, S>(
435436
fetcher = source as ResourceFetcher<S, T>;
436437
source = true as ResourceSource<S>;
437438
}
438-
439439
const contexts = new Set<SuspenseContextType>();
440440
const id = sharedConfig.getNextContextId();
441441
let resource: { ref?: any; data?: T } = {};
@@ -494,7 +494,51 @@ export function createResource<T, S>(
494494
if (lookup == null || lookup === false) return;
495495
p = (fetcher as ResourceFetcher<S, T>)(lookup, { value });
496496
}
497-
if (p != undefined && typeof p === "object" && "then" in p) {
497+
498+
const handleResolvedValue = (
499+
p: T | Promise<T> | null,
500+
ctx: {
501+
id?: string;
502+
count?: number;
503+
serialize: any;
504+
nextRoot?: (v: any) => string;
505+
replace?: (id: string, replacement: () => any) => void;
506+
block?: (p: Promise<any>) => void;
507+
resources: any;
508+
suspense?: Record<string, SuspenseContextType>;
509+
registerFragment?: (v: string) => (v?: string, err?: any) => boolean;
510+
lazy?: Record<string, Promise<any>>;
511+
async?: boolean | undefined;
512+
noHydrate?: boolean;
513+
},
514+
id: string
515+
) => {
516+
ctx.resources[id].data = p;
517+
if (ctx.serialize) ctx.serialize(id, p);
518+
p = null;
519+
return ctx.resources[id].data;
520+
};
521+
522+
if (
523+
p != undefined &&
524+
typeof p === "object" &&
525+
"then" in p &&
526+
p.constructor.name === "Promise"
527+
) {
528+
if (
529+
lookup === 0 && // 'lookup' of the value returned by createResource
530+
fetcher!.constructor.name !== "AsyncFunction" &&
531+
!inspect(p).startsWith(`Promise {
532+
<pending>,
533+
`)
534+
) {
535+
let temp = p;
536+
p = new Promise(resolve => {
537+
setTimeout(() => {
538+
resolve(temp.then(val => handleResolvedValue(val, ctx, id)));
539+
}, 300); // A safe number that won't throw an error.
540+
});
541+
}
498542
read.loading = true;
499543
read.state = "pending";
500544
p = p
@@ -517,10 +561,7 @@ export function createResource<T, S>(
517561
if (ctx.serialize) ctx.serialize(id, p, options.deferStream);
518562
return p;
519563
}
520-
ctx.resources[id].data = p;
521-
if (ctx.serialize) ctx.serialize(id, p);
522-
p = null;
523-
return ctx.resources[id].data;
564+
return handleResolvedValue(p, ctx, id);
524565
}
525566
if (options.ssrLoadFrom !== "initial") load();
526567
const ref = [read, { refetch: load, mutate: (v: T) => (value = v) }] as ResourceReturn<T>;

0 commit comments

Comments
 (0)