Vite Configuration#
Entry point: web/vite.config.ts
The Dify frontend uses Vite (via the vite-plus wrapper) as its build and dev-server pipeline. The configuration in web/vite.config.ts is a single defineConfig factory that branches on three mutually exclusive runtime modes — test, Storybook, and normal dev/build — to assemble the appropriate plugin set for each context.
Runtime Mode Detection#
Two boolean flags drive plugin selection :
| Flag | Detection logic |
|---|---|
isTest | mode === 'test' (Vitest sets this) |
isStorybook | process.env.STORYBOOK === 'true' OR any CLI arg contains "storybook" |
Plugin Sets#
Plugins are chosen based on the active mode :
Test mode (isTest)
nextStaticImageTestPlugin— transforms static image imports into stub objects for unit testsreact()— JSX transformmdx-stub— inline plugin that stubs.mdximports (export default () => null) so components importing MDX can be unit-tested without a full MDX pipeline
Storybook mode (isStorybook)
react()only
All other plugins are intentionally excluded. vite-plugin-inspect would crash Storybook with Error: Can not found environment context for client . The fix — introduced in PR #33039 — added the isStorybook flag and reduced the Storybook plugin list to the minimum viable set.
Normal dev/build mode
Inspect()— vite-plugin-inspect for build pipeline introspectioncreateCodeInspectorPlugin/createForceInspectorClientInjectionPlugin— custom plugins for click-to-source code inspectiontailwindcss()— @tailwindcss/vite pluginreact()— JSX transformvinext({ react: false })— Next.js-to-Vite compatibility layercustomI18nHmrPlugin— hot-reloads i18n JSON files without a full page reload
Module Resolution#
resolve block:
tsconfigPaths: true— delegates path alias resolution totsconfig.json, replacing the older manualresolve.aliasentry for~@. Switched in PR #33363.loro-crdtalias — maps bareloro-crdtimports toloro-crdt/base64. The defaultloro-crdtpackage uses a WebAssembly loader that is incompatible with Vite-based pipelines (Vitest and vinext); thebase64build inlines WASM as a Base64 string, sidestepping the loader issue.
vinext-Specific Config#
The optimizeDeps, server, and ssr settings only apply in normal dev/build mode (!isTest && !isStorybook) :
optimizeDeps.exclude: ['@tanstack/react-query']— prevents pre-bundling conflicts with vinextserver.port: 3000ssr.noExternal: ['emoji-mart']— avoids CJS named-export errors foremoji-martunder SSR
Vitest Config#
The test block is always present in the exported config and configures Vitest :
- Pool:
threads - Environment:
happy-dom - Globals: enabled
- Setup file:
./vitest.setup.ts - Coverage: v8 provider; JSON reporters in CI, text + JSON locally
Custom Vite Plugins#
All project-local plugins live in web/plugins/vite/:
| File | Purpose |
|---|---|
code-inspector.ts | Click-to-source code inspector, injected into dev client |
custom-i18n-hmr.ts | HMR for i18n JSON files |
inject-target.ts | Resolves instrumentation-client.ts as the injection target |
next-static-image-test.ts | Stubs static image imports for unit tests |
utils.ts | Shared helpers for module ID normalization and client code injection |
Storybook Config#
Storybook configuration lives in web/.storybook/main.ts. It uses the @storybook/nextjs-vite framework and scans for stories in app/components/** and features/** . Vite configuration for Storybook is sourced from the same shared vite.config.ts, controlled by the isStorybook flag.