From 7a1b8d93134c4ea144cd9642f08b96a522bc9471 Mon Sep 17 00:00:00 2001 From: Pedro Cattori Date: Tue, 3 May 2022 10:45:03 -0400 Subject: [PATCH] docs: replace `{runtime}` in imports with concrete server runtime (#3072) so that our example are actual code and is less confusing to newcomers fixes #3007 --- docs/api/conventions.md | 36 +++++++++++------------ docs/api/remix.md | 52 +++++++++++++++++----------------- docs/guides/constraints.md | 12 ++++---- docs/guides/data-loading.md | 30 ++++++++++---------- docs/guides/data-writes.md | 10 +++---- docs/guides/mdx.md | 2 +- docs/guides/optimistic-ui.md | 10 +++---- docs/guides/resource-routes.md | 10 +++---- docs/guides/styling.md | 10 +++---- docs/other-api/node.md | 2 +- docs/other-api/serve.md | 2 +- docs/pages/faq.md | 2 +- docs/pages/gotchas.md | 8 +++--- docs/pages/philosophy.md | 2 +- 14 files changed, 94 insertions(+), 94 deletions(-) diff --git a/docs/api/conventions.md b/docs/api/conventions.md index 26c0db30ea1..4918debb29f 100644 --- a/docs/api/conventions.md +++ b/docs/api/conventions.md @@ -263,7 +263,7 @@ import { useParams } from "@remix-run/react"; import type { LoaderFunction, ActionFunction, -} from "@remix-run/{runtime}"; +} from "@remix-run/node"; // or "@remix-run/cloudflare" export const loader: LoaderFunction = async ({ params, @@ -426,7 +426,7 @@ import { useParams } from "@remix-run/react"; import type { LoaderFunction, ActionFunction, -} from "@remix-run/{runtime}"; +} from "@remix-run/node"; // or "@remix-run/cloudflare" export const loader: LoaderFunction = async ({ params, @@ -488,7 +488,7 @@ import { renderToString } from "react-dom/server"; import type { EntryContext, HandleDataRequestFunction, -} from "@remix-run/{runtime}"; +} from "@remix-run/node"; // or "@remix-run/cloudflare" import { RemixServer } from "@remix-run/react"; export default function handleRequest( @@ -549,7 +549,7 @@ export default function SomeRouteComponent() { Each route can define a "loader" function that will be called on the server before rendering to provide data to the route. ```js -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" export const loader = async () => { // The `json` function converts a serializable object into a JSON response @@ -560,8 +560,8 @@ export const loader = async () => { ```ts // Typescript -import { json } from "@remix-run/{runtime}"; -import type { LoaderFunction } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" +import type { LoaderFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" export const loader: LoaderFunction = async () => { return json({ ok: true }); @@ -573,7 +573,7 @@ This function is only ever run on the server. On the initial server render it wi Using the database ORM Prisma as an example: ```tsx lines=[1-2,6-8,11] -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import { useLoaderData } from "@remix-run/react"; import { prisma } from "../db"; @@ -684,7 +684,7 @@ export const loader: LoaderFunction = async () => { Using the `json` helper simplifies this so you don't have to construct them yourself, but these two examples are effectively the same! ```tsx -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" export const loader: LoaderFunction = async () => { const users = await fakeDb.users.findMany(); @@ -695,7 +695,7 @@ export const loader: LoaderFunction = async () => { You can see how `json` just does a little of the work to make your loader a lot cleaner. You can also use the `json` helper to add headers or a status code to your response: ```tsx -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" export const loader: LoaderFunction = async ({ params, @@ -724,7 +724,7 @@ Along with returning responses, you can also throw Response objects from your lo Here is a full example showing how you can create utility functions that throw responses to stop code execution in the loader and move over to an alternative UI. ```ts filename=app/db.ts -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import type { ThrownResponse } from "@remix-run/react"; export type InvoiceNotFoundResponse = ThrownResponse< @@ -742,7 +742,7 @@ export function getInvoice(id, user) { ``` ```ts filename=app/http.ts -import { redirect } from "@remix-run/{runtime}"; +import { redirect } from "@remix-run/node"; // or "@remix-run/cloudflare" import { getSession } from "./session"; @@ -838,7 +838,7 @@ Actions have the same API as loaders, the only difference is when they are calle This enables you to co-locate everything about a data set in a single route module: the data read, the component that renders the data, and the data writes: ```tsx -import { json, redirect } from "@remix-run/{runtime}"; +import { json, redirect } from "@remix-run/node"; // or "@remix-run/cloudflare" import { Form } from "@remix-run/react"; import { fakeGetTodos, fakeCreateTodo } from "~/utils/db"; @@ -971,7 +971,7 @@ Note that you can also add headers in your `entry.server` file for things that s ```tsx lines=[16] import { renderToString } from "react-dom/server"; import { RemixServer } from "@remix-run/react"; -import type { EntryContext } from "@remix-run/{runtime}"; +import type { EntryContext } from "@remix-run/node"; // or "@remix-run/cloudflare" export default function handleRequest( request: Request, @@ -1000,7 +1000,7 @@ Just keep in mind that doing this will apply to _all_ document requests, but doe The meta export will set meta tags for your html document. We highly recommend setting the title and description on every route besides layout routes (their index route will set the meta). ```tsx -import type { MetaFunction } from "@remix-run/{runtime}"; +import type { MetaFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" export const meta: MetaFunction = () => { return { @@ -1030,7 +1030,7 @@ As a last option, you can also pass an object of attribute/value pairs as the va Examples: ```tsx -import type { MetaFunction } from "@remix-run/{runtime}"; +import type { MetaFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" export const meta: MetaFunction = () => ({ // Special cases @@ -1081,7 +1081,7 @@ export const meta: MetaFunction = ({ data, params }) => { The links function defines which `` elements to add to the page when the user visits a route. ```tsx -import type { LinksFunction } from "@remix-run/{runtime}"; +import type { LinksFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" export const links: LinksFunction = () => { return [ @@ -1115,7 +1115,7 @@ The `links` export from a route should return an array of `HtmlLinkDescriptor` o Examples: ```tsx -import type { LinksFunction } from "@remix-run/{runtime}"; +import type { LinksFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" import stylesHref from "../styles/something.css"; @@ -1392,7 +1392,7 @@ Any files inside the `app` folder can be imported into your modules. Remix will: It's most common for stylesheets, but can used for anything. ```tsx filename=app/routes/root.tsx -import type { LinksFunction } from "@remix-run/{runtime}"; +import type { LinksFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" import styles from "./styles/app.css"; import banner from "./images/banner.jpg"; diff --git a/docs/api/remix.md b/docs/api/remix.md index 525a27da54b..960b710e105 100644 --- a/docs/api/remix.md +++ b/docs/api/remix.md @@ -33,7 +33,7 @@ These components are to be used once inside of your root route (`root.tsx`). The import type { LinksFunction, MetaFunction, -} from "@remix-run/{runtime}"; +} from "@remix-run/node"; // or "@remix-run/cloudflare" import { Links, LiveReload, @@ -331,7 +331,7 @@ In order to avoid (usually) the client-side routing "scroll flash" on refresh or This hook returns the JSON parsed data from your route loader function. ```tsx lines=[2,9] -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import { useLoaderData } from "@remix-run/react"; export async function loader() { @@ -349,7 +349,7 @@ export default function Invoices() { This hook returns the JSON parsed data from your route action. It returns `undefined` if there hasn't been a submission at the current location yet. ```tsx lines=[2,11,20] -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import { useActionData, Form } from "@remix-run/react"; export async function action({ request }) { @@ -377,7 +377,7 @@ export default function Invoices() { The most common use-case for this hook is form validation errors. If the form isn't right, you can simply return the errors and let the user try again (instead of pushing all the errors into sessions and back out of the loader). ```tsx lines=[22, 31, 39-41, 45-47] -import { redirect, json } from "@remix-run/{runtime}"; +import { redirect, json } from "@remix-run/node"; // or "@remix-run/cloudflare" import { Form, useActionData } from "@remix-run/react"; export async function action({ request }) { @@ -522,7 +522,7 @@ Returns the function that may be used to submit a `
` (or some raw `FormDat This is useful whenever you need to programmatically submit a form. For example, you may wish to save a user preferences form whenever any field changes. ```tsx filename=app/routes/prefs.tsx lines=[2,14,18] -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import { useSubmit, useTransition } from "@remix-run/react"; export async function loader() { @@ -1433,8 +1433,8 @@ function SomeForm() { This is a shortcut for creating `application/json` responses. It assumes you are using `utf-8` encoding. ```ts lines=[2,6] -import type { LoaderFunction } from "@remix-run/{runtime}"; -import { json } from "@remix-run/{runtime}"; +import type { LoaderFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" export const loader: LoaderFunction = async () => { // So you can write this: @@ -1470,8 +1470,8 @@ export const loader: LoaderFunction = async () => { This is shortcut for sending 30x responses. ```ts lines=[2,8] -import type { ActionFunction } from "@remix-run/{runtime}"; -import { redirect } from "@remix-run/{runtime}"; +import type { ActionFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" +import { redirect } from "@remix-run/node"; // or "@remix-run/cloudflare" export const action: ActionFunction = async () => { const userSession = await getUserSessionOrWhatever(); @@ -1651,7 +1651,7 @@ Most of the time, you'll probably want to proxy the file stream to a file host. **Example:** ```tsx -import type { UploadHandler } from "@remix-run/{runtime}"; +import type { UploadHandler } from "@remix-run/node"; // or "@remix-run/cloudflare" import type { UploadApiErrorResponse, UploadApiOptions, @@ -1739,8 +1739,8 @@ Your job is to do whatever you need with the `stream` and return a value that's We have the built-in `unstable_createFileUploadHandler` and `unstable_createMemoryUploadHandler` and we also expect more upload handler utilities to be developed in the future. If you have a form that needs to use different upload handlers, you can compose them together with a custom handler, here's a theoretical example: ```tsx filename=file-upload-handler.server.tsx -import type { UploadHandler } from "@remix-run/{runtime}"; -import { unstable_createFileUploadHandler } from "@remix-run/{runtime}"; +import type { UploadHandler } from "@remix-run/node"; // or "@remix-run/cloudflare" +import { unstable_createFileUploadHandler } from "@remix-run/node"; // or "@remix-run/cloudflare" import { createCloudinaryUploadHandler } from "some-handy-remix-util"; export const standardFileUploadHandler = @@ -1781,7 +1781,7 @@ Let's say you have a banner on your e-commerce site that prompts users to check First, create a cookie: ```js filename=app/cookies.js -import { createCookie } from "@remix-run/{runtime}"; +import { createCookie } from "@remix-run/node"; // or "@remix-run/cloudflare" export const userPrefs = createCookie("user-prefs", { maxAge: 604_800, // one week @@ -1793,7 +1793,7 @@ Then, you can `import` the cookie and use it in your `loader` and/or `action`. T **Note:** We recommend (for now) that you create all the cookies your app needs in `app/cookies.js` and `import` them into your route modules. This allows the Remix compiler to correctly prune these imports out of the browser build where they are not needed. We hope to eventually remove this caveat. ```tsx filename=app/routes/index.tsx lines=[4,8-9,15-16,20] -import { json, redirect } from "@remix-run/{runtime}"; +import { json, redirect } from "@remix-run/node"; // or "@remix-run/cloudflare" import { useLoaderData } from "@remix-run/react"; import { userPrefs } from "~/cookies"; @@ -1913,7 +1913,7 @@ export async function loader({ request }) { Creates a logical container for managing a browser cookie from the server. ```ts -import { createCookie } from "@remix-run/{runtime}"; +import { createCookie } from "@remix-run/node"; // or "@remix-run/cloudflare" const cookie = createCookie("cookie-name", { // all of these are optional defaults that can be overridden at runtime @@ -1935,7 +1935,7 @@ To learn more about each attribute, please see the [MDN Set-Cookie docs](https:/ Returns `true` if an object is a Remix cookie container. ```ts -import { isCookie } from "@remix-run/{runtime}"; +import { isCookie } from "@remix-run/node"; // or "@remix-run/cloudflare" const cookie = createCookie("user-prefs"); console.log(isCookie(cookie)); // true @@ -2027,7 +2027,7 @@ This is an example of a cookie session storage: ```js filename=app/sessions.js // app/sessions.js -import { createCookieSessionStorage } from "@remix-run/{runtime}"; +import { createCookieSessionStorage } from "@remix-run/node"; // or "@remix-run/cloudflare" const { getSession, commitSession, destroySession } = createCookieSessionStorage({ @@ -2059,7 +2059,7 @@ You'll use methods to get access to sessions in your `loader` and `action` funct A login form might look something like this: ```tsx filename=app/routes/login.js lines=[4,7-9,11,16,20,26-28,39,44,49,54] -import { json, redirect } from "@remix-run/{runtime}"; +import { json, redirect } from "@remix-run/node"; // or "@remix-run/cloudflare" import { useLoaderData } from "@remix-run/react"; import { getSession, commitSession } from "../sessions"; @@ -2186,7 +2186,7 @@ TODO: Returns `true` if an object is a Remix session. ```js -import { isSession } from "@remix-run/{runtime}"; +import { isSession } from "@remix-run/node"; // or "@remix-run/cloudflare" const sessionData = { foo: "bar" }; const session = createSession(sessionData, "remix-session"); @@ -2201,7 +2201,7 @@ Remix makes it easy to store sessions in your own database if needed. The `creat The following example shows how you could do this using a generic database client: ```js -import { createSessionStorage } from "@remix-run/{runtime}"; +import { createSessionStorage } from "@remix-run/node"; // or "@remix-run/cloudflare" function createDatabaseSessionStorage({ cookie, @@ -2258,7 +2258,7 @@ The main advantage of cookie session storage is that you don't need any addition The downside is that you have to `commitSession` in almost every loader and action. If your loader or action changes the session at all, it must be committed. That means if you `session.flash` in an action, and then `session.get` in another, you must commit it for that flashed message to go away. With other session storage strategies you only have to commit it when it's created (the browser cookie doesn't need to change because it doesn't store the session data, just the key to find it elsewhere). ```js -import { createCookieSessionStorage } from "@remix-run/{runtime}"; +import { createCookieSessionStorage } from "@remix-run/node"; // or "@remix-run/cloudflare" const { getSession, commitSession, destroySession } = createCookieSessionStorage({ @@ -2282,7 +2282,7 @@ This storage keeps all the cookie information in your server's memory. import { createCookie, createMemorySessionStorage, -} from "@remix-run/{runtime}"; +} from "@remix-run/node"; // or "@remix-run/cloudflare" // In this example the Cookie is created separately. const sessionCookie = createCookie("__session", { @@ -2464,7 +2464,7 @@ Now we can read the message in a loader. You must commit the session whenever you read a `flash`. This is different than you might be used to where some type of middleware automatically sets the cookie header for you. ```jsx -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import { Meta, Links, @@ -2551,7 +2551,7 @@ This component is a wrapper around React Router's Outlet with the ability to pas Here's a practical example of when you may want to use this feature. Let's say you've got a list of companies that have invoices and you want to display those companies in an accordion. We'll render our outlet in that accordion, but we want the invoice sorting to be controlled by the parent (so changing companies preserves the invoice sorting). This is a perfect use case for ``. ```tsx filename=app/routes/companies.tsx lines=[5,28-31,36-44,53-57,68] -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import { useLoaderData, useParams, @@ -2636,8 +2636,8 @@ This hook returns the context from the `` that rendered you. Continuing from the `` example above, here's what the child route could do to use the sort order. ```tsx filename=app/routes/companies/$companyId.tsx lines=[5,8,25,27-30] -import type { LoaderFunction } from "@remix-run/{runtime}"; -import { json } from "@remix-run/{runtime}"; +import type { LoaderFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import { useLoaderData, useOutletContext, diff --git a/docs/guides/constraints.md b/docs/guides/constraints.md index d82fc0e8882..6162bb92736 100644 --- a/docs/guides/constraints.md +++ b/docs/guides/constraints.md @@ -19,7 +19,7 @@ The Remix compiler will automatically remove server code from the browser bundle Consider a route module that exports `loader`, `meta`, and a component: ```tsx -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import { useLoaderData } from "@remix-run/react"; import PostsView from "../PostsView"; @@ -77,7 +77,7 @@ Simply put, a **side effect** is any code that might _do something_. A **module Taking our code from earlier, we saw how the compiler can remove the exports and their imports that aren't used. But if we add this seemingly harmless line of code your app will break! ```tsx bad lines=[7] -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import { useLoaderData } from "@remix-run/react"; import PostsView from "../PostsView"; @@ -124,7 +124,7 @@ The loader is gone but the prisma dependency stayed! Had we logged something har To fix this, remove the side effect by simply moving the code _into the loader_. ```tsx lines=[8] -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import { useLoaderData } from "@remix-run/react"; import PostsView from "../PostsView"; @@ -154,7 +154,7 @@ Occasionally, the build may have trouble tree-shaking code that should only run Some Remix newcomers try to abstract their loaders with "higher order functions". Something like this: ```js bad filename=app/http.js -import { redirect } from "@remix-run/{runtime}"; +import { redirect } from "@remix-run/node"; // or "@remix-run/cloudflare" export function removeTrailingSlash(loader) { return function (arg) { @@ -188,7 +188,7 @@ You can probably now see that this is a module side effect so the compiler can't This type of abstraction is introduced to try to return a response early. Since you can throw a Response in a loader, we can make this simpler and remove the module side effect at the same time so that the server code can be pruned: ```js filename=app/http.js -import { redirect } from "@remix-run/{runtime}"; +import { redirect } from "@remix-run/node"; // or "@remix-run/cloudflare" export function removeTrailingSlash(url) { if (url.pathname !== "/" && url.pathname.endsWith("/")) { @@ -202,7 +202,7 @@ export function removeTrailingSlash(url) { And then use it like this: ```js bad filename=app/root.js -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import { removeTrailingSlash } from "~/http"; diff --git a/docs/guides/data-loading.md b/docs/guides/data-loading.md index bde8289083e..5f0410be949 100644 --- a/docs/guides/data-loading.md +++ b/docs/guides/data-loading.md @@ -22,8 +22,8 @@ One of the primary features of Remix is simplifying interactions with the server Each [route module][route-module] can export a component and a [`loader`][loader]. [`useLoaderData`][useloaderdata] will provide the loader's data to your component: ```tsx filename=app/routes/products.tsx lines=[1-3,5-10,13] -import type { LoaderFunction } from "@remix-run/{runtime}"; -import { json } from "@remix-run/{runtime}"; +import type { LoaderFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import { useLoaderData } from "@remix-run/react"; export const loader: LoaderFunction = async () => { @@ -55,7 +55,7 @@ If your server side modules end up in client bundles, move the imports for those When you name a file with `$` like `routes/users/$userId.tsx` and `routes/users/$userId/projects/$projectId.tsx` the dynamic segments (the ones starting with `$`) will be parsed from the URL and passed to your loader on a `params` object. ```tsx filename=routes/users/$userId/projects/$projectId.tsx -import type { LoaderFunction } from "@remix-run/{runtime}"; +import type { LoaderFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" export const loader: LoaderFunction = async ({ params, @@ -75,8 +75,8 @@ Given the following URLs, the params would be parsed as follows: These params are most useful for looking up data: ```tsx filename=routes/users/$userId/projects/$projectId.tsx lines=[8,9] -import { json } from "@remix-run/{runtime}"; -import type { LoaderFunction } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" +import type { LoaderFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" export const loader: LoaderFunction = async ({ params, @@ -98,7 +98,7 @@ Because these params come from the URL and not your source code, you can't know ```tsx filename=routes/users/$userId/projects/$projectId.tsx lines=[1,7-8] import invariant from "tiny-invariant"; -import type { LoaderFunction } from "@remix-run/{runtime}"; +import type { LoaderFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" export const loader: LoaderFunction = async ({ params, @@ -117,7 +117,7 @@ While you may be uncomfortable throwing errors like this with `invariant` when i Remix polyfills the `fetch` API on your server so it's very easy to fetch data from existing JSON APIs. Instead of managing state, errors, race conditions, and more yourself, you can do the fetch from your loader (on the server) and let Remix handle the rest. ```tsx filename=app/routes/gists.jsx lines=[5] -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import { useLoaderData } from "@remix-run/react"; export async function loader() { @@ -154,8 +154,8 @@ export { db }; And then your routes can import it and make queries against it: ```tsx filename=app/routes/products/$categoryId.tsx -import type { LoaderFunction } from "@remix-run/{runtime}"; -import { json } from "@remix-run/{runtime}"; +import type { LoaderFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import { useLoaderData } from "@remix-run/react"; import { db } from "~/db.server"; @@ -186,7 +186,7 @@ export default function ProductCategory() { If you are using TypeScript, you can use type inference to use Prisma Client generated types on when calling `useLoaderData`. This allowes better type safety and intellisense when writing your code that uses the loaded data. ```tsx filename=tsx filename=app/routes/products/$productId.tsx -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import { useLoaderData } from "@remix-run/react"; import { db } from "~/db.server"; @@ -224,8 +224,8 @@ export default function Product() { If you picked Cloudflare Workers as your environment, [Cloudflare Key Value][cloudflare-kv] storage allows you to persist data at the edge as if it were a static resource. You'll need to [do some configuration][cloudflare-kv-setup] but then you can access the data from your loaders: ```tsx filename=app/routes/products/$productId.tsx -import type { LoaderFunction } from "@remix-run/{runtime}"; -import { json } from "@remix-run/{runtime}"; +import type { LoaderFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import { useLoaderData } from "@remix-run/react"; export const loader: LoaderFunction = async ({ @@ -282,8 +282,8 @@ export const loader: LoaderFunction = async ({ URL Search Params are the portion of the URL after a `?`. Other names for this are "query string", "search string", or "location search". You can access the values by creating a URL out of the `request.url`: ```tsx filename=routes/products.tsx lines=[7,8] -import { json } from "@remix-run/{runtime}"; -import type { LoaderFunction } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" +import type { LoaderFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" export const loader: LoaderFunction = async ({ request, @@ -363,7 +363,7 @@ Then the url will be: `/products/shoes?brand=nike&brand=adidas` Note that `brand` is repeated in the URL search string since both checkboxes were named `"brand"`. In your loader you can get access to all of those values with [`searchParams.getAll`][search-params-getall] ```tsx lines=[5] -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" export async function loader({ request }) { const url = new URL(request.url); diff --git a/docs/guides/data-writes.md b/docs/guides/data-writes.md index 62c2a2b7980..fa7d3056ea6 100644 --- a/docs/guides/data-writes.md +++ b/docs/guides/data-writes.md @@ -176,8 +176,8 @@ export default function NewProject() { Now add the route action. Any form submissions that are "post" will call your data "action". Any "get" submissions (``) will be handled by your "loader". ```tsx [5-11] -import type { ActionFunction } from "@remix-run/{runtime}"; -import { redirect } from "@remix-run/{runtime}"; +import type { ActionFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" +import { redirect } from "@remix-run/node"; // or "@remix-run/cloudflare" // Note the "action" export name, this will handle our form POST export const action: ActionFunction = async ({ @@ -230,7 +230,7 @@ export const action: ActionFunction = async ({ Just like `useLoaderData` returns the values from the `loader`, `useActionData` will return the data from the action. It will only be there if the navigation was a form submission, so you always have to check if you've got it or not. ```tsx [2,11,21,26-30,38,43-47] -import { redirect } from "@remix-run/{runtime}"; +import { redirect } from "@remix-run/node"; // or "@remix-run/cloudflare" import { useActionData } from "@remix-run/react"; export const action: ActionFunction = async ({ @@ -295,7 +295,7 @@ You can ship this code as-is. The browser will handle the pending UI and interru Let's use progressive enhancement to make this UX a bit more fancy. By changing it from `` to ``, Remix will emulate the browser behavior with `fetch`. It will also give you access to the pending form data so you can build pending UI. ```tsx [2, 11] -import { redirect } from "@remix-run/{runtime}"; +import { redirect } from "@remix-run/node"; // or "@remix-run/cloudflare" import { useActionData, Form } from "@remix-run/react"; // ... @@ -319,7 +319,7 @@ If you don't have the time or drive to do the rest of the job here, use ``FormData` object. You'll be most interested in the `formData.get()` method.. ```tsx [5, 13, 19, 65-67] -import { redirect } from "@remix-run/{runtime}"; +import { redirect } from "@remix-run/node"; // or "@remix-run/cloudflare" import { useActionData, Form, diff --git a/docs/guides/mdx.md b/docs/guides/mdx.md index cda2e71fd50..cb15ca602de 100644 --- a/docs/guides/mdx.md +++ b/docs/guides/mdx.md @@ -87,7 +87,7 @@ The following example demonstrates how you might build a simple blog with MDX, i In `app/routes/index.jsx`: ```tsx -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import { Link, useLoaderData } from "@remix-run/react"; // Import all your posts from the app/routes/posts directory. Since these are diff --git a/docs/guides/optimistic-ui.md b/docs/guides/optimistic-ui.md index 295c49a2738..fb74531d112 100644 --- a/docs/guides/optimistic-ui.md +++ b/docs/guides/optimistic-ui.md @@ -23,7 +23,7 @@ Remix can help you build optimistic UI with [`useTransition`][use-transition] an Consider the workflow for viewing and creating a new project. The project route loads the project and renders it. ```tsx filename=app/routes/project/$id.tsx -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import { useLoaderData } from "@remix-run/react"; import { ProjectView } from "~/components/project"; @@ -59,7 +59,7 @@ export function ProjectView({ project }) { Now we can get to the fun part. Here's what a "new project" route might look like: ```tsx filename=app/routes/projects/new.tsx -import { redirect } from "@remix-run/{runtime}"; +import { redirect } from "@remix-run/node"; // or "@remix-run/cloudflare" import { Form } from "@remix-run/react"; import { createProject } from "~/utils"; @@ -93,7 +93,7 @@ export default function NewProject() { At this point, typically you'd render a busy spinner on the page while the user waits for the project to be sent to the server, added to the database, and sent back to the browser and then redirected to the project. Remix makes that pretty easy: ```tsx filename=app/routes/projects/new.tsx lines=[2,16,28,30-32] -import { redirect } from "@remix-run/{runtime}"; +import { redirect } from "@remix-run/node"; // or "@remix-run/cloudflare" import { Form, useTransition } from "@remix-run/react"; import { createProject } from "~/utils"; @@ -135,7 +135,7 @@ export default function NewProject() { Since we know that almost every time this form is submitted it's going to succeed, we can just skip the busy spinners and show the UI as we know it's going to be: the ``. ```tsx filename=app/routes/projects/new.tsx lines=[5,17-23] -import { redirect } from "@remix-run/{runtime}"; +import { redirect } from "@remix-run/node"; // or "@remix-run/cloudflare" import { Form, useTransition } from "@remix-run/react"; import { createProject } from "~/utils"; @@ -183,7 +183,7 @@ One of the hardest parts about implementing optimistic UI is how to handle failu If you want to have more control over the UI when an error occurs and put the user right back where they were without losing any state, you can catch your own error and send it down through action data. ```tsx filename=app/routes/projects/new.tsx lines=[4-5,16-24,29,48] -import { json, redirect } from "@remix-run/{runtime}"; +import { json, redirect } from "@remix-run/node"; // or "@remix-run/cloudflare" import { Form, useTransition, diff --git a/docs/guides/resource-routes.md b/docs/guides/resource-routes.md index 2750f83c337..36ccc6db442 100644 --- a/docs/guides/resource-routes.md +++ b/docs/guides/resource-routes.md @@ -86,8 +86,8 @@ app/routes/reports/$id[.]pdf.ts To handle `GET` requests export a loader function: ```ts -import { json } from "@remix-run/{runtime}"; -import type { LoaderFunction } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" +import type { LoaderFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" export const loader: LoaderFunction = async ({ request, @@ -101,7 +101,7 @@ export const loader: LoaderFunction = async ({ To handle `POST`, `PUT`, `PATCH` or `DELETE` requests export an action function: ```ts -import type { ActionFunction } from "@remix-run/{runtime}"; +import type { ActionFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" export const action: ActionFunction = async ({ request, @@ -128,8 +128,8 @@ export const action: ActionFunction = async ({ Resource routes can be used to handle webhooks. For example, you can create a webhook that receives notifications from GitHub when a new commit is pushed to a repository: ```ts -import type { ActionFunction } from "@remix-run/{runtime}"; -import { json } from "@remix-run/{runtime}"; +import type { ActionFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import crypto from "crypto"; export const action: ActionFunction = async ({ diff --git a/docs/guides/styling.md b/docs/guides/styling.md index f5dde5d253f..d0f621a5d64 100644 --- a/docs/guides/styling.md +++ b/docs/guides/styling.md @@ -254,7 +254,7 @@ Now Remix can prefetch, load, and unload the styles for `button.css`, `primary-b An initial reaction to this is that routes have to know more than you want them to. Keep in mind each component must be imported already, so it's not introducing a new dependency, just some boilerplate to get the assets. For example, consider a product category page like this: ```tsx filename=app/routes/$category.js lines=[4-8,24-31] -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import { useLoaderData } from "@remix-run/react"; import { TileGrid } from "~/components/tile-grid"; @@ -508,7 +508,7 @@ If you're using VS Code, it's recommended you install the [Tailwind IntelliSense You can load stylesheets from any server, here's an example of loading a modern css reset from unpkg. ```ts filename=app/root.tsx -import type { LinksFunction } from "@remix-run/{runtime}"; +import type { LinksFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" export const links: LinksFunction = () => { return [ @@ -596,7 +596,7 @@ Here's how to set it up: Then import like any other css file: ```tsx filename=root.tsx - import type { LinksFunction } from "@remix-run/{runtime}"; + import type { LinksFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" import styles from "./styles/app.css"; @@ -685,7 +685,7 @@ Here's some sample code to show how you might use Styled Components with Remix ( 1. First you'll need to put a placeholder in your root component to control where the styles are inserted. ```tsx filename=app/root.tsx lines=[22-24] - import type { MetaFunction } from "@remix-run/{runtime}"; + import type { MetaFunction } from "@remix-run/node"; // or "@remix-run/cloudflare" import { Links, LiveReload, @@ -726,7 +726,7 @@ Here's some sample code to show how you might use Styled Components with Remix ( ```tsx filename=entry.server.tsx lines=[4,12,15-20,22-23] import { renderToString } from "react-dom/server"; import { RemixServer } from "@remix-run/react"; - import type { EntryContext } from "@remix-run/{runtime}"; + import type { EntryContext } from "@remix-run/node"; // or "@remix-run/cloudflare" import { ServerStyleSheet } from "styled-components"; export default function handleRequest( diff --git a/docs/other-api/node.md b/docs/other-api/node.md index 00d05c42a67..65f8c4025a3 100644 --- a/docs/other-api/node.md +++ b/docs/other-api/node.md @@ -13,7 +13,7 @@ Since Remix relies on browser API's such as fetch that are not natively availabl Your testing framework should provide you with a hook or location to polyfill globals / mock out API's; here you can add the following lines to install the globals that Remix relies on: ```ts -import { installGlobals } from "@remix-run/{runtime}"; +import { installGlobals } from "@remix-run/node"; // or "@remix-run/cloudflare" // This installs globals such as "fetch", "Response", "Request" and "Headers". installGlobals(); diff --git a/docs/other-api/serve.md b/docs/other-api/serve.md index 218873eb503..de94d64100d 100644 --- a/docs/other-api/serve.md +++ b/docs/other-api/serve.md @@ -40,7 +40,7 @@ In development, `remix-serve` will ensure the latest code is run by purging the - Any **module side effects** will remain in place! This may cause problems, but should probably be avoided anyway. ```ts [3-6] - import { json } from "@remix-run/{runtime}"; + import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" // this starts running the moment the module is imported setInterval(() => { diff --git a/docs/pages/faq.md b/docs/pages/faq.md index 864f39e2a93..4bbe8614d5b 100644 --- a/docs/pages/faq.md +++ b/docs/pages/faq.md @@ -17,7 +17,7 @@ We recommend you create a function that validates the user session that can be a import { createCookieSessionStorage, redirect, -} from "@remix-run/{runtime}"; +} from "@remix-run/node"; // or "@remix-run/cloudflare" // somewhere you've got a session storage const { getSession } = createCookieSessionStorage(); diff --git a/docs/pages/gotchas.md b/docs/pages/gotchas.md index d75d974d3b5..05179290aef 100644 --- a/docs/pages/gotchas.md +++ b/docs/pages/gotchas.md @@ -19,7 +19,7 @@ TypeError: Cannot read properties of undefined (reading 'root') For example, you can't import "fs-extra" directly into a route module: ```jsx bad filename=app/routes/index.jsx lines=[2] nocopy -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import fs from "fs-extra"; export async function loader() { @@ -40,7 +40,7 @@ export * from "fs-extra"; And then change our import in the route to the new "wrapper" module: ```jsx filename=app/routes/index.jsx lines=[3] -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" import fs from "../utils/fs-extra.server"; @@ -62,7 +62,7 @@ For example, [Remix upload handlers like `unstable_createFileUploadHandler` and So instead of doing: ```jsx bad filename=app/routes/some-route.jsx lines=[3-6] -import { unstable_createFileUploadHandler } from "@remix-run/{runtime}"; +import { unstable_createFileUploadHandler } from "@remix-run/node"; // or "@remix-run/cloudflare" const uploadHandler = unstable_createFileUploadHandler({ maxFileSize: 5_000_000, @@ -77,7 +77,7 @@ export async function action() { You should be doing: ```jsx filename=app/routes/some-route.jsx good lines=[4-7] -import { unstable_createFileUploadHandler } from "@remix-run/{runtime}"; +import { unstable_createFileUploadHandler } from "@remix-run/node"; // or "@remix-run/cloudflare" export async function action() { const uploadHandler = unstable_createFileUploadHandler({ diff --git a/docs/pages/philosophy.md b/docs/pages/philosophy.md index 0ee28d8083f..46f0c2bbc1b 100644 --- a/docs/pages/philosophy.md +++ b/docs/pages/philosophy.md @@ -56,7 +56,7 @@ export default function Gists() { With Remix, you can filter down the data _on the server_ before sending it to the user: ```js [3-16] -import { json } from "@remix-run/{runtime}"; +import { json } from "@remix-run/node"; // or "@remix-run/cloudflare" export async function loader() { const res = await fetch("https://api.github.com/gists");