UNPKG

one

Version:

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

390 lines (388 loc) 18.6 kB
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