Skip to content

chore: refactoring react server component client#1186

Merged
joker23 merged 5 commits into
mainfrom
skz/sdk-2021/react-server
Mar 16, 2026
Merged

chore: refactoring react server component client#1186
joker23 merged 5 commits into
mainfrom
skz/sdk-2021/react-server

Conversation

@joker23

@joker23 joker23 commented Mar 12, 2026

Copy link
Copy Markdown
Contributor

This PR is to finalize how the react server components can access server side LDClient. A few key points:

  • Developers will spin up a "ld server session" which is a wrapper around the global server sdk (which should be separately managed) on every request session. This wrapper would provide some React-esque capabilities to the underlying sdk.
  • This sdk session will be encapsulated in a react cache which should be cleaned after every request session.
  • Developers can also manage these sessions themselves as we provide the create wrapper function without having to deal with react cache.

This address:
SDK-2026
SDK-2021


Note

Medium Risk
Moderate risk due to a breaking redesign of the server entrypoint API (removing createReactServerClient/context-provider options and changing browser behavior from no-op to throw), which could affect existing integrations and bundling boundaries.

Overview
Refactors the React SDK server entrypoint to use a per-request LDServerSession (context bound at creation) stored in React cache(), exposed via createLDServerSession/useLDServerSession, and enforces server-only usage by throwing in browser environments rather than returning a no-op client.

Removes the previous createReactServerClient + LDContextProvider/LDReactServerOptions API, introduces LDServerBaseClient as a minimal structural interface, and updates docs/examples accordingly. Adds Jest coverage for session binding/caching behavior and adjusts build tooling to emit separate client/server bundles (including a "use client" banner for the client entry) plus small eslint/gitignore tweaks for examples.

Written by Cursor Bugbot for commit 80eca87. This will update automatically on new commits. Configure here.


Open with Devin

@github-actions

Copy link
Copy Markdown
Contributor

@launchdarkly/js-sdk-common size report
This is the brotli compressed size of the ESM build.
Compressed size: 25566 bytes
Compressed size limit: 26000
Uncompressed size: 125383 bytes

@github-actions

github-actions Bot commented Mar 12, 2026

Copy link
Copy Markdown
Contributor

@launchdarkly/browser size report
This is the brotli compressed size of the ESM build.
Compressed size: 172611 bytes
Compressed size limit: 200000
Uncompressed size: 802217 bytes

@github-actions

github-actions Bot commented Mar 12, 2026

Copy link
Copy Markdown
Contributor

@launchdarkly/js-client-sdk-common size report
This is the brotli compressed size of the ESM build.
Compressed size: 22203 bytes
Compressed size limit: 24000
Uncompressed size: 115238 bytes

@github-actions

github-actions Bot commented Mar 12, 2026

Copy link
Copy Markdown
Contributor

@launchdarkly/js-client-sdk size report
This is the brotli compressed size of the ESM build.
Compressed size: 24537 bytes
Compressed size limit: 25000
Uncompressed size: 85098 bytes

@joker23

joker23 commented Mar 12, 2026

Copy link
Copy Markdown
Contributor Author

@cursor review
@devin review

cursor[bot]

This comment was marked as resolved.

@joker23 joker23 force-pushed the skz/sdk-2021/react-server branch from 6e30ca5 to 562a3e6 Compare March 12, 2026 17:49
devin-ai-integration[bot]

This comment was marked as resolved.

@joker23 joker23 force-pushed the skz/sdk-2021/react-server branch from 848e4c8 to 562a3e6 Compare March 12, 2026 18:28
@joker23

joker23 commented Mar 12, 2026

Copy link
Copy Markdown
Contributor Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

@joker23 joker23 marked this pull request as ready for review March 12, 2026 18:41
@joker23 joker23 requested a review from a team as a code owner March 12, 2026 18:41
// of meta with exclusions.
// eslint-disable-next-line no-param-reassign
opts.mangleProps = /^_([^m|_]|m[^e]|me[^t]|met[^a])/;
opts.banner = { js: '"use client";' };

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is the reason that we separated the client bundle and server bundle

