This package contains abstraction of logic to handle feature flags.
We use this package across multiple projects. We want an abstract and standardised way to manage feature flags across applications, and this package provides that for us.
import { FeatureFlags } from "@theopensource-company/feature-flags";
// Create a schema for your feature flags
const schema = {
devTools: {
options: [false, true],
},
migrateDatabase: {
readonly: true,
options: [false, true],
},
} as const;
// Create a new feature flags instance
const flags = new FeatureFlags({ schema });
// Read feature flags
flags.store.devTools; // false
flags.get("devTools"); // false
// Update feature flags
flags.store.devTools = true;
flags.set("devTools", true);
// Will throw an error, value is not in schema
flags.store.devTools = 123;
// Will throw an error, flag is readonly
flags.store.migrateDatabase = true;
// Schema's define your feature flags
// Every feature flag must have at least one option
// The first option is always the "schema default"
// You can also pass on defaults per environment. If set, they will overwrite schema defaults
const schema = {
// You can store booleans, string literals and numbers
boolean: {
options: [false, true],
},
string: {
options: ["Hello", "World!"],
},
number: {
options: [123, 456, 789],
},
// Or also mix them up
mixed: {
options: [1, "String", true],
},
// Readonly properties are special
// Once the default value is set, they can not be overwritten afterwards
readonly: {
readonly: true,
options: [false, true],
},
} as const;
// Instead of "as const", you can also import the FeatureFlagSchema type and use the satisfied keyword
The library accepts defaults per environment. In combination with a passed environment, the library will prefer these defaults over schema defaults
// We are using the static createOptions method here to abstract away the environment that we will need to set.
// This method will simply return the same argument that you passed, but adds the benefit that you can easily type your schema and defaults while being able to reuse them.
const options = FeatureFlags.createOptions({
schema,
defaults: {
dev: {
migrateDatabase: true,
preLaunchPage: false,
},
preview: {
preLaunchPage: false,
},
},
});
This library exposes a provider and a hook to use this library in a reactive manner with React.js. The below snippets give an example as to how you could implement this library. It might differ for your usecase.
This file contains all configuration for the feature flags
import React, { type ReactNode } from "react";
import { FeatureFlags } from "@theopensource-company/feature-flags";
import { featureFlagsHookFactory } from "@theopensource-company/feature-flags/react";
export const featureFlags = new FeatureFlags({
schema: {
test: {
options: [true, false],
},
},
});
// By passing the FeatureFlags instance, the factory will automatically inherit types from the schema.
export const useFeatureFlags = featureFlagsHookFactory(featureFlags);
Some file which renders only on the client. Usually a central place in react applications to wrap all providers in one place.
import React from "react";
import { featureFlags } from "feature-flags.ts";
import { FeatureFlagProvider } from "@theopensource-company/feature-flags/react";
export default function Providers(
{ children }: { children: ReactNode },
) {
return (
<FeatureFlagProvider featureFlags={featureFlags}>
{children}
</FeatureFlagProvider>
);
}
Some page which needs feature flags
import { useFeatureFlags } from "feature-flags.ts";
export default function Page() {
const [flags, setFlags] = useFeatureFlags();
return (
<>
<label htmlFor="test">
Test enabled
</label>
<input
id="test"
type="checkbox"
checked={flags.test}
onChange={() =>
setFlags({
test: !flags.test,
})}
/>
</>
);
}
This library exposes a hook to use this library in a reactive manner with Vue.js. The below snippets give an example as to how you could implement this library. It might differ for your usecase.
This file contains all configuration for the feature flags
import { FeatureFlags } from "@theopensource-company/feature-flags";
import { featureFlagsHookFactory } from "@theopensource-company/feature-flags/vue";
export const featureFlags = new FeatureFlags({
schema: {
test: {
options: [true, false],
},
},
});
export const useFeatureFlags = featureFlagsHookFactory(featureFlags);
Some page which needs feature flags
<script>
import { useFeatureFlags } from 'feature-flags.ts';
const [flags, setFlags] = useFeatureFlags();
</script>
<template>
<button v-on:click="setFlags({ test: !flags.test })">
{{ flags.toString() }}
</button>
</template>