Skip to content

Commit 75b70d3

Browse files
authored
Experiment flags (#979)
1 parent f09d883 commit 75b70d3

File tree

4 files changed

+30
-2
lines changed

4 files changed

+30
-2
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,22 @@ GCLOUD_PROJECT=<project-id> FIREBASE_EMULATOR_HUB=localhost:4400 npm start
6969

7070
Open [http://localhost:3000](http://localhost:3000) to view it in the browser. Note: The development server runs by default on port **3000**, so please make sure you are visiting that URL instead of the production Emulator UI (which defaults on port **4000**).
7171

72+
### Developing features behind flags
73+
74+
Experimental CLI features that are activated/deactivated with the `firebase experiments:enable` command are surfaced to the UI via an environment variable. UI components can check if an experiment is active with the `useExperiment` hook:
75+
76+
```jsx
77+
function ExperimentalFeatureUI() {
78+
const showNewFeature = useExperiment("pineapple-smoothie");
79+
80+
if (showNewFeature === true) {
81+
return <h1>Hi, I am an experimental feature</h1>;
82+
} else {
83+
return null;
84+
}
85+
}
86+
```
87+
7288
### Other Available Scripts
7389

7490
In the project directory, you can run:

server.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,19 @@ app.get(
5656
const emulatorsRes = await fetch(hubDiscoveryUrl.toString());
5757
const emulators = (await emulatorsRes.json()) as any;
5858

59-
const json = { projectId, ...emulators };
59+
const json = { projectId, experiments: [], ...emulators };
6060

6161
// Googlers: see go/firebase-emulator-ui-usage-collection-design?pli=1#heading=h.jwz7lj6r67z8
6262
// for more detail
6363
if (process.env.FIREBASE_GA_SESSION) {
6464
json.analytics = JSON.parse(process.env.FIREBASE_GA_SESSION);
6565
}
6666

67+
// pick up any experiments enabled with `firebase experiment:enable`
68+
if (process.env.FIREBASE_ENABLED_EXPERIMENTS) {
69+
json.experiments = JSON.parse(process.env.FIREBASE_ENABLED_EXPERIMENTS);
70+
}
71+
6772
return json;
6873
})
6974
);

src/components/common/EmulatorConfigProvider.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,11 @@ export function useEmulatorConfig<E extends Emulator>(
161161
return emulatorConfig as NonNullable<Config[E]>;
162162
}
163163

164+
export function useExperiment(experimentName: string): Boolean {
165+
const { experiments } = useConfig();
166+
return experiments.includes(experimentName);
167+
}
168+
164169
export function useIsEmulatorDisabled(emulator?: Emulator): boolean {
165170
const config = useConfigOptional();
166171
if (config === undefined) {
@@ -204,9 +209,10 @@ async function configFetcher(url: string): Promise<Config> {
204209
const result: Config = {
205210
projectId: json.projectId as string,
206211
analytics: json.analytics as AnalyticsSession,
212+
experiments: json.experiments as Array<string>,
207213
};
208214
for (const [key, value] of Object.entries<any>(json)) {
209-
if (key === 'projectId' || key === 'analytics') {
215+
if (key === 'projectId' || key === 'analytics' || key === 'experiments') {
210216
continue;
211217
}
212218
let host = value.host as string;

src/store/config/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,5 @@ export interface Config {
8181
hosting?: EmulatorConfig;
8282
storage?: EmulatorConfig;
8383
pubsub?: EmulatorConfig;
84+
experiments: Array<string>;
8485
}

0 commit comments

Comments
 (0)