Skip to content

Conversation

@marbemac
Copy link
Contributor

@marbemac marbemac commented Jul 24, 2023

Copied from #5775, rebased on beta branch.


Make sure that on the server we always resolve the resource data to a hydrate-able value, otherwise solid will silently call onHydrated on the client with an empty object which can cause a variety of problems.

The specific code branch we were missing was when createQuery is called and observer.getOptimisticResult(defaultedOptions) returns an already loaded query (if, for example, preloadQuery was called prior to the components mounting - for example with router data loaders).


As always, these SSR / hydration cases are difficult to test, so I added an example to the solid-start-streaming to manually verify for now. This example simply calls preloadQuery on the server, and then renders a component that uses that same query.

Before 1

This is with deferStream: false on the user query - note how the content ends up getting rendered twice, and in the dev console you can see that onHydrated is called with an empty object. Things work as expected after the changes in this PR.

Screenshot 2023-07-10 at 11 59 11 AM

Before 2

This is with deferStream: true on the user query - note how it ends up calling the user query on the server AND on the client (see logs in dev console), and in the dev console you can see that onHydrated is called with an empty object (which causes the client to think that it needs to refetch, hence the client call).

Screenshot 2023-07-10 at 11 58 26 AM

After

Screenshot 2023-07-10 at 11 57 58 AM

marbemac added 6 commits July 24, 2023 10:45
Signed-off-by: marbemac <marbemac@gmail.com>

# Conflicts:
#	packages/solid-query/src/createBaseQuery.ts
Signed-off-by: marbemac <marbemac@gmail.com>

# Conflicts:
#	packages/solid-query/src/createBaseQuery.ts
Signed-off-by: marbemac <marbemac@gmail.com>
Signed-off-by: marbemac <marbemac@gmail.com>

# Conflicts:
#	examples/solid/solid-start-streaming/package.json
#	pnpm-lock.yaml
Signed-off-by: marbemac <marbemac@gmail.com>
Signed-off-by: marbemac <marbemac@gmail.com>
@vercel
Copy link

vercel bot commented Jul 24, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

1 Ignored Deployment
Name Status Preview Comments Updated (UTC)
query ⬜️ Ignored (Inspect) Jul 25, 2023 3:03pm

"test:types": "tsc",
"test:lib": "vitest run --coverage",
"test:lib:dev": "pnpm run test:lib --watch",
"test:lib:dev": "vitest watch --coverage",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vitest --watch is a thing, vitest run --watch isn't - they have a dedicated watch command instead.

Comment on lines -100 to -102
if (process.env['NODE_ENV'] === 'development') {
console.error(unwrappedResult.error)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't sure if this log is supposed to be here or an accidental leftover - lmk if it should stay and I can add it back.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We added a log in there because of this discussion https://discord.com/channels/719702312431386674/1072140965910949929

Please let me know if you have a better way to resolve/fix this 😅

Comment on lines -105 to +135
if (unwrappedResult.isSuccess) {
// Use of any here is fine
// We cannot include refetch since it is not serializable
resolve(unwrappedResult as any)
} else {
resolve(unwrappedResult)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO we should always fall back to calling resolve(). I ran into an issue where neither reject nor resolve were called, resulting in a hung promise (and this was on the server, resulting in the entire page being hung). LMK if there's a reason to sometimes not resolve the promise.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we dont call reject here. How do we throw an error to the ErrorBoundary on the server?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well it's still calling reject like it was before. There was just an additional check where if we decided not to reject, we would only call resolve under certain conditions. Thus there was a scenario where neither reject NOR resolve would get called, leaving a hanging promise. Does that make sense?

Comment on lines -163 to +192
resolve(state)
const query = observer.getCurrentQuery()
resolve(hydrateableObserverResult(query, state))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is the code path that wasn't covered - this is triggered if the data is already pre-loaded prior to createQuery. We need to "sanitize" the state on the server before resolving, so that it can be correctly hydrated back to the client.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! This is looking great! Thanks for working on this :D

@codesandbox-ci
Copy link

codesandbox-ci bot commented Jul 24, 2023

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit b57acbf:

Sandbox Source
@tanstack/query-example-react-basic-typescript Configuration
@tanstack/query-example-solid-basic-typescript Configuration
@tanstack/query-example-svelte-basic Configuration
@tanstack/query-example-vue-basic Configuration

@codecov-commenter
Copy link

Codecov Report

Patch coverage has no change and project coverage change: -13.14 ⚠️

Comparison is base (e0aad73) 97.11% compared to head (d79aef9) 83.97%.

❗ Your organization is not using the GitHub App Integration. As a result you may experience degraded service beginning May 15th. Please install the Github App Integration for your organization. Read more.

Additional details and impacted files
@@             Coverage Diff             @@
##             beta    #5775       +/-   ##
===========================================
- Coverage   97.11%   83.97%   -13.14%     
===========================================
  Files          50       11       -39     
  Lines        2391      181     -2210     
  Branches      706       36      -670     
===========================================
- Hits         2322      152     -2170     
+ Misses         67       25       -42     
- Partials        2        4        +2     

see 61 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@nx-cloud
Copy link

nx-cloud bot commented Jul 24, 2023

☁️ Nx Cloud Report

CI is running/has finished running commands for commit b57acbf. As they complete they will appear below. Click to see the status, the terminal output, and the build insights.

📂 See all runs for this branch


✅ Successfully ran 1 target

Sent with 💌 from NxCloud.

Comment on lines -163 to +192
resolve(state)
const query = observer.getCurrentQuery()
resolve(hydrateableObserverResult(query, state))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! This is looking great! Thanks for working on this :D

Comment on lines -105 to +135
if (unwrappedResult.isSuccess) {
// Use of any here is fine
// We cannot include refetch since it is not serializable
resolve(unwrappedResult as any)
} else {
resolve(unwrappedResult)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we dont call reject here. How do we throw an error to the ErrorBoundary on the server?

Comment on lines -100 to -102
if (process.env['NODE_ENV'] === 'development') {
console.error(unwrappedResult.error)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We added a log in there because of this discussion https://discord.com/channels/719702312431386674/1072140965910949929

Please let me know if you have a better way to resolve/fix this 😅

@ardeora ardeora merged commit 7bfecd6 into TanStack:beta Jul 25, 2023
@apatrida
Copy link

apatrida commented Dec 2, 2023

@marbemac doesn't this change make the SSR returned object no longer a proxy / store and therefore it is not reactive? See: #6373

Shouldn't it be a Resource or some reactive form other than unwrap to a standard object?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants