Skip to content
Merged
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
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
"packages/sdk/combined-browser",
"packages/sdk/shopify-oxygen",
"packages/sdk/shopify-oxygen/contract-tests",
"packages/sdk/shopify-oxygen/example"
"packages/sdk/shopify-oxygen/example",
"packages/sdk/browser/example"
],
"private": true,
"scripts": {
Expand Down
5 changes: 5 additions & 0 deletions packages/sdk/browser/example/.env.template
Copy link
Member

Choose a reason for hiding this comment

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

nit: Newlines at the end of files.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Set LD_CLIENT_SIDE_ID to your LaunchDarkly client-side ID
LD_CLIENT_SIDE_ID=

# Set LD_FLAG_KEY to the feature flag key you want to evaluate
LD_FLAG_KEY=
52 changes: 52 additions & 0 deletions packages/sdk/browser/example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# LaunchDarkly sample javascript application

# ⛔️⛔️⛔️⛔️

> [!CAUTION]
> This example is created against a non-production SDK which means things may change and this example might
> not work while this message is visible.

# ☝️☝️☝️☝️☝️☝️

We've built a simple browser application that demonstrates how this LaunchDarkly SDK works.

Below, you'll find the build procedure. For more comprehensive instructions, you can visit your [Quickstart page](https://app.launchdarkly.com/quickstart#/) or
the [{name of SDK} reference guide](https://docs.launchdarkly.com/sdk/client-side/javascript).

## Prerequisites

Nodejs 20.6.0 or later

## Build instructions

1. Make a copy of the `.env.template` and name it `.env`
```
cp .env.template .env
```

2. Set the variables in `.env` to your specific LD values
```
# Set LD_CLIENT_SIDE_ID to your LaunchDarkly client-side ID
LD_CLIENT_SIDE_ID=

# Set LD_FLAG_KEY to the feature flag key you want to evaluate
LD_FLAG_KEY=
```
> [!NOTE]
> Setting these values is equivilent to modifying the `clientSideID` and `flagKey`
> in [app.ts](./src/app.ts).

3. Install and build the project:
```bash
yarn && yarn build
```

4. On the command line, run `yarn start`
```bash
yarn start
```
> [!NOTE]
> The `yarn start` script simply runs `open index.html`. If that is not working for you,
> you can open the `index.html` file in a browser for the same results.

The application will run continuously and react to the flag changes in LaunchDarkly.
11 changes: 11 additions & 0 deletions packages/sdk/browser/example/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
body {
margin: 0;
background: #373841;
color: white;
font-family:
-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell',
'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
}
11 changes: 11 additions & 0 deletions packages/sdk/browser/example/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge;chrome=1">
<title>LaunchDarkly tutorial</title>
<script src="./dist/app.js" defer></script>
<link rel="stylesheet" href="./index.css">
</head>
<body></body>
</html>
26 changes: 26 additions & 0 deletions packages/sdk/browser/example/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "@launchdarkly/browser-example",
"version": "0.0.0",
"private": true,
"description": "LaunchDarkly example for JavaScript Browser SDK",
"homepage": "https://github.com/launchdarkly/js-core/tree/main/packages/sdk/browser/example",
"repository": {
"type": "git",
"url": "https://github.com/launchdarkly/js-core.git"
},
"license": "Apache-2.0",
"packageManager": "[email protected]",
"type": "module",
"scripts": {
"start": "open index.html",
"clean": "rm -rf dist dist-static",
"build": "npm run clean && tsdown"
},
"dependencies": {
"@launchdarkly/js-client-sdk": "workspace:^"
},
"devDependencies": {
"tsdown": "^0.17.0-beta.4",
"typescript": "^5.9.3"
}
}
61 changes: 61 additions & 0 deletions packages/sdk/browser/example/src/app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { initialize } from '@launchdarkly/js-client-sdk';

// Set clientSideID to your LaunchDarkly client-side ID
const clientSideID = 'LD_CLIENT_SIDE_ID';

// Set flagKey to the feature flag key you want to evaluate
const flagKey = 'LD_FLAG_KEY';

// Set up the evaluation context. This context should appear on your
// LaunchDarkly contexts dashboard soon after you run the demo.
const context = {
kind: 'user',
key: 'example-user-key',
name: 'Sandy',
};

const div = document.createElement('div');
const statusBox = document.createElement('div');

document.body.appendChild(statusBox);
document.body.appendChild(div);

div.appendChild(document.createTextNode('No flag evaluations yet'));
statusBox.appendChild(document.createTextNode('Initializing...'));

const main = async () => {
const ldclient = initialize(clientSideID);
const render = () => {
const flagValue = ldclient.variation(flagKey, false);
const label = `The ${flagKey} feature flag evaluates to ${flagValue}.`;
document.body.style.background = flagValue ? '#00844B' : '#373841';
div.replaceChild(document.createTextNode(label), div.firstChild as Node);
};

ldclient.on('error', () => {
statusBox.replaceChild(
document.createTextNode('Error caught in client SDK'),
statusBox.firstChild as Node,
);
});

// Listen for flag changes
ldclient.on('change', () => {
render();
});

const { status } = await ldclient.identify(context);

if (status === 'completed') {
statusBox.replaceChild(document.createTextNode('Initialized'), statusBox.firstChild as Node);
} else if (status === 'error') {
statusBox.replaceChild(
document.createTextNode('Error identifying client'),
statusBox.firstChild as Node,
);
}

render();
};

main();
22 changes: 22 additions & 0 deletions packages/sdk/browser/example/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"declaration": true,
"declarationMap": true,
"lib": ["ES2017", "dom"],
"module": "ESNext",
"moduleResolution": "node",
"noImplicitOverride": true,
"resolveJsonModule": true,
"rootDir": ".",
"outDir": "dist",
"skipLibCheck": true,
"sourceMap": true,
"inlineSources": true,
"strict": true,
"stripInternal": true,
"target": "ES2017",
"allowJs": true
},
"include": ["src"]
}
37 changes: 37 additions & 0 deletions packages/sdk/browser/example/tsdown.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/* eslint-disable import/no-extraneous-dependencies */
import fs from 'node:fs';
import path from 'node:path';
import { loadEnvFile } from 'node:process';
import { defineConfig } from 'tsdown';

