Skip to content

Preact

The React bindings run on Preact through preact/compat — the SDK imports only react (no react-dom, no JSX runtime), so one alias covers it. Requires Preact ≥ 10.11 (preact/compat gained useSyncExternalStore there). Every binding runs through this alias in the SDK's own CI.

Vite

@preact/preset-vite sets up the JSX transform and the reactpreact/compat aliases in one step:

ts
// vite.config.ts
import preact from "@preact/preset-vite";
import { defineConfig } from "vite";

export default defineConfig({
  plugins: [preact()],
});

Without the preset, alias manually and point the JSX transform at Preact:

ts
// vite.config.ts
import { defineConfig } from "vite";

export default defineConfig({
  resolve: {
    alias: {
      react: "preact/compat",
      "react-dom": "preact/compat",
    },
  },
  esbuild: {
    jsxImportSource: "preact",
  },
});

For TypeScript, mirror the alias so the bindings' React types resolve:

jsonc
// tsconfig.json
{
  "compilerOptions": {
    "jsxImportSource": "preact",
    "paths": {
      "react": ["./node_modules/preact/compat"],
      "react-dom": ["./node_modules/preact/compat"],
    },
  },
}

Usage

Identical to React — same imports, same components:

tsx
import { Feature, GatesProvider } from "@lucerna-dev/gates-browser/react";
import { gates } from "./lib/gates";

export function App() {
  return (
    <GatesProvider client={gates}>
      <Feature name="new_billing" fallback={<OldBilling />}>
        <NewBilling />
      </Feature>
    </GatesProvider>
  );
}

Peer dependency note

The SDK declares an optional peer on react >=18. With the alias in place Preact satisfies it at runtime; if your package manager warns about the missing peer it's safe to ignore (or silence it — e.g. pnpm's peerDependencyRules.ignoreMissing).

Lucerna Developer Docs