One Logo Pool Ball

System

Configuration

One is a single Vite plugin and most of the configuration is done through the plugin in your vite.config.ts, it takes a single object with optional properties:

vite.config.ts

import type { UserConfig } from 'vite'
import { one } from 'one/vite'
export default {
plugins: [
one({
// all web-specific configuration nests in web:
web: {
// Choose the default strategy for routes without path-specifiers to render in
// can be one of "spa", "ssg" or "ssr"
defaultRenderMode: 'spa', // defaults to 'ssg'
// If using a server-rendered render mode, looseHydration will collapse large hydration
// error logs in development mode. React can gracefully recover from hydration issues,
// and they can often be ignored, but by default React produces large error logs.
// Turning this on will collapse those logs to one line.
looseHydration: false, // defaults to true
// Define server redirects for development and production
redirects: [
{
source: '/vite',
destination: 'https://vxrn.dev',
permanent: true,
},
{
source: '/docs/components/:slug/:version',
destination: '/ui/:slug/:version',
permanent: true,
},
],
},
// all native-specific config nests in app:
app: {
// One will set up your React Native app to run via AppRegistry.registerComponent(app.key)
// This setting determines app.key and must match the React Native app container you've built
key: 'AppName',
},
config: {
// Disable or configure the auto-added vite-tsconfig-paths
// https://www.npmjs.com/package/vite-tsconfig-paths
tsConfigPaths: false
// Disable auto-adding default tsconfig.json if not found
ensureTSConfig: false
},
server: {
// Configures production server to be compatible
platform: 'node' | 'vercel' // defaults to node
// Runs after the production web server starts
// (options: VXRNOptions, app: Hono) => void | Promise<void>
afterStart() {},
// Runs before the production web server starts
// (options: VXRNOptions, app: Hono) => void | Promise<void>
beforeStart() {},
},
// The deps configuration is a powerful way to apply patches to node_modules
// to configure patching and optimizeDeps for server-side.
// we found the React Native and general node module package ecosystem to not always
// play nice with universal apps, and this provides an easy way to configure them
deps: {
'moti/author': true,
'@sentry/react-native': {
version: '~15.2.0',
'**/*.js': ['jsx']
}
},
})
]
} satisfies UserConfig

web

The web object allows you to configure web specific settings.

defaultRenderMode

Choose between one of ssg, spa or ssr. The default is ssg.

Each mode has trade-offs:

  • ssg stands for "Static Site Generated", it is the default mode.

SSG is a great general purpose strategy, where your pages are rendered fully at build-time and turned into static HTML. This means you can get a "perfect" first load, where your app is fully rendered with all content, servable easily by a CDN.

The JS is sent alongside it, and React will hydrate your app and resume running from there. The downside is that you do have some complexity in needing to ensure your pages can render in node, the upside is increased performance and SEO on the web.

  • spa stands for "Single Page App", which is the simplest strategy.

SPA mode will not render the page on the server at all, and instead only serve the JavaScript to render your page to the users browser. This mode avoids some complexity - you don't have to make your React code

  • ssr stands for "Sever Side Rendered".

This mode will render your page on the server at the time the browser requests it, running loaders as well for each request.

This mode is likely the least useful, as it means that you must make a full trip to your database at the time of each request, and your client is left waiting for the full render from the server before it can show anything. That said, this mode can be useful if you have dynamically generated content but still want to have the best possible SEO, at the cost of some complexity in supporting server rendering.

redirects

You can apply server-level redirects. One serves your app with Hono in production, and so the redirect pattern is simple: your source will be passed to Hono.app.get(source). Any matching path segments that start with : will be replaced into the matching segments in destination. And the redirect will send a response type of 301 if permanent is true, otherwise it will be 302.

deps

While building One we found ourselves needing to apply small patches to a variety of packages. Packages in the React Native ecosystem are often published only for Metro, and so have a variety of weird setups.

We built an internal Vite plugin to easily apply patches across any package manager, but after installing One into a few larger production projects, we found ourselves wanting to have access to it.

The deps option is a powerful way to coerce your node_modules to be compatible with Vite.

Here's an example:

vite.config.ts

import type { UserConfig } from 'vite'
import { one } from 'one/vite'
export default {
plugins: [
one({
deps: {
// setting to true is the same as setting:
// viteConfig.ssr.optimizeDeps.include.push('moti/author')
'moti/author': true,
// setting to 'interop' is the same as setting:
// viteConfig.ssr.optimizeDeps.include.push('node-fetch')
// viteConfig.ssr.optimizeDeps.needsInterop.push('node-fetch')
'node-fetch': 'interop',
// passing an object lets you easily apply patches to your actual node_modules
'@sentry/react-native': {
// you can specify a semver range to only apply to certain versions:
version: '~15.2.0',
// you can use globs to apply to only specific files
// if you pass an array value, One will apply one of two transforms to matching files:
// swc => @swc/core will transform your file into CommonJS compatible code, removing JSX as well
// flow => the FlowType transformer will run to remove Flow types
'**/*.js': ['flow', 'swc']
// you can also apply custom transforms using a function
'dist/js/utils/environment.js': (contents) => {
if (typeof contents !== 'string') return
return contents.replace(
`import { version as RNV } from 'react-native/Libraries/Core/ReactNativeVersion';`,
`import { Platform } from 'react-native';\nconst RNV = Platform.constants.reactNativeVersion;\n`
)
},
},
},
})
]
} satisfies UserConfig

Any transforms that are applied to specific files in node_modules will only be applied once. The original files will be stored alongside the transformed ones.

Edit this page on GitHub.