Skip to content

Frontend ‐ Feature Flagging

Jeremy Asuncion edited this page Sep 13, 2023 · 1 revision

Feature flagging is a practice of hiding in-progress features in production, allowing us to toggle features on or off at runtime without deploying new code.

Feature flagging code decouples feature release from the deployment process, making it possible to release features any time outside of the deployment window. Additionally, it allows us to easily rollback features in production when critical bugs are found.

Feature flags also allow us to dynamically configure features at runtime. For example, the napari hub banner is a feature flag where the message is a configuration value we can change.

Split.io

Split.io is the feature flagging service that the napari hub uses for features.

Flags

Flags in Split.io are called splits, and can be created in the UI using the Create Split button.

image image

Environments

There are 3 environments for each deployment environment of the hub:

image

Enabling a feature

To enable a feature flag, you can set the targeting rule to on:

image

Flag Configuration

To add configuration to a flag, you can set a custom JSON in the treatment for when the flag is on:

image

Server Side Rendering (SSR)

In order for the frontend to render properly, we need to integrate it with the hub's SSR framework. This works by fetching the feature flags on the server, rendering the UI via SSR, and hydrating the browser UI using the feature flags from the server.

This is important because if we only fetched the feature flags on the browser, the Next.js server would throw error due to a UI mismatch between the client and server. When rendering the UI, the resulting HTML needs to match for hydration to work. Otherwise, we'd be rendering the old UI on the server and then rendering the new UI on the browser, negating the performance benefits of hydration in SSR.

This is also beneficial to us from a security perspective because accessing the feature flags requires a Split.io API token. While it is is possible to use a browser token for Split.io that is more secure than a normal API token, it is still a lot more secure fetching it on the hub server so the API token is not exposed in the frontend.

How to use in React?

The following hooks can be used for accessing the value or config of a feature flag:

/**
 * Hook to check if a feature flag is enabled.
 */
export function useIsFeatureFlagEnabled(key: FeatureFlagKey): boolean

/**
 * Hook to check if a feature flag is enabled.
 */
export function useFeatureFlagConfig<T = Record<string, unknown>>;

The useIsFeatureFlagEnabled() hook can be used for conditionally rendering code. It can be used within custom hooks or for rendering different UIs:

// useAppBarLinks.ts
const isCollectionsEnabled = useIsFeatureFlagEnabled('collections')

if (isCollectionsEnabled) {
  return [links.PLUGINS, links.COLLECTIONS]
}

return [links.ABOUT, links.FAQ]
// PluginPage.tsx
const isActivityDashboardEnabled = useIsFeatureFlagEnabled('activityDashboard')

isActivityDashboardEnabled ? <PluginTabs /> : <PluginPageContent />

The useFeatureFlagConfig() hook can be used for changing the runtime value within a hook or component:

interface BannerConfig {
  message?: string
}

export function Banner() {
  const banner = useFeatureFlagConfig<BannerConfig>('banner')

  if (!banner?.message) {
    return <></>
  }

  return (
    <div
      className={clsx(
        'flex items-center justify-center w-full p-4',
        'bg-hub-primary-200 text-center'
      )}
    >
      <Markdown>{banner?.message}</Markdown>
    </div>
  )
}

Local Development

Split.io is disabled for the hub by default for local development with all features enabled, but you can enable it by setting the ENV variable to dev.

However, this requires an API token and so only CZI employees and contractors would have access. The API tokens for Split.io should be available in 1Password under Split.io Keys. The env for the API key is set using the SPLIT_IO_SERVER_KEY variable. You can set these values in the .env file:

ENV=dev
SPLIT_IO_SERVER_KEY=<token>

Cleanup

Feature flags should eventually be cleaned up so that we can remove unused code. Having too many flags adds a lot of overhead for the developer because contributors will end up either not knowing where to implement a new feature, or having to duplicate the effort in multiple places.

Query Parameter Overrides

The value of the feature flag can be overridden by setting a query parameter. To enable a feature flag, use the --enable-feature=<flag-key> parameter. To disable a flag, use the --disable-feature=<flag-key> parameter.

For example, the following URL enables collections:

https://www.napari-hub.org/?enable-feature=collections

And the following URL enables the activity dashboard but disables npe2:

https://www.napari-hub.org/plugins/napari-spreadsheet?disable-feature=npe2&enable-feature=activityDashboard

Parameters can be stacked, so you can enable and disable any combination of feature flags.