Featurevisor

Advanced

Code Generation

For additional compile-time and runtime safety including autocompletion, we can generate code from our already defined features for improved developer experience.

Why generate code?

This is an optional step that we may wish to adopt in our workflow. If we do, it will help us avoid some common mistakes:

  • any unintentional spelling mistakes in feature and variable keys
  • worrying about the types of our variables
  • worrying about passing attributes in wrong types in context

All of it done being code-driven, thus reducing overall cognitive load of multiple teams.

Supported languages

Currently only TypeScript is supported.

Support for other languages is planned in future, as Featurevisor SDK becomes available in more languages.

Generate code

From the root of our Featurevisor project directory, use the CLI for generating code in a specified directory:

Command
$ npx featurevisor generate-code \
--language typescript \
--out-dir ./src \
--react

The generated files can be found in ./src directory.

Some of the key generated files are:

  • context.ts: typed Context interface for SDK evaluation
  • attributes.ts: generated attribute types, such as CountryAttribute or AccountAttribute
  • schemas.ts: generated reusable schema types
  • features.ts: feature keys, variation values, variable keys, and variable value types
  • functions.ts: typed isEnabled, getVariation, and getVariable functions
  • instance.ts: SDK instance wiring through setInstance
  • react.ts: optional typed React hooks when --react is used
  • index.ts: exports the generated modules

Optional flags:

  • --tag=<tag>: generate code for features with the given tag
  • --target=<target>: generate code for features selected by the target
  • --react: also generate typed React hooks in react.ts

Both --tag and --target can be repeated. Repeated values and a combination of both options form a union, which is useful when one generated package serves several datafiles:

Command
$ npx featurevisor generate-code \
--language typescript \
--out-dir ./src \
--tag=shared \
--target=web \
--target=mobile

A target uses the same tag or tags, includeFeatures, and excludeFeatures selection as its datafile build. Its build-time context does not remove feature types because code generation is not tied to one environment or one specialized datafile result.

Publishing the generated code

We are free to use the generated code in any way we want.

We can choose to either:

  • copy/paste the code in our applications, or
  • publish the generated code as a private npm package and use it in multiple applications, like as @yourorg/features package

The publishing part can be done in the same deployment process right after deploying our generated datafiles.

Consuming the generated code

Assuming we published the generated code as a private npm package @yourorg/features, we can consume it in our applications as follows.

Initialize Featurevisor SDK as usual, and make our newly created package aware of the SDK instance:

your-app/index.js
import { createFeaturevisor } from '@featurevisor/sdk'
import { setInstance } from '@yourorg/features'
const f = createFeaturevisor({
// ...
})
setInstance(f)

Afterwards, we can import a common set of functions which are already aware of which feature keys we are allowed to use including their variable keys.

Importing functions

Similar to JavaScript SDK's methods isEnabled, getVariation, and getVariable, we can import these functions with the same names:

import { isEnabled, getVariation, getVariable } from '@yourorg/features'
const featureIsEnabled = isEnabled('featureKey')
const featureVariation = getVariation('featureKey')
const featureVariable = getVariable('featureKey', 'variableKey')

We can optionally pass additional context as the last argument:

const context = {
userId: '123',
}
const featureIsEnabled = isEnabled('featureKey', context)
const featureVariation = getVariation('featureKey', context)
const featureVariable = getVariable('featureKey', 'variableKey', context)

Everything here is typed as per our defined features.

If we pass a wrong feature key, or a variable key that does not belong to the same feature, we will get a TypeScript error.

Importing React hooks

If we passed --react in CLI, we can import React hooks with the same names as the original package @featurevisor/react:

import { useFlag, useVariation, useVariable } from '@yourorg/features'
const isEnabled = useFlag('featureKey')
const variation = useVariation('featureKey')
const variable = useVariable('featureKey', 'variableKey')

Passing any wrong feature key or variable key combination will result in a TypeScript error.

We can optionally pass additional context as the last argument:

const context = {
userId: '123',
}
const isEnabled = useFlag('featureKey', context)
const variation = useVariation('featureKey', context)
const variable = useVariable('featureKey', 'variableKey', context)

Suggestions for package publishing

You are advised to publish the generated code as a private npm package, with support for ES Modules (ESM).

When published as ES Modules, it will enable tree-shaking in your applications, thus reducing the bundle size.

Previous
Datasource