one
Version:
One is a new React Framework that makes Vite serve both native and web.
390 lines (388 loc) • 18.6 kB
JavaScript
import { configureVXRNCompilerPlugin } from "@vxrn/compiler";
import { resolvePath } from "@vxrn/resolve";
import { getPlatformEnvDefine } from "@vxrn/vite-plugin-metro";
import events from "events";
import path from "path";
import tsconfigPaths from "vite-tsconfig-paths";
import { autoDepOptimizePlugin, getOptionsFilled, loadEnv } from "vxrn";
import vxrnVitePlugin from "vxrn/vite-plugin";
import { CACHE_KEY } from "../constants.native.js";
import { getViteMetroPluginOptions } from "../metro-config/getViteMetroPluginOptions.native.js";
import "../polyfills-server.native.js";
import { getRouterRootFromOneOptions } from "../utils/getRouterRootFromOneOptions.native.js";
import { ensureTSConfig } from "./ensureTsConfig.native.js";
import { setOneOptions } from "./loadConfig.native.js";
import { clientTreeShakePlugin } from "./plugins/clientTreeShakePlugin.native.js";
import { createDevtoolsPlugin } from "./plugins/devtoolsPlugin.native.js";
import { createFileSystemRouterPlugin } from "./plugins/fileSystemRouterPlugin.native.js";
import { fixDependenciesPlugin } from "./plugins/fixDependenciesPlugin.native.js";
import { generateFileSystemRouteTypesPlugin } from "./plugins/generateFileSystemRouteTypesPlugin.native.js";
import { imageDataPlugin } from "./plugins/imageDataPlugin.native.js";
import { sourceInspectorPlugin } from "./plugins/sourceInspectorPlugin.native.js";
import { SSRCSSPlugin } from "./plugins/SSRCSSPlugin.native.js";
import { virtualEntryId } from "./plugins/virtualEntryConstants.native.js";
import { createVirtualEntry } from "./plugins/virtualEntryPlugin.native.js";
import { environmentGuardPlugin } from "./plugins/environmentGuardPlugin.native.js";
function _type_of(obj) {
"@swc/helpers - typeof";
return obj && typeof Symbol < "u" && obj.constructor === Symbol ? "symbol" : typeof obj;
}
events.setMaxListeners(1e3);
globalThis.__vxrnEnableNativeEnv = !0;
function one() {
var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {},
_options_config,
_options_react,
_options_ssr,
_options_config1,
_options_router_experimental,
_options_router,
routerRoot = getRouterRootFromOneOptions(options),
metroOptions = function () {
var _options_native, _options_router2, _options_native_bundlerOptions, _options_native1, _options_native2, _options_react2, _options_react1;
if (((_options_native = options.native) === null || _options_native === void 0 ? void 0 : _options_native.bundler) !== "metro" && !process.env.ONE_METRO_MODE) return null;
process.env.ONE_METRO_MODE && console.info("ONE_METRO_MODE environment variable is set, enabling Metro mode");
var routerRoot2 = getRouterRootFromOneOptions(options),
defaultMetroOptions = getViteMetroPluginOptions({
projectRoot: process.cwd(),
// TODO: hard-coded process.cwd(), we should make this optional since the plugin can have a default to vite's `config.root`.
relativeRouterRoot: routerRoot2,
ignoredRouteFiles: (_options_router2 = options.router) === null || _options_router2 === void 0 ? void 0 : _options_router2.ignoredRouteFiles,
userDefaultConfigOverrides: (_options_native1 = options.native) === null || _options_native1 === void 0 || (_options_native_bundlerOptions = _options_native1.bundlerOptions) === null || _options_native_bundlerOptions === void 0 ? void 0 : _options_native_bundlerOptions.defaultConfigOverrides,
setupFile: options.setupFile
}),
userMetroOptions = (_options_native2 = options.native) === null || _options_native2 === void 0 ? void 0 : _options_native2.bundlerOptions,
babelConfig = {
...defaultMetroOptions?.babelConfig,
...userMetroOptions?.babelConfig
};
return {
...defaultMetroOptions,
...userMetroOptions,
defaultConfigOverrides: defaultMetroOptions?.defaultConfigOverrides,
// defaultConfigOverrides is merged by getViteMetroPluginOptions, so we need to set it here again.
argv: {
...defaultMetroOptions?.argv,
...userMetroOptions?.argv
},
babelConfig: {
...babelConfig,
plugins: [...(babelConfig.plugins || []), ...(((_options_react2 = options.react) === null || _options_react2 === void 0 ? void 0 : _options_react2.compiler) === !0 || ((_options_react1 = options.react) === null || _options_react1 === void 0 ? void 0 : _options_react1.compiler) === "native" ? ["babel-plugin-react-compiler"] : [])]
},
mainModuleName: "one/metro-entry",
// So users won't need to write `"main": "one/metro-entry"` in their `package.json` like ordinary Expo apps.
// allow env var to enable lazy startup
startup: process.env.ONE_METRO_LAZY ? "lazy" : userMetroOptions?.startup
};
}(),
vxrnPlugins = [];
if (!process.env.IS_VXRN_CLI) console.warn("Experimental: running VxRN as a Vite plugin. This is not yet stable."), vxrnPlugins.push(vxrnVitePlugin({
metro: metroOptions
}));else if (!globalThis.__oneOptions) return setOneOptions(options), globalThis.__vxrnPluginConfig__ = options, globalThis.__vxrnMetroOptions__ = metroOptions, [];
((_options_config = options.config) === null || _options_config === void 0 ? void 0 : _options_config.ensureTSConfig) !== !1 && ensureTSConfig();
var vxrnOptions = getOptionsFilled(),
root = vxrnOptions?.root || process.cwd(),
compiler = (_options_react = options.react) === null || _options_react === void 0 ? void 0 : _options_react.compiler;
compiler && configureVXRNCompilerPlugin({
enableCompiler:
// pass through object config, regex, or function directly
(typeof compiler > "u" ? "undefined" : _type_of(compiler)) === "object" || typeof compiler == "function" ? compiler : compiler === "native" ? ["ios", "android"] : compiler === "web" ? ["ssr", "client"] : !0
});
var autoDepsOptions = (_options_ssr = options.ssr) === null || _options_ssr === void 0 ? void 0 : _options_ssr.autoDepsOptimization,
devAndProdPlugins = [{
name: "one:config",
__get: options
}, {
name: "one:env-prefix",
config(userConfig) {
if (!userConfig.envPrefix) return {
envPrefix: ["VITE_", "EXPO_PUBLIC_"]
};
}
}, environmentGuardPlugin(options.environmentGuards), imageDataPlugin(), {
name: "one-define-client-env",
async config(userConfig) {
var _ref,
_ref1,
clientEnvDefine = options.skipEnv ? {} : (await loadEnv((_ref = (_ref1 = vxrnOptions?.mode) !== null && _ref1 !== void 0 ? _ref1 : userConfig?.mode) !== null && _ref !== void 0 ? _ref : "development", process.cwd(), userConfig?.envPrefix)).clientEnvDefine;
return {
define: {
...clientEnvDefine,
...(process.env.ONE_DEBUG_ROUTER && {
"process.env.ONE_DEBUG_ROUTER": JSON.stringify(process.env.ONE_DEBUG_ROUTER)
})
}
};
}
}, ...(autoDepsOptions === !1 ? [] : [autoDepOptimizePlugin({
onScannedDeps(param) {
var {
hasReanimated,
hasNativewind
} = param,
_ref,
_options_native;
configureVXRNCompilerPlugin({
enableReanimated: hasReanimated,
enableNativeCSS: (_ref = (_options_native = options.native) === null || _options_native === void 0 ? void 0 : _options_native.css) !== null && _ref !== void 0 ? _ref : hasNativewind,
enableNativewind: hasNativewind
});
},
root,
include: /node_modules/,
...(autoDepsOptions === !0 ? {} : autoDepsOptions)
})]), ...(((_options_config1 = options.config) === null || _options_config1 === void 0 ? void 0 : _options_config1.tsConfigPaths) === !1 ? [] : [function () {
var _options_config2,
pathsConfig = (_options_config2 = options.config) === null || _options_config2 === void 0 ? void 0 : _options_config2.tsConfigPaths,
skipDotDirs = function (dir) {
var name = dir.split("/").pop() || "";
return name.startsWith(".");
},
tsPathsPlugin = tsconfigPaths({
projectDiscovery: "eager",
ignoreConfigErrors: !0,
skip: skipDotDirs,
...(pathsConfig && (typeof pathsConfig > "u" ? "undefined" : _type_of(pathsConfig)) === "object" ? pathsConfig : {})
});
return {
...tsPathsPlugin,
// let vite aliases (e.g. react-native → react-native-web) resolve first
enforce: void 0,
// parallel viteBuild() calls share this plugin, so the second
// build's buildStart can fire before configResolved initializes
// tsconfigResolvers — swallow the error since buildStart only
// resets caches which isn't needed for parallel builds
buildStart() {
try {
var _tsPathsPlugin_buildStart;
return (_tsPathsPlugin_buildStart = tsPathsPlugin.buildStart) === null || _tsPathsPlugin_buildStart === void 0 ? void 0 : _tsPathsPlugin_buildStart.call(this);
} catch {}
}
};
}()]), {
name: "one-aliases",
enforce: "pre",
config() {
var tslibLitePath = "";
try {
tslibLitePath = resolvePath("@vxrn/tslib-lite", process.cwd());
} catch (err) {
console.info("Can't find tslib-lite, falling back to tslib"), process.env.DEBUG && console.error(err);
}
return {
resolve: {
alias: {
// testing getting transition between routes working
// 'use-sync-external-store/with-selector': resolvePath(
// 'use-sync-external-store/shim/with-selector'
// ),
...(tslibLitePath && {
tslib: tslibLitePath
})
}
}
};
}
}, {
name: "one:init-config",
config() {
var _options_web,
_options_web1,
_options_web2,
setupFileDefines = function () {
if (!options.setupFile) return {};
var setupFiles;
return typeof options.setupFile == "string" ? setupFiles = {
client: options.setupFile,
server: options.setupFile,
ios: options.setupFile,
android: options.setupFile
} : "native" in options.setupFile ? setupFiles = {
client: options.setupFile.client,
server: options.setupFile.server,
ios: options.setupFile.native,
android: options.setupFile.native
} : setupFiles = options.setupFile, {
...(setupFiles.client && {
"process.env.ONE_SETUP_FILE_CLIENT": JSON.stringify(setupFiles.client)
}),
...(setupFiles.server && {
"process.env.ONE_SETUP_FILE_SERVER": JSON.stringify(setupFiles.server)
}),
...(setupFiles.ios && {
"process.env.ONE_SETUP_FILE_IOS": JSON.stringify(setupFiles.ios)
}),
...(setupFiles.android && {
"process.env.ONE_SETUP_FILE_ANDROID": JSON.stringify(setupFiles.android)
})
};
}();
return {
// Platform env defined at root level for client (workaround for Vite bug with environment.client.define)
define: {
...getPlatformEnvDefine("client"),
...setupFileDefines,
...(((_options_web = options.web) === null || _options_web === void 0 ? void 0 : _options_web.defaultRenderMode) && {
"process.env.ONE_DEFAULT_RENDER_MODE": JSON.stringify(options.web.defaultRenderMode),
"import.meta.env.ONE_DEFAULT_RENDER_MODE": JSON.stringify(options.web.defaultRenderMode)
}),
...(process.env.NODE_ENV !== "production" && vxrnOptions && {
"process.env.ONE_SERVER_URL": JSON.stringify(vxrnOptions.server.url),
"import.meta.env.ONE_SERVER_URL": JSON.stringify(vxrnOptions.server.url)
}),
...(((_options_web1 = options.web) === null || _options_web1 === void 0 ? void 0 : _options_web1.linkPrefetch) && {
"process.env.ONE_LINK_PREFETCH": JSON.stringify(options.web.linkPrefetch)
}),
...(((_options_web2 = options.web) === null || _options_web2 === void 0 ? void 0 : _options_web2.skewProtection) !== void 0 && {
"process.env.ONE_SKEW_PROTECTION": JSON.stringify(options.web.skewProtection === !0 ? "true" : options.web.skewProtection === !1 ? "false" : options.web.skewProtection)
})
},
// 'proactive'
environments: {
ssr: {
define: getPlatformEnvDefine("ssr")
},
ios: {
define: getPlatformEnvDefine("ios")
},
android: {
define: getPlatformEnvDefine("android")
}
},
ssr: {
// ensure server-only/client-only go through vite so our environmentGuardPlugin can handle them
noExternal: ["server-only", "client-only"]
}
};
}
}, {
name: "one:tamagui",
config() {
return {
define: {
// safe to set because it only affects web in tamagui, and one is always react 19
"process.env.TAMAGUI_REACT_19": '"1"'
},
environments: {
ssr: {
define: {
"process.env.TAMAGUI_IS_SERVER": '"1"',
"process.env.TAMAGUI_KEEP_THEMES": '"1"'
}
},
ios: {
define: {
"process.env.TAMAGUI_KEEP_THEMES": '"1"'
}
},
android: {
define: {
"process.env.TAMAGUI_KEEP_THEMES": '"1"'
}
}
}
};
}
}, {
name: "route-module-hmr-fix",
hotUpdate(param) {
var {
server,
modules,
file
} = param,
_this_environment,
envName = (_this_environment = this.environment) === null || _this_environment === void 0 ? void 0 : _this_environment.name,
fileRelativePath = path.relative(server.config.root, file),
fileRootDir = fileRelativePath.split(path.sep)[0],
isAppFile = fileRootDir === "app";
if (envName === "ssr" && isAppFile) return [];
var hasRouteUpdate = !1,
result = modules.map(function (m) {
var {
id
} = m;
if (!id) return m;
var relativePath = path.relative(server.config.root, id),
rootDir = relativePath.split(path.sep)[0];
if (rootDir === "app") {
m.acceptedHmrExports = /* @__PURE__ */new Set();
var isRootLayout = relativePath === path.join("app", "_layout.tsx") || /^app[\\/]\([^)]+\)[\\/]_layout\.tsx$/.test(relativePath);
isRootLayout && (hasRouteUpdate = !0);
}
return m;
});
return hasRouteUpdate && server.hot.send({
type: "custom",
event: "one:route-update",
data: {
file: fileRelativePath
}
}), result;
}
},
// Plugins may transform the source code and add imports of `react/jsx-dev-runtime`, which won't be discovered by Vite's initial `scanImports` since the implementation is using ESbuild where such plugins are not executed.
// Thus, if the project has a valid `react/jsx-dev-runtime` import, we tell Vite to optimize it, so Vite won't only discover it on the next page load and trigger a full reload.
{
name: "one:optimize-dev-deps",
config(_, env) {
if (env.mode === "development") return {
optimizeDeps: {
include: ["react/jsx-dev-runtime", "react/compiler-runtime"]
}
};
}
}, {
name: "one:remove-server-from-client",
enforce: "pre",
transform(code, id) {
if (this.environment.name === "client" && id.includes("one-server-only")) return code.replace('import { AsyncLocalStorage } from "node:async_hooks"', "class AsyncLocalStorage {}");
}
}],
nativeWebDevAndProdPlugsin = [clientTreeShakePlugin()];
globalThis.__vxrnAddNativePlugins = nativeWebDevAndProdPlugsin, globalThis.__vxrnAddWebPluginsProd = devAndProdPlugins;
var flags = {
experimentalPreventLayoutRemounting: (_options_router = options.router) === null || _options_router === void 0 || (_options_router_experimental = _options_router.experimental) === null || _options_router_experimental === void 0 ? void 0 : _options_router_experimental.preventLayoutRemounting
};
return [...vxrnPlugins, ...devAndProdPlugins, ...nativeWebDevAndProdPlugsin,
/**
* This is really the meat of one, where it handles requests:
*/
createFileSystemRouterPlugin(options), generateFileSystemRouteTypesPlugin(options), fixDependenciesPlugin(options.deps), createVirtualEntry({
...options,
flags,
root: routerRoot
}), {
name: "one-define-environment",
config() {
var _options_native;
return {
define: {
...(((_options_native = options.native) === null || _options_native === void 0 ? void 0 : _options_native.key) && {
"process.env.ONE_APP_NAME": JSON.stringify(options.native.key),
"import.meta.env.ONE_APP_NAME": JSON.stringify(options.native.key)
}),
"process.env.ONE_CACHE_KEY": JSON.stringify(CACHE_KEY),
"import.meta.env.ONE_CACHE_KEY": JSON.stringify(CACHE_KEY)
}
};
}
}, SSRCSSPlugin({
entries: [virtualEntryId]
}),
// devtools (always includes refresh preamble for HMR, optionally includes UI)
...function () {
var _options_devtools,
_devtools_inspector,
devtools = (_options_devtools = options.devtools) !== null && _options_devtools !== void 0 ? _options_devtools : !0,
includeUI = devtools !== !1,
inspector = devtools === !0 || devtools !== !1 && ((_devtools_inspector = devtools.inspector) !== null && _devtools_inspector !== void 0 ? _devtools_inspector : !0);
return [
// always include devtools plugin for refresh preamble (required for HMR)
createDevtoolsPlugin({
includeUI
}), ...(inspector ? sourceInspectorPlugin() : [])];
}()];
}
export { one };
//# sourceMappingURL=one.native.js.map