npm package: @softwareimaging/backstage
Description: Backstage is a headless environment & feature flag library that isn't tied to any specific service or format. It's a React based library that focuses on being easy to use and simple to integrate with any (and multiple) feature providers.
Latest version: 3.2.0

# Backstage

Backstage is a headless environment & feature flag library that isn't tied to any specific service or format. It's a React based library that focuses on being easy to use and simple to integrate with any (and multiple) feature providers.

The current available providers are:

- [`@softwareimaging/backstage-local`]() - A provider for a local JSON file as configuration.
- [`@softwareimaging/backstage-azure-config`]() - A provider to use the [Azure App Configuration](https://docs.microsoft.com/en-us/azure/azure-app-configuration/) flag backend.

- `[TODO]` - `@softwareimaging/backstage-cra` - [`create-react-app` environment variables.](https://create-react-app.dev/docs/adding-custom-environment-variables/)
- `[TODO]` - `@softwareimaging/backstage-http` - A provider for using a simple, single endpoint with optional headers.

---

## Usage

Install the main library first.

```
npm i @softwareimaging/backstage --save
```

And then any providers you want to use, e.g.

```
npm i @softwareimaging/backstage-local @softwareimaging/backstage-azure-config --save
```

> See the [@softwareimaging/backstage-local]() documentation on how to set up a local environment file.

Adopt and configure the provider as close to the top of component tree as possible.

```js
// backstage-provider.jsx
import { Backstage } from '@softwareimaging/backstage'
import LocalProvider from '@softwareimaging/backstage-local'
import config from './backstage.local'

const BackstageProvider = ({ children }) => {
  const providers = [LocalProvider(1, { config })]

  return <Backstage providers={providers}>{children}</Backstage>
}
```

Backstage uses suspense to manage it's loading state. Provide a suspense boundary and a fallback state. See the React documentation for more information.

```js
import { Suspense } from 'react'
import { BackstageProvider } from './backstage-provider'

const App = () => {
  return (
    <Suspense fallback="Loading...">
      <BackstageProvider>
        <RestOfApplication />
      </BackstageProvider>
    </Suspense>
  )
}
```

To use it in your components, use the `useVariable` and `useFlag` hooks.

```js
import { useVariable, useFlag } from '@softwareimaging/backstage'
const Component = () => {
  const name = useVariable('name') // string
  const showBanner = useFlag('banner') // boolean

  return <div>{showBanner && <Banner>Hello {name}!</Banner>}</div>
}
```

```ts
const Component = () => {
  const name = useVariable('name') // string

  return (
    <div>
      <Flag name="banner">
        <Banner>Hello {name}!</Banner>
      </Flag>
    </div>
  )
}
```

## Use with TypeScript

It's recommend for TypeScript projects to use an interface to define the known options for your configuration for all of the type-safe-goodness that comes with TypeScript.

Firstly, define your config interface.

```typescript
// backstage-config.ts
export interface MyConfig extends BackstageConfig {
  variables: {
    apiKey: string
    name: string
  }
  flags: {
    banner: boolean
    promotion: boolean
  }
}

export type Variables = keyof MyConfig['variables']
export type Flags = keyof MyConfig['flags']
```

It's also worth defining an extra export of your possible variable & flag names. This will make typing your hook calls have less boilerplate.

While that may look a bit weird, it is simply just a type represents the keys in the object. In the example above `Variables` is equal to `'apiKey' | 'name'` and `Flags` is equal to `'banner' | 'promotion'`.

To use this in your components, add the type to your hook calls.

```typescript
import { useFlag } from '@softwareimaging/backstage'
import { Flags } from './backstage-config'
const Text = () => {
  const promotion = useFlag<Flags>('promotion') // <- This key is typechecked.
  return promotion ? <p>Discount: £10!</p> : <p>Normal pricing: £100</p>
}
```

## Provider Development

If you want to implement a new provider, please use the example and types below as a starting point.

```ts
// Please note the nested function, this allows for custom
// priorities at run time. Feel free to use additional arguments
// for configuration.
const provider: BackstageProvider = (priority: number = 0) => () => {
  return {
    priority,
    name: 'Example Provider',
    get: async () => {
      return {
        variables: {
          name: 'Website name',
          colour: '#29008a'
        },
        flags: {
          banner: true
        }
      }
    }
  }
}
```