Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uncaught ReferenceError: Buffer is not defined #2248

Closed
abdessamadely opened this issue Mar 7, 2022 · 32 comments
Closed

Uncaught ReferenceError: Buffer is not defined #2248

abdessamadely opened this issue Mar 7, 2022 · 32 comments
Labels
bug Something isn't working

Comments

@abdessamadely
Copy link

What version of Remix are you using?

v1.2.3

Steps to Reproduce

The examples in the docs https://remix.run/docs/en/v1/api/remix#uploadhandler

Just after adding this code inside a route

let uploadHandler = unstable_createFileUploadHandler({
  maxFileSize: 5_000_000,
  file: ({ filename }) => filename,
})

Expected Behavior

To work, as expected from the docs

Actual Behavior

Log the error to the the browser console on page load

Screen Shot 2022-03-07 at 23 30 32

@abdessamadely abdessamadely added the bug Something isn't working label Mar 7, 2022
@mzaatar
Copy link

mzaatar commented Mar 8, 2022

I have had the same problem for a few days now.
My investigation is that one of the node_modules didn't make it to the client-side. I tried extracting the functionality from the route main file into the xyz.client.ts and explicitly import the nodes modules but no luck
following...

@abdessamadely
Copy link
Author

I think some node code end-up in the client side, as Buffer available for node but not for the browser
But i can't find where's it's coming from, currently looking for a way to handle uploads with external express server

@Jaikant
Copy link

Jaikant commented Mar 8, 2022

I am facing a similar error, while trying to include graphql-ws in my app.

constants.js:5 Uncaught ReferenceError: Buffer is not defined
    at node_modules/ws/lib/constants.js (constants.js:5:17)
    at __require2 (chunk-FDP6WGZF.js:19:44)
    at node_modules/ws/lib/buffer-util.js (buffer-util.js:3:26)
    at __require2 (chunk-FDP6WGZF.js:19:44)
    at node_modules/ws/lib/permessage-deflate.js (permessage-deflate.js:5:20)
    at __require2 (chunk-FDP6WGZF.js:19:44)
    at node_modules/ws/lib/receiver.js (receiver.js:5:27)
    at __require2 (chunk-FDP6WGZF.js:19:44)
    at wrapper.mjs:2:22

@Jaikant
Copy link

Jaikant commented Mar 8, 2022

I think my issue is documented here (I need to try it though)

@kiliman
Copy link
Collaborator

kiliman commented Mar 8, 2022

I show a way to import the buffer polyfill package. NOTE: it does require a patch of Remix compiler since it complains about importing package of node built-ins.

https://github.com/kiliman/remix-walletconnect

@fergusmeiklejohn
Copy link
Contributor

fergusmeiklejohn commented Mar 9, 2022

