-
Notifications
You must be signed in to change notification settings - Fork 39
chore: Add Vue SDK data-saving-mode example #1852
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| # Set when running yarn start / yarn build | ||
| # (e.g. LAUNCHDARKLY_CLIENT_SIDE_ID=xxx LAUNCHDARKLY_FLAG_KEY=my-flag yarn start). | ||
|
|
||
| LAUNCHDARKLY_CLIENT_SIDE_ID= | ||
| LAUNCHDARKLY_FLAG_KEY=sample-feature |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| /node_modules | ||
| /dist | ||
| .DS_Store | ||
| .env.local | ||
| .env.development.local | ||
| .env.test.local | ||
| .env.production.local | ||
| .env | ||
| npm-debug.log* | ||
| yarn-debug.log* | ||
| yarn-error.log* |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| # LaunchDarkly Vue SDK FDv2 example | ||
|
|
||
| A minimal [Vite](https://vitejs.dev/) + Vue 3 app that exercises the Vue SDK's | ||
| FDv2 **data saving mode** (`dataSystem`) configuration. | ||
|
|
||
| > [!NOTE] | ||
| > Data saving mode is a LaunchDarkly Early Access Program (EAP) feature. The | ||
| > `dataSystem` option and its behaviors are not stable and may change before | ||
| > General Availability. | ||
|
|
||
| ## What it demonstrates | ||
|
|
||
| - Enabling the FDv2 data system through the plugin's `ldOptions` | ||
| (`dataSystem: {}`), in [`src/LDClient.ts`](./src/LDClient.ts). | ||
| - Evaluating a flag with `useBoolVariation`, which updates live once you switch | ||
| the connection mode to `streaming` or `polling` (the browser default, | ||
| `one-shot`, fetches once at page load and does not update afterward). | ||
| - Switching the connection mode at runtime (`streaming`, `polling`, `offline`, | ||
| `one-shot`, `background`, or automatic) via `useLDClient().setConnectionMode`. | ||
| - Toggling streaming via `setStreaming`. | ||
| - Switching the evaluation context via `identify`. | ||
|
|
||
| ## Run it | ||
|
|
||
| This example uses the workspace build of `@launchdarkly/vue-client-sdk`. From the | ||
| repository root, build the SDK and its dependencies first: | ||
|
|
||
| ```bash | ||
| yarn workspaces foreach -pR --topological-dev --from '@launchdarkly/vue-client-sdk' run build | ||
| ``` | ||
|
|
||
| Then start the example with your client-side ID (and optionally a flag key): | ||
|
|
||
| ```bash | ||
| LAUNCHDARKLY_CLIENT_SIDE_ID=your-client-side-id \ | ||
| LAUNCHDARKLY_FLAG_KEY=your-flag-key \ | ||
| yarn workspace @launchdarkly/vue-client-sdk-example-data-saving-mode start | ||
| ``` | ||
|
|
||
| Open the URL Vite prints (default <http://localhost:5173>). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| <!DOCTYPE html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="UTF-8" /> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
| <title>LaunchDarkly Vue SDK FDv2 Example</title> | ||
| </head> | ||
| <body> | ||
| <div id="app"></div> | ||
| <script type="module" src="/src/main.ts"></script> | ||
| </body> | ||
| </html> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| { | ||
| "name": "@launchdarkly/vue-client-sdk-example-data-saving-mode", | ||
| "version": "0.1.0", | ||
| "private": true, | ||
| "type": "module", | ||
| "scripts": { | ||
| "start": "vite", | ||
| "build": "vite build", | ||
| "preview": "vite preview", | ||
| "tsc": "vue-tsc --noEmit" | ||
| }, | ||
| "dependencies": { | ||
| "@launchdarkly/vue-client-sdk": "0.2.0", | ||
| "vue": "^3.3.0" | ||
| }, | ||
| "devDependencies": { | ||
| "@vitejs/plugin-vue": "^5.1.2", | ||
| "vue-tsc": "3.3.9", | ||
| "typescript": "^5.5.3", | ||
| "vite": "^5.4.1" | ||
| } | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lockfile omitted for new workspaceHigh Severity The new Reviewed by Cursor Bugbot for commit 076ac60. Configure here. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,176 @@ | ||
| <template> | ||
| <div class="App"> | ||
| <h1>LaunchDarkly Vue FDv2 Demo</h1> | ||
| <p class="status">{{ statusMessage }}</p> | ||
|
|
||
| <section> | ||
| <h2>Flag</h2> | ||
| <p> | ||
| <code>{{ FLAG_KEY }}</code> = <strong>{{ ready ? String(flagValue) : '...' }}</strong> | ||
| </p> | ||
| </section> | ||
|
|
||
| <section> | ||
| <h2>Connection mode</h2> | ||
| <p>Current: <strong>{{ mode }}</strong></p> | ||
| <div class="buttons"> | ||
| <button v-for="m in CONNECTION_MODES" :key="m" @click="onSetConnectionMode(m)"> | ||
| {{ m }} | ||
| </button> | ||
| <button @click="onSetConnectionMode(undefined)">automatic (clear)</button> | ||
| </div> | ||
| </section> | ||
|
|
||
| <section> | ||
| <h2>Streaming</h2> | ||
| <p>Current: <strong>{{ streaming }}</strong></p> | ||
| <div class="buttons"> | ||
| <button @click="onSetStreaming(true)">setStreaming(true)</button> | ||
| <button @click="onSetStreaming(false)">setStreaming(false)</button> | ||
| <button @click="onSetStreaming(undefined)">setStreaming(undefined)</button> | ||
| </div> | ||
| </section> | ||
|
|
||
| <section> | ||
| <h2>Context</h2> | ||
| <p>Current: <code>{{ JSON.stringify(CONTEXTS[contextIndex]) }}</code></p> | ||
| <div class="buttons"> | ||
| <button @click="onSwitchContext">Switch context (identify)</button> | ||
| </div> | ||
| </section> | ||
|
|
||
| <section> | ||
| <h2>Log</h2> | ||
| <pre class="log">{{ log.join('\n') }}</pre> | ||
| </section> | ||
| </div> | ||
| </template> | ||
|
|
||
| <script setup lang="ts"> | ||
| import { computed, ref } from 'vue'; | ||
|
|
||
| import { | ||
| useBoolVariation, | ||
| useInitializationStatus, | ||
| useLDClient, | ||
| } from '@launchdarkly/vue-client-sdk'; | ||
| import type { LDContext } from '@launchdarkly/vue-client-sdk'; | ||
|
|
||
| const FLAG_KEY = import.meta.env.LAUNCHDARKLY_FLAG_KEY ?? 'sample-feature'; | ||
|
|
||
| // FDv2 connection modes the data system supports. | ||
| const CONNECTION_MODES = ['streaming', 'polling', 'offline', 'one-shot', 'background'] as const; | ||
| type ConnectionMode = (typeof CONNECTION_MODES)[number]; | ||
|
|
||
| const CONTEXTS: LDContext[] = [ | ||
| { kind: 'user', key: 'example-user-key', name: 'Sandy' }, | ||
| { kind: 'user', key: 'example-user-key-2', name: 'Alex' }, | ||
| ]; | ||
|
|
||
| const initStatus = useInitializationStatus(); | ||
| const flagValue = useBoolVariation(FLAG_KEY, false); | ||
| const ldc = useLDClient(); | ||
|
|
||
| const mode = ref<string>('automatic'); | ||
| const streaming = ref<string>('default'); | ||
| const contextIndex = ref(0); | ||
| const log = ref<string[]>([]); | ||
|
|
||
| function addLog(line: string) { | ||
| log.value = [`${new Date().toISOString().slice(11, 23)} ${line}`, ...log.value].slice(0, 25); | ||
| } | ||
|
|
||
| function onSetConnectionMode(next?: ConnectionMode) { | ||
| // setConnectionMode is part of the FDv2 data saving mode Early Access feature, and is | ||
| // not subject to backwards compatibility guarantees until the API stabilizes. | ||
| ldc.setConnectionMode(next); | ||
| mode.value = next ?? 'automatic'; | ||
| addLog(`setConnectionMode(${next ?? 'undefined'})`); | ||
| } | ||
|
|
||
| function onSetStreaming(next?: boolean) { | ||
| ldc.setStreaming(next); | ||
| streaming.value = next === undefined ? 'default' : String(next); | ||
| addLog(`setStreaming(${next === undefined ? 'undefined' : next})`); | ||
| } | ||
|
|
||
| async function onSwitchContext() { | ||
| const next = (contextIndex.value + 1) % CONTEXTS.length; | ||
| contextIndex.value = next; | ||
| addLog(`identify(${JSON.stringify(CONTEXTS[next])})`); | ||
| const result = await ldc.identify(CONTEXTS[next]); | ||
| addLog(`identify result: ${result.status}`); | ||
| } | ||
|
|
||
| const ready = computed(() => initStatus.value.status !== 'initializing'); | ||
|
|
||
| const statusMessage = computed(() => { | ||
| const s = initStatus.value.status; | ||
| if (s === 'complete') return 'SDK successfully initialized.'; | ||
| if (s === 'failed') return 'SDK failed to initialize. Check your client-side ID and network.'; | ||
| if (s === 'timeout') return 'SDK timed out during initialization.'; | ||
| return 'Initializing...'; | ||
| }); | ||
| </script> | ||
|
|
||
| <style scoped> | ||
| .App { | ||
| max-width: 640px; | ||
| margin: 0 auto; | ||
| padding: 24px 16px 48px; | ||
| } | ||
|
|
||
| .App h1 { | ||
| font-size: 22px; | ||
| } | ||
|
|
||
| .App h2 { | ||
| font-size: 15px; | ||
| text-transform: uppercase; | ||
| letter-spacing: 0.04em; | ||
| color: #5a5f6b; | ||
| margin-bottom: 6px; | ||
| } | ||
|
|
||
| .status { | ||
| font-style: italic; | ||
| color: #5a5f6b; | ||
| } | ||
|
|
||
| section { | ||
| border-top: 1px solid #e1e3e8; | ||
| padding: 12px 0; | ||
| } | ||
|
|
||
| .buttons { | ||
| display: flex; | ||
| flex-wrap: wrap; | ||
| gap: 8px; | ||
| } | ||
|
|
||
| .buttons button { | ||
| background-color: #405bff; | ||
| color: #fff; | ||
| border: none; | ||
| border-radius: 6px; | ||
| padding: 8px 12px; | ||
| font-size: 14px; | ||
| cursor: pointer; | ||
| } | ||
|
|
||
| .buttons button:hover { | ||
| background-color: #2f47cc; | ||
| } | ||
|
|
||
| .log { | ||
| background-color: #1a1a1a; | ||
| color: #ffa500; | ||
| font-family: monospace; | ||
| font-size: 12px; | ||
| border-radius: 6px; | ||
| padding: 10px; | ||
| max-height: 200px; | ||
| overflow: auto; | ||
| white-space: pre-wrap; | ||
| } | ||
| </style> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import type { LDContext, LDVueClientOptions } from '@launchdarkly/vue-client-sdk'; | ||
|
|
||
| export const LAUNCHDARKLY_CLIENT_SIDE_ID = import.meta.env.LAUNCHDARKLY_CLIENT_SIDE_ID ?? ''; | ||
|
|
||
| // The initial evaluation context. This context should appear on your | ||
| // LaunchDarkly contexts dashboard soon after you run the demo. | ||
| export const initialContext: LDContext = { | ||
| kind: 'user', | ||
| key: 'example-user-key', | ||
| name: 'Sandy', | ||
| }; | ||
|
|
||
| // Enable the FDv2 data system. An empty object opts in with the browser default: | ||
| // a one-time flag fetch at page load (cache, then polling, then streaming as | ||
| // fallbacks), with no further updates afterward. | ||
| // | ||
| // Data saving mode is an Early Access feature. To get live updates, or to pin | ||
| // a specific connection mode, use manual mode switching, for example: | ||
| // dataSystem: { | ||
| // automaticModeSwitching: { type: 'manual', initialConnectionMode: 'polling' }, | ||
| // }, | ||
| export const ldOptions: LDVueClientOptions = { dataSystem: {} }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| body { | ||
| margin: 0; | ||
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; | ||
| background-color: #f4f5f8; | ||
| color: #21242b; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import { createApp } from 'vue'; | ||
| import { LDVuePlugin } from '@launchdarkly/vue-client-sdk'; | ||
|
|
||
| import App from './App.vue'; | ||
| import { initialContext, LAUNCHDARKLY_CLIENT_SIDE_ID, ldOptions } from './LDClient'; | ||
| import './index.css'; | ||
|
|
||
| createApp(App) | ||
| .use(LDVuePlugin, { | ||
| clientSideID: LAUNCHDARKLY_CLIENT_SIDE_ID, | ||
| context: initialContext, | ||
| ldOptions, | ||
| }) | ||
| .mount('#app'); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| declare module '*.vue' { | ||
| import type { DefineComponent } from 'vue'; | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| const component: DefineComponent<Record<string, never>, Record<string, never>, any>; | ||
| export default component; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| /// <reference types="vite/client" /> |


Uh oh!
There was an error while loading. Please reload this page.