UNPKG

one

Version:

One is a new React Framework that makes Vite serve both native and web.

366 lines (329 loc) 11.6 kB
import type { GetTransform } from '@vxrn/compiler' import type { metroPlugin } from '@vxrn/vite-plugin-metro' import type { PluginOptions as TSConfigPluginOptions } from 'vite-tsconfig-paths' import type { AutoDepOptimizationOptions, DepOptimize, DepPatch, AfterBuildProps as VXRNAfterBuildProps, VXRNBuildOptions, VXRNOptions, } from 'vxrn' import type { RouteNode } from '../router/Route' type MetroPluginOptions = Parameters<typeof metroPlugin>[0] export type RouteInfo<TRegex = string> = { file: string page: string namedRegex: TRegex loaderPath?: string loaderServerPath?: string urlPath: string urlCleanPath: string routeKeys: Record<string, string> layouts?: RouteNode[] middlewares?: RouteNode[] type: One.RouteType isNotFound?: boolean } export namespace One { export type Options = Omit<VXRNOptions, keyof PluginOptions> & PluginOptions export type RouteRenderMode = 'ssg' | 'spa' | 'ssr' export type RouteType = RouteRenderMode | 'api' | 'layout' export type ClientData = Record<string, any> export type RouteOptions = { routeModes?: Record<string, RouteRenderMode> } // todo move into vxrn export type FixDependencies = { [key: string]: DepOptimize | DepPatch['patchFiles'] } type PluginPlatformTarget = 'native' | 'web' export type PluginOptions = { /** * Enabling zero does a couple very simple things: * * - It makes zero hand of seamelessly from server to client without flicker * */ // zero?: boolean /** * Per-file control over how code transforms. * Defaults to SWC, runs babel before SWC if: * * - options.react.compiler is `true`, on tsx files in your app * - `react-native-reanimated` is in your dependencies and a file contains a reanimated keyword * * Otherwise One defaults to using `@swc/core`. * * Accepts a function: * * (props: { * id: string * code: string * development: boolean * environment: Environment * reactForRNVersion: '18' | '19' * }) => * | true // default transforms * | false // no transforms * | 'babel' // force babel default transform * | 'swc' // force swc default transform * * // force babel, custom transform * * | { * transform: 'babel' * excludeDefaultPlugins?: boolean * } & babel.TransformOptions * * // force swc, custom transform * * | { * transform: 'swc' * } & SWCOptions * * Babel defaults to preset `@babel/preset-typescript` with plugins: * * - @babel/plugin-transform-destructuring * - @babel/plugin-transform-runtime * - @babel/plugin-transform-react-jsx * - @babel/plugin-transform-async-generator-functions * - @babel/plugin-transform-async-to-generator * * * SWC defaults to target es5 for native, es2020 for web. * */ transform?: GetTransform router?: { /** * An array of globs that One uses to ignore files in your routes directory. If a file matches any pattern, it will not be treated as a route. * * This is useful for ignoring test or utility files you wish to colocate. * * Currently, we only support patterns starting with <code>&#42;&#42;/&#42;</code>. * * Example: * * <code>&#42;&#42;/&#42;.test.*</code> */ ignoredRouteFiles?: Array<`**/*${string}`> /** * Dangerously customize the router root directory. This may lead to unexpected behavior. */ root?: string experimental?: { /** * If enabled, the router will try to avoid unnecessary remounts of _layout components. * * We aren't sure that this won't cause any side effects and break things, so this is still experimental and defaults to `false`. * * Currently, this will only effect the `<Slot />` navigator, where it will modify the screen element provided by `react-navigation` and set the `key` to a static value to prevent re-mounting. */ preventLayoutRemounting?: boolean } } react?: { /** * Enable the React Compiler, for all or specific platforms * @default false */ compiler?: boolean | PluginPlatformTarget } optimization?: { /** * Turn on [vite-plugin-barrel](https://github.com/JiangWeixian/vite-plugin-barrel/tree/master). * Optimizes barrel export files to speed up your build, you must list the packages that have * barrel exports. Especially useful for icon packs. * * @default ['@tamagui/lucide-icons'] */ barrel?: boolean | string[] /** * By default One scans your fs routes and adds them as Vite `entries`, this prevents some hard * reloads on web as you navigate to new pages, but can slow things startup. * * The 'flat' option is default and will automatically add just the routes at the root of your * app but nothing nested in non-group folders below that. * * @default 'flat' */ autoEntriesScanning?: boolean | 'flat' } /** * Path to a js or ts file to import before the rest of your app runs * One controls your root, but you may want to runs some JS before anything else * Use this to give One the entrypoint to run */ setupFile?: string config?: { ensureTSConfig?: false /** * One automatically adds vite-tsconfig-paths, set this to false to disable, or * pass in an object to pass options down. If you add your own vite-tsconfig-paths * we will avoid adding it again internally. * * See: https://github.com/aleclarson/vite-tsconfig-paths * * @default false */ tsConfigPaths?: boolean | TSConfigPluginOptions } native?: { /** * The uid of your native app, this will be used internally in one to call * `AppRegistry.registerComponent(key)` */ key?: string /** * Turns on react-native-css-interop support when importing CSS on native */ css?: boolean /** * Specifies the bundler to use for native builds. Defaults to 'vite'. * * - 'metro' is recommended for production stability. Note that this option comes with some limitations, see https://onestack.dev/docs/metro-mode#limitations for more info. * - 'vite' is experimental but offers faster builds with SWC. * * Note that the ONE_METRO_MODE environment variable can override this setting to 'metro'. */ bundler?: 'metro' | 'vite' } & ( | { bundler: 'metro' /** Options merging for Metro is not fully implemented in the One plugin, changing this may not work properly. Search for "METRO-OPTIONS-MERGING" in the codebase for details. */ bundlerOptions?: MetroPluginOptions } | { bundler?: 'vite' /** No configurable options with the default vite bundler. */ bundlerOptions?: { currentlyHaveNoOptions?: null } } ) web?: { /** * Choose the default strategy for pages to be rendered on the web. * * For sites that are mostly static, choose "ssg": * SSG stands for "server side generated", in this mode when you run `build` * your pages will all be fully rendered on the server once during the build, * outputting a static HTML page with the rendered page and loader data inlined. * This gives better performance for initial render, and better SEO. * * * For apps that are mostly dynamic, choose "spa": * SPA stands for "single page app", in this mode when you run `build` your * pages will only render out an empty shell of HTML and will not attempt to * server render at all. Loaders will be run on the server side and the data will * be available to your app on initial render. * * @default 'ssg' */ defaultRenderMode?: RouteRenderMode /** * An array of redirect objects, works in development and production: * * @example * * [ * { * source: '/vite', * destination: 'https://vxrn.dev', * permanent: true, * }, * { * source: '/docs/components/:slug/:version', * destination: '/ui/:slug/:version', * permanent: true, * }, * ] * */ redirects?: Redirect[] /** * Can be one of "node" or "vercel" ("vercel" support is experimental and currently not recommended for production use), this will determine the Hono adapter and build to run * properly in production for each platform. * * @default node */ deploy?: 'vercel' | 'node' } server?: VXRNOptions['server'] build?: { server?: VXRNBuildOptions | false api?: VXRNBuildOptions } deps?: FixDependencies ssr?: { /** * One scans dependencies on startup and decides which ones to optimize based on known broken * dependencies. These include react-native and react, which need to be optimized to work. * It finds all parent dependencies of the know bad deps and adds them to ssr.optimizeDeps.include. * * You can disable with false, or configure the include/exclude with options. * * Note: the **full path** (e.g. `<your_project_path>/node_modules/<some_package>`) will be used to match dependencies, if you are using a string to match a package name you may want to add `*` + `/` at the start and `/*` the end. * * @default { include: /node_modules/ } */ autoDepsOptimization?: boolean | AutoDepOptimizationOptions } } export interface RouteContext { keys(): string[] (id: string): any <T>(id: string): T resolve(id: string): string id: string } export type Redirect = { source: string destination: string permanent: boolean } export type BuildInfo = { constants: { CACHE_KEY: string } oneOptions?: PluginOptions routeToBuildInfo: Record<string, Omit<One.RouteBuildInfo, 'loaderData'>> /** A mapping to lookup the full route name from a path */ pathToRoute: Record<string, string> routeMap: Record<string, string> manifest: { pageRoutes: RouteInfo[] apiRoutes: RouteInfo[] allRoutes: RouteInfo[] } // for quick checking if preload exists preloads: Record<string, boolean> loaders: Record<string, boolean> } export type AfterBuildProps = VXRNAfterBuildProps & BuildInfo export type RouteBuildInfo = { type: One.RouteType path: string routeFile: string middlewares: string[] preloadPath: string loaderPath: string cleanPath: string htmlPath: string clientJsPath: string serverJsPath: string params: Object loaderData: any preloads: string[] css: string[] } export type ServerContext = { css?: string[] postRenderData?: any loaderData?: any loaderProps?: any mode?: 'spa' | 'ssg' | 'ssr' } export type Flags = { /** See PluginOptions.router.experimental.PreventLayoutRemounting */ experimentalPreventLayoutRemounting?: boolean } }