UNPKG

one

Version:

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

473 lines (469 loc) 22.9 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf, __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: !0 }); }, __copyProps = (to, from, except, desc) => { if (from && typeof from == "object" || typeof from == "function") for (let key of __getOwnPropNames(from)) !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: !0 }) : target, mod)), __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", { value: !0 }), mod); var fileSystemRouterPlugin_exports = {}; __export(fileSystemRouterPlugin_exports, { createFileSystemRouterPlugin: () => createFileSystemRouterPlugin }); module.exports = __toCommonJS(fileSystemRouterPlugin_exports); var import_path = __toESM(require("path"), 1), import_stream = require("stream"), import_perfect_debounce = require("perfect-debounce"), import_vite = require("vite"), import_constants = require("../../constants.native.js"), import_createHandleRequest = require("../../createHandleRequest.native.js"), import_getRouterRootFromOneOptions = require("../../utils/getRouterRootFromOneOptions.native.js"), import_isResponse = require("../../utils/isResponse.native.js"), import_isStatus = require("../../utils/isStatus.native.js"), import_promiseWithResolvers = require("../../utils/promiseWithResolvers.native.js"), import_trackLoaderDependencies = require("../../utils/trackLoaderDependencies.native.js"), import_constants2 = require("../../vite/constants.native.js"), import_replaceLoader = require("../../vite/replaceLoader.native.js"), import_one_server_only = require("../one-server-only.native.js"), import_virtualEntryConstants = require("./virtualEntryConstants.native.js"); function _instanceof(left, right) { return right != null && typeof Symbol < "u" && right[Symbol.hasInstance] ? !!right[Symbol.hasInstance](left) : left instanceof right; } function _type_of(obj) { "@swc/helpers - typeof"; return obj && typeof Symbol < "u" && obj.constructor === Symbol ? "symbol" : typeof obj; } var debugRouter = process.env.ONE_DEBUG_ROUTER, debugLoaderDeps = process.env.ONE_DEBUG_LOADER_DEPS, USE_SERVER_ENV = !1; //!!process.env.USE_SERVER_ENV function createFileSystemRouterPlugin(options) { var preloads = ["/@vite/client", import_virtualEntryConstants.virtalEntryIdClient], runner, server, loaderFileDependencies = /* @__PURE__ */new Map(), handleRequest = createRequestHandler(), renderPromise = null; function createRequestHandler() { var routerRoot = (0, import_getRouterRootFromOneOptions.getRouterRootFromOneOptions)(options); return (0, import_createHandleRequest.createHandleRequest)({ async handlePage(param) { var { route, url, loaderProps } = param; if (console.info(` \u24F5 [${route.type}] ${url} resolved to ${route.isNotFound ? "\u203C\uFE0F 404 not found" : `app/${route.file.slice(2)}`}`), route.type === "spa") return `<html><head> ${(0, import_constants.getSpaHeaderElements)({ serverContext: { mode: "spa" } })} <script type="module"> import { injectIntoGlobalHook } from "/@react-refresh"; injectIntoGlobalHook(window); window.$RefreshReg$ = () => {}; window.$RefreshSig$ = () => (type) => type; </script> <script type="module" src="/@vite/client" async=""></script> <script type="module" src="/@id/__x00__virtual:one-entry" async=""></script> </head></html>`; renderPromise && (await renderPromise); var { promise, resolve: resolveRender } = (0, import_promiseWithResolvers.promiseWithResolvers)(); renderPromise = promise; try { var _globalThis___vxrnresetState, _globalThis, routeFile = import_path.default.join(routerRoot, route.file); runner.clearCache(), (_globalThis___vxrnresetState = (_globalThis = globalThis).__vxrnresetState) === null || _globalThis___vxrnresetState === void 0 || _globalThis___vxrnresetState.call(_globalThis); var exported = routeFile === "" ? {} : await runner.import(routeFile), loaderData; if (exported.loader) { var tracked = await (0, import_trackLoaderDependencies.trackLoaderDependencies)(function () { return exported.loader(loaderProps); }); loaderData = tracked.result; var routePath = loaderProps?.path || "/", _iteratorNormalCompletion = !0, _didIteratorError = !1, _iteratorError = void 0; try { for (var _iterator = tracked.dependencies[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = !0) { var dep = _step.value, absoluteDep = import_path.default.resolve(dep); loaderFileDependencies.has(absoluteDep) || (loaderFileDependencies.set(absoluteDep, /* @__PURE__ */new Set()), server?.watcher.add(absoluteDep), debugLoaderDeps && console.info(` \u24F5 [loader-dep] watching: ${absoluteDep}`)), loaderFileDependencies.get(absoluteDep).add(routePath); } } catch (err) { _didIteratorError = !0, _iteratorError = err; } finally { try { !_iteratorNormalCompletion && _iterator.return != null && _iterator.return(); } finally { if (_didIteratorError) throw _iteratorError; } } } eval("process.env.TAMAGUI_IS_SERVER = '1'"); var entry = await runner.import(import_virtualEntryConstants.virtualEntryId), render = entry.default.render; (0, import_one_server_only.setServerContext)({ loaderData, loaderProps }), import_constants2.LoaderDataCache[route.file] = loaderData; var is404 = route.isNotFound || !exported.default, html = await render({ mode: route.type === "ssg" ? "ssg" : route.type === "ssr" ? "ssr" : "spa", loaderData, loaderProps, path: loaderProps?.path || "/", preloads }); return is404 ? new Response(html, { status: 404, headers: { "Content-Type": "text/html" } }) : html; } catch (err) { if ((0, import_isResponse.isResponse)(err)) return err; console.error(`SSR error while loading file ${route.file} from URL ${url.href} `, err); var title = `Error rendering ${url.pathname} on server`, message = _instanceof(err, Error) ? err.message : `${err}`, stack = _instanceof(err, Error) && err.stack || "", isDuplicateReactError = /at (useEffect|useState|useReducer|useContext|useLayoutEffect)\s*\(.*?react\.development\.js/g.test(stack), subMessage = isDuplicateReactError ? ` <h2>Duplicate React Error</h2> <p style="font-size: 18px; line-height: 24px; max-width: 850px;">Note: These types of errors happen during SSR because One needs all dependencies that use React to be optimized. Find the dependency on the line after the react.development.js line below to find the failing dependency. So long as that dependency has "react" as a sub-dependency, you can add it to your package.json and One will optimize it automatically. If it doesn't list it properly, you can fix this manually by changing your vite.config.ts One plugin to add "one({ deps: { depName: true })" so One optimizes depName.</p> ` : ""; return console.error(`${title} ${message} ${stack} `), ` <html> <body style="background: #000; color: #fff; padding: 5%; font-family: monospace; line-height: 2rem;"> <h1 style="display: inline-flex; background: red; color: white; padding: 5px; margin: -5px;">${title}</h1> <h2>${message}</h2> ${subMessage} ${stack ? `<pre style="font-size: 15px; line-height: 24px; white-space: pre;"> ${stack} </pre>` : ""} </body> </html> `; } finally { resolveRender(); } }, async handleLoader(param2) { var { request, route: route2, url: url2, loaderProps: loaderProps2 } = param2, _this, routeFile2 = import_path.default.join(routerRoot, route2.file), transformedJS = (_this = await server.transformRequest(routeFile2)) === null || _this === void 0 ? void 0 : _this.code; if (!transformedJS) throw new Error("No transformed js returned"); var exported2 = await runner.import(routeFile2), loaderData2; if (exported2.loader) { var tracked2 = await (0, import_trackLoaderDependencies.trackLoaderDependencies)(function () { return exported2.loader(loaderProps2); }); loaderData2 = tracked2.result; var routePath2 = loaderProps2?.path || "/", _iteratorNormalCompletion2 = !0, _didIteratorError2 = !1, _iteratorError2 = void 0; try { for (var _iterator2 = tracked2.dependencies[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = !0) { var dep2 = _step2.value, absoluteDep2 = import_path.default.resolve(dep2); loaderFileDependencies.has(absoluteDep2) || (loaderFileDependencies.set(absoluteDep2, /* @__PURE__ */new Set()), server?.watcher.add(absoluteDep2), debugLoaderDeps && console.info(` \u24F5 [loader-dep] watching: ${absoluteDep2}`)), loaderFileDependencies.get(absoluteDep2).add(routePath2); } } catch (err) { _didIteratorError2 = !0, _iteratorError2 = err; } finally { try { !_iteratorNormalCompletion2 && _iterator2.return != null && _iterator2.return(); } finally { if (_didIteratorError2) throw _iteratorError2; } } } loaderData2 && (transformedJS = (0, import_replaceLoader.replaceLoader)({ code: transformedJS, loaderData: loaderData2 })); var platform = url2.searchParams.get("platform"); if (platform === "ios" || platform === "android") { var environment = server.environments[platform || ""]; if (!environment) throw new Error(`[handleLoader] No Vite environment found for platform '${platform}'`); var nativeTransformedJS = `exports.loader = () => (${JSON.stringify(loaderData2)});`; return nativeTransformedJS; } return transformedJS; }, async handleAPI(param2) { var { route: route2 } = param2; return await runner.import(import_path.default.join(routerRoot, route2.file)); }, async loadMiddleware(route2) { return await runner.import(import_path.default.join(routerRoot, route2.contextKey)); } }, { routerRoot }); } return { name: "one-router-fs", enforce: "post", apply: "serve", async config(userConfig) { var _ref, _options_optimization, setting = (_ref = (_options_optimization = options.optimization) === null || _options_optimization === void 0 ? void 0 : _options_optimization.autoEntriesScanning) !== null && _ref !== void 0 ? _ref : "flat"; if (setting !== !1 && handleRequest.manifest.pageRoutes) { var routesAndLayouts = [...new Set(handleRequest.manifest.pageRoutes.flatMap(function (route2) { var _route_layouts; return route2.isNotFound ? [] : route2.file ? setting === "flat" && route2.file.split("/").filter(function (x) { return !x.startsWith("("); }).length > 3 ? [] : [import_path.default.join("./app", route2.file), ...(((_route_layouts = route2.layouts) === null || _route_layouts === void 0 ? void 0 : _route_layouts.flatMap(function (layout) { return layout.contextKey ? [import_path.default.join("./app", layout.contextKey)] : []; })) || [])] : []; }))]; return { optimizeDeps: { /** * This adds all our routes and layouts as entries which fixes initial load making * optimizeDeps be triggered which causes hard refreshes (also on initial navigations) * * see: https://vitejs.dev/config/dep-optimization-options.html#optimizedeps-entries * and: https://github.com/remix-run/remix/pull/9921 */ entries: routesAndLayouts } }; } }, // if (USE_SERVER_ENV) { // return { // appType: 'custom', // environments: { // server: { // resolve: { // dedupe: optimizeDeps.include, // external: [], // noExternal: optimizeDeps.include, // conditions: ['vxrn-web'], // alias: { // react: '@vxrn/vendor/react-19', // 'react-dom': '@vxrn/vendor/react-dom-19', // }, // }, // // webCompatible: true, // nodeCompatible: true, // dev: { // optimizeDeps, // createEnvironment(name, config) { // const worker = new Worker(path.join(import.meta.dirname, 'server.js')) // // const hot = new // return new DevEnvironment(name, config, { // hot: false, // runner: { // transport: new RemoteEnvironmentTransport({ // send: (data) => worker.postMessage(data), // onMessage: (listener) => worker.on('message', listener), // }), // }, // }) // }, // }, // }, // }, // } // } configureServer(serverIn) { server = serverIn, runner = (0, import_vite.createServerModuleRunner)(USE_SERVER_ENV ? server.environments.server : server.environments.ssr); var appDir = import_path.default.join(process.cwd(), (0, import_getRouterRootFromOneOptions.getRouterRootFromOneOptions)(options)), fileWatcherChangeListener = (0, import_perfect_debounce.debounce)(async function (type, changedPath) { if (type === "add" || type === "delete") { var absolutePath = import_path.default.resolve(changedPath); absolutePath.startsWith(appDir) && (handleRequest = createRequestHandler()); } }, 100); server.watcher.addListener("all", fileWatcherChangeListener); var loaderDepChangeListener = (0, import_perfect_debounce.debounce)(function (changedPath) { var absolutePath = import_path.default.resolve(changedPath), routePaths = loaderFileDependencies.get(absolutePath); routePaths && routePaths.size > 0 && (debugLoaderDeps && console.info(` \u24F5 [loader-dep] changed: ${absolutePath}, triggering loader refetch for routes:`, [...routePaths]), server.hot.send({ type: "custom", event: "one:loader-data-update", data: { routePaths: [...routePaths] } })); }, 100); return server.watcher.on("change", loaderDepChangeListener), function () { server.middlewares.use(async function (req, res, next) { try { var _options_web, redirects = (_options_web = options.web) === null || _options_web === void 0 ? void 0 : _options_web.redirects; if (redirects) { var url2 = new URL(req.url || "", `http://${req.headers.host}`), _iteratorNormalCompletion2 = !0, _didIteratorError2 = !1, _iteratorError2 = void 0; try { for (var _loop = function () { var redirect = _step2.value, regexStr = `^${redirect.source.replace(/:\w+/g, "([^/]+)")}$`, match = url2.pathname.match(new RegExp(regexStr)); if (match) { var destination = redirect.destination, params = redirect.source.match(/:\w+/g); return params && params.forEach(function (param2, index) { destination = destination.replace(param2, match[index + 1] || ""); }), debugRouter && console.info(`[one] \u21AA redirect ${url2.pathname} \u2192 ${destination}`), res.writeHead(redirect.permanent ? 301 : 302, { Location: destination }), res.end(), { v: void 0 }; } }, _iterator2 = redirects[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = !0) { var _ret = _loop(); if (_type_of(_ret) === "object") return _ret.v; } } catch (err) { _didIteratorError2 = !0, _iteratorError2 = err; } finally { try { !_iteratorNormalCompletion2 && _iterator2.return != null && _iterator2.return(); } finally { if (_didIteratorError2) throw _iteratorError2; } } } var reply = await handleRequest.handler(convertIncomingMessageToRequest(req)); if (!reply) return next(); if (typeof reply != "string" && (0, import_isResponse.isResponse)(reply)) { if (debugRouter) { var headers = {}; reply.headers.forEach(function (v, k) { headers[k] = v; }), console.info(`[one] \u{1F4E4} response ${reply.status}`, headers); } if (reply.headers.forEach(function (value, key) { if (key === "set-cookie") { var cookies = value.split(", "), _iteratorNormalCompletion3 = !0, _didIteratorError3 = !1, _iteratorError3 = void 0; try { for (var _iterator3 = cookies[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = !0) { var cookie = _step3.value; res.appendHeader("Set-Cookie", cookie); } } catch (err) { _didIteratorError3 = !0, _iteratorError3 = err; } finally { try { !_iteratorNormalCompletion3 && _iterator3.return != null && _iterator3.return(); } finally { if (_didIteratorError3) throw _iteratorError3; } } } else res.setHeader(key, value); }), (0, import_isStatus.isStatusRedirect)(reply.status)) { var location = `${reply.headers.get("location") || ""}`; if (debugRouter && console.info(`[one] \u21AA response redirect \u2192 ${location}`), location) { res.writeHead(reply.status, { Location: location }), res.end(); return; } console.error("No location provided to redirected status reply", reply); } if (res.statusCode = reply.status, res.statusMessage = reply.statusText, reply.body && reply.body.locked) { console.warn("Body is locked??", req.url), res.write(""), res.end(); return; } if (reply.body) { if (reply.body.locked) { console.warn("Body is locked??", req.url), res.end(); return; } try { import_stream.Readable.fromWeb(reply.body).pipe(res); } catch (err) { console.warn("Error piping reply body to response:", err), res.end(); } return; } res.end(); return; } if (reply && (typeof reply > "u" ? "undefined" : _type_of(reply)) === "object") { res.setHeader("Content-Type", "application/json"), res.write(JSON.stringify(reply)), res.end(); return; } res.write(reply), res.end(); return; } catch (error) { console.error(`[one] routing error ${req.url}: ${error}`), next(error); } console.warn(`SSR handler didn't send a response for url: ${req.url}`); }); }; } }; } var convertIncomingMessageToRequest = function (req) { if (!req.originalUrl) throw new Error("Can't convert: originalUrl is missing"); var urlBase = `http://${req.headers.host}`, urlString = req.originalUrl, url2 = new URL(urlString, urlBase), headers = new Headers(); for (var key in req.headers) req.headers[key] && headers.append(key, req.headers[key]); var hasBody = ["POST", "PUT", "PATCH", "DELETE"].includes(req.method || ""), body = hasBody ? import_stream.Readable.toWeb(req) : null; return new Request(url2, { method: req.method, headers, body, // Required for streaming bodies in Node's experimental fetch: duplex: "half" }); }; //# sourceMappingURL=fileSystemRouterPlugin.native.js.map