if (fs.existsSync('.env')) {
loadEnvFile('.env');
}

const ENTRY_FILE = path.join('src', 'app.ts');
const OUTPUT_FILE = path.join('dist', 'app.js');
const { LD_CLIENT_SIDE_ID, LD_FLAG_KEY } = process.env;

const CLIENT_SIDE_ID_PLACEHOLDER = 'LD_CLIENT_SIDE_ID';
const FLAG_KEY_PLACEHOLDER = 'LD_FLAG_KEY';

export default defineConfig({
entry: ENTRY_FILE,
platform: 'browser',
outDir: 'dist',
noExternal: ['@launchdarkly/js-client-sdk'],
hooks(hooks) {
hooks.hook('build:done', () => {
if (LD_CLIENT_SIDE_ID) {
const content = fs.readFileSync(OUTPUT_FILE).toString();
fs.writeFileSync(
OUTPUT_FILE,
content.replaceAll(CLIENT_SIDE_ID_PLACEHOLDER, LD_CLIENT_SIDE_ID),
);
}
const flagKey = LD_FLAG_KEY || 'sample-feature';
const content = fs.readFileSync(OUTPUT_FILE).toString();
fs.writeFileSync(OUTPUT_FILE, content.replaceAll(FLAG_KEY_PLACEHOLDER, flagKey));
Copy link

Choose a reason for hiding this comment

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

Bug: Inconsistent fallback behavior for build-time configuration variables

The build configuration has inconsistent handling of environment variables. LD_FLAG_KEY gets a sensible default ('sample-feature') when not provided, but LD_CLIENT_SIDE_ID has no default and leaves the literal placeholder string 'LD_CLIENT_SIDE_ID' in the built output. This causes the SDK to silently fail initialization with an invalid client-side ID if the user forgets to configure it.

Fix in Cursor Fix in Web

});
},
});