Repository navigation
feat(LiveProvider): add opt-in server-rendered previews - #414
tujoworker wants to merge 4 commits into
Conversation
|
@tujoworker is attempting to deploy a commit to the formidable-labs Team on Vercel. A member of the Team first needs to authorize it. |
fa9e0c8 to
4ab62dc
Compare
🦋 Changeset detectedLatest commit: dae0d9a The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
4ab62dc to
188edc8
Compare
|
Hi @ryan-roemer. This is now rebased onto v5 and reworked as opt-in SSR through an GitHub Actions is waiting for maintainer approval because this is an external contribution, and Vercel also needs team authorization. Would you have time to approve CI and review the API direction? Feedback on whether this approach fits the project would also be very helpful. |
|
Hi @ilteoood, would opt-in initial SSR through I've rebased this onto v5.0.1, added a runnable before/after example, and strengthened coverage for hydration, StrictMode, delayed rendering, and error recovery. React 18.0.0 and 19.3.0 both pass locally, and the public fork CI run uses the upstream workflow. The description now includes the rationale and review checklist. An API-direction check would help before a full review. If this is a direction you'd accept, could you also approve the upstream CI run? Thanks. |
|
If anyone is interested in SSR support, I could publish a separate adapter package you can use with the original react-live dependency, without patching it. We're taking this adapter approach internally for now while we wait for upstream SSR support. Here is the implementation PR: dnbexperience/eufemia#9739 |
|
Hi @tujoworker, feel free to open a PR and we'll review it asap |
| }); | ||
| // StrictMode invokes the client initializer twice; the server invokes it once. | ||
| expect(transformCode).toHaveBeenCalledTimes(3); | ||
| expect(container.textContent).toBe("hello"); |
There was a problem hiding this comment.
instead of checking it in this way, could we use a snapshot tests instead?
this allows us to check that the rendered html contains also the strong tag
There was a problem hiding this comment.
Thanks, switched this to an HTML snapshot so we check the tag too.
| await act(async () => { | ||
| root = hydrateRoot(container, preview); | ||
| }); | ||
| expect(container.querySelector("pre").textContent).toBe( |
There was a problem hiding this comment.
Updated this one too, including the
markup.
| </LiveProvider>, | ||
| ); | ||
| }); | ||
| expect(container.querySelector("strong").textContent).toBe("fixed"); |
There was a problem hiding this comment.
Done, the snapshot now covers the recovered preview and confirms the error is gone.
| </LiveProvider>, | ||
| ); | ||
|
|
||
| expect(html).toBe("<div><strong>Hello SSR!</strong></div>"); |
There was a problem hiding this comment.
I would apply it to other html checks as well
There was a problem hiding this comment.
Applied snapshots to all the HTML checks in this file.
| await act(async () => { | ||
| resolvers.forEach((resolve) => resolve("<strong>Hello SSR!</strong>")); | ||
| }); |
There was a problem hiding this comment.
Here we are not awaiting anything inside the act function, so it shouldn't be async at all.
There was a problem hiding this comment.
Removed async here. Still awaiting act() so the preview settles before the snapshot.
| new Promise((resolve) => { | ||
| resolvers.push(resolve); | ||
| }), |
There was a problem hiding this comment.
can we simplify this using Promise.withResolvers?
There was a problem hiding this comment.
Yes, switched both deferred-promise setups to Promise.withResolvers().
| scope, | ||
| code: "capture(() => render(<strong>old</strong>))", | ||
| }); | ||
| await act(async () => {}); |
There was a problem hiding this comment.
It was flushing the effect so capture had assigned the callback before rerendering. Replaced it with an explicit waitFor on capture.
| </LiveProvider>, | ||
| ); | ||
| await screen.findByText("new"); | ||
| act(() => complete()); |
There was a problem hiding this comment.
| act(() => complete()); | |
| act(complete); |
|
Thanks for the good review, @ilteoood ❤️ I've pushed the updates. Could you approve the pending CI run and authorize Vercel when you have a moment? The checks haven't run yet, so it would be good to get them going and see this turn green. |
|
Thanks for running the checks, @ilteoood. The React 18 job was ignoring the lockfile and picking up a declaration bundler that doesn't support TypeScript 7.0. I've pushed dae0d9a to preserve the locked tooling and keep React and its types aligned for shared dependencies. Builds, typechecks, 77 unit tests and 37 browser tests pass locally on both React 18 and 19. Could you approve the new CI run when you have a moment? |
Description
Documentation pages using
LiveProvidercurrently send an empty preview in their initial HTML, even for static examples. This makes that content depend on downloading and running JavaScript. Related to #396 and the earlier initial-render work in #321/#322.This adds
<LiveProvider ssr>for trusted, deterministic examples. Forcode="<strong>Hello from SSR</strong>", the server output changes from<div></div>to<div><strong>Hello from SSR</strong></div>. Existing consumers stay client-only becausessrdefaults tofalse.Synchronous inline and
noInlinepreviews render immediately. Async transforms leave the server preview empty and reuse the client initialization result during hydration. DelayednoInlinecallbacks still update the client preview. Transform/evaluation failures useLiveError, and obsolete async results are ignored. Preview component render errors retain React's normal SSR behavior; the docs explain the server-safe code requirements.The runnable SSR example prints and asserts both HTML outputs.
Type of change
Review checklist
Public validation run uses the unchanged upstream CI workflow against this exact commit. Upstream CI still requires maintainer approval; the fork run provides inspectable evidence while that is pending.