Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/vue.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,15 @@ jobs:
workspace_name: '@launchdarkly/vue-client-sdk'
workspace_path: packages/sdk/vue
should_build_docs: false
- name: Build example
- name: Build getting-started example
run: |
yarn workspaces focus @launchdarkly/vue-client-sdk-example-getting-started
yarn workspaces foreach -pR --topological-dev --from '@launchdarkly/vue-client-sdk-example-getting-started' run build
- name: Build and type-check data-saving-mode example
run: |
yarn workspaces focus @launchdarkly/vue-client-sdk-example-data-saving-mode
yarn workspaces foreach -pR --topological-dev --from '@launchdarkly/vue-client-sdk-example-data-saving-mode' run build
yarn workspace @launchdarkly/vue-client-sdk-example-data-saving-mode run tsc

run-example:
runs-on: ubuntu-latest
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@
"packages/sdk/openfeature-node-server/examples/getting-started",
"packages/sdk/vue",
"packages/sdk/vue/contract-tests",
"packages/sdk/vue/examples/getting-started"
"packages/sdk/vue/examples/getting-started",
"packages/sdk/vue/examples/features/data-saving-mode"
],
"private": true,
"scripts": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ FDv2 **data saving mode** (`dataSystem`) configuration.

- Enabling the FDv2 data system through the provider's `ldOptions`
(`dataSystem: {}`), in [`src/LDClient.tsx`](./src/LDClient.tsx).
- Evaluating a flag with `useBoolVariation`, which updates live as the data
system delivers changes.
- 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`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ export const initialContext: LDContext = {

const options: LDReactProviderOptions = {
ldOptions: {
// Enable the FDv2 data system. An empty object opts in with default
// behavior: a streaming connection for real-time flag updates, with
// polling as a fallback.
// 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 pin a specific
// connection mode instead, use manual mode switching, for example:
// 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' },
// },
Expand Down
1 change: 1 addition & 0 deletions packages/sdk/vue/examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ This directory contains example applications demonstrating the LaunchDarkly Vue
| Example | Description |
|---------|-------------|
| [getting-started](./getting-started/) | Minimal Vite + Vue app that evaluates a boolean feature flag and reactively displays the result with real-time updates. This is the recommended starting point. |
| [features/data-saving-mode](./features/data-saving-mode/) | Minimal Vite + Vue app that exercises the Vue SDK's FDv2 data saving mode (`dataSystem`) configuration. Data saving mode is an Early Access Program (EAP) feature. |
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
11 changes: 11 additions & 0 deletions packages/sdk/vue/examples/features/data-saving-mode/.gitignore
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*
40 changes: 40 additions & 0 deletions packages/sdk/vue/examples/features/data-saving-mode/README.md
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>).
12 changes: 12 additions & 0 deletions packages/sdk/vue/examples/features/data-saving-mode/index.html
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"
Comment thread
cursor[bot] marked this conversation as resolved.
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.1.2",
"vue-tsc": "3.3.9",
"typescript": "^5.5.3",
"vite": "^5.4.1"
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Lockfile omitted for new workspace

High Severity

The new @launchdarkly/vue-client-sdk-example-data-saving-mode workspace and its vue-tsc dependency are added without a matching yarn.lock update. CI uses Yarn immutable installs, so yarn workspaces focus for this example will fail before the new build and type-check steps run.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 076ac60. Configure here.

176 changes: 176 additions & 0 deletions packages/sdk/vue/examples/features/data-saving-mode/src/App.vue
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;
}
14 changes: 14 additions & 0 deletions packages/sdk/vue/examples/features/data-saving-mode/src/main.ts
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" />
Loading
Loading