yeah I have the same problem :-(
It's a difficultly of working with Remix that the app actually crashes (no JS) but still renders the html so it's not clear that it's crashed.

A solution is to bring in the unstable_... functions that are throwing in a .server file (eg postData.server.ts) and call this function from the action

import {
  unstable_createMemoryUploadHandler,
  unstable_parseMultipartFormData,
} from "remix";

const uploadHandler = unstable_createMemoryUploadHandler({
  maxFileSize: 5_000_000,
});
export async function uploadAvatar(request: Request) {
  const formData = await unstable_parseMultipartFormData(
    request,
    uploadHandler
  );

  const file = formData.get("file");
  console.log("file in action function: ", file);
  return file;
}

@abdessamadely
Copy link
Author

I have moved to Next.js for the moment as i already have some working examples of what i'm trying to do.

Please @fergusmeiklejohn if this solution is working for you, let me know so i can close this issue.

Thanks

@fergusmeiklejohn
Copy link
Contributor

putting the code in a server only file solves the problem but the Remix team should still be made aware of this bug. It's probably a problem the Buffer package authors need to fix

@Shaquu
Copy link

Shaquu commented Mar 10, 2022

Same problem for me. Using @emotion/server/create-instance leads to ReferenceError: Buffer is not defined

@Jaikant
Copy link

Jaikant commented Mar 10, 2022

I moved on to nextjs mainly because remix doesn't have websockets connecting its node server to client.

@drewdecarme
Copy link

drewdecarme commented Mar 11, 2022

@Shaquu I'm having roughly the same issues as well. I'm using Cloudflare Pages as my preferred Remix setup. I tried the example locally and it seems to build fine in dev mode using the @remix-run/serve package.

I also tried to change the emotion context files to context.server.ts and context.client.ts to better model their documentation to see if the compiler would leave out the that code but it appears that it's not.

Hopefully that info helps others who are troubleshooting this. TBH, I tried styled-components first but ran into SSR issues and inconsistencies between the server and client generated classes. I tried shimming Linaria but there's too many unknowns with that so I came to emotion. It seems like a fully baked example but this one issue just seems to be sticky

@Shaquu
Copy link

Shaquu commented Mar 11, 2022

@drewdecarme to be honest, I just removed emotion references from the code and I am going forward.
It is not that important to stop me from getting to know remix.

@drewdecarme
Copy link

Yeah I'm completely with you on that one. I'm fine with writing the styles I need outside the context of the component. I just love the convenience of co-locating the styles with the component which I've gotten accustomed to over the years.

@Shaquu
Copy link

Shaquu commented Mar 13, 2022

Yeah I'm completely with you on that one. I'm fine with writing the styles I need outside the context of the component. I just love the convenience of co-locating the styles with the component which I've gotten accustomed to over the years.

Maybe try this one?

emotion-js/emotion#2554 (comment)

@mocon
Copy link

mocon commented Mar 15, 2022

Thanks a lot for the fix @fergusmeiklejohn! Do you know if it's possible to update the maxFileSize for a custom uploadHandler? I'm trying to allow large video file uploads, but it seems to be inheriting the default 3_000_000 from unstable_createFileUploadHandler.

@fergusmeiklejohn
Copy link
Contributor

Sure you just do something like this:

const uploadHandler = unstable_createMemoryUploadHandler({
  maxFileSize: 5_000_000,
});

@chaance
Copy link
Collaborator

chaance commented Mar 18, 2022

Is anyone able to reproduce this with the latest release? We added some node browser polyfills and removed some node-specific code from the runtime package in the last few updates.

@kiliman
Copy link
Collaborator

kiliman commented Mar 18, 2022

Checked on 1.3.2 and still can't use Buffer on client.

If you just try to use Buffer on the client, it compiles but you get runtime error: ReferenceError: Buffer is not defined

If you install polyfill buffer package, you get the error: It appears you're using a module that is built in to node, but you installed it as a dependency which could cause problems. Please remove buffer before continuing.

This is why I have the patch that removes the check for node builtins.

@julienmonnard
Copy link
Contributor

Hello!
I was trying to achieve the same as in the doc here https://remix.run/docs/en/v1/api/remix#unstable_createfileuploadhandler and this Buffer is not defined error happened to me as well...

But I noticed that if instead of this:

// Code from the doc
const uploadHandler = unstable_createFileUploadHandler({
    maxFileSize: 5_000_000,
    file: ({ filename }) => filename,
});

export const action: ActionFunction = async ({ request }) => {
    const formData = await unstable_parseMultipartFormData(
        request,
        uploadHandler
    );

    const file = formData.get('avatar');

    // file is a "NodeFile" which has a similar API to "File"
    // ... etc
};

you do this:

// Notice the uploadHandler being defined INSIDE the action function
export const action: ActionFunction = async ({ request }) => {
    const uploadHandler = unstable_createFileUploadHandler({
        maxFileSize: 5_000_000,
        file: ({ filename }) => filename,
    });

    const formData = await unstable_parseMultipartFormData(
        request,
        uploadHandler
    );

    const file = formData.get('avatar');

    // file is a "NodeFile" which has a similar API to "File"
    // ... etc
};

Then the error doesn't appear anymore and the file is available with formData.get('avatar')

I just started using Remix, so not sure it's a correct approach, but maybe it's at least a step in the right direction 🙂

@clintonwoo
Copy link

I actually got this error on 1.3.3 also when only using the regular formData parser like await request.formData(); in an action but downgrading to 1.3.2 fixed it.

Pretty big bug since crashes all the client side js.

@s-oram
Copy link

s-oram commented Apr 1, 2022

I'm also running into this error since upgrading to Remix 1.3.4. Downgrading to Remix 1.3.2 resolves the error.

Edit:

I encountered this issue on a project built on the Remix grunge stack.

I cannot reproduce this issue in a newly initialised project. That includes a new Remix grunge stack and a new vanilla remix project.

After seeing that the error only occurs in my project, i started chopping out code. In my case the error was triggered by a Cypress test route with two imports:

import { createUser } from "~/models/user.server";
import { createUserSession } from "~/session.server";

Removing these imports was enough to avoid triggering the error.

This same code exists in the Remix grunge stack project and doesn't trigger the error, so something else may be at play here. I haven't dug any deeper yet.

@jacargentina
Copy link
Contributor

Same error, but not using unstable_parseMultipartFormData at all.

@timfee
Copy link

timfee commented Apr 4, 2022

I have a very trivial example where it appears React 18 is the culprit, cloudflare/workers-sdk#754 -- not sure if anyone else has such an issue

@chaance
Copy link
Collaborator

chaance commented Apr 8, 2022

FYI, I am working on this, but in the mean time you can either create a separate .server.js file as mentioned before, or initialize your server code inside your loader or action instead of the top-level scope of the route module.

I spoke with @jacob-ebey about this and the problem ultimately is our documentation. When you call a function in the top-level scope of your route module, our compiler can't reliably code-split that bit from the browser build. And while we do shim Node built-ins, we don't shim Node globals and would prefer that Buffer not end up in your browser build at all.

So to solve this, you have two options:

  1. Create a separate *.server.js file that wraps your server handlers so that our compiler can reliably remove it from the browser, as documented here
  2. Initialize the handler inside your loader or action instead of the root level, as we already remove those exports from the browser build
// instead of this...
let uploadHandler = unstable_createFileUploadHandler({
  maxFileSize: 5_000_000,
  file: ({ filename }) => filename,
});

export async function action({ request }) {
  let formData = await unstable_parseMultipartFormData(request, uploadHandler);
  // ...
};

// do this...
export async function action({ request }) {
  let uploadHandler = unstable_createFileUploadHandler({
    maxFileSize: 5_000_000,
    file: ({ filename }) => filename,
  });
  let formData = await unstable_parseMultipartFormData(request, uploadHandler);
  // ...
};

Understand that unstable_createFileUploadHandler is the example, but this "gotcha" would generally apply to any functions you might call in a route. Functions called at the top-level or the Route component will be included in both bundles, functions called in actions/loaders will only be in the server bundle.

In the meantime, I'll make sure all of our examples and documentation are updated to fix any bugs and clarify!

@chaance chaance closed this as completed Apr 8, 2022
@jacargentina
Copy link
Contributor

jacargentina commented Apr 8, 2022

@chaance

i dont get it: why the same route code, migrating to react18 + latest remix throws the error? I’m not using any unstable_parseMultipartFormData as i posted early.

chaance added a commit that referenced this issue Apr 8, 2022
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.
@chaance
Copy link
Collaborator

chaance commented Apr 8, 2022

@chaance

i dont get it: why the same route code, migrating to react18 + latest remix throws the error? I’m not using any unstable_parseMultipartFormData as i posted early.

I'm unsure how React 18 specifically would cause an issue like this, but this isn't just about unstable_parseMultipartFormData, it's about any code that should only be in your server bundle.

If you can create a new issue with a minimal repro showing your problem with React 18 we can try to help out there.

chaance added a commit that referenced this issue Apr 10, 2022
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.
@drewdecarme
Copy link

drewdecarme commented Apr 21, 2022

@chaance Unfortunately, I'm still getting the same issues when trying to follow the emotion example in the examples directory for Remix. I've tried a few of the fixes that you have mentioned before but still experiencing the

ReferenceError: Buffer is not defined

I would assume that the culprit is @emotion/server/create-instance/dist/emotion-server-create-instance.cjs.dev.js and it's getting bundled in the code. It's strange since this is being called in the entry.server.tsx file so I'd wonder if you would have any guidance based upon how the example is setup in the docs at the moment?

For what it's worth, I'm using Cloudflare Pages and am currently using Remix 1.4.1

@shymarrai
Copy link

shymarrai commented Jun 30, 2022

for me what worked was:

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
import inject from '@rollup/plugin-inject'

export default defineConfig({
	plugins: [vue()],
	resolve: {
		alias: {
			'@': path.resolve(__dirname, 'src'),
		}
	},
	build: {
		rollupOptions: {
			plugins: [inject({ Buffer: ['buffer', 'Buffer'] })],
		},
	},
})

reply to this comment:

vitejs/vite#2785 (reply in thread)

@artokun
Copy link

artokun commented Aug 17, 2022

I'd like to point out that if you're a dummy like me, and googling Uncaught ReferenceError: Buffer is not defined brought you here while setting up WebSockets in the Remix client. You might have done this:

// ws.client.ts
import WebSocket from 'ws';
const ws = new WebSocket('ws://localhost: 3000');

Turns out WebSocket is native to modern browsers, so you really just need to omit the import and you're good to go
I hope this helps at least one other dev out there!

@mhmdunl1
Copy link

mhmdunl1 commented Sep 7, 2022

Use this on the page or function where you get an error:

window.Buffer = window.Buffer || require("buffer").Buffer;

@makerovski
Copy link

Thank you @mhmdunl1, your solution helped me :)

@jdnichollsc
Copy link

Hey folks, check my example to fix this issue https://gist.github.com/jdnichollsc/b73eca1f34bdd1e3a95283774fda2212

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests