mirror of
https://github.com/Dvorinka/Devour.git
synced 2026-06-03 20:13:03 +00:00
188 lines
109 KiB
JSON
188 lines
109 KiB
JSON
{
|
|
"id": "4dda2f67241253385a412de5",
|
|
"source": "remix:does",
|
|
"type": "html",
|
|
"title": "Introduction, Technical Explanation | Remix",
|
|
"content": "DocsBlogResourcesReact Router v7 has been released. View the docsDocsBlogResourcesView code on GitHubChat on DiscordReact Router v7 has been released. View the docsIntroduction, Technical ExplanationGetting StartedQuick Start (5m) Tutorial (30m) Upgrading to v2 Community Future Flags Changelog Discussion TopicsIntroduction, Technical Explanation Runtimes, Adapters, Templates, and Deployment Route Configuration Fullstack Data Flow Server vs. Client Code Execution React Router Progressive Enhancement Pending UI State Management Network Concurrency Management Form vs. fetcher Hot Module Replacement Form Resubmissions File Conventions.client modules .server modules Asset Imports entry.client entry.server root Route File Naming vite.config.ts Route Moduleaction clientAction clientLoader Component ErrorBoundary handle headers HydrateFallback links loader meta shouldRevalidate ComponentsAwait Form Link Links LiveReload Meta NavLink Outlet PrefetchPageLinks Scripts ScrollRestoration HooksuseActionData useAsyncError 🆕useAsyncValue 🆕useBeforeUnload useBlocker useFetcher useFetchers useFormAction useHref useLoaderData useLocation useMatches useNavigate useNavigation useNavigationType useOutlet useOutletContext useParams unstable_usePrompt useResolvedPath useRevalidator 🆕useRouteError 🆕useRouteLoaderData useSearchParams useSubmit useViewTransitionState UtilitiesCookies createRemixStub data defer isRouteErrorResponse json unstable_parseMultipartFormData redirect redirectDocument replace Sessions unstable_createFileUploadHandler unstable_createMemoryUploadHandler StylingCSS Bundling Regular CSS CSS Imports CSS in JS CSS Modules PostCSS Tailwind Vanilla Extract Other API@remix-run/dev CLI 🆕@remix-run/{adapter} @remix-run/serve create-remix (CLI) @remix-run/node @remix-run/testing GuidesAccessibility Development Strategy API Routes Backend For Frontend Breadcrumbs Guide Browser Support Client Data Module Constraints Contributing CSS Files Data Loading Data Writes Dependency optimization Deployment Disabling JavaScript Environment Variables Error Handling FAQs File Uploads Form Validation Gotchas Index Query Param Lazy Route Discovery Local TLS Manual Dev Server MDX Migrating from React Router Not Found Handling Performance Presets Resource Routes Server Bundles Single Fetch SPA Mode Streaming Templates TypeScript Vite Getting StartedQuick Start (5m) Tutorial (30m) Upgrading to v2 Community Future Flags Changelog Discussion TopicsIntroduction, Technical Explanation Runtimes, Adapters, Templates, and Deployment Route Configuration Fullstack Data Flow Server vs. Client Code Execution React Router Progressive Enhancement Pending UI State Management Network Concurrency Management Form vs. fetcher Hot Module Replacement Form Resubmissions File Conventions.client modules .server modules Asset Imports entry.client entry.server root Route File Naming vite.config.ts Route Moduleaction clientAction clientLoader Component ErrorBoundary handle headers HydrateFallback links loader meta shouldRevalidate ComponentsAwait Form Link Links LiveReload Meta NavLink Outlet PrefetchPageLinks Scripts ScrollRestoration HooksuseActionData useAsyncError 🆕useAsyncValue 🆕useBeforeUnload useBlocker useFetcher useFetchers useFormAction useHref useLoaderData useLocation useMatches useNavigate useNavigation useNavigationType useOutlet useOutletContext useParams unstable_usePrompt useResolvedPath useRevalidator 🆕useRouteError 🆕useRouteLoaderData useSearchParams useSubmit useViewTransitionState UtilitiesCookies createRemixStub data defer isRouteErrorResponse json unstable_parseMultipartFormData redirect redirectDocument replace Sessions unstable_createFileUploadHandler unstable_createMemoryUploadHandler StylingCSS Bundling Regular CSS CSS Imports CSS in JS CSS Modules PostCSS Tailwind Vanilla Extract Other API@remix-run/dev CLI 🆕@remix-run/{adapter} @remix-run/serve create-remix (CLI) @remix-run/node @remix-run/testing GuidesAccessibility Development Strategy API Routes Backend For Frontend Breadcrumbs Guide Browser Support Client Data Module Constraints Contributing CSS Files Data Loading Data Writes Dependency optimization Deployment Disabling JavaScript Environment Variables Error Handling FAQs File Uploads Form Validation Gotchas Index Query Param Lazy Route Discovery Local TLS Manual Dev Server MDX Migrating from React Router Not Found Handling Performance Presets Resource Routes Server Bundles Single Fetch SPA Mode Streaming Templates TypeScript Vite On this pageCompilerHTTP Handler and AdaptersServer FrameworkBrowser FrameworkOn this pageCompilerHTTP Handler and AdaptersServer FrameworkBrowser FrameworkIntroduction, Technical Explanation Built on top of React Router, Remix is four things: A compiler A server-side HTTP handler A server framework A browser framework Compiler Everything in Remix starts with the compiler: remix vite:build. Using Vite, this creates a few things: A server HTTP handler, usually in build/server/index.js (it's configurable) that includes all routes and modules together to be able to render on the server and handle any other server-side requests for resources. A browser build, usually in build/client/*. This includes automatic code splitting by route, fingerprinted asset imports (like CSS and images), etc. Anything needed to run an application in the browser. An asset manifest. Both the client and the server use this manifest to know the entire dependency graph. This is useful for preloading resources in the initial server render as well as prefetching them for client-side transitions. This is how Remix is able to eliminate the render+fetch waterfalls so common in web apps today. With these build artifacts, an application can be deployed to any hosting service that runs JavaScript. HTTP Handler and Adapters While Remix runs on the server, it is not actually a server. It's just a handler that is given to an actual JavaScript server. It's built on the Web Fetch API instead of Node.js. This enables Remix to run in any Node.js server like Vercel, Netlify, Architect, etc. as well as non-Node.js environments like Cloudflare Workers and Deno Deploy. This is what Remix looks like when running in an express app: const remix = require(\"@remix-run/express\"); const express = require(\"express\"); const app = express(); app.all( \"*\", remix.createRequestHandler({ build: require(\"./build/server\"), }) ); Express (or Node.js) is the actual server, Remix is just a handler on that server. The \"@remix-run/express\" package is called an adapter. Remix handlers are server agnostic. Adapters make them work for a specific server by converting the server's request/response API into the Fetch API on the way in and then adapting the Fetch Response coming from Remix into the server's response API. Here's some pseudocode of what an adapter does: export function createRequestHandler({ build }) { // creates a Fetch API request handler from the server build const handleRequest = createRemixRequestHandler(build); // returns an express.js specific handler for the express server return async (req, res) =\u003e { // adapts the express.req to a Fetch API request const request = createRemixRequest(req); // calls the app handler and receives a Fetch API response const response = await handleRequest(request); // adapts the Fetch API response to the express.res sendRemixResponse(res, response); }; } Real adapters do a bit more than that, but that's the gist of it. Not only does this enable you to deploy Remix anywhere, it also lets you incrementally adopt it in an existing JavaScript server since you can have routes outside of Remix that your server continues to handle before getting to Remix. Additionally, if Remix doesn't have an adapter for your server already, you can look at the source of one of the adapters and build your own. Server Framework If you're familiar with server-side MVC web frameworks like Rails and Laravel, Remix is the View and Controller, but it leaves the Model up to you. There are a lot of great databases, ORMs, mailers, etc. in the JavaScript ecosystem to fill that space. Remix also has helpers around the Fetch API for cookie and session management. Instead of having a split between View and Controller, Remix Route modules take on both responsibilities. Most server-side frameworks are \"model focused\". A controller manages multiple URLs for a single model. Remix is UI-focused. Routes can handle an entire URL or just a segment of the URL. When a route maps to just a segment, the nested URL segments become nested layouts in the UI. In this way, each layout (view) can be its own controller and then Remix will aggregate the data and components to build the complete UI. More often than not, a Remix route module can contain both the UI and the interactions with the models in the same file, which leads to really nice developer ergonomics and productivity. Route modules have three primary exports: loader, action, and default (component). // Loaders only run on the server and provide data // to your component on GET requests export async function loader() { return json(await db.projects.findAll()); } // The default export is the component that will be // rendered when a route matches the URL. This runs // both on the server and the client export default function Projects() { const projects = useLoaderData\u003ctypeof loader\u003e(); const actionData = useActionData\u003ctypeof action\u003e(); return ( \u003cdiv\u003e {projects.map((project) =\u003e ( \u003cLink key={project.slug} to={project.slug}\u003e {project.title} \u003c/Link\u003e ))} \u003cForm method=\"post\"\u003e \u003cinput name=\"title\" /\u003e \u003cbutton type=\"submit\"\u003eCreate New Project\u003c/button\u003e \u003c/Form\u003e {actionData?.errors ? ( \u003cErrorMessages errors={actionData.errors} /\u003e ) : null} {/* outlets render the nested child routes that match the URL deeper than this route, allowing each layout to co-locate the UI and controller code in the same file */} \u003cOutlet /\u003e \u003c/div\u003e ); } // Actions only run on the server and handle POST // PUT, PATCH, and DELETE. They can also provide data // to the component export async function action({ request, }: ActionFunctionArgs) { const form = await request.formData(); const errors = validate(form); if (errors) { return json({ errors }); } await createProject({ title: form.get(\"title\") }); return json({ ok: true }); } You can actually use Remix as just a server-side framework without using any browser JavaScript at all. The route conventions for data loading with loader, mutations with action and HTML forms, and components that render at URLs, can provide the core feature set of a lot of web projects. In this way, Remix scales down. Not every page in your application needs a bunch of JavaScript in the browser, and not every user interaction requires any extra flair than the browser's default behaviors. In Remix, you can build it the simple way first, and then scale up without changing the fundamental model. Additionally, the majority of the app works before JavaScript loads in the browser, which makes Remix apps resilient to choppy network conditions by design. If you're not familiar with traditional back-end web frameworks, you can think of Remix routes as React components that are already their own API route and already know how to load and submit data to themselves on the server. Browser Framework Once Remix has served the document to the browser, it \"hydrates\" the page with the browser build's JavaScript modules. This is where we talk a lot about Remix \"emulating the browser\". When the user clicks a link, instead of making a round trip to the server for the entire document and all the assets, Remix simply fetches the data for the next page and updates the UI. Additionally, when users submit a \u003cForm\u003e to update data, instead of doing a normal HTML document request, the browser runtime will make a fetch to the server instead and automatically revalidate all data on the page and update it with React. This has many performance benefits over making a full-document request: Assets don't need to be re-downloaded (or pulled from the cache) Assets don't need to be parsed by the browser again The data fetched is much smaller than the entire document (sometimes orders of magnitude) Because Remix enhances HTML APIs (\u003ca\u003e and \u003cform\u003e), your app tends to work even before JavaScript has loaded on the page Remix also has some built-in optimizations for client-side navigation. It knows which layouts will persist between the two URLs, so it only fetches the data for the ones that are changing. A full document request would require all data to be fetched on the server, wasting resources on your back end and slowing down your app. This approach also has UX benefits like not resetting the scroll position of a sidebar nav and allowing you to move focus to something that makes more sense than the top of the document. Remix can also prefetch all resources for a page when the user is about to click a link. The browser framework knows about the compiler's asset manifest. It can match the URL of the link, read the manifest, and then prefetch all data, JavaScript modules, and even CSS resources for the next page. This is how Remix apps feel fast even when networks are slow. Remix then provides client side APIs, so you can create rich user experiences without changing the fundamental model of HTML and browsers. Taking our route module from before, here are a few small but useful UX improvements to the form that you can only do with JavaScript in the browser: Disable the button when the form is being submitted Focus the input when server-side form validation fails Animate in the error messages export default function Projects() { const projects = useLoaderData\u003ctypeof loader\u003e(); const actionData = useActionData\u003ctypeof action\u003e(); const { state } = useNavigation(); const busy = state === \"submitting\"; const inputRef = React.useRef(); React.useEffect(() =\u003e { if (actionData.errors) { inputRef.current.focus(); } }, [actionData]); return ( \u003cdiv\u003e {projects.map((project) =\u003e ( \u003cLink key={project.slug} to={project.slug}\u003e {project.title} \u003c/Link\u003e ))} \u003cForm method=\"post\"\u003e \u003cinput ref={inputRef} name=\"title\" /\u003e \u003cbutton type=\"submit\" disabled={busy}\u003e {busy ? \"Creating...\" : \"Create New Project\"} \u003c/button\u003e \u003c/Form\u003e {actionData?.errors ? ( \u003cFadeIn\u003e \u003cErrorMessages errors={actionData.errors} /\u003e \u003c/FadeIn\u003e ) : null} \u003cOutlet /\u003e \u003c/div\u003e ); } What's most interesting about this code sample is that it is only additive. The entire interaction is still fundamentally the same thing and even works at a basic level before JavaScript loads, the only difference is the user will be provided by the browser (spinning favicon, etc.) instead of the app (useNavigation().state). Because Remix reaches into the controller level of the backend, it can do this seamlessly. And while it doesn't reach as far back into the stack as server-side frameworks like Rails and Laravel, it does reach way farther up the stack into the browser to make the transition from the back end to the front end seamless. For example. Building a plain HTML form and server-side handler in a back-end heavy web framework is just as easy to do as it is in Remix. But as soon as you want to cross over into an experience with animated validation messages, focus management, and pending UI, it requires a fundamental change in the code. Typically, people build an API route and then bring in a splash of client-side JavaScript to connect the two. With Remix, you simply add some code around the existing \"server side view\" without changing how it works fundamentally. The browser runtime takes over the server communication to provide an enhanced user experience beyond the default browser behaviors. We borrowed an old term and called this Progressive Enhancement in Remix. Start small with a plain HTML form (Remix scales down) and then scale the UI up when you have the time and ambition.© Shopify, Inc.•Docs and examples licensed under MITEdit((storageKey2, restoreKey) =\u003e { if (!window.history.state || !window.history.state.key) { let key = Math.random().toString(32).slice(2); window.history.replaceState({ key }, \"\"); } try { let positions = JSON.parse(sessionStorage.getItem(storageKey2) || \"{}\"); let storedY = positions[restoreKey || window.history.state.key]; if (typeof storedY === \"number\") { window.scrollTo(0, storedY); } } catch (error) { console.error(error); sessionStorage.removeItem(storageKey2); } })(\"react-router-scroll-positions\", null)window.__reactRouterContext = {\"basename\":\"/\",\"future\":{\"unstable_optimizeDeps\":true,\"unstable_subResourceIntegrity\":false,\"v8_middleware\":true,\"v8_splitRouteModules\":true,\"v8_viteEnvironmentApi\":true},\"routeDiscovery\":{\"mode\":\"initial\"},\"ssr\":true,\"isSpaMode\":false};window.__reactRouterContext.stream = new ReadableStream({start(controller){window.__reactRouterContext.streamController = controller;}}).pipeThrough(new TextEncoderStream());import \"/assets/manifest-b010e014.js\"; import * as route0 from \"/assets/root-CtUYAfRS.js\"; import * as route1 from \"/assets/docs-DauuYQK6.js\"; import * as route2 from \"/assets/docs._-B4dRXAHv.js\"; window.__reactRouterRouteModules = {\"root\":route0,\"routes/docs\":route1,\"routes/docs.$\":route2}; import(\"/assets/entry.client-q2ogymM2.js\");window.__reactRouterContext.streamController.enqueue(\"[{\\\"_1\\\":2,\\\"_975\\\":-5,\\\"_976\\\":-5},\\\"loaderData\\\",{\\\"_3\\\":4,\\\"_11\\\":12,\\\"_949\\\":950},\\\"root\\\",{\\\"_5\\\":6,\\\"_7\\\":8,\\\"_9\\\":10},\\\"host\\\",\\\"localhost\\\",\\\"siteUrl\\\",\\\"https://v2.remix.run\\\",\\\"noIndex\\\",false,\\\"routes/docs\\\",{\\\"_13\\\":14},\\\"menu\\\",[15,72,160,214,292,364,527,611,665,707],{\\\"_16\\\":17,\\\"_22\\\":23,\\\"_24\\\":25,\\\"_26\\\":10,\\\"_27\\\":28},\\\"attrs\\\",{\\\"_18\\\":19,\\\"_20\\\":21},\\\"title\\\",\\\"Getting Started\\\",\\\"order\\\",1,\\\"filename\\\",\\\"start/index.md\\\",\\\"slug\\\",\\\"start\\\",\\\"hasContent\\\",\\\"children\\\",[29,36,43,50,59,66],{\\\"_16\\\":30,\\\"_22\\\":32,\\\"_24\\\":33,\\\"_26\\\":34,\\\"_27\\\":35},{\\\"_18\\\":31,\\\"_20\\\":21},\\\"Quick Start (5m)\\\",\\\"start/quickstart.md\\\",\\\"start/quickstart\\\",true,[],{\\\"_16\\\":37,\\\"_22\\\":40,\\\"_24\\\":41,\\\"_26\\\":34,\\\"_27\\\":42},{\\\"_18\\\":38,\\\"_20\\\":39},\\\"Tutorial (30m)\\\",2,\\\"start/tutorial.md\\\",\\\"start/tutorial\\\",[],{\\\"_16\\\":44,\\\"_22\\\":47,\\\"_24\\\":48,\\\"_26\\\":34,\\\"_27\\\":49},{\\\"_18\\\":45,\\\"_20\\\":46},\\\"Upgrading to v2\\\",3,\\\"start/v2.md\\\",\\\"start/v2\\\",[],{\\\"_16\\\":51,\\\"_22\\\":56,\\\"_24\\\":57,\\\"_26\\\":34,\\\"_27\\\":58},{\\\"_18\\\":52,\\\"_53\\\":54,\\\"_20\\\":55},\\\"Community\\\",\\\"description\\\",\\\"Community resources for learning Remix and related technologies\\\",4,\\\"start/community.md\\\",\\\"start/community\\\",[],{\\\"_16\\\":60,\\\"_22\\\":63,\\\"_24\\\":64,\\\"_26\\\":34,\\\"_27\\\":65},{\\\"_18\\\":61,\\\"_20\\\":62},\\\"Future Flags\\\",5,\\\"start/future-flags.md\\\",\\\"start/future-flags\\\",[],{\\\"_16\\\":67,\\\"_22\\\":69,\\\"_24\\\":70,\\\"_26\\\":34,\\\"_27\\\":71},{\\\"_18\\\":68},\\\"Changelog\\\",\\\"start/changelog.md\\\",\\\"start/changelog\\\",[],{\\\"_16\\\":73,\\\"_22\\\":75,\\\"_24\\\":76,\\\"_26\\\":10,\\\"_27\\\":77},{\\\"_18\\\":74,\\\"_20\\\":39},\\\"Discussion Topics\\\",\\\"discussion/index.md\\\",\\\"discussion\\\",[78,84,90,96,102,108,115,122,129,136,142,148,154],{\\\"_16\\\":79,\\\"_22\\\":81,\\\"_24\\\":82,\\\"_26\\\":34,\\\"_27\\\":83},{\\\"_18\\\":80,\\\"_20\\\":21},\\\"Introduction, Technical Explanation\\\",\\\"discussion/introduction.md\\\",\\\"discussion/introduction\\\",[],{\\\"_16\\\":85,\\\"_22\\\":87,\\\"_24\\\":88,\\\"_26\\\":34,\\\"_27\\\":89},{\\\"_18\\\":86,\\\"_20\\\":39},\\\"Runtimes, Adapters, Templates, and Deployment\\\",\\\"discussion/runtimes.md\\\",\\\"discussion/runtimes\\\",[],{\\\"_16\\\":91,\\\"_22\\\":93,\\\"_24\\\":94,\\\"_26\\\":34,\\\"_27\\\":95},{\\\"_18\\\":92,\\\"_20\\\":46},\\\"Route Configuration\\\",\\\"discussion/routes.md\\\",\\\"discussion/routes\\\",[],{\\\"_16\\\":97,\\\"_22\\\":99,\\\"_24\\\":100,\\\"_26\\\":34,\\\"_27\\\":101},{\\\"_18\\\":98,\\\"_20\\\":55},\\\"Fullstack Data Flow\\\",\\\"discussion/data-flow.md\\\",\\\"discussion/data-flow\\\",[],{\\\"_16\\\":103,\\\"_22\\\":105,\\\"_24\\\":106,\\\"_26\\\":34,\\\"_27\\\":107},{\\\"_18\\\":104,\\\"_20\\\":62},\\\"Server vs. Client Code Execution\\\",\\\"discussion/server-vs-client.md\\\",\\\"discussion/server-vs-client\\\",[],{\\\"_16\\\":109,\\\"_22\\\":112,\\\"_24\\\":113,\\\"_26\\\":34,\\\"_27\\\":114},{\\\"_18\\\":110,\\\"_20\\\":111},\\\"React Router\\\",6,\\\"discussion/react-router.md\\\",\\\"discussion/react-router\\\",[],{\\\"_16\\\":116,\\\"_22\\\":119,\\\"_24\\\":120,\\\"_26\\\":34,\\\"_27\\\":121},{\\\"_18\\\":117,\\\"_20\\\":118},\\\"Progressive Enhancement\\\",7,\\\"discussion/progressive-enhancement.md\\\",\\\"discussion/progressive-enhancement\\\",[],{\\\"_16\\\":123,\\\"_22\\\":126,\\\"_24\\\":127,\\\"_26\\\":34,\\\"_27\\\":128},{\\\"_18\\\":124,\\\"_20\\\":125},\\\"Pending UI\\\",8,\\\"discussion/pending-ui.md\\\",\\\"discussion/pending-ui\\\",[],{\\\"_16\\\":130,\\\"_22\\\":133,\\\"_24\\\":134,\\\"_26\\\":34,\\\"_27\\\":135},{\\\"_18\\\":131,\\\"_20\\\":132},\\\"State Management\\\",9,\\\"discussion/state-management.md\\\",\\\"discussion/state-management\\\",[],{\\\"_16\\\":137,\\\"_22\\\":139,\\\"_24\\\":140,\\\"_26\\\":34,\\\"_27\\\":141},{\\\"_18\\\":138},\\\"Network Concurrency Management\\\",\\\"discussion/concurrency.md\\\",\\\"discussion/concurrency\\\",[],{\\\"_16\\\":143,\\\"_22\\\":145,\\\"_24\\\":146,\\\"_26\\\":34,\\\"_27\\\":147},{\\\"_18\\\":144},\\\"Form vs. fetcher\\\",\\\"discussion/form-vs-fetcher.md\\\",\\\"discussion/form-vs-fetcher\\\",[],{\\\"_16\\\":149,\\\"_22\\\":151,\\\"_24\\\":152,\\\"_26\\\":34,\\\"_27\\\":153},{\\\"_18\\\":150},\\\"Hot Module Replacement\\\",\\\"discussion/hot-module-replacement.md\\\",\\\"discussion/hot-module-replacement\\\",[],{\\\"_16\\\":155,\\\"_22\\\":157,\\\"_24\\\":158,\\\"_26\\\":34,\\\"_27\\\":159},{\\\"_18\\\":156},\\\"Form Resubmissions\\\",\\\"discussion/resubmissions.md\\\",\\\"discussion/resubmissions\\\",[],{\\\"_16\\\":161,\\\"_22\\\":163,\\\"_24\\\":164,\\\"_26\\\":10,\\\"_27\\\":165},{\\\"_18\\\":162,\\\"_20\\\":46},\\\"File Conventions\\\",\\\"file-conventions/index.md\\\",\\\"file-conventions\\\",[166,173,179,185,191,197,202,208],{\\\"_16\\\":167,\\\"_22\\\":170,\\\"_24\\\":171,\\\"_26\\\":34,\\\"_27\\\":172},{\\\"_18\\\":168,\\\"_169\\\":10},\\\".client modules\\\",\\\"toc\\\",\\\"file-conventions/-client.md\\\",\\\"file-conventions/-client\\\",[],{\\\"_16\\\":174,\\\"_22\\\":176,\\\"_24\\\":177,\\\"_26\\\":34,\\\"_27\\\":178},{\\\"_18\\\":175,\\\"_169\\\":10},\\\".server modules\\\",\\\"file-conventions/-server.md\\\",\\\"file-conventions/-server\\\",[],{\\\"_16\\\":180,\\\"_22\\\":182,\\\"_24\\\":183,\\\"_26\\\":34,\\\"_27\\\":184},{\\\"_18\\\":181,\\\"_169\\\":10},\\\"Asset Imports\\\",\\\"file-conventions/asset-imports.md\\\",\\\"file-conventions/asset-imports\\\",[],{\\\"_16\\\":186,\\\"_22\\\":188,\\\"_24\\\":189,\\\"_26\\\":34,\\\"_27\\\":190},{\\\"_18\\\":187,\\\"_169\\\":10},\\\"entry.client\\\",\\\"file-conventions/entry.client.md\\\",\\\"file-conventions/entry.client\\\",[],{\\\"_16\\\":192,\\\"_22\\\":194,\\\"_24\\\":195,\\\"_26\\\":34,\\\"_27\\\":196},{\\\"_18\\\":193,\\\"_169\\\":10},\\\"entry.server\\\",\\\"file-conventions/entry.server.md\\\",\\\"file-conventions/entry.server\\\",[],{\\\"_16\\\":198,\\\"_22\\\":199,\\\"_24\\\":200,\\\"_26\\\":34,\\\"_27\\\":201},{\\\"_18\\\":3,\\\"_169\\\":10},\\\"file-conventions/root.md\\\",\\\"file-conventions/root\\\",[],{\\\"_16\\\":203,\\\"_22\\\":205,\\\"_24\\\":206,\\\"_26\\\":34,\\\"_27\\\":207},{\\\"_18\\\":204},\\\"Route File Naming\\\",\\\"file-conventions/routes.md\\\",\\\"file-conventions/routes\\\",[],{\\\"_16\\\":209,\\\"_22\\\":211,\\\"_24\\\":212,\\\"_26\\\":34,\\\"_27\\\":213},{\\\"_18\\\":210},\\\"vite.config.ts\\\",\\\"file-conventions/vite-config.md\\\",\\\"file-conventions/vite-config\\\",[],{\\\"_16\\\":215,\\\"_22\\\":217,\\\"_24\\\":218,\\\"_26\\\":10,\\\"_27\\\":219},{\\\"_18\\\":216,\\\"_20\\\":55},\\\"Route Module\\\",\\\"route/index.md\\\",\\\"route\\\",[220,226,232,238,244,250,256,262,268,274,280,286],{\\\"_16\\\":221,\\\"_22\\\":223,\\\"_24\\\":224,\\\"_26\\\":34,\\\"_27\\\":225},{\\\"_18\\\":222},\\\"action\\\",\\\"route/action.md\\\",\\\"route/action\\\",[],{\\\"_16\\\":227,\\\"_22\\\":229,\\\"_24\\\":230,\\\"_26\\\":34,\\\"_27\\\":231},{\\\"_18\\\":228},\\\"clientAction\\\",\\\"route/client-action.md\\\",\\\"route/client-action\\\",[],{\\\"_16\\\":233,\\\"_22\\\":235,\\\"_24\\\":236,\\\"_26\\\":34,\\\"_27\\\":237},{\\\"_18\\\":234},\\\"clientLoader\\\",\\\"route/client-loader.md\\\",\\\"route/client-loader\\\",[],{\\\"_16\\\":239,\\\"_22\\\":241,\\\"_24\\\":242,\\\"_26\\\":34,\\\"_27\\\":243},{\\\"_18\\\":240},\\\"Component\\\",\\\"route/component.md\\\",\\\"route/component\\\",[],{\\\"_16\\\":245,\\\"_22\\\":247,\\\"_24\\\":248,\\\"_26\\\":34,\\\"_27\\\":249},{\\\"_18\\\":246},\\\"ErrorBoundary\\\",\\\"route/error-boundary.md\\\",\\\"route/error-boundary\\\",[],{\\\"_16\\\":251,\\\"_22\\\":253,\\\"_24\\\":254,\\\"_26\\\":34,\\\"_27\\\":255},{\\\"_18\\\":252},\\\"handle\\\",\\\"route/handle.md\\\",\\\"route/handle\\\",[],{\\\"_16\\\":257,\\\"_22\\\":259,\\\"_24\\\":260,\\\"_26\\\":34,\\\"_27\\\":261},{\\\"_18\\\":258},\\\"headers\\\",\\\"route/headers.md\\\",\\\"route/headers\\\",[],{\\\"_16\\\":263,\\\"_22\\\":265,\\\"_24\\\":266,\\\"_26\\\":34,\\\"_27\\\":267},{\\\"_18\\\":264},\\\"HydrateFallback\\\",\\\"route/hydrate-fallback.md\\\",\\\"route/hydrate-fallback\\\",[],{\\\"_16\\\":269,\\\"_22\\\":271,\\\"_24\\\":272,\\\"_26\\\":34,\\\"_27\\\":273},{\\\"_18\\\":270},\\\"links\\\",\\\"route/links.md\\\",\\\"route/links\\\",[],{\\\"_16\\\":275,\\\"_22\\\":277,\\\"_24\\\":278,\\\"_26\\\":34,\\\"_27\\\":279},{\\\"_18\\\":276},\\\"loader\\\",\\\"route/loader.md\\\",\\\"route/loader\\\",[],{\\\"_16\\\":281,\\\"_22\\\":283,\\\"_24\\\":284,\\\"_26\\\":34,\\\"_27\\\":285},{\\\"_18\\\":282},\\\"meta\\\",\\\"route/meta.md\\\",\\\"route/meta\\\",[],{\\\"_16\\\":287,\\\"_22\\\":289,\\\"_24\\\":290,\\\"_26\\\":34,\\\"_27\\\":291},{\\\"_18\\\":288},\\\"shouldRevalidate\\\",\\\"route/should-revalidate.md\\\",\\\"route/should-revalidate\\\",[],{\\\"_16\\\":293,\\\"_22\\\":295,\\\"_24\\\":296,\\\"_26\\\":10,\\\"_27\\\":297},{\\\"_18\\\":294,\\\"_20\\\":62},\\\"Components\\\",\\\"components/index.md\\\",\\\"components\\\",[298,304,310,316,322,328,334,340,346,352,358],{\\\"_16\\\":299,\\\"_22\\\":301,\\\"_24\\\":302,\\\"_26\\\":34,\\\"_27\\\":303},{\\\"_18\\\":300},\\\"Await\\\",\\\"components/await.md\\\",\\\"components/await\\\",[],{\\\"_16\\\":305,\\\"_22\\\":307,\\\"_24\\\":308,\\\"_26\\\":34,\\\"_27\\\":309},{\\\"_18\\\":306},\\\"Form\\\",\\\"components/form.md\\\",\\\"components/form\\\",[],{\\\"_16\\\":311,\\\"_22\\\":313,\\\"_24\\\":314,\\\"_26\\\":34,\\\"_27\\\":315},{\\\"_18\\\":312},\\\"Link\\\",\\\"components/link.md\\\",\\\"components/link\\\",[],{\\\"_16\\\":317,\\\"_22\\\":319,\\\"_24\\\":320,\\\"_26\\\":34,\\\"_27\\\":321},{\\\"_18\\\":318,\\\"_169\\\":10},\\\"Links\\\",\\\"components/links.md\\\",\\\"components/links\\\",[],{\\\"_16\\\":323,\\\"_22\\\":325,\\\"_24\\\":326,\\\"_26\\\":34,\\\"_27\\\":327},{\\\"_18\\\":324,\\\"_169\\\":10},\\\"LiveReload\\\",\\\"components/live-reload.md\\\",\\\"components/live-reload\\\",[],{\\\"_16\\\":329,\\\"_22\\\":331,\\\"_24\\\":332,\\\"_26\\\":34,\\\"_27\\\":333},{\\\"_18\\\":330,\\\"_169\\\":10},\\\"Meta\\\",\\\"components/meta.md\\\",\\\"components/meta\\\",[],{\\\"_16\\\":335,\\\"_22\\\":337,\\\"_24\\\":338,\\\"_26\\\":34,\\\"_27\\\":339},{\\\"_18\\\":336},\\\"NavLink\\\",\\\"components/nav-link.md\\\",\\\"components/nav-link\\\",[],{\\\"_16\\\":341,\\\"_22\\\":343,\\\"_24\\\":344,\\\"_26\\\":34,\\\"_27\\\":345},{\\\"_18\\\":342},\\\"Outlet\\\",\\\"components/outlet.md\\\",\\\"components/outlet\\\",[],{\\\"_16\\\":347,\\\"_22\\\":349,\\\"_24\\\":350,\\\"_26\\\":34,\\\"_27\\\":351},{\\\"_18\\\":348,\\\"_169\\\":10},\\\"PrefetchPageLinks\\\",\\\"components/prefetch-page-links.md\\\",\\\"components/prefetch-page-links\\\",[],{\\\"_16\\\":353,\\\"_22\\\":355,\\\"_24\\\":356,\\\"_26\\\":34,\\\"_27\\\":357},{\\\"_18\\\":354,\\\"_169\\\":10},\\\"Scripts\\\",\\\"components/scripts.md\\\",\\\"components/scripts\\\",[],{\\\"_16\\\":359,\\\"_22\\\":361,\\\"_24\\\":362,\\\"_26\\\":34,\\\"_27\\\":363},{\\\"_18\\\":360},\\\"ScrollRestoration\\\",\\\"components/scroll-restoration.md\\\",\\\"components/scroll-restoration\\\",[],{\\\"_16\\\":365,\\\"_22\\\":367,\\\"_24\\\":368,\\\"_26\\\":10,\\\"_27\\\":369},{\\\"_18\\\":366,\\\"_20\\\":111},\\\"Hooks\\\",\\\"hooks/index.md\\\",\\\"hooks\\\",[370,376,383,389,395,401,407,413,419,425,431,437,443,449,455,461,467,473,479,485,491,497,503,509,515,521],{\\\"_16\\\":371,\\\"_22\\\":373,\\\"_24\\\":374,\\\"_26\\\":34,\\\"_27\\\":375},{\\\"_18\\\":372,\\\"_169\\\":10},\\\"useActionData\\\",\\\"hooks/use-action-data.md\\\",\\\"hooks/use-action-data\\\",[],{\\\"_16\\\":377,\\\"_22\\\":380,\\\"_24\\\":381,\\\"_26\\\":34,\\\"_27\\\":382},{\\\"_18\\\":378,\\\"_379\\\":34},\\\"useAsyncError\\\",\\\"new\\\",\\\"hooks/use-async-error.md\\\",\\\"hooks/use-async-error\\\",[],{\\\"_16\\\":384,\\\"_22\\\":386,\\\"_24\\\":387,\\\"_26\\\":34,\\\"_27\\\":388},{\\\"_18\\\":385,\\\"_379\\\":34},\\\"useAsyncValue\\\",\\\"hooks/use-async-value.md\\\",\\\"hooks/use-async-value\\\",[],{\\\"_16\\\":390,\\\"_22\\\":392,\\\"_24\\\":393,\\\"_26\\\":34,\\\"_27\\\":394},{\\\"_18\\\":391,\\\"_169\\\":10},\\\"useBeforeUnload\\\",\\\"hooks/use-before-unload.md\\\",\\\"hooks/use-before-unload\\\",[],{\\\"_16\\\":396,\\\"_22\\\":398,\\\"_24\\\":399,\\\"_26\\\":34,\\\"_27\\\":400},{\\\"_18\\\":397},\\\"useBlocker\\\",\\\"hooks/use-blocker.md\\\",\\\"hooks/use-blocker\\\",[],{\\\"_16\\\":402,\\\"_22\\\":404,\\\"_24\\\":405,\\\"_26\\\":34,\\\"_27\\\":406},{\\\"_18\\\":403},\\\"useFetcher\\\",\\\"hooks/use-fetcher.md\\\",\\\"hooks/use-fetcher\\\",[],{\\\"_16\\\":408,\\\"_22\\\":410,\\\"_24\\\":411,\\\"_26\\\":34,\\\"_27\\\":412},{\\\"_18\\\":409,\\\"_169\\\":10},\\\"useFetchers\\\",\\\"hooks/use-fetchers.md\\\",\\\"hooks/use-fetchers\\\",[],{\\\"_16\\\":414,\\\"_22\\\":416,\\\"_24\\\":417,\\\"_26\\\":34,\\\"_27\\\":418},{\\\"_18\\\":415},\\\"useFormAction\\\",\\\"hooks/use-form-action.md\\\",\\\"hooks/use-form-action\\\",[],{\\\"_16\\\":420,\\\"_22\\\":422,\\\"_24\\\":423,\\\"_26\\\":34,\\\"_27\\\":424},{\\\"_18\\\":421},\\\"useHref\\\",\\\"hooks/use-href.md\\\",\\\"hooks/use-href\\\",[],{\\\"_16\\\":426,\\\"_22\\\":428,\\\"_24\\\":429,\\\"_26\\\":34,\\\"_27\\\":430},{\\\"_18\\\":427},\\\"useLoaderData\\\",\\\"hooks/use-loader-data.md\\\",\\\"hooks/use-loader-data\\\",[],{\\\"_16\\\":432,\\\"_22\\\":434,\\\"_24\\\":435,\\\"_26\\\":34,\\\"_27\\\":436},{\\\"_18\\\":433},\\\"useLocation\\\",\\\"hooks/use-location.md\\\",\\\"hooks/use-location\\\",[],{\\\"_16\\\":438,\\\"_22\\\":440,\\\"_24\\\":441,\\\"_26\\\":34,\\\"_27\\\":442},{\\\"_18\\\":439,\\\"_169\\\":10},\\\"useMatches\\\",\\\"hooks/use-matches.md\\\",\\\"hooks/use-matches\\\",[],{\\\"_16\\\":444,\\\"_22\\\":446,\\\"_24\\\":447,\\\"_26\\\":34,\\\"_27\\\":448},{\\\"_18\\\":445},\\\"useNavigate\\\",\\\"hooks/use-navigate.md\\\",\\\"hooks/use-navigate\\\",[],{\\\"_16\\\":450,\\\"_22\\\":452,\\\"_24\\\":453,\\\"_26\\\":34,\\\"_27\\\":454},{\\\"_18\\\":451},\\\"useNavigation\\\",\\\"hooks/use-navigation.md\\\",\\\"hooks/use-navigation\\\",[],{\\\"_16\\\":456,\\\"_22\\\":458,\\\"_24\\\":459,\\\"_26\\\":34,\\\"_27\\\":460},{\\\"_18\\\":457},\\\"useNavigationType\\\",\\\"hooks/use-navigation-type.md\\\",\\\"hooks/use-navigation-type\\\",[],{\\\"_16\\\":462,\\\"_22\\\":464,\\\"_24\\\":465,\\\"_26\\\":34,\\\"_27\\\":466},{\\\"_18\\\":463},\\\"useOutlet\\\",\\\"hooks/use-outlet.md\\\",\\\"hooks/use-outlet\\\",[],{\\\"_16\\\":468,\\\"_22\\\":470,\\\"_24\\\":471,\\\"_26\\\":34,\\\"_27\\\":472},{\\\"_18\\\":469},\\\"useOutletContext\\\",\\\"hooks/use-outlet-context.md\\\",\\\"hooks/use-outlet-context\\\",[],{\\\"_16\\\":474,\\\"_22\\\":476,\\\"_24\\\":477,\\\"_26\\\":34,\\\"_27\\\":478},{\\\"_18\\\":475},\\\"useParams\\\",\\\"hooks/use-params.md\\\",\\\"hooks/use-params\\\",[],{\\\"_16\\\":480,\\\"_22\\\":482,\\\"_24\\\":483,\\\"_26\\\":34,\\\"_27\\\":484},{\\\"_18\\\":481},\\\"unstable_usePrompt\\\",\\\"hooks/use-prompt.md\\\",\\\"hooks/use-prompt\\\",[],{\\\"_16\\\":486,\\\"_22\\\":488,\\\"_24\\\":489,\\\"_26\\\":34,\\\"_27\\\":490},{\\\"_18\\\":487},\\\"useResolvedPath\\\",\\\"hooks/use-resolved-path.md\\\",\\\"hooks/use-resolved-path\\\",[],{\\\"_16\\\":492,\\\"_22\\\":494,\\\"_24\\\":495,\\\"_26\\\":34,\\\"_27\\\":496},{\\\"_18\\\":493,\\\"_379\\\":34},\\\"useRevalidator\\\",\\\"hooks/use-revalidator.md\\\",\\\"hooks/use-revalidator\\\",[],{\\\"_16\\\":498,\\\"_22\\\":500,\\\"_24\\\":501,\\\"_26\\\":34,\\\"_27\\\":502},{\\\"_18\\\":499,\\\"_379\\\":34},\\\"useRouteError\\\",\\\"hooks/use-route-error.md\\\",\\\"hooks/use-route-error\\\",[],{\\\"_16\\\":504,\\\"_22\\\":506,\\\"_24\\\":507,\\\"_26\\\":34,\\\"_27\\\":508},{\\\"_18\\\":505,\\\"_169\\\":10},\\\"useRouteLoaderData\\\",\\\"hooks/use-route-loader-data.md\\\",\\\"hooks/use-route-loader-data\\\",[],{\\\"_16\\\":510,\\\"_22\\\":512,\\\"_24\\\":513,\\\"_26\\\":34,\\\"_27\\\":514},{\\\"_18\\\":511},\\\"useSearchParams\\\",\\\"hooks/use-search-params.md\\\",\\\"hooks/use-search-params\\\",[],{\\\"_16\\\":516,\\\"_22\\\":518,\\\"_24\\\":519,\\\"_26\\\":34,\\\"_27\\\":520},{\\\"_18\\\":517},\\\"useSubmit\\\",\\\"hooks/use-submit.md\\\",\\\"hooks/use-submit\\\",[],{\\\"_16\\\":522,\\\"_22\\\":524,\\\"_24\\\":525,\\\"_26\\\":34,\\\"_27\\\":526},{\\\"_18\\\":523,\\\"_169\\\":10},\\\"useViewTransitionState\\\",\\\"hooks/use-view-transition-state.md\\\",\\\"hooks/use-view-transition-state\\\",[],{\\\"_16\\\":528,\\\"_22\\\":530,\\\"_24\\\":531,\\\"_26\\\":10,\\\"_27\\\":532},{\\\"_18\\\":529,\\\"_20\\\":111},\\\"Utilities\\\",\\\"utils/index.md\\\",\\\"utils\\\",[533,539,545,551,557,563,569,575,581,587,593,599,605],{\\\"_16\\\":534,\\\"_22\\\":536,\\\"_24\\\":537,\\\"_26\\\":34,\\\"_27\\\":538},{\\\"_18\\\":535},\\\"Cookies\\\",\\\"utils/cookies.md\\\",\\\"utils/cookies\\\",[],{\\\"_16\\\":540,\\\"_22\\\":542,\\\"_24\\\":543,\\\"_26\\\":34,\\\"_27\\\":544},{\\\"_18\\\":541},\\\"createRemixStub\\\",\\\"utils/create-remix-stub.md\\\",\\\"utils/create-remix-stub\\\",[],{\\\"_16\\\":546,\\\"_22\\\":548,\\\"_24\\\":549,\\\"_26\\\":34,\\\"_27\\\":550},{\\\"_18\\\":547,\\\"_169\\\":10},\\\"data\\\",\\\"utils/data.md\\\",\\\"utils/data\\\",[],{\\\"_16\\\":552,\\\"_22\\\":554,\\\"_24\\\":555,\\\"_26\\\":34,\\\"_27\\\":556},{\\\"_18\\\":553,\\\"_169\\\":10},\\\"defer\\\",\\\"utils/defer.md\\\",\\\"utils/defer\\\",[],{\\\"_16\\\":558,\\\"_22\\\":560,\\\"_24\\\":561,\\\"_26\\\":34,\\\"_27\\\":562},{\\\"_18\\\":559,\\\"_169\\\":10},\\\"isRouteErrorResponse\\\",\\\"utils/is-route-error-response.md\\\",\\\"utils/is-route-error-response\\\",[],{\\\"_16\\\":564,\\\"_22\\\":566,\\\"_24\\\":567,\\\"_26\\\":34,\\\"_27\\\":568},{\\\"_18\\\":565,\\\"_169\\\":10},\\\"json\\\",\\\"utils/json.md\\\",\\\"utils/json\\\",[],{\\\"_16\\\":570,\\\"_22\\\":572,\\\"_24\\\":573,\\\"_26\\\":34,\\\"_27\\\":574},{\\\"_18\\\":571},\\\"unstable_parseMultipartFormData\\\",\\\"utils/parse-multipart-form-data.md\\\",\\\"utils/parse-multipart-form-data\\\",[],{\\\"_16\\\":576,\\\"_22\\\":578,\\\"_24\\\":579,\\\"_26\\\":34,\\\"_27\\\":580},{\\\"_18\\\":577,\\\"_169\\\":10},\\\"redirect\\\",\\\"utils/redirect.md\\\",\\\"utils/redirect\\\",[],{\\\"_16\\\":582,\\\"_22\\\":584,\\\"_24\\\":585,\\\"_26\\\":34,\\\"_27\\\":586},{\\\"_18\\\":583,\\\"_169\\\":10},\\\"redirectDocument\\\",\\\"utils/redirectDocument.md\\\",\\\"utils/redirectDocument\\\",[],{\\\"_16\\\":588,\\\"_22\\\":590,\\\"_24\\\":591,\\\"_26\\\":34,\\\"_27\\\":592},{\\\"_18\\\":589,\\\"_169\\\":10},\\\"replace\\\",\\\"utils/replace.md\\\",\\\"utils/replace\\\",[],{\\\"_16\\\":594,\\\"_22\\\":596,\\\"_24\\\":597,\\\"_26\\\":34,\\\"_27\\\":598},{\\\"_18\\\":595},\\\"Sessions\\\",\\\"utils/sessions.md\\\",\\\"utils/sessions\\\",[],{\\\"_16\\\":600,\\\"_22\\\":602,\\\"_24\\\":603,\\\"_26\\\":34,\\\"_27\\\":604},{\\\"_18\\\":601,\\\"_169\\\":10},\\\"unstable_createFileUploadHandler\\\",\\\"utils/unstable-create-file-upload-handler.md\\\",\\\"utils/unstable-create-file-upload-handler\\\",[],{\\\"_16\\\":606,\\\"_22\\\":608,\\\"_24\\\":609,\\\"_26\\\":34,\\\"_27\\\":610},{\\\"_18\\\":607,\\\"_169\\\":10},\\\"unstable_createMemoryUploadHandler\\\",\\\"utils/unstable-create-memory-upload-handler.md\\\",\\\"utils/unstable-create-memory-upload-handler\\\",[],{\\\"_16\\\":612,\\\"_22\\\":614,\\\"_24\\\":615,\\\"_26\\\":10,\\\"_27\\\":616},{\\\"_18\\\":613,\\\"_20\\\":118},\\\"Styling\\\",\\\"styling/index.md\\\",\\\"styling\\\",[617,623,629,635,641,647,653,659],{\\\"_16\\\":618,\\\"_22\\\":620,\\\"_24\\\":621,\\\"_26\\\":34,\\\"_27\\\":622},{\\\"_18\\\":619},\\\"CSS Bundling\\\",\\\"styling/bundling.md\\\",\\\"styling/bundling\\\",[],{\\\"_16\\\":624,\\\"_22\\\":626,\\\"_24\\\":627,\\\"_26\\\":34,\\\"_27\\\":628},{\\\"_18\\\":625},\\\"Regular CSS\\\",\\\"styling/css.md\\\",\\\"styling/css\\\",[],{\\\"_16\\\":630,\\\"_22\\\":632,\\\"_24\\\":633,\\\"_26\\\":34,\\\"_27\\\":634},{\\\"_18\\\":631},\\\"CSS Imports\\\",\\\"styling/css-imports.md\\\",\\\"styling/css-imports\\\",[],{\\\"_16\\\":636,\\\"_22\\\":638,\\\"_24\\\":639,\\\"_26\\\":34,\\\"_27\\\":640},{\\\"_18\\\":637},\\\"CSS in JS\\\",\\\"styling/css-in-js.md\\\",\\\"styling/css-in-js\\\",[],{\\\"_16\\\":642,\\\"_22\\\":644,\\\"_24\\\":645,\\\"_26\\\":34,\\\"_27\\\":646},{\\\"_18\\\":643},\\\"CSS Modules\\\",\\\"styling/css-modules.md\\\",\\\"styling/css-modules\\\",[],{\\\"_16\\\":648,\\\"_22\\\":650,\\\"_24\\\":651,\\\"_26\\\":34,\\\"_27\\\":652},{\\\"_18\\\":649},\\\"PostCSS\\\",\\\"styling/postcss.md\\\",\\\"styling/postcss\\\",[],{\\\"_16\\\":654,\\\"_22\\\":656,\\\"_24\\\":657,\\\"_26\\\":34,\\\"_27\\\":658},{\\\"_18\\\":655},\\\"Tailwind\\\",\\\"styling/tailwind.md\\\",\\\"styling/tailwind\\\",[],{\\\"_16\\\":660,\\\"_22\\\":662,\\\"_24\\\":663,\\\"_26\\\":34,\\\"_27\\\":664},{\\\"_18\\\":661},\\\"Vanilla Extract\\\",\\\"styling/vanilla-extract.md\\\",\\\"styling/vanilla-extract\\\",[],{\\\"_16\\\":666,\\\"_22\\\":668,\\\"_24\\\":669,\\\"_26\\\":10,\\\"_27\\\":670},{\\\"_18\\\":667,\\\"_20\\\":132},\\\"Other API\\\",\\\"other-api/index.md\\\",\\\"other-api\\\",[671,677,683,689,695,701],{\\\"_16\\\":672,\\\"_22\\\":674,\\\"_24\\\":675,\\\"_26\\\":34,\\\"_27\\\":676},{\\\"_18\\\":673,\\\"_20\\\":39,\\\"_379\\\":34},\\\"@remix-run/dev CLI\\\",\\\"other-api/dev.md\\\",\\\"other-api/dev\\\",[],{\\\"_16\\\":678,\\\"_22\\\":680,\\\"_24\\\":681,\\\"_26\\\":34,\\\"_27\\\":682},{\\\"_18\\\":679,\\\"_20\\\":46},\\\"@remix-run/{adapter}\\\",\\\"other-api/adapter.md\\\",\\\"other-api/adapter\\\",[],{\\\"_16\\\":684,\\\"_22\\\":686,\\\"_24\\\":687,\\\"_26\\\":34,\\\"_27\\\":688},{\\\"_18\\\":685,\\\"_20\\\":46},\\\"@remix-run/serve\\\",\\\"other-api/serve.md\\\",\\\"other-api/serve\\\",[],{\\\"_16\\\":690,\\\"_22\\\":692,\\\"_24\\\":693,\\\"_26\\\":34,\\\"_27\\\":694},{\\\"_18\\\":691},\\\"create-remix (CLI)\\\",\\\"other-api/create-remix.md\\\",\\\"other-api/create-remix\\\",[],{\\\"_16\\\":696,\\\"_22\\\":698,\\\"_24\\\":699,\\\"_26\\\":34,\\\"_27\\\":700},{\\\"_18\\\":697},\\\"@remix-run/node\\\",\\\"other-api/node.md\\\",\\\"other-api/node\\\",[],{\\\"_16\\\":702,\\\"_22\\\":704,\\\"_24\\\":705,\\\"_26\\\":34,\\\"_27\\\":706},{\\\"_18\\\":703},\\\"@remix-run/testing\\\",\\\"other-api/testing.md\\\",\\\"other-api/testing\\\",[],{\\\"_16\\\":708,\\\"_22\\\":711,\\\"_24\\\":712,\\\"_26\\\":10,\\\"_27\\\":713},{\\\"_18\\\":709,\\\"_20\\\":710},\\\"Guides\\\",10,\\\"guides/index.md\\\",\\\"guides\\\",[714,720,726,732,738,744,750,756,762,769,775,782,788,794,800,806,812,818,825,831,837,843,849,855,861,867,874,881,887,893,899,905,911,917,923,930,937,943],{\\\"_16\\\":715,\\\"_22\\\":717,\\\"_24\\\":718,\\\"_26\\\":34,\\\"_27\\\":719},{\\\"_18\\\":716},\\\"Accessibility\\\",\\\"guides/accessibility.md\\\",\\\"guides/accessibility\\\",[],{\\\"_16\\\":721,\\\"_22\\\":723,\\\"_24\\\":724,\\\"_26\\\":34,\\\"_27\\\":725},{\\\"_18\\\":722},\\\"Development Strategy\\\",\\\"guides/api-development-strategy.md\\\",\\\"guides/api-development-strategy\\\",[],{\\\"_16\\\":727,\\\"_22\\\":729,\\\"_24\\\":730,\\\"_26\\\":34,\\\"_27\\\":731},{\\\"_18\\\":728},\\\"API Routes\\\",\\\"guides/api-routes.md\\\",\\\"guides/api-routes\\\",[],{\\\"_16\\\":733,\\\"_22\\\":735,\\\"_24\\\":736,\\\"_26\\\":34,\\\"_27\\\":737},{\\\"_18\\\":734,\\\"_169\\\":10},\\\"Backend For Frontend\\\",\\\"guides/bff.md\\\",\\\"guides/bff\\\",[],{\\\"_16\\\":739,\\\"_22\\\":741,\\\"_24\\\":742,\\\"_26\\\":34,\\\"_27\\\":743},{\\\"_18\\\":740},\\\"Breadcrumbs Guide\\\",\\\"guides/breadcrumbs.md\\\",\\\"guides/breadcrumbs\\\",[],{\\\"_16\\\":745,\\\"_22\\\":747,\\\"_24\\\":748,\\\"_26\\\":34,\\\"_27\\\":749},{\\\"_18\\\":746},\\\"Browser Support\\\",\\\"guides/browser-support.md\\\",\\\"guides/browser-support\\\",[],{\\\"_16\\\":751,\\\"_22\\\":753,\\\"_24\\\":754,\\\"_26\\\":34,\\\"_27\\\":755},{\\\"_18\\\":752},\\\"Client Data\\\",\\\"guides/client-data.md\\\",\\\"guides/client-data\\\",[],{\\\"_16\\\":757,\\\"_22\\\":759,\\\"_24\\\":760,\\\"_26\\\":34,\\\"_27\\\":761},{\\\"_18\\\":758},\\\"Module Constraints\\\",\\\"guides/constraints.md\\\",\\\"guides/constraints\\\",[],{\\\"_16\\\":763,\\\"_22\\\":766,\\\"_24\\\":767,\\\"_26\\\":34,\\\"_27\\\":768},{\\\"_18\\\":764,\\\"_53\\\":765},\\\"Contributing\\\",\\\"Thank you for contributing to Remix! Here's everything you need to know before you open a pull request.\\\",\\\"guides/contributing.md\\\",\\\"guides/contributing\\\",[],{\\\"_16\\\":770,\\\"_22\\\":772,\\\"_24\\\":773,\\\"_26\\\":34,\\\"_27\\\":774},{\\\"_18\\\":771},\\\"CSS Files\\\",\\\"guides/css-files.md\\\",\\\"guides/css-files\\\",[],{\\\"_16\\\":776,\\\"_22\\\":779,\\\"_24\\\":780,\\\"_26\\\":34,\\\"_27\\\":781},{\\\"_18\\\":777,\\\"_53\\\":778},\\\"Data Loading\\\",\\\"One of the primary features of Remix is simplifying interactions with the server to get data into components. This document will help you get the most out of data loading in Remix.\\\",\\\"guides/data-loading.md\\\",\\\"guides/data-loading\\\",[],{\\\"_16\\\":783,\\\"_22\\\":785,\\\"_24\\\":786,\\\"_26\\\":34,\\\"_27\\\":787},{\\\"_18\\\":784},\\\"Data Writes\\\",\\\"guides/data-writes.md\\\",\\\"guides/data-writes\\\",[],{\\\"_16\\\":789,\\\"_22\\\":791,\\\"_24\\\":792,\\\"_26\\\":34,\\\"_27\\\":793},{\\\"_18\\\":790},\\\"Dependency optimization\\\",\\\"guides/dependency-optimization.md\\\",\\\"guides/dependency-optimization\\\",[],{\\\"_16\\\":795,\\\"_22\\\":797,\\\"_24\\\":798,\\\"_26\\\":34,\\\"_27\\\":799},{\\\"_18\\\":796,\\\"_169\\\":10},\\\"Deployment\\\",\\\"guides/deployment.md\\\",\\\"guides/deployment\\\",[],{\\\"_16\\\":801,\\\"_22\\\":803,\\\"_24\\\":804,\\\"_26\\\":34,\\\"_27\\\":805},{\\\"_18\\\":802,\\\"_169\\\":10},\\\"Disabling JavaScript\\\",\\\"guides/disabling-javascript.md\\\",\\\"guides/disabling-javascript\\\",[],{\\\"_16\\\":807,\\\"_22\\\":809,\\\"_24\\\":810,\\\"_26\\\":34,\\\"_27\\\":811},{\\\"_18\\\":808},\\\"Environment Variables\\\",\\\"guides/envvars.md\\\",\\\"guides/envvars\\\",[],{\\\"_16\\\":813,\\\"_22\\\":815,\\\"_24\\\":816,\\\"_26\\\":34,\\\"_27\\\":817},{\\\"_18\\\":814},\\\"Error Handling\\\",\\\"guides/errors.md\\\",\\\"guides/errors\\\",[],{\\\"_16\\\":819,\\\"_22\\\":822,\\\"_24\\\":823,\\\"_26\\\":34,\\\"_27\\\":824},{\\\"_18\\\":820,\\\"_53\\\":821},\\\"FAQs\\\",\\\"Frequently Asked Questions about Remix\\\",\\\"guides/faq.md\\\",\\\"guides/faq\\\",[],{\\\"_16\\\":826,\\\"_22\\\":828,\\\"_24\\\":829,\\\"_26\\\":34,\\\"_27\\\":830},{\\\"_18\\\":827},\\\"File Uploads\\\",\\\"guides/file-uploads.md\\\",\\\"guides/file-uploads\\\",[],{\\\"_16\\\":832,\\\"_22\\\":834,\\\"_24\\\":835,\\\"_26\\\":34,\\\"_27\\\":836},{\\\"_18\\\":833},\\\"Form Validation\\\",\\\"guides/form-validation.md\\\",\\\"guides/form-validation\\\",[],{\\\"_16\\\":838,\\\"_22\\\":840,\\\"_24\\\":841,\\\"_26\\\":34,\\\"_27\\\":842},{\\\"_18\\\":839},\\\"Gotchas\\\",\\\"guides/gotchas.md\\\",\\\"guides/gotchas\\\",[],{\\\"_16\\\":844,\\\"_22\\\":846,\\\"_24\\\":847,\\\"_26\\\":34,\\\"_27\\\":848},{\\\"_18\\\":845,\\\"_169\\\":10},\\\"Index Query Param\\\",\\\"guides/index-query-param.md\\\",\\\"guides/index-query-param\\\",[],{\\\"_16\\\":850,\\\"_22\\\":852,\\\"_24\\\":853,\\\"_26\\\":34,\\\"_27\\\":854},{\\\"_18\\\":851},\\\"Lazy Route Discovery\\\",\\\"guides/lazy-route-discovery.md\\\",\\\"guides/lazy-route-discovery\\\",[],{\\\"_16\\\":856,\\\"_22\\\":858,\\\"_24\\\":859,\\\"_26\\\":34,\\\"_27\\\":860},{\\\"_18\\\":857},\\\"Local TLS\\\",\\\"guides/local-tls.md\\\",\\\"guides/local-tls\\\",[],{\\\"_16\\\":862,\\\"_22\\\":864,\\\"_24\\\":865,\\\"_26\\\":34,\\\"_27\\\":866},{\\\"_18\\\":863},\\\"Manual Dev Server\\\",\\\"guides/manual-mode.md\\\",\\\"guides/manual-mode\\\",[],{\\\"_16\\\":868,\\\"_22\\\":871,\\\"_24\\\":872,\\\"_26\\\":34,\\\"_27\\\":873},{\\\"_18\\\":869,\\\"_53\\\":870},\\\"MDX\\\",\\\"Remix makes integrating MDX into your project a breeze with built in routes and \\\\\\\"import\\\\\\\" support.\\\",\\\"guides/mdx.md\\\",\\\"guides/mdx\\\",[],{\\\"_16\\\":875,\\\"_22\\\":878,\\\"_24\\\":879,\\\"_26\\\":34,\\\"_27\\\":880},{\\\"_18\\\":876,\\\"_53\\\":877},\\\"Migrating from React Router\\\",\\\"Migrating your React Router app to Remix can be done all at once or in stages. This guide will walk you through an iterative approach to get your app running quickly.\\\",\\\"guides/migrating-react-router-app.md\\\",\\\"guides/migrating-react-router-app\\\",[],{\\\"_16\\\":882,\\\"_22\\\":884,\\\"_24\\\":885,\\\"_26\\\":34,\\\"_27\\\":886},{\\\"_18\\\":883},\\\"Not Found Handling\\\",\\\"guides/not-found.md\\\",\\\"guides/not-found\\\",[],{\\\"_16\\\":888,\\\"_22\\\":890,\\\"_24\\\":891,\\\"_26\\\":34,\\\"_27\\\":892},{\\\"_18\\\":889},\\\"Performance\\\",\\\"guides/performance.md\\\",\\\"guides/performance\\\",[],{\\\"_16\\\":894,\\\"_22\\\":896,\\\"_24\\\":897,\\\"_26\\\":34,\\\"_27\\\":898},{\\\"_18\\\":895},\\\"Presets\\\",\\\"guides/presets.md\\\",\\\"guides/presets\\\",[],{\\\"_16\\\":900,\\\"_22\\\":902,\\\"_24\\\":903,\\\"_26\\\":34,\\\"_27\\\":904},{\\\"_18\\\":901},\\\"Resource Routes\\\",\\\"guides/resource-routes.md\\\",\\\"guides/resource-routes\\\",[],{\\\"_16\\\":906,\\\"_22\\\":908,\\\"_24\\\":909,\\\"_26\\\":34,\\\"_27\\\":910},{\\\"_18\\\":907},\\\"Server Bundles\\\",\\\"guides/server-bundles.md\\\",\\\"guides/server-bundles\\\",[],{\\\"_16\\\":912,\\\"_22\\\":914,\\\"_24\\\":915,\\\"_26\\\":34,\\\"_27\\\":916},{\\\"_18\\\":913},\\\"Single Fetch\\\",\\\"guides/single-fetch.md\\\",\\\"guides/single-fetch\\\",[],{\\\"_16\\\":918,\\\"_22\\\":920,\\\"_24\\\":921,\\\"_26\\\":34,\\\"_27\\\":922},{\\\"_18\\\":919},\\\"SPA Mode\\\",\\\"guides/spa-mode.md\\\",\\\"guides/spa-mode\\\",[],{\\\"_16\\\":924,\\\"_22\\\":927,\\\"_24\\\":928,\\\"_26\\\":34,\\\"_27\\\":929},{\\\"_18\\\":925,\\\"_53\\\":926},\\\"Streaming\\\",\\\"When, why, and how to stream with React 18 and Remix's deferred API.\\\",\\\"guides/streaming.md\\\",\\\"guides/streaming\\\",[],{\\\"_16\\\":931,\\\"_22\\\":934,\\\"_24\\\":935,\\\"_26\\\":34,\\\"_27\\\":936},{\\\"_18\\\":932,\\\"_53\\\":933},\\\"Templates\\\",\\\"The quickest way to get rocking and rolling with Remix\\\",\\\"guides/templates.md\\\",\\\"guides/templates\\\",[],{\\\"_16\\\":938,\\\"_22\\\":940,\\\"_24\\\":941,\\\"_26\\\":34,\\\"_27\\\":942},{\\\"_18\\\":939,\\\"_169\\\":10},\\\"TypeScript\\\",\\\"guides/typescript.md\\\",\\\"guides/typescript\\\",[],{\\\"_16\\\":944,\\\"_22\\\":946,\\\"_24\\\":947,\\\"_26\\\":34,\\\"_27\\\":948},{\\\"_18\\\":945},\\\"Vite\\\",\\\"guides/vite.md\\\",\\\"guides/vite\\\",[],\\\"routes/docs.$\\\",{\\\"_951\\\":952},\\\"doc\\\",{\\\"_16\\\":953,\\\"_22\\\":954,\\\"_955\\\":956,\\\"_24\\\":957,\\\"_958\\\":959,\\\"_27\\\":974},{\\\"_18\\\":80,\\\"_20\\\":21},\\\"docs/discussion/introduction.md\\\",\\\"html\\\",\\\"\\u003ch1 id=\\\\\\\"introduction-technical-explanation\\\\\\\"\\u003e\\u003ca aria-hidden=\\\\\\\"true\\\\\\\" tabindex=\\\\\\\"-1\\\\\\\" href=\\\\\\\"#introduction-technical-explanation\\\\\\\"\\u003e\\u003cspan class=\\\\\\\"icon icon-link\\\\\\\"\\u003e\\u003c/span\\u003e\\u003c/a\\u003eIntroduction, Technical Explanation\\u003c/h1\\u003e\\\\n\\u003cp\\u003eBuilt on top of \\u003ca href=\\\\\\\"https://reactrouter.com\\\\\\\"\\u003eReact Router\\u003c/a\\u003e, Remix is four things:\\u003c/p\\u003e\\\\n\\u003col\\u003e\\\\n\\u003cli\\u003eA compiler\\u003c/li\\u003e\\\\n\\u003cli\\u003eA server-side HTTP handler\\u003c/li\\u003e\\\\n\\u003cli\\u003eA server framework\\u003c/li\\u003e\\\\n\\u003cli\\u003eA browser framework\\u003c/li\\u003e\\\\n\\u003c/ol\\u003e\\\\n\\u003ch2 id=\\\\\\\"compiler\\\\\\\"\\u003e\\u003ca aria-hidden=\\\\\\\"true\\\\\\\" tabindex=\\\\\\\"-1\\\\\\\" href=\\\\\\\"#compiler\\\\\\\"\\u003e\\u003cspan class=\\\\\\\"icon icon-link\\\\\\\"\\u003e\\u003c/span\\u003e\\u003c/a\\u003eCompiler\\u003c/h2\\u003e\\\\n\\u003cp\\u003eEverything in Remix starts with the compiler: \\u003ccode\\u003eremix vite:build\\u003c/code\\u003e. Using \\u003ca href=\\\\\\\"https://vitejs.dev\\\\\\\"\\u003eVite\\u003c/a\\u003e, this creates a few things:\\u003c/p\\u003e\\\\n\\u003col\\u003e\\\\n\\u003cli\\u003eA server HTTP handler, usually in \\u003ccode\\u003ebuild/server/index.js\\u003c/code\\u003e (it's configurable) that includes all routes and modules together to be able to render on the server and handle any other server-side requests for resources.\\u003c/li\\u003e\\\\n\\u003cli\\u003eA browser build, usually in \\u003ccode\\u003ebuild/client/*\\u003c/code\\u003e. This includes automatic code splitting by route, fingerprinted asset imports (like CSS and images), etc. Anything needed to run an application in the browser.\\u003c/li\\u003e\\\\n\\u003cli\\u003eAn asset manifest. Both the client and the server use this manifest to know the entire dependency graph. This is useful for preloading resources in the initial server render as well as prefetching them for client-side transitions. This is how Remix is able to eliminate the render+fetch waterfalls so common in web apps today.\\u003c/li\\u003e\\\\n\\u003c/ol\\u003e\\\\n\\u003cp\\u003eWith these build artifacts, an application can be deployed to any hosting service that runs JavaScript.\\u003c/p\\u003e\\\\n\\u003ch2 id=\\\\\\\"http-handler-and-adapters\\\\\\\"\\u003e\\u003ca aria-hidden=\\\\\\\"true\\\\\\\" tabindex=\\\\\\\"-1\\\\\\\" href=\\\\\\\"#http-handler-and-adapters\\\\\\\"\\u003e\\u003cspan class=\\\\\\\"icon icon-link\\\\\\\"\\u003e\\u003c/span\\u003e\\u003c/a\\u003eHTTP Handler and Adapters\\u003c/h2\\u003e\\\\n\\u003cp\\u003eWhile Remix runs on the server, it is not actually a server. It's just a handler that is given to an actual JavaScript server.\\u003c/p\\u003e\\\\n\\u003cp\\u003eIt's built on the \\u003ca href=\\\\\\\"https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API\\\\\\\"\\u003eWeb Fetch API\\u003c/a\\u003e instead of Node.js. This enables Remix to run in any Node.js server like \\u003ca href=\\\\\\\"https://vercel.com\\\\\\\"\\u003eVercel\\u003c/a\\u003e, \\u003ca href=\\\\\\\"https://netlify.com\\\\\\\"\\u003eNetlify\\u003c/a\\u003e, \\u003ca href=\\\\\\\"https://arc.codes\\\\\\\"\\u003eArchitect\\u003c/a\\u003e, etc. as well as non-Node.js environments like \\u003ca href=\\\\\\\"https://workers.cloudflare.com/\\\\\\\"\\u003eCloudflare Workers\\u003c/a\\u003e and \\u003ca href=\\\\\\\"https://deno.com/deploy/docs\\\\\\\"\\u003eDeno Deploy\\u003c/a\\u003e.\\u003c/p\\u003e\\\\n\\u003cp\\u003eThis is what Remix looks like when running in an express app:\\u003c/p\\u003e\\\\n\\u003cdiv data-code-block=\\\\\\\"\\\\\\\" data-line-numbers=\\\\\\\"true\\\\\\\" data-lang=\\\\\\\"typescript\\\\\\\"\\u003e\\u003cpre data-line-numbers=\\\\\\\"true\\\\\\\" data-lang=\\\\\\\"typescript\\\\\\\" style=\\\\\\\"color: var(--base05);\\\\\\\"\\u003e\\u003ccode\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"1\\\\\\\"\\u003e\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003econst\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eremix\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003erequire\\u003c/span\\u003e(\\\\\\\"\\u003cspan style=\\\\\\\"color: var(--base0B)\\\\\\\"\\u003e@remix-run/express\\u003c/span\\u003e\\\\\\\");\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-highlight=\\\\\\\"true\\\\\\\" data-line-number=\\\\\\\"2\\\\\\\"\\u003e\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003econst\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eexpress\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003erequire\\u003c/span\\u003e(\\\\\\\"\\u003cspan style=\\\\\\\"color: var(--base0B)\\\\\\\"\\u003eexpress\\u003c/span\\u003e\\\\\\\");\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"3\\\\\\\"\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"4\\\\\\\"\\u003e\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003econst\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eapp\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003eexpress\\u003c/span\\u003e();\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"5\\\\\\\"\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-highlight=\\\\\\\"true\\\\\\\" data-line-number=\\\\\\\"6\\\\\\\"\\u003e\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eapp\\u003c/span\\u003e.\\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003eall\\u003c/span\\u003e(\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-highlight=\\\\\\\"true\\\\\\\" data-line-number=\\\\\\\"7\\\\\\\"\\u003e \\\\\\\"\\u003cspan style=\\\\\\\"color: var(--base0B)\\\\\\\"\\u003e*\\u003c/span\\u003e\\\\\\\",\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-highlight=\\\\\\\"true\\\\\\\" data-line-number=\\\\\\\"8\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eremix\\u003c/span\\u003e.\\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003ecreateRequestHandler\\u003c/span\\u003e({\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-highlight=\\\\\\\"true\\\\\\\" data-line-number=\\\\\\\"9\\\\\\\"\\u003e build: \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003erequire\\u003c/span\\u003e(\\\\\\\"\\u003cspan style=\\\\\\\"color: var(--base0B)\\\\\\\"\\u003e./build/server\\u003c/span\\u003e\\\\\\\"),\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"10\\\\\\\"\\u003e })\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"11\\\\\\\"\\u003e);\\\\n\\u003c/span\\u003e\\u003c/code\\u003e\\u003c/pre\\u003e\\u003c/div\\u003e\\\\n\\u003cp\\u003eExpress (or Node.js) is the actual server, Remix is just a handler on that server. The \\u003ccode\\u003e\\\\\\\"@remix-run/express\\\\\\\"\\u003c/code\\u003e package is called an adapter. Remix handlers are server agnostic. Adapters make them work for a specific server by converting the server's request/response API into the Fetch API on the way in and then adapting the Fetch Response coming from Remix into the server's response API. Here's some pseudocode of what an adapter does:\\u003c/p\\u003e\\\\n\\u003cdiv data-code-block=\\\\\\\"\\\\\\\" data-line-numbers=\\\\\\\"true\\\\\\\" data-lang=\\\\\\\"typescript\\\\\\\"\\u003e\\u003cpre data-line-numbers=\\\\\\\"true\\\\\\\" data-lang=\\\\\\\"typescript\\\\\\\" style=\\\\\\\"color: var(--base05);\\\\\\\"\\u003e\\u003ccode\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"1\\\\\\\"\\u003e\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003eexport\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003efunction\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003ecreateRequestHandler\\u003c/span\\u003e({ \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003ebuild\\u003c/span\\u003e }) {\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"2\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base03)\\\\\\\"\\u003e// creates a Fetch API request handler from the server build\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"3\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003econst\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003ehandleRequest\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003ecreateRemixRequestHandler\\u003c/span\\u003e(\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003ebuild\\u003c/span\\u003e);\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"4\\\\\\\"\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"5\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base03)\\\\\\\"\\u003e// returns an express.js specific handler for the express server\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"6\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003ereturn\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003easync\\u003c/span\\u003e (\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003ereq\\u003c/span\\u003e, \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eres\\u003c/span\\u003e) \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003e=\\u003e\\u003c/span\\u003e {\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"7\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base03)\\\\\\\"\\u003e// adapts the express.req to a Fetch API request\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"8\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003econst\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003erequest\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003ecreateRemixRequest\\u003c/span\\u003e(\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003ereq\\u003c/span\\u003e);\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"9\\\\\\\"\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"10\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base03)\\\\\\\"\\u003e// calls the app handler and receives a Fetch API response\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"11\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003econst\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eresponse\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003eawait\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003ehandleRequest\\u003c/span\\u003e(\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003erequest\\u003c/span\\u003e);\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"12\\\\\\\"\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"13\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base03)\\\\\\\"\\u003e// adapts the Fetch API response to the express.res\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"14\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003esendRemixResponse\\u003c/span\\u003e(\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eres\\u003c/span\\u003e, \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eresponse\\u003c/span\\u003e);\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"15\\\\\\\"\\u003e };\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"16\\\\\\\"\\u003e}\\\\n\\u003c/span\\u003e\\u003c/code\\u003e\\u003c/pre\\u003e\\u003c/div\\u003e\\\\n\\u003cp\\u003eReal adapters do a bit more than that, but that's the gist of it. Not only does this enable you to deploy Remix anywhere, it also lets you incrementally adopt it in an existing JavaScript server since you can have routes outside of Remix that your server continues to handle before getting to Remix.\\u003c/p\\u003e\\\\n\\u003cp\\u003eAdditionally, if Remix doesn't have an adapter for your server already, you can look at the source of one of the adapters and build your own.\\u003c/p\\u003e\\\\n\\u003ch2 id=\\\\\\\"server-framework\\\\\\\"\\u003e\\u003ca aria-hidden=\\\\\\\"true\\\\\\\" tabindex=\\\\\\\"-1\\\\\\\" href=\\\\\\\"#server-framework\\\\\\\"\\u003e\\u003cspan class=\\\\\\\"icon icon-link\\\\\\\"\\u003e\\u003c/span\\u003e\\u003c/a\\u003eServer Framework\\u003c/h2\\u003e\\\\n\\u003cp\\u003eIf you're familiar with server-side MVC web frameworks like Rails and Laravel, Remix is the View and Controller, but it leaves the Model up to you. There are a lot of great databases, ORMs, mailers, etc. in the JavaScript ecosystem to fill that space. Remix also has helpers around the Fetch API for cookie and session management.\\u003c/p\\u003e\\\\n\\u003cp\\u003eInstead of having a split between View and Controller, Remix Route modules take on both responsibilities.\\u003c/p\\u003e\\\\n\\u003cp\\u003eMost server-side frameworks are \\\\\\\"model focused\\\\\\\". A controller manages \\u003cem\\u003emultiple URLs\\u003c/em\\u003e for a single model.\\u003c/p\\u003e\\\\n\\u003cp\\u003eRemix is \\u003cem\\u003eUI-focused\\u003c/em\\u003e. Routes can handle an entire URL or just a segment of the URL. When a route maps to just a segment, the nested URL segments become nested layouts in the UI. In this way, each layout (view) can be its own controller and then Remix will aggregate the data and components to build the complete UI.\\u003c/p\\u003e\\\\n\\u003cp\\u003eMore often than not, a Remix route module can contain both the UI and the interactions with the models in the same file, which leads to really nice developer ergonomics and productivity.\\u003c/p\\u003e\\\\n\\u003cp\\u003eRoute modules have three primary exports: \\u003ccode\\u003eloader\\u003c/code\\u003e, \\u003ccode\\u003eaction\\u003c/code\\u003e, and \\u003ccode\\u003edefault\\u003c/code\\u003e (component).\\u003c/p\\u003e\\\\n\\u003cdiv data-code-block=\\\\\\\"\\\\\\\" data-line-numbers=\\\\\\\"true\\\\\\\" data-lang=\\\\\\\"tsx\\\\\\\"\\u003e\\u003cpre data-line-numbers=\\\\\\\"true\\\\\\\" data-lang=\\\\\\\"tsx\\\\\\\" style=\\\\\\\"color: var(--base05);\\\\\\\"\\u003e\\u003ccode\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"1\\\\\\\"\\u003e\\u003cspan style=\\\\\\\"color: var(--base03)\\\\\\\"\\u003e// Loaders only run on the server and provide data\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"2\\\\\\\"\\u003e\\u003cspan style=\\\\\\\"color: var(--base03)\\\\\\\"\\u003e// to your component on GET requests\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"3\\\\\\\"\\u003e\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003eexport\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003easync\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003efunction\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003eloader\\u003c/span\\u003e() {\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"4\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003ereturn\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003ejson\\u003c/span\\u003e(\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003eawait\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003edb\\u003c/span\\u003e.\\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003eprojects\\u003c/span\\u003e.\\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003efindAll\\u003c/span\\u003e());\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"5\\\\\\\"\\u003e}\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"6\\\\\\\"\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"7\\\\\\\"\\u003e\\u003cspan style=\\\\\\\"color: var(--base03)\\\\\\\"\\u003e// The default export is the component that will be\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"8\\\\\\\"\\u003e\\u003cspan style=\\\\\\\"color: var(--base03)\\\\\\\"\\u003e// rendered when a route matches the URL. This runs\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"9\\\\\\\"\\u003e\\u003cspan style=\\\\\\\"color: var(--base03)\\\\\\\"\\u003e// both on the server and the client\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"10\\\\\\\"\\u003e\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003eexport\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003edefault\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003efunction\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003eProjects\\u003c/span\\u003e() {\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"11\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003econst\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eprojects\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003euseLoaderData\\u003c/span\\u003e\\u0026#x3C;\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003etypeof\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eloader\\u003c/span\\u003e\\u003e();\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"12\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003econst\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eactionData\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003euseActionData\\u003c/span\\u003e\\u0026#x3C;\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003etypeof\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eaction\\u003c/span\\u003e\\u003e();\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"13\\\\\\\"\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"14\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003ereturn\\u003c/span\\u003e (\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"15\\\\\\\"\\u003e \\u0026#x3C;\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003ediv\\u003c/span\\u003e\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"16\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e{\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eprojects\\u003c/span\\u003e.\\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003emap\\u003c/span\\u003e((\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eproject\\u003c/span\\u003e) \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003e=\\u003e\\u003c/span\\u003e (\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"17\\\\\\\"\\u003e \\u0026#x3C;\\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003eLink\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003ekey\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e{\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eproject\\u003c/span\\u003e.\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eslug\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e}\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003eto\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e{\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eproject\\u003c/span\\u003e.\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eslug\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e}\\u003c/span\\u003e\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"18\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e{\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eproject\\u003c/span\\u003e.\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003etitle\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e}\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"19\\\\\\\"\\u003e \\u0026#x3C;/\\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003eLink\\u003c/span\\u003e\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"20\\\\\\\"\\u003e ))\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e}\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"21\\\\\\\"\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"22\\\\\\\"\\u003e \\u0026#x3C;\\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003eForm\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003emethod\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e\\\\\\\"\\u003cspan style=\\\\\\\"color: var(--base0B)\\\\\\\"\\u003epost\\u003c/span\\u003e\\\\\\\"\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"23\\\\\\\"\\u003e \\u0026#x3C;\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003einput\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003ename\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e\\\\\\\"\\u003cspan style=\\\\\\\"color: var(--base0B)\\\\\\\"\\u003etitle\\u003c/span\\u003e\\\\\\\" /\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"24\\\\\\\"\\u003e \\u0026#x3C;\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003ebutton\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003etype\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e\\\\\\\"\\u003cspan style=\\\\\\\"color: var(--base0B)\\\\\\\"\\u003esubmit\\u003c/span\\u003e\\\\\\\"\\u003eCreate New Project\\u0026#x3C;/\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003ebutton\\u003c/span\\u003e\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"25\\\\\\\"\\u003e \\u0026#x3C;/\\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003eForm\\u003c/span\\u003e\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"26\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e{\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eactionData\\u003c/span\\u003e?.\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eerrors\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e?\\u003c/span\\u003e (\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"27\\\\\\\"\\u003e \\u0026#x3C;\\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003eErrorMessages\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003eerrors\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e{\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eactionData\\u003c/span\\u003e.\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eerrors\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e}\\u003c/span\\u003e /\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"28\\\\\\\"\\u003e ) \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e:\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base09)\\\\\\\"\\u003enull\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e}\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"29\\\\\\\"\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"30\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e{\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base03)\\\\\\\"\\u003e/* outlets render the nested child routes\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"31\\\\\\\"\\u003e\\u003cspan style=\\\\\\\"color: var(--base03)\\\\\\\"\\u003e that match the URL deeper than this route,\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"32\\\\\\\"\\u003e\\u003cspan style=\\\\\\\"color: var(--base03)\\\\\\\"\\u003e allowing each layout to co-locate the UI and\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"33\\\\\\\"\\u003e\\u003cspan style=\\\\\\\"color: var(--base03)\\\\\\\"\\u003e controller code in the same file */\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e}\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"34\\\\\\\"\\u003e \\u0026#x3C;\\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003eOutlet\\u003c/span\\u003e /\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"35\\\\\\\"\\u003e \\u0026#x3C;/\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003ediv\\u003c/span\\u003e\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"36\\\\\\\"\\u003e );\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"37\\\\\\\"\\u003e}\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"38\\\\\\\"\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"39\\\\\\\"\\u003e\\u003cspan style=\\\\\\\"color: var(--base03)\\\\\\\"\\u003e// Actions only run on the server and handle POST\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"40\\\\\\\"\\u003e\\u003cspan style=\\\\\\\"color: var(--base03)\\\\\\\"\\u003e// PUT, PATCH, and DELETE. They can also provide data\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"41\\\\\\\"\\u003e\\u003cspan style=\\\\\\\"color: var(--base03)\\\\\\\"\\u003e// to the component\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"42\\\\\\\"\\u003e\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003eexport\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003easync\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003efunction\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003eaction\\u003c/span\\u003e({\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"43\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003erequest\\u003c/span\\u003e,\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"44\\\\\\\"\\u003e}\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e:\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003eActionFunctionArgs\\u003c/span\\u003e) {\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"45\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003econst\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eform\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003eawait\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003erequest\\u003c/span\\u003e.\\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003eformData\\u003c/span\\u003e();\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"46\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003econst\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eerrors\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003evalidate\\u003c/span\\u003e(\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eform\\u003c/span\\u003e);\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"47\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003eif\\u003c/span\\u003e (\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eerrors\\u003c/span\\u003e) {\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"48\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003ereturn\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003ejson\\u003c/span\\u003e({ \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eerrors\\u003c/span\\u003e });\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"49\\\\\\\"\\u003e }\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"50\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003eawait\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003ecreateProject\\u003c/span\\u003e({ title: \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eform\\u003c/span\\u003e.\\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003eget\\u003c/span\\u003e(\\\\\\\"\\u003cspan style=\\\\\\\"color: var(--base0B)\\\\\\\"\\u003etitle\\u003c/span\\u003e\\\\\\\") });\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"51\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003ereturn\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003ejson\\u003c/span\\u003e({ ok: \\u003cspan style=\\\\\\\"color: var(--base09)\\\\\\\"\\u003etrue\\u003c/span\\u003e });\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"52\\\\\\\"\\u003e}\\\\n\\u003c/span\\u003e\\u003c/code\\u003e\\u003c/pre\\u003e\\u003c/div\\u003e\\\\n\\u003cp\\u003eYou can actually use Remix as just a server-side framework without using any browser JavaScript at all. The route conventions for data loading with \\u003ccode\\u003eloader\\u003c/code\\u003e, mutations with \\u003ccode\\u003eaction\\u003c/code\\u003e and HTML forms, and components that render at URLs, can provide the core feature set of a lot of web projects.\\u003c/p\\u003e\\\\n\\u003cp\\u003eIn this way, \\u003cstrong\\u003eRemix scales down\\u003c/strong\\u003e. Not every page in your application needs a bunch of JavaScript in the browser, and not every user interaction requires any extra flair than the browser's default behaviors. In Remix, you can build it the simple way first, and then scale up without changing the fundamental model. Additionally, the majority of the app works before JavaScript loads in the browser, which makes Remix apps resilient to choppy network conditions by design.\\u003c/p\\u003e\\\\n\\u003cp\\u003eIf you're not familiar with traditional back-end web frameworks, you can think of Remix routes as React components that are already their own API route and already know how to load and submit data to themselves on the server.\\u003c/p\\u003e\\\\n\\u003ch2 id=\\\\\\\"browser-framework\\\\\\\"\\u003e\\u003ca aria-hidden=\\\\\\\"true\\\\\\\" tabindex=\\\\\\\"-1\\\\\\\" href=\\\\\\\"#browser-framework\\\\\\\"\\u003e\\u003cspan class=\\\\\\\"icon icon-link\\\\\\\"\\u003e\\u003c/span\\u003e\\u003c/a\\u003eBrowser Framework\\u003c/h2\\u003e\\\\n\\u003cp\\u003eOnce Remix has served the document to the browser, it \\\\\\\"hydrates\\\\\\\" the page with the browser build's JavaScript modules. This is where we talk a lot about Remix \\\\\\\"emulating the browser\\\\\\\".\\u003c/p\\u003e\\\\n\\u003cp\\u003eWhen the user clicks a link, instead of making a round trip to the server for the entire document and all the assets, Remix simply fetches the data for the next page and updates the UI.\\u003c/p\\u003e\\\\n\\u003cp\\u003eAdditionally, when users submit a \\u003ccode\\u003e\\u0026#x3C;Form\\u003e\\u003c/code\\u003e to update data, instead of doing a normal HTML document request, the browser runtime will make a fetch to the server instead and automatically revalidate all data on the page and update it with React.\\u003c/p\\u003e\\\\n\\u003cp\\u003eThis has many performance benefits over making a full-document request:\\u003c/p\\u003e\\\\n\\u003col\\u003e\\\\n\\u003cli\\u003eAssets don't need to be re-downloaded (or pulled from the cache)\\u003c/li\\u003e\\\\n\\u003cli\\u003eAssets don't need to be parsed by the browser again\\u003c/li\\u003e\\\\n\\u003cli\\u003eThe data fetched is much smaller than the entire document (sometimes orders of magnitude)\\u003c/li\\u003e\\\\n\\u003cli\\u003eBecause Remix enhances HTML APIs (\\u003ccode\\u003e\\u0026#x3C;a\\u003e\\u003c/code\\u003e and \\u003ccode\\u003e\\u0026#x3C;form\\u003e\\u003c/code\\u003e), your app tends to work even before JavaScript has loaded on the page\\u003c/li\\u003e\\\\n\\u003c/ol\\u003e\\\\n\\u003cp\\u003eRemix also has some built-in optimizations for client-side navigation. It knows which layouts will persist between the two URLs, so it only fetches the data for the ones that are changing. A full document request would require all data to be fetched on the server, wasting resources on your back end and slowing down your app.\\u003c/p\\u003e\\\\n\\u003cp\\u003eThis approach also has UX benefits like not resetting the scroll position of a sidebar nav and allowing you to move focus to something that makes more sense than the top of the document.\\u003c/p\\u003e\\\\n\\u003cp\\u003eRemix can also prefetch all resources for a page when the user is about to click a link. The browser framework knows about the compiler's asset manifest. It can match the URL of the link, read the manifest, and then prefetch all data, JavaScript modules, and even CSS resources for the next page. This is how Remix apps feel fast even when networks are slow.\\u003c/p\\u003e\\\\n\\u003cp\\u003eRemix then provides client side APIs, so you can create rich user experiences without changing the fundamental model of HTML and browsers.\\u003c/p\\u003e\\\\n\\u003cp\\u003eTaking our route module from before, here are a few small but useful UX improvements to the form that you can only do with JavaScript in the browser:\\u003c/p\\u003e\\\\n\\u003col\\u003e\\\\n\\u003cli\\u003eDisable the button when the form is being submitted\\u003c/li\\u003e\\\\n\\u003cli\\u003eFocus the input when server-side form validation fails\\u003c/li\\u003e\\\\n\\u003cli\\u003eAnimate in the error messages\\u003c/li\\u003e\\\\n\\u003c/ol\\u003e\\\\n\\u003cdiv data-code-block=\\\\\\\"\\\\\\\" data-nocopy=\\\\\\\"\\\\\\\" data-line-numbers=\\\\\\\"true\\\\\\\" data-lang=\\\\\\\"tsx\\\\\\\"\\u003e\\u003cpre data-nocopy=\\\\\\\"\\\\\\\" data-line-numbers=\\\\\\\"true\\\\\\\" data-lang=\\\\\\\"tsx\\\\\\\" style=\\\\\\\"color: var(--base05);\\\\\\\"\\u003e\\u003ccode\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"1\\\\\\\"\\u003e\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003eexport\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003edefault\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003efunction\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003eProjects\\u003c/span\\u003e() {\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"2\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003econst\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eprojects\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003euseLoaderData\\u003c/span\\u003e\\u0026#x3C;\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003etypeof\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eloader\\u003c/span\\u003e\\u003e();\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"3\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003econst\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eactionData\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003euseActionData\\u003c/span\\u003e\\u0026#x3C;\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003etypeof\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eaction\\u003c/span\\u003e\\u003e();\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-highlight=\\\\\\\"true\\\\\\\" data-line-number=\\\\\\\"4\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003econst\\u003c/span\\u003e { \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003estate\\u003c/span\\u003e } \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003euseNavigation\\u003c/span\\u003e();\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-highlight=\\\\\\\"true\\\\\\\" data-line-number=\\\\\\\"5\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003econst\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003ebusy\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003estate\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e===\\u003c/span\\u003e \\\\\\\"\\u003cspan style=\\\\\\\"color: var(--base0B)\\\\\\\"\\u003esubmitting\\u003c/span\\u003e\\\\\\\";\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-highlight=\\\\\\\"true\\\\\\\" data-line-number=\\\\\\\"6\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003econst\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003einputRef\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eReact\\u003c/span\\u003e.\\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003euseRef\\u003c/span\\u003e();\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"7\\\\\\\"\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-highlight=\\\\\\\"true\\\\\\\" data-line-number=\\\\\\\"8\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eReact\\u003c/span\\u003e.\\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003euseEffect\\u003c/span\\u003e(() \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003e=\\u003e\\u003c/span\\u003e {\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-highlight=\\\\\\\"true\\\\\\\" data-line-number=\\\\\\\"9\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003eif\\u003c/span\\u003e (\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eactionData\\u003c/span\\u003e.\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eerrors\\u003c/span\\u003e) {\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-highlight=\\\\\\\"true\\\\\\\" data-line-number=\\\\\\\"10\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003einputRef\\u003c/span\\u003e.\\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003ecurrent\\u003c/span\\u003e.\\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003efocus\\u003c/span\\u003e();\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-highlight=\\\\\\\"true\\\\\\\" data-line-number=\\\\\\\"11\\\\\\\"\\u003e }\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-highlight=\\\\\\\"true\\\\\\\" data-line-number=\\\\\\\"12\\\\\\\"\\u003e }, [\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eactionData\\u003c/span\\u003e]);\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"13\\\\\\\"\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"14\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003ereturn\\u003c/span\\u003e (\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"15\\\\\\\"\\u003e \\u0026#x3C;\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003ediv\\u003c/span\\u003e\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"16\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e{\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eprojects\\u003c/span\\u003e.\\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003emap\\u003c/span\\u003e((\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eproject\\u003c/span\\u003e) \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003e=\\u003e\\u003c/span\\u003e (\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"17\\\\\\\"\\u003e \\u0026#x3C;\\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003eLink\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003ekey\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e{\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eproject\\u003c/span\\u003e.\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eslug\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e}\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003eto\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e{\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eproject\\u003c/span\\u003e.\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eslug\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e}\\u003c/span\\u003e\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"18\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e{\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eproject\\u003c/span\\u003e.\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003etitle\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e}\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"19\\\\\\\"\\u003e \\u0026#x3C;/\\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003eLink\\u003c/span\\u003e\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"20\\\\\\\"\\u003e ))\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e}\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"21\\\\\\\"\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"22\\\\\\\"\\u003e \\u0026#x3C;\\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003eForm\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003emethod\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e\\\\\\\"\\u003cspan style=\\\\\\\"color: var(--base0B)\\\\\\\"\\u003epost\\u003c/span\\u003e\\\\\\\"\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-highlight=\\\\\\\"true\\\\\\\" data-line-number=\\\\\\\"23\\\\\\\"\\u003e \\u0026#x3C;\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003einput\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003eref\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e{\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003einputRef\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e}\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003ename\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e\\\\\\\"\\u003cspan style=\\\\\\\"color: var(--base0B)\\\\\\\"\\u003etitle\\u003c/span\\u003e\\\\\\\" /\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-highlight=\\\\\\\"true\\\\\\\" data-line-number=\\\\\\\"24\\\\\\\"\\u003e \\u0026#x3C;\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003ebutton\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003etype\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e\\\\\\\"\\u003cspan style=\\\\\\\"color: var(--base0B)\\\\\\\"\\u003esubmit\\u003c/span\\u003e\\\\\\\" \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003edisabled\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e{\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003ebusy\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e}\\u003c/span\\u003e\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-highlight=\\\\\\\"true\\\\\\\" data-line-number=\\\\\\\"25\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e{\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003ebusy\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e?\\u003c/span\\u003e \\\\\\\"\\u003cspan style=\\\\\\\"color: var(--base0B)\\\\\\\"\\u003eCreating...\\u003c/span\\u003e\\\\\\\" \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e:\\u003c/span\\u003e \\\\\\\"\\u003cspan style=\\\\\\\"color: var(--base0B)\\\\\\\"\\u003eCreate New Project\\u003c/span\\u003e\\\\\\\"\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e}\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-highlight=\\\\\\\"true\\\\\\\" data-line-number=\\\\\\\"26\\\\\\\"\\u003e \\u0026#x3C;/\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003ebutton\\u003c/span\\u003e\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"27\\\\\\\"\\u003e \\u0026#x3C;/\\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003eForm\\u003c/span\\u003e\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"28\\\\\\\"\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"29\\\\\\\"\\u003e \\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e{\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eactionData\\u003c/span\\u003e?.\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eerrors\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e?\\u003c/span\\u003e (\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-highlight=\\\\\\\"true\\\\\\\" data-line-number=\\\\\\\"30\\\\\\\"\\u003e \\u0026#x3C;\\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003eFadeIn\\u003c/span\\u003e\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-highlight=\\\\\\\"true\\\\\\\" data-line-number=\\\\\\\"31\\\\\\\"\\u003e \\u0026#x3C;\\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003eErrorMessages\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base0D)\\\\\\\"\\u003eerrors\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e=\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e{\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eactionData\\u003c/span\\u003e.\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003eerrors\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e}\\u003c/span\\u003e /\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-highlight=\\\\\\\"true\\\\\\\" data-line-number=\\\\\\\"32\\\\\\\"\\u003e \\u0026#x3C;/\\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003eFadeIn\\u003c/span\\u003e\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"33\\\\\\\"\\u003e ) \\u003cspan style=\\\\\\\"color: var(--base0E)\\\\\\\"\\u003e:\\u003c/span\\u003e \\u003cspan style=\\\\\\\"color: var(--base09)\\\\\\\"\\u003enull\\u003c/span\\u003e\\u003cspan style=\\\\\\\"color: var(--base0F)\\\\\\\"\\u003e}\\u003c/span\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"34\\\\\\\"\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"35\\\\\\\"\\u003e \\u0026#x3C;\\u003cspan style=\\\\\\\"color: var(--base0A)\\\\\\\"\\u003eOutlet\\u003c/span\\u003e /\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"36\\\\\\\"\\u003e \\u0026#x3C;/\\u003cspan style=\\\\\\\"color: var(--base08)\\\\\\\"\\u003ediv\\u003c/span\\u003e\\u003e\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"37\\\\\\\"\\u003e );\\\\n\\u003c/span\\u003e\\u003cspan class=\\\\\\\"codeblock-line\\\\\\\" data-line-number=\\\\\\\"38\\\\\\\"\\u003e}\\\\n\\u003c/span\\u003e\\u003c/code\\u003e\\u003c/pre\\u003e\\u003c/div\\u003e\\\\n\\u003cp\\u003eWhat's most interesting about this code sample is that it is \\u003cstrong\\u003eonly additive\\u003c/strong\\u003e. The entire interaction is still fundamentally the same thing and even works at a basic level before JavaScript loads, the only difference is the user will be provided by the browser (spinning favicon, etc.) instead of the app (\\u003ccode\\u003euseNavigation().state\\u003c/code\\u003e).\\u003c/p\\u003e\\\\n\\u003cp\\u003eBecause Remix reaches into the controller level of the backend, it can do this seamlessly.\\u003c/p\\u003e\\\\n\\u003cp\\u003eAnd while it doesn't reach as far back into the stack as server-side frameworks like Rails and Laravel, it does reach way farther up the stack into the browser to make the transition from the back end to the front end seamless.\\u003c/p\\u003e\\\\n\\u003cp\\u003eFor example. Building a plain HTML form and server-side handler in a back-end heavy web framework is just as easy to do as it is in Remix. But as soon as you want to cross over into an experience with animated validation messages, focus management, and pending UI, it requires a fundamental change in the code. Typically, people build an API route and then bring in a splash of client-side JavaScript to connect the two. With Remix, you simply add some code around the existing \\\\\\\"server side view\\\\\\\" without changing how it works fundamentally. The browser runtime takes over the server communication to provide an enhanced user experience beyond the default browser behaviors.\\u003c/p\\u003e\\\\n\\u003cp\\u003eWe borrowed an old term and called this Progressive Enhancement in Remix. Start small with a plain HTML form (Remix scales down) and then scale the UI up when you have the time and ambition.\\u003c/p\\u003e\\\",\\\"docs/discussion/introduction\\\",\\\"headings\\\",[960,965,968,971],{\\\"_961\\\":962,\\\"_955\\\":963,\\\"_24\\\":964},\\\"headingLevel\\\",\\\"h2\\\",\\\"Compiler\\\",\\\"compiler\\\",{\\\"_961\\\":962,\\\"_955\\\":966,\\\"_24\\\":967},\\\"HTTP Handler and Adapters\\\",\\\"http-handler-and-adapters\\\",{\\\"_961\\\":962,\\\"_955\\\":969,\\\"_24\\\":970},\\\"Server Framework\\\",\\\"server-framework\\\",{\\\"_961\\\":962,\\\"_955\\\":972,\\\"_24\\\":973},\\\"Browser Framework\\\",\\\"browser-framework\\\",[],\\\"actionData\\\",\\\"errors\\\"]\\n\");function $RC(a,b){a=document.getElementById(a);b=document.getElementById(b);b.parentNode.removeChild(b);if(a){a=a.previousSibling;var f=a.parentNode,c=a.nextSibling,e=0;do{if(c\u0026\u00268===c.nodeType){var d=c.data;if(\"/$\"===d)if(0===e)break;else e--;else\"$\"!==d\u0026\u0026\"$?\"!==d\u0026\u0026\"$!\"!==d||e++}d=c.nextSibling;f.removeChild(c);c=d}while(c);for(;b.firstChild;)f.insertBefore(b.firstChild,c);a.data=\"$\";a._reactRetry\u0026\u0026a._reactRetry()}};$RC(\"B:0\",\"S:0\")window.__reactRouterContext.streamController.close();$RC(\"B:1\",\"S:1\")",
|
|
"url": "https://v2.remix.run/docs/discussion/introduction",
|
|
"metadata": {
|
|
"description": "",
|
|
"headings": [
|
|
"Introduction, Technical Explanation",
|
|
"Compiler",
|
|
"HTTP Handler and Adapters",
|
|
"Server Framework",
|
|
"Browser Framework"
|
|
],
|
|
"images": [
|
|
"/assets/icons-CZ8v8NWl.svg"
|
|
],
|
|
"links": [
|
|
"/",
|
|
"/docs",
|
|
"https://remix.run/blog",
|
|
"/resources",
|
|
"https://reactrouter.com/home",
|
|
"https://github.com/remix-run/remix/tree/v2",
|
|
"https://rmx.as/discord",
|
|
"/docs/start/quickstart",
|
|
"/docs/start/tutorial",
|
|
"/docs/start/v2",
|
|
"/docs/start/community",
|
|
"/docs/start/future-flags",
|
|
"/docs/start/changelog",
|
|
"/docs/discussion/introduction",
|
|
"/docs/discussion/runtimes",
|
|
"/docs/discussion/routes",
|
|
"/docs/discussion/data-flow",
|
|
"/docs/discussion/server-vs-client",
|
|
"/docs/discussion/react-router",
|
|
"/docs/discussion/progressive-enhancement",
|
|
"/docs/discussion/pending-ui",
|
|
"/docs/discussion/state-management",
|
|
"/docs/discussion/concurrency",
|
|
"/docs/discussion/form-vs-fetcher",
|
|
"/docs/discussion/hot-module-replacement",
|
|
"/docs/discussion/resubmissions",
|
|
"/docs/file-conventions/-client",
|
|
"/docs/file-conventions/-server",
|
|
"/docs/file-conventions/asset-imports",
|
|
"/docs/file-conventions/entry.client",
|
|
"/docs/file-conventions/entry.server",
|
|
"/docs/file-conventions/root",
|
|
"/docs/file-conventions/routes",
|
|
"/docs/file-conventions/vite-config",
|
|
"/docs/route/action",
|
|
"/docs/route/client-action",
|
|
"/docs/route/client-loader",
|
|
"/docs/route/component",
|
|
"/docs/route/error-boundary",
|
|
"/docs/route/handle",
|
|
"/docs/route/headers",
|
|
"/docs/route/hydrate-fallback",
|
|
"/docs/route/links",
|
|
"/docs/route/loader",
|
|
"/docs/route/meta",
|
|
"/docs/route/should-revalidate",
|
|
"/docs/components/await",
|
|
"/docs/components/form",
|
|
"/docs/components/link",
|
|
"/docs/components/links",
|
|
"/docs/components/live-reload",
|
|
"/docs/components/meta",
|
|
"/docs/components/nav-link",
|
|
"/docs/components/outlet",
|
|
"/docs/components/prefetch-page-links",
|
|
"/docs/components/scripts",
|
|
"/docs/components/scroll-restoration",
|
|
"/docs/hooks/use-action-data",
|
|
"/docs/hooks/use-async-error",
|
|
"/docs/hooks/use-async-value",
|
|
"/docs/hooks/use-before-unload",
|
|
"/docs/hooks/use-blocker",
|
|
"/docs/hooks/use-fetcher",
|
|
"/docs/hooks/use-fetchers",
|
|
"/docs/hooks/use-form-action",
|
|
"/docs/hooks/use-href",
|
|
"/docs/hooks/use-loader-data",
|
|
"/docs/hooks/use-location",
|
|
"/docs/hooks/use-matches",
|
|
"/docs/hooks/use-navigate",
|
|
"/docs/hooks/use-navigation",
|
|
"/docs/hooks/use-navigation-type",
|
|
"/docs/hooks/use-outlet",
|
|
"/docs/hooks/use-outlet-context",
|
|
"/docs/hooks/use-params",
|
|
"/docs/hooks/use-prompt",
|
|
"/docs/hooks/use-resolved-path",
|
|
"/docs/hooks/use-revalidator",
|
|
"/docs/hooks/use-route-error",
|
|
"/docs/hooks/use-route-loader-data",
|
|
"/docs/hooks/use-search-params",
|
|
"/docs/hooks/use-submit",
|
|
"/docs/hooks/use-view-transition-state",
|
|
"/docs/utils/cookies",
|
|
"/docs/utils/create-remix-stub",
|
|
"/docs/utils/data",
|
|
"/docs/utils/defer",
|
|
"/docs/utils/is-route-error-response",
|
|
"/docs/utils/json",
|
|
"/docs/utils/parse-multipart-form-data",
|
|
"/docs/utils/redirect",
|
|
"/docs/utils/redirectDocument",
|
|
"/docs/utils/replace",
|
|
"/docs/utils/sessions",
|
|
"/docs/utils/unstable-create-file-upload-handler",
|
|
"/docs/utils/unstable-create-memory-upload-handler",
|
|
"/docs/styling/bundling",
|
|
"/docs/styling/css",
|
|
"/docs/styling/css-imports",
|
|
"/docs/styling/css-in-js",
|
|
"/docs/styling/css-modules",
|
|
"/docs/styling/postcss",
|
|
"/docs/styling/tailwind",
|
|
"/docs/styling/vanilla-extract",
|
|
"/docs/other-api/dev",
|
|
"/docs/other-api/adapter",
|
|
"/docs/other-api/serve",
|
|
"/docs/other-api/create-remix",
|
|
"/docs/other-api/node",
|
|
"/docs/other-api/testing",
|
|
"/docs/guides/accessibility",
|
|
"/docs/guides/api-development-strategy",
|
|
"/docs/guides/api-routes",
|
|
"/docs/guides/bff",
|
|
"/docs/guides/breadcrumbs",
|
|
"/docs/guides/browser-support",
|
|
"/docs/guides/client-data",
|
|
"/docs/guides/constraints",
|
|
"/docs/guides/contributing",
|
|
"/docs/guides/css-files",
|
|
"/docs/guides/data-loading",
|
|
"/docs/guides/data-writes",
|
|
"/docs/guides/dependency-optimization",
|
|
"/docs/guides/deployment",
|
|
"/docs/guides/disabling-javascript",
|
|
"/docs/guides/envvars",
|
|
"/docs/guides/errors",
|
|
"/docs/guides/faq",
|
|
"/docs/guides/file-uploads",
|
|
"/docs/guides/form-validation",
|
|
"/docs/guides/gotchas",
|
|
"/docs/guides/index-query-param",
|
|
"/docs/guides/lazy-route-discovery",
|
|
"/docs/guides/local-tls",
|
|
"/docs/guides/manual-mode",
|
|
"/docs/guides/mdx",
|
|
"/docs/guides/migrating-react-router-app",
|
|
"/docs/guides/not-found",
|
|
"/docs/guides/performance",
|
|
"/docs/guides/presets",
|
|
"/docs/guides/resource-routes",
|
|
"/docs/guides/server-bundles",
|
|
"/docs/guides/single-fetch",
|
|
"/docs/guides/spa-mode",
|
|
"/docs/guides/streaming",
|
|
"/docs/guides/templates",
|
|
"/docs/guides/typescript",
|
|
"/docs/guides/vite",
|
|
"/docs/discussion/introduction/#compiler",
|
|
"/docs/discussion/introduction/#http-handler-and-adapters",
|
|
"/docs/discussion/introduction/#server-framework",
|
|
"/docs/discussion/introduction/#browser-framework",
|
|
"https://reactrouter.com",
|
|
"https://vitejs.dev",
|
|
"https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API",
|
|
"https://vercel.com",
|
|
"https://netlify.com",
|
|
"https://arc.codes",
|
|
"https://workers.cloudflare.com/",
|
|
"https://deno.com/deploy/docs",
|
|
"https://remix.run",
|
|
"https://opensource.org/licenses/MIT",
|
|
"https://github.com/remix-run/remix-v2-website/edit/main/data/docs/discussion/introduction.md"
|
|
]
|
|
},
|
|
"hash": "e07a4ca51d1b0f61947613228d3b5936bf915d9fd9855beb05fb07e7c6c783b7",
|
|
"timestamp": "2026-02-23T11:36:17.684740972+01:00"
|
|
} |