Skip to content

Commit

Permalink
bootstrapping docs (#656)
Browse files Browse the repository at this point in the history
* bootstrapping docs

* delete file

* link to node docs

* updates

* update sdk key field

* fix some hyphens

* bootstrapping example

* icon

* update
  • Loading branch information
ajwootto authored May 3, 2024
1 parent ddb5fb0 commit 4948fdb
Show file tree
Hide file tree
Showing 7 changed files with 1,668 additions and 1,502 deletions.
4 changes: 4 additions & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
compressionLevel: mixed

enableGlobalCache: false

nodeLinker: pnpm
27 changes: 27 additions & 0 deletions docs/sdk/client-side-sdks/javascript/javascript-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,33 @@ subscribe to an event that doesn't exist. These are the events you can subscribe
| Feature Updated | `featureUpdated:*` | <code>(key: string, feature: DVCFeature &#124; null)</code> | This event gets triggered when a feature's variation changes for a user. You can subscribe to all feature updates using the `*` identifier, or you can pass in the key of the feature you want to subscribe to, e.g. `featureUpdated:my_feature_key`. |
| Config Updated | `configUpdated` | | This event gets triggered when there are any variable, variation, or feature changes. |
## Bootstrapping and Server-Side Rendering
:::info
If you are using Next.js, we recommend using the [Next.js SDK](/sdk/client-side-sdks/nextjs) instead of this option.
:::
The SDK supports the ability to have its configuration bootstrapped during initialization, which allows it to
start serving up-to-date Variable values immediately. Using this option skips the initial configuration fetch that normally
occurs when the page is first loaded, reducing the time before correct content can be shown.
This is especially useful for server-side rendering use-cases, where you may have a configuration already on the server which can be provided in the page response.
To provide a bootstrapped config, pass the option when initializing the SDK:
```javascript
const user = { user_id: 'my_user' }
const devcycleClient = initializeDevCycle(
'<DEVCYCLE_CLIENT_SDK_KEY>',
user,
{
bootstrapConfig: CONFIG_DATA
},
)
```
If you are using a Javascript-based server rendering framework like Remix, the DevCycle Node.js SDK provides a
convenient way to obtain the configuration data needed for bootstrapping. See the [Node.js documentation](/sdk/server-side-sdks/node/node-bootstrapping) for more information.
## EdgeDB
EdgeDB allows you to save user data to our EdgeDB storage so that you don't have to pass in all the user data every time you identify a user.
Expand Down
27 changes: 27 additions & 0 deletions docs/sdk/client-side-sdks/react/react-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,33 @@ devcycleClient.flushEvents(() => {
})
```

## Bootstrapping and Server-Side Rendering
:::info
If you are using Next.js, we recommend using the [Next.js SDK](/sdk/client-side-sdks/nextjs) instead of this option.
:::

The SDK supports the ability to have its configuration bootstrapped during initialization, which allows it to
start serving up-to-date Variable values immediately. Using this option skips the initial configuration fetch that normally
occurs when the page is first loaded, reducing the time before correct content can be shown.

This is especially useful for server-side rendering use-cases, where you may have a configuration already on the server which can be provided in the page response.

To provide a bootstrapped config, pass the option when initializing the SDK:
```javascript
const user = { user_id: 'my_user' }
const devcycleClient = initializeDevCycle(
'<DEVCYCLE_CLIENT_SDK_KEY>',
user,
{
bootstrapConfig: CONFIG_DATA
},
)
```

If you are using a Javascript-based server rendering framework like Remix, the DevCycle Node.js SDK provides a
convenient way to obtain the configuration data needed for bootstrapping. See the [Node.js documentation](/sdk/server-side-sdks/node/node-bootstrapping) for more information.


## EdgeDB

EdgeDB allows you to save user data to our EdgeDB storage so that you don't have to pass in all the user data every time you identify a user.
Expand Down
108 changes: 108 additions & 0 deletions docs/sdk/server-side-sdks/node/node-bootstrapping.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
---
title: Bootstrapping / Server-Side Rendering
sidebar_label: Bootstrapping / SSR
sidebar_position: 5
description: SDK features for bootstrapping a client SDK on the server
sidebar_custom_props: { icon: material-symbols:sync-alt }
---

# Bootstrapping and Server-Side Rendering
:::info
If you are using Next.js, we recommend using the [Next.js SDK](/sdk/client-side-sdks/nextjs) instead of this option.
:::

When using a server rendering framework such as Remix, Nuxt, or SvelteKit, you will likely be rendering content on the server and sending it to the client for hydration. When feature flagging is involved, you need to make sure that rendering on the server uses the same flag values as the client. It is also important to avoid the performance impact of the initial client-side DevCycle configuration fetch that would normally have to occur when the page is first loaded.

To support these use-cases, the Node.js SDK provides functionality for generating client-side configurations on the server, for use during server-side rendering as well as bootstrapping on the client.

To use it, you must also have the DevCycle JS Client SDK installed in your server application. Follow the [setup docs](/sdk/client-side-sdks/javascript/javascript-install)
for that SDK to get started.

To enable this feature, initialize a Node.js client on the server and enable client bootstrapping mode:

```javascript
// devcycle.ts
import { initializeDevCycle } from '@devcycle/nodejs-server-sdk'

export const devcycleClient = await initializeDevCycle(
'<DEVCYCLE_SERVER_SDK_KEY>',
{
enableClientBootstrapping: true,
}
).onClientInitialized()
```

This will instruct the SDK to keep a copy of the client configuration up-to-date in addition to the server configuration.

Now, call the client's method for obtaining the bootstrapping config, using the user data representing the current request.
You should also pass the userAgent from the request, which allows the SDK to determine some built-in attributes about the user:

```javascript
const user = {
user_id: 'some user data'
}
const bootstrapConfig = await devcycleClient.getClientBootstrapConfig(user, userAgent)
```

Calling this method will run a fast, local evaluation of your project's Targeting Rules using a cached copy of the configuration.
You can expect the same level of performance as with any server-side evaluation.

Now pass the result in wherever you initialize your DevCycle client SDK. For example with the React SDK:

```jsx
import { DevCycleProvider } from '@devcycle/react-client-sdk'
export default function App() {
return (
<DevCycleProvider options={{
sdkKey: bootstrapConfig.clientSDKKey,
bootstrapConfig: bootstrapConfig,
user: user
}}>
<TheRestofYourApp />
</DevCycleProvider>
)
}
```

Make sure you also pass the same "user" that was used to obtain the bootstrap config. You must also provide the client SDK key
so that the client-side SDK can initialize. The SDK key you should use is available as the `sdkKey` field of the bootstrap config.

## Example
Here is an example that connects all these pieces in Remix with the React SDK:

```tsx
// app/root.tsx
import type { LoaderFunctionArgs } from "@remix-run/node"
import { json } from "@remix-run/node"
import { DevCycleProvider } from '@devcycle/react-client-sdk'
import { devcycleClient } from '../devcycle'

export async function loader({
request,
}: LoaderFunctionArgs) {
const user = await getUser(request);
const userAgent = request.headers.get('user-agent');
const devcycleNodeClient = getDevCycleNodejsClient();
const config = await devcycleNodeClient.getClientBootstrapConfig(user, userAgent);
return json({user, config});
}

export default function Component() {
const data = useLoaderData<typeof loader>();
return (
<DevCycleProvider options={{
sdkKey: data.config.clientSDKKey,
bootstrapConfig: data.config,
user: data.user
}}>
<TheRestofYourApp />
</DevCycleProvider>
);
}
```

Once these pieces are in place, Remix will supply the component with the client configuration for the current user. It can then
be provided to the React SDK by passing it to the `bootstrapConfig` option of the `DevCycleProvider`. From this point downwards in the component
tree, the React SDK will return Variable values from this bootstrapped config during server-side rendering, and will hydrate with the same configuration on the client.

To see this in action, check out the [Remix bootstrapping example application](https://github.com/DevCycleHQ-Sandbox/bootstrap-example-remix).
2 changes: 1 addition & 1 deletion docs/sdk/server-side-sdks/node/node.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ title: Node.js SDK
import CustomDocCardList from '@site/src/components/CustomDocCardList'
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';

# DevCycle NodeJS Server SDK
# DevCycle Node.js Server SDK

There are two modes for the SDK, Cloud bucketing (using the [Bucketing API](https://docs.devcycle.com/bucketing-api/)) and Local Bucketing.

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,5 @@
"last 1 safari version"
]
},
"packageManager": "yarn@4.1.1"
"packageManager": "yarn@4.2.1"
}
Loading

0 comments on commit 4948fdb

Please sign in to comment.