Skip to content
LogoLogo

Vite Plugin

@picked/vite-plugin-picked adds Picked to your Vite project. It reads the options of your project at build time. It then puts them in a module that gives them to the SDK, so the SDK makes no API request at runtime. In development it also serves a launcher page. On that page you can see a preview of an experience with your own feature flag values.

How it works

Build-time config injection

When Vite starts, in both dev and build, the plugin does this:

  1. It reads the configuration of your project from the Picked API.
  2. It embeds those options in your bundle.
  3. The module gives the options to the SDK as the browser loads it.
  4. The SDK reads the embedded configuration at runtime and makes no network request.

Step 3 is a function call. The module gives the options to the SDK as it loads, and does not wait for the SDK to ask.

When a preview token is there at runtime, the SDK ignores the embedded configuration and reads fresh data from the API.

Preload of the data file

Vite puts the options of your project in their own JavaScript file. For each HTML page in your build, the plugin adds a <link rel="modulepreload"> for that file. The browser then gets it while it reads the page, and not later when the SDK starts.

The CMS content of an experience stays in its own file and gets no preload. The browser gets it only when an experience needs it.

Some applications make their HTML from the code, and not from an HTML file in your project. React Router in server mode is one of these. Such a build has no page for the plugin to add the link to. Add this line to the code that runs in the browser instead:

import 'virtual:picked/data'

Your framework then sees the file in its own list and adds the preload for you.

The line reads no value from the module. It is there for the work the module does as it loads. A bundler removes a module that only declares values, and removes the line with it. This module gives your project options to the SDK, which is work, so the bundler keeps both.

Your application is correct without this line. The SDK gets the same data later, as it starts. The line moves that work earlier.

Types for the data file

The plugin makes virtual:picked/data at build time. Because the module is not a file in your project, TypeScript cannot find its types. The plugin gives you a type file for the module. Point your project at that type file to import from the module:

{
  "compilerOptions": {
    "types": ["@picked/vite-plugin-picked/client"]
  }
}

Use one of the two. The types option applies to all files in your project. The reference comment applies to one file.

The module gives three values: projectConfig, experienceContent and manifestMetadata. You do not give these values to the SDK. The module gives them to the SDK itself as the browser loads it.

Dev launcher

In development, the plugin serves an HTML page at /. On that page you can:

  • see every feature flag in your project with its current state;
  • turn a feature flag on or off for a local test;
  • see a preview of an experience with your own feature flag values.

After the dev server starts, the launcher URL appears next to the Vite output:

  ➜  Picked:  http://localhost:5173/
  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose

Options

Project identity belongs in picked.config.ts. The two options that carry it are deprecated, and the table marks them.

OptionTypeDefaultDescription
disableLauncherbooleanfalseTurns the launcher page off in both dev and build output.
generateTypesbooleantrueWhether the plugin writes types from the workspace schema.
mode'bundle' | 'api''bundle'Whether the build carries your project data.
projectIdstring—Deprecated. Use picked.config.ts.
apiUrlstring—Deprecated. Use picked.config.ts.

projectId and apiUrl

These two options moved to picked.config.ts, which the picked command and type generation also read. A later release removes them.

The plugin still reads an option for a field that picked.config.ts leaves out, so a project that has yet to move needs no change. It stops when the two values are different, rather than choose one for you.

generateTypes

The plugin reads the workspace schema and writes picked-env.d.ts, on vite dev and on vite build. Type generation describes the output and the picked.config.ts options that control it.

A failure stops the run. Set generateTypes: false for a build that must not write types, such as a build for one more entry point.

mode

'bundle' reads your project options at build time and puts them in your bundle.

'api' does not read them. Your build then makes no request to the Picked API, and writes no .picked directory. The SDK reads your project options from the API at runtime instead. Use this when your build must not depend on the Picked API.

The SDK has no equivalent option. It uses the data your build gives it, and the API when your build gives none.

Build output

For a production build, vite build, the plugin writes an index.html file that holds the launcher page. Set disableLauncher to stop this. The file lets you deploy the launcher next to your application, so that a stakeholder can see a preview.

The plugin writes that file only when your build made no index.html of its own. An application that has an HTML entry keeps its own page at the root of the output.

The plugin also writes a .picked directory next to your Vite root. It holds the options of your project and the CMS content of each experience.