Ionify is intentionally config-light. The goal is: a small, explicit config surface that maps to real pipeline behavior (graph versioning, CAS isolation, deps optimizer).
ionify.config.ts
Ionify looks for one of:
- `ionify.config.ts`
- `ionify.config.mts`
- `ionify.config.js` / `ionify.config.mjs` / `ionify.config.cjs`
You can export an object or use `defineConfig`: ```ts import { defineConfig } from "@ionify/ionify";
export default defineConfig({ entry: "/src/main.tsx", }); ```
create-ionify
Scaffold a new project (optionally monorepo) via:
Common CLI flags:
- `--template basic|dashboard`
- `--monorepo` / `--no-monorepo`
- `--testing vitest|playwright|both`
- `--pm pnpm|npm|yarn|bun`
- `--yes` (defaults)
Workspace identity (workspaces + monorepos)
Ionify automatically discovers the workspace root (pnpm/yarn/npm workspaces + Git submodules) and unifies state under the workspace `.ionify/` directory.
Ionify also sets these environment variables for engine components and tooling:
- `IONIFY_WORKSPACE_ROOT`
- `IONIFY_PROJECT_ROOT`
- `IONIFY_STATE_DIR`
- `IONIFY_WORKSPACE_ID`
- `IONIFY_PROJECT_ID`
Scaffolding extras
The scaffolder can optionally configure:
- AI assistant setup: `.cursorrules`, `.github/copilot-instructions.md`, and `docs/ai-prompts/`
- Performance budget enforcement: Lighthouse config + CI workflow + a `performanceBudget` section in `ionify.config.ts`
- Visual regression testing: Percy/Chromatic setup + example tests + CI workflow
performanceBudget
When enabled by the scaffolder, `performanceBudget` is used by the generated CI/scripts to fail builds when budgets are exceeded.
```ts import { defineConfig } from "@ionify/ionify";
export default defineConfig({ // Example (preset-based) performanceBudget: "strict", // "moderate" | "relaxed" | false }); ```
Generated files typically include:
- `lighthouserc.json`
- `.github/workflows/performance.yml`
- `scripts/analyze-bundle.js`
Visual regression testing
When enabled by the scaffolder, visual tests run on CI and catch UI diffs before merge.
Generated files typically include:
- `tests/visual/`
- `.github/workflows/visual-tests.yml`
- `percy.config.js` (or Chromatic config)
DX metrics
Ionify build/dev output reflects real engine state (CAS-first hydration + deterministic planning).
- `ionify build` prints: Modules in plan, CAS hits, transforms needed, and total time.
- `ionify analyze` summarizes `.ionify/` state (graph + packs + slimming when enabled).
root
`root` sets the project root directory Ionify uses for:
- Resolving `entry` and imports
- Locating env files (`.env*`)
- Storing caches under `.ionify/` (CAS + deps artifacts)
Notes:
- In a monorepo/workspace, Ionify stores `.ionify/` at the workspace root (shared across apps).
Defaults:
- If you have an `ionify.config.*`, Ionify uses the config file’s directory
- If you don’t, Ionify uses `process.cwd()`
Entry
- `entry`: string or string[] (project-relative, `/src/...` is supported)
This feeds the graph and the build planner.
Resolve
```ts export default { resolve: { alias: { "@core": "/core", }, extensions: [".mjs", ".js", ".mts", ".ts", ".jsx", ".tsx", ".json"], conditions: ["import", "module", "browser", "default"], mainFields: ["module", "jsnext:main", "jsnext", "main"], }, }; ```
optimizeDeps (deps optimizer + packs)
Ionify’s deps optimizer serves node_modules through `/@deps/*` and caches deterministic artifacts under `.ionify/deps/
Core options:
- `optimizeDeps.include: string[]` Pre-optimize these on dev server start (background pre-warm).
- `optimizeDeps.exclude: string[]` Skip optimization and pack selection for these deps.
- `optimizeDeps.bundleEsm: boolean` (default `true`) Bundle ESM deps into self-contained files to reduce request waterfalls.
- `optimizeDeps.sourcemap: boolean` (default `false`) Sourcemaps for optimized deps.
sharedChunks
- `optimizeDeps.sharedChunks: "auto" | boolean` Build shared chunks when optimizing multiple dep entries as one graph.
Notes:
- Vendor packs require `sharedChunks !== false` to be effective.
- For best request reduction, keep `bundleEsm=true` and `sourcemap=false`.
vendor (preloader)
- `optimizeDeps.vendor: "auto" | string[] | false` Build a `vendor.
.js` preloader module to start fetching hot deps earlier.
This can improve cold-start waterfalls, but it does not collapse request count by itself.
vendorPacks (few-request mode)
`vendorPacks` is the real “few-request mode”: it bundles many deps into a small number of pack files, then Ionify rewrites imports to route through those packs.
Modes:
- `false` Disable packs (default)
- `true` Force one heuristic “app vendor” pack
- `"auto"` Progressive layered vendor: build core first, then lazy-build feature packs in the background when the graph proves they’re needed
- `{ [packName]: string[] }` Manual packs
Auto-selection caps:
- `optimizeDeps.vendorPackMaxBytes: number` (default: 600KB)
- `optimizeDeps.vendorPackMaxMembers: number` (default: 25)
packSlimming (usage-driven)
- `optimizeDeps.packSlimming: "auto" | boolean`
When enabled, Ionify writes a deterministic usage index (`deps-usage.v1.json`) and builds usage-minimized pack variants in the background. On warm reload, Ionify prefers the slim pack if it’s ready, otherwise falls back to the base pack or `/@deps/*` wrappers.
Example (recommended progressive config): ```ts import { defineConfig } from "@ionify/ionify";
export default defineConfig({ entry: "/src/main.tsx", optimizeDeps: { sharedChunks: "auto", vendorPacks: "auto", packSlimming: "auto",
// Optional helpers
vendor: "auto",
include: ["lodash"],
}, }); ```
Example (manual packs: core/ui/data): ```ts import { defineConfig } from "@ionify/ionify";
export default defineConfig({ entry: "/src/main.tsx", optimizeDeps: { sharedChunks: true, vendorPacks: { core: [ "react", "react-dom/", "scheduler", "scheduler/", "react/jsx-runtime", "react/jsx-dev-runtime", "react-router", "react-router-dom", "@remix-run/router", "react-refresh", "react-refresh/", ], ui: ["@mui/", "@radix-ui/"], data: [ "@tanstack/react-query", "@tanstack/react-query/", "axios", "axios/", "zod", "zod/", "react-hook-form", "react-hook-form/", "@hookform/resolvers", "@hookform/resolvers/", "zustand", "zustand/*", ], }, packSlimming: "auto", }, }); ```
Env handling (Vite-compatible)
Ionify loads env files (Vite-style):
- `.env`
- `.env.local`
- `.env.
` - `.env.
.local`
envPrefix
`envPrefix` controls which env vars Ionify is allowed to expose to the browser via `import.meta.env.*`.
- Default: `["VITE_", "IONIFY_"]`
- Ionify always exposes: `MODE`, `NODE_ENV`, plus `DEV` / `PROD`
Ionify auto-exposes env vars to the client as `import.meta.env.*` when they match `envPrefix`.
You can also declare types in your app (example from `react-basic/src/ionify-env.d.ts`): ```ts declare global { interface ImportMetaEnv { readonly MODE: string; readonly NODE_ENV: string; readonly DEV: boolean; readonly PROD: boolean; readonly IONIFY_API_URL: string; } } ```
define (compile-time constants)
```ts export default { define: { __APP_VERSION__: JSON.stringify("1.0.0"), "process.env.NODE_ENV": JSON.stringify("development"), }, }; ```
Engine-level flags (optional)
Ionify also supports env flags for pipeline selection:
- `IONIFY_PARSER=oxc|swc|hybrid`
- `IONIFY_MINIFIER=oxc|swc|auto`
- `IONIFY_OPTIMIZATION_LEVEL=0|1|2|3`
Output directory (today)
Build output defaults to `dist/`. Override via CLI: ```bash ionify build --out-dir dist ```