Skip to content
IC Reactor

@ic-reactor/vite-plugin

@ic-reactor/vite-plugin runs the shared @ic-reactor/codegen pipeline inside Vite. It generates declarations and typed reactor entrypoints, with optional React hooks, from .did files, watches for changes, and can inject the ic_env cookie used by ClientManager.

Terminal window
pnpm add -D @ic-reactor/vite-plugin
pnpm add @ic-reactor/react @tanstack/react-query @icp-sdk/core

For non-React output, set target: "core" and install the matching runtime package instead of @ic-reactor/react.

import { defineConfig } from "vite"
import react from "@vitejs/plugin-react"
import { icReactor } from "@ic-reactor/vite-plugin"
export default defineConfig({
plugins: [
react(),
icReactor({
canisters: [{ name: "backend", didFile: "./backend/backend.did" }],
}),
],
})

By default, generated files go to src/declarations/<canister>/, and the plugin imports clientManager from ../../clients.

Relative outDir and didFile paths resolve against Vite’s resolved config.root, not the directory you ran vite from. If you set root: "frontend" or pass the root positionally (vite build apps/web), paths are relative to that directory. Note that --config on its own only selects the config file — it does not change the root.

For each canister, generation produces:

  • declarations/<did-basename>.js, .d.ts, and a .did copy
  • index.generated.ts: managed implementation regenerated on every run
  • index.ts: stable entry wrapper that re-exports from index.generated.ts

With the default target: "react", index.generated.ts exports the reactor plus hooks named after the canister — for a canister named backend: useBackendQuery, useBackendSuspenseQuery, useBackendInfiniteQuery, useBackendSuspenseInfiniteQuery, useBackendMutation, and useBackendMethod.

Option Type Default Description
canisters CanisterConfig[] Canister configurations (required).
outDir string "src/declarations" Base output directory for generated files.
clientManagerPath string "../../clients" Default client manager import path (relative from generated files).
target "react" | "core" "react" Default generated runtime target.
injectEnvironment boolean true Inject ic_env cookie and proxy during vite dev.
failOnError boolean true on vite build, false on vite dev Abort the Vite run when a canister fails to generate.
Option Type Description
name string Canister name (required).
didFile string Path to the .did file (required).
mode string Reactor class: Reactor, DisplayReactor (default), CandidReactor, CandidDisplayReactor, MetadataDisplayReactor.
outDir string Override output directory for this canister.
clientManagerPath string Override client manager path for this canister.
target string Override runtime target for this canister.
canisterId string Fixed canister ID (overrides auto-detected value during local dev).

Set mode per canister to choose the generated reactor class:

icReactor({
canisters: [
{ name: "backend", didFile: "./backend/backend.did" },
{
name: "workflow_engine",
didFile: "./workflow/workflow_engine.did",
mode: "Reactor",
},
],
})

Supported modes:

  • Reactor
  • DisplayReactor
  • CandidReactor
  • CandidDisplayReactor
  • MetadataDisplayReactor

Set target to control whether generated files include React hooks:

  • react (default): generates the reactor plus bound React hooks
  • core: generates only the typed reactor exports with no React dependency

When injectEnvironment is enabled during vite dev, the plugin tries to read local network details from the icp CLI, then:

  1. resolves canister IDs (including internet_identity, which is added automatically if not already in your canister list)
  2. sets the ic_env cookie
  3. proxies /api to the local replica

If icp CLI environment detection is unavailable, the plugin still falls back to proxying /api to http://127.0.0.1:4943, but it skips cookie injection.

If you provide canisterId in the plugin config, that fixed ID overrides the auto-detected development value for that canister.

Set the ICP_ENVIRONMENT environment variable to target a non-default network (defaults to "local").

When a watched .did file changes, the plugin:

  1. regenerates declarations
  2. regenerates index.generated.ts
  3. preserves custom index.ts files, while updating the default wrapper or migrating older generated entrypoints to the wrapper model
  4. triggers a full browser reload

A generation failure aborts vite build by default — a build that silently ships the bindings from the last successful run is worse than no build. Under vite dev the default is the opposite, because the dev server has to survive the broken intermediate states of a .did being edited; there the failure is reported to the terminal and to the browser error overlay instead. Set failOnError explicitly to override either default.