@joker23 joker23 force-pushed the skz/sdk-2021/react-server branch from 562a3e6 to 4bcbba2 Compare March 12, 2026 19:28
devin-ai-integration[bot]

This comment was marked as resolved.

@joker23 joker23 force-pushed the skz/sdk-2021/react-server branch from 4bcbba2 to 61658d1 Compare March 12, 2026 20:32

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ditching the context getter design and instead we are give the users a way to create a "scoped proxy" of the base server sdk for each request session that the LDClient is needed.

devin-ai-integration[bot]

This comment was marked as resolved.

@joker23 joker23 marked this pull request as draft March 13, 2026 15:03
@joker23

joker23 commented Mar 13, 2026

Copy link
Copy Markdown
Contributor Author

@cursor review

client.jsonVariationDetail(key, context, defaultValue),
allFlagsState: (options?: LDFlagsStateOptions) => client.allFlagsState(context, options),
};
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Internal helper createLDServerWrapper is publicly exported

Medium Severity

createLDServerWrapper is exported from LDServerSession.ts and re-exported via export * from './LDServerSession' in index.ts, making it part of the public API. However, it's only called internally by createLDServerSession and bypasses the cache() storage. If a user calls createLDServerWrapper directly, the session won't be stored in React's per-request cache, causing useLDServerSession() to return null — silently breaking the documented pattern. This function is an internal implementation detail and likely shouldn't be exported.

Additional Locations (1)
Fix in Cursor Fix in Web

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is by design in case developers do not want to use our cache implementation. This is the same reasoning as the ability to use named context in client components.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I do wonder if we need some way of highlighting this as an exposing API.

Most of the time everything exposed is inside api, with the exception of like a factory in the index.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yea I'll think about that some more... I believe we did have a few issues in the past where clients didn't know about certain APIs are available.

@joker23 joker23 force-pushed the skz/sdk-2021/react-server branch from fc1d11f to f2eee29 Compare March 13, 2026 16:25
@joker23 joker23 marked this pull request as ready for review March 13, 2026 21:06
devin-ai-integration[bot]

This comment was marked as resolved.

@joker23 joker23 force-pushed the skz/sdk-2021/react-server branch from 1f577ee to ef011c4 Compare March 16, 2026 14:38
@@ -0,0 +1,3 @@
# Temporary ignore to keep PRs manageable.

server-only

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Will commit the example application in a separate PR. Wanted to focus this one on the implementation changes

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Comment thread packages/sdk/react/src/server/LDServerSession.ts
// cache() creates a per-request memoized store — each React render tree (request)
// gets its own isolated instance. The store is populated by createLDServerSession
// and read by useLDServerSession.
const withCache = cache(() => ({ session: null as LDServerSession | null }));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Server bundle uses cache unavailable in peer dependency range

Low Severity

The server bundle now imports cache from react at module scope and calls it immediately (const withCache = cache(...)). react.cache only exists in React 19+ (or React 18 canary used by Next.js). The package's peerDependencies declares react >= 18.0.0, which includes React 18 stable where cache is not exported. Anyone importing @launchdarkly/react-sdk/server with React 18 stable will get a crash at module load time since cache is undefined.

Fix in Cursor Fix in Web

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This will need to be documented. This also should not be a problem functionally speaking because RSC were not stabilized until react 19. This means that developer should hit errors much sooner if they import from @launchdarkly/react-sdk/server when using a react 18 base.

/**
* The LaunchDarkly server client interface for React.
* A per-request evaluation scope that binds an {@link LDServerBaseClient} to a specific
* {@link LDContext}.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I assume this approximately matches the broader scoped-client design?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think so, I made it so that it should be easily compatible/migrate-able if we decide to implement scoped client capabilities in the underlying server sdks

Comment thread packages/sdk/react/src/server/LDServerSession.ts Outdated
@joker23 joker23 merged commit 5defaa7 into main Mar 16, 2026
41 checks passed
@joker23 joker23 deleted the skz/sdk-2021/react-server branch March 16, 2026 18:14
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.

2 participants