Files
zeekayandHanzo Dev c9c37c0ca8 Read the API reference from the shipped types
The framework was documented in hand-written MDX, which drifts the moment a
signature changes. The declarations each package emits already say what it
exports; a page that quotes them says the same thing and cannot say anything
else.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-07 18:57:28 -07:00

253 lines
6.3 KiB
TypeScript

import { createRequire } from 'node:module'
import { resolve as pathResolve } from 'node:path'
import { one } from 'one/vite'
import { visualizer } from 'rollup-plugin-visualizer'
import type { UserConfig } from 'vite'
Error.stackTraceLimit = Number.POSITIVE_INFINITY
// @ts-ignore
if (!import.meta.dirname) {
throw new Error(`Not on Node 22`)
}
// use createRequire instead of import.meta.resolve for bun compatibility in vite config
const require = createRequire(import.meta.url)
const resolve = (path: string) => {
return require.resolve(path)
}
const include = [
// pre-bundle common web deps to avoid mid-navigation optimization in dev mode
'react-native',
'react-dom',
'zod',
'swr/mutation',
'@vxrn/mdx-rust/client',
// core hanzogui packages must be pre-bundled together to avoid duplicate instances
'@hanzo/gui',
'@hanzogui/core',
'@hanzogui/web',
// existing
'secure-json-parse',
'ai',
'@docsearch/react',
'@leeoniya/ufuzzy',
'react-hook-form',
'@github/mini-throttle',
'swr',
'is-buffer',
'extend',
'minimatch',
'gray-matter',
'execa',
'jiti',
'hsluv',
'rehype-parse',
'refractor',
'glob',
'reading-time',
'unified',
'@hanzogui/get-font-sized',
'@hanzogui/linear-gradient',
'@rehookify/datepicker',
'@hanzogui/get-token',
'@hanzogui/roving-focus',
'react-native-safe-area-context',
'@hookform/resolvers/zod',
'@hanzogui/react-native-svg',
'react-native-gesture-handler',
'@tanstack/react-table',
'@hanzogui/focus-scope',
'react-dropzone',
]
export default {
// the runtime asks process.env.GUI_TARGET which platform it is on; a browser
// bundle has no process, so the answer is written in here
define: { 'process.env.GUI_TARGET': JSON.stringify('web') },
envPrefix: 'NEXT_PUBLIC_',
server: {
fs: {
allow: ['..'],
},
},
build: {
cssCodeSplit: false,
rolldownOptions: {
output: {
// fix non-deterministic __esm init ordering bug
// https://github.com/rolldown/rolldown/issues/3143
strictExecutionOrder: true,
},
},
},
resolve: {
preserveSymlinks: false,
alias: [
// `~` is app source, and the only specifier here that is not a package.
// Everything else resolves through node_modules, where each workspace
// package is linked at its one real path.
{
find: '~',
replacement: pathResolve(import.meta.dirname, '.'),
},
// Standard string-based aliases
{
find: 'react-native-svg',
replacement: '@hanzogui/react-native-svg',
},
{
find: 'react-native/Libraries/Core/ReactNativeVersion',
replacement: resolve('@hanzogui/proxy-worm'),
},
],
dedupe: [
'react',
'react-dom',
'react-hook-form',
'react-native',
'react-native-web',
'react-native-svg',
...include,
],
},
optimizeDeps: {
include,
},
ssr: {
// oxc-parser is a native binding, and the API reference calls it on the
// server only. Bundling it would ask rolldown for a .node file.
external: [
'@vxrn/mdx-rust',
'satteri',
'satteri-expressive-code',
'ws',
'postmark',
'oxc-parser',
],
noExternal: true,
},
plugins: [
// the published site names the source each chunk came from. one's build
// states sourcemap: false inline for both bundles; a plugin's config hook
// merges after that, so this is where the answer holds.
{ name: 'hanzo:sourcemap', config: () => ({ build: { sourcemap: true } }) },
one({
// tsconfig `paths` answers "where does the source live" for the type
// checker, which tries every entry of a fallback list. One's resolver
// reads the first entry only, so `@hanzogui/*` -> pkgs/core/* was applied
// to all 88 packages that live elsewhere. Packages resolve through
// node_modules instead; `~` is a vite alias above.
config: {
tsConfigPaths: false,
},
setupFile: {
server: './setup.server.ts',
},
server: {
cacheControl: {
'fonts/**': 'public, max-age=604800, stale-while-revalidate=86400',
'*.svg': 'public, max-age=86400',
'*.png': 'public, max-age=86400',
'*.jpg': 'public, max-age=86400',
'*.woff2': 'public, max-age=604800',
},
},
ssr: {
dedupeSymlinkedModules: true,
autoDepsOptimization: {
include: /.*/,
},
},
patches: {
'@react-navigation/core': {
version: '^7',
'lib/module/useOnGetState.js': (contents) => {
return contents?.replace(
'if (route.state === childState)',
'if (!childState || route.state === childState)'
)
},
},
},
build: {
api: {
config: {
build: {
rollupOptions: {
external: ['@discordjs/rest', '@discordjs/ws', '@vercel/og', 'zlib-sync'],
},
},
},
},
},
web: {
skewProtection: 'proactive',
experimental_scriptLoading: 'after-lcp-aggressive',
redirects: [
// llms.txt, llms-full.txt, docs.txt are handled by middleware directly
{
source: '/docs',
destination: '/docs/intro/introduction',
permanent: true,
},
{
source: '/vite',
destination: 'https://vxrn.dev',
permanent: true,
},
{
source: '/docs/components/:slug/:version',
destination: '/ui/:slug/:version',
permanent: true,
},
{
source: '/docs/components/:slug',
destination: '/ui/:slug',
permanent: true,
},
],
},
}),
// removeReactNativeWebAnimatedPlugin(),
...(process.env.ANALYZE
? [
visualizer({
filename: 'bundle_stats.html',
open: false,
gzipSize: true,
brotliSize: true,
emitFile: true,
}),
visualizer({
filename: 'bundle_stats.json',
template: 'raw-data',
gzipSize: true,
brotliSize: true,
emitFile: true,
}),
]
: []),
],
} satisfies UserConfig