Skip to content

Commit

Permalink
docs: Fix upload handler examples + add context
Browse files Browse the repository at this point in the history
A few of our examples incorrectly called server-only functions at the
top-level scope of a route module which will result in an error when
they use Node globals. The examples were fixed and clarity added where
needed. Addresses issue raised in #2248.
  • Loading branch information
chaance committed Apr 8, 2022
1 parent 46b96f5 commit 3086f19
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 13 deletions.
24 changes: 11 additions & 13 deletions docs/api/remix.md
Original file line number Diff line number Diff line change
Expand Up @@ -1555,14 +1555,13 @@ These are fully featured utilities for handling fairly simple use cases. It's no
**Example:**

```tsx
const uploadHandler = unstable_createFileUploadHandler({
maxFileSize: 5_000_000,
file: ({ filename }) => filename,
});

export const action: ActionFunction = async ({
request,
}) => {
const uploadHandler = unstable_createFileUploadHandler({
maxFileSize: 5_000_000,
file: ({ filename }) => filename,
});
const formData = await unstable_parseMultipartFormData(
request,
uploadHandler
Expand Down Expand Up @@ -1594,13 +1593,12 @@ The `filter` function accepts an `object` and returns a `boolean` (or a promise
**Example:**

```tsx
const uploadHandler = unstable_createMemoryUploadHandler({
maxFileSize: 500_000,
});

export const action: ActionFunction = async ({
request,
}) => {
const uploadHandler = unstable_createMemoryUploadHandler({
maxFileSize: 500_000,
});
const formData = await unstable_parseMultipartFormData(
request,
uploadHandler
Expand Down Expand Up @@ -1709,12 +1707,12 @@ 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
```tsx filename=file-upload-handler.server.tsx
import type { UploadHandler } from "@remix-run/{runtime}";
import { unstable_createFileUploadHandler } from "@remix-run/{runtime}";
import { createCloudinaryUploadHandler } from "some-handy-remix-util";

export const fileUploadHandler =
export const standardFileUploadHandler =
unstable_createFileUploadHandler({
directory: "public/calendar-events",
});
Expand All @@ -1724,9 +1722,9 @@ export const cloudinaryUploadHandler =
folder: "/my-site/avatars",
});

export const multHandler: UploadHandler = (args) => {
export const fileUploadHandler: UploadHandler = (args) => {
if (args.name === "calendarEvent") {
return fileUploadHandler(args);
return standardFileUploadHandler(args);
} else if (args.name === "eventBanner") {
return cloudinaryUploadHandler(args);
} else {
Expand Down
25 changes: 25 additions & 0 deletions docs/pages/gotchas.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,31 @@ export default function SomeRoute() {

Even better, send a PR to the project to add `"sideEffects": false` to their package.json so that bundlers that tree shake know they can safely remove the code from browser bundles.

Similarly, you may run into a the same error if you call a function at the top-level scope of your route module that depends on server-only code.

For example, [Remix upload handlers like `unstable_createFileUploadHandler` and `unstable_createMemoryUploadHandler`](../api/remix#uploadhandler) use Node globals under the hood and should only be called on the server. You can call either of these functions in a `*.server.js` or `*.server.ts` file, or you can move them into your route's `action` or `loader` function:

```tsx filename=app/routes/some-route.jsx
import { unstable_createFileUploadHandler } from "@remix-run/{runtime}";

// Instead of this…
const uploadHandler = unstable_createFileUploadHandler({
maxFileSize: 5_000_000,
file: ({ filename }) => filename,
});

// …do this

export async function action({ request }) {
const uploadHandler = unstable_createFileUploadHandler({
maxFileSize: 5_000_000,
file: ({ filename }) => filename,
});

// ...
}
```

> Why does this happen?
Remix uses "tree shaking" to remove server code from browser bundles. Anything inside of Route module `loader`, `action`, and `headers` exports will be removed. It's a great approach but suffers from ecosystem compatibility.
Expand Down

0 comments on commit 3086f19

Please sign in to comment.