remix icon indicating copy to clipboard operation
remix copied to clipboard

Uncaught Error: Dynamic require of "fs/promises" is not supported - when importing json from @remix-run/node

Open meglio opened this issue 3 years ago • 10 comments

What version of Remix are you using?

1.7.1

Steps to Reproduce

import { json } from "@remix-run/node";

export default function SomePage(props) {
    return <div>
        Page
    </div>
}

Then yarn dev.

Expected Behavior

No errors in developer console.

Actual Behavior

Error in developer console:

image

package.json

{
  "private": true,
  "sideEffects": false,
  "scripts": {
    "build": "remix build",
    "dev": "remix dev",
    "start": "remix-serve build"
  },
  "dependencies": {
    "@remix-run/node": "^1.7.1",
    "@remix-run/react": "^1.7.1",
    "@remix-run/serve": "^1.7.1",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@remix-run/dev": "^1.7.1",
    "@remix-run/eslint-config": "^1.7.1",
    "eslint": "^8.20.0"
  },
  "engines": {
    "node": ">=14"
  },
  "packageManager": "[email protected]"
}


Yarn and Node

  • node version: 18.9.0
  • Yarn: 3.x

NB. I tried creating the project with using Yarn 1.x and it worked fine. The problem appears after migrating to yarn 3.x

Might be related:

https://github.com/yarnpkg/berry/issues/638#issuecomment-1124629341

Looks like Yarn 3.x supports ESM module loading. So I tried the following in my .yarnrc.yml file, following the recommendations from the link above:

yarnPath: .yarn/releases/yarn-3.2.3.cjs
pnpEnableEsmLoader: true
nodeLinker: "pnp"

But this did not help.

So, the thread above makes me think that yarn 3.x should work with Remix. But it does not. I'm wondering if this is Remix or Yarn issue?

The only workaround that works for me is to rollback to using nodeLinker: node-modules.

meglio avatar Sep 20 '22 10:09 meglio

Just hit this. You need to import things from @remix-run/cloudflare instead

mwood23 avatar Sep 23 '22 04:09 mwood23

@mwood23 I am not using cloudflare.

meglio avatar Sep 24 '22 06:09 meglio

@meglio I hit this too... A temp workaround is just change how "fs/promises" imports...

You need to change this row in file node_modules/@remix-run/node/dist/upload/fileUploadHandler.js:

var fs = require('fs');
-var promises = require('fs/promises');
+var promises = require('fs').promises;
var os = require('os');

it is at the top of the file... but still annoys...

Explanation is on Stackoverflow So... a fix for devs must be just updating a node version... or change how they import promises from fs...

mkikets99 avatar Oct 01 '22 18:10 mkikets99

So... a fix for devs must be just updating a node version... or change how they import promises from fs...

Could you explain this part, please, @mkikets99 ? What devs do you mean - the Remix devs? If so, what node version do you mean? I am the package user and my Node version is 18.9, but it does not prevent the error from happening.

meglio avatar Oct 04 '22 02:10 meglio

So... a fix for devs must be just updating a node version... or change how they import promises from fs...

Could you explain this part, please, @mkikets99 ? What devs do you mean - the Remix devs? If so, what node version do you mean? I am the package user and my Node version is 18.9, but it does not prevent the error from happening.

Yes, i meant the Remix Devs. But... i think on TS it will be better to use something like

import { promises as fspromises } from "fs";

rather than

import fspromises from "fs/promises"

because that is causing the error...

mkikets99 avatar Oct 04 '22 09:10 mkikets99

Node changed the way how "sub-modules" are imported... And fs/promises are now a part of fs... maybe from Node v12... and Node trying to not use the "path-requirement" for integrated values... But TypeScript skipped this part... and allowing to use path import while Node doesn't like it

mkikets99 avatar Oct 04 '22 10:10 mkikets99

I may rewrite that file on TS... a bit later... Now i just added a script in postinstall section of scripts...

cat ./node_modules/@remix-run/node/dist/upload/fileUploadHandler.js | sed -e \"s/var promises = require('fs\\/promises');/var promises = require('fs').promises;/g\" | tee ./node_modules/@remix-run/node/dist/upload/fileUploadHandler.js >/dev/null

you can try run this command in your project root folder and this must solve it... Maybe in 2-3 days ill make a PR with fix...

mkikets99 avatar Oct 04 '22 10:10 mkikets99

In my case, working with sessions, I had not specifically scoped my module to the server, e.g.: session.server.ts -- so the module had leaked to the client producing the titled error.

naturalethic avatar Oct 20 '22 17:10 naturalethic

So, at the end of the day, is it something that Remix can/going to fix/improve?

meglio avatar Oct 28 '22 01:10 meglio

Also running into this problem, any status updates?

NRodriguezcuellar avatar Nov 05 '22 13:11 NRodriguezcuellar

also hit this problem

ErlanBelekov avatar Nov 30 '22 05:11 ErlanBelekov

This problem happened to me because server-only code was in the client. I had to re-name the server-only files with .server extension and it worked!

I though Remix would do a better job at distinguishing the server/client JS bundles.

ErlanBelekov avatar Nov 30 '22 11:11 ErlanBelekov

Remix requires Node v14 or newer, so changing internal code should not be necessary since importing from fs/promises was added in Node v14(click on "history" dropdown to see it).

As @ErlanBelekov points out, this is likely due to server code being incorrectly included in your browser/client bundle.

In the example from @meglio :

import { json } from "@remix-run/node";

export default function SomePage(props) {
    return <div>
        Page
    </div>
}

The @remix-run/node import should be treeshaken from the browser bundle.

pcattori avatar Nov 30 '22 17:11 pcattori

I was facing the same issue.

Solution that worked for me : moved createCookie helper to .server file

shubumpc91 avatar Dec 12 '22 16:12 shubumpc91

also facing it

alexpunct avatar Apr 12 '23 07:04 alexpunct

@alexpunct like the others, move the import into a .server file and re-export it. I think esbuild has issues tree-shaking node internal packages. I typically have a node.server file that I re-export from.

kiliman avatar Apr 12 '23 14:04 kiliman

@kiliman We have been struggling with this for a while. Could you provide a brief example of how to import and re-export this?

jshay21 avatar Apr 14 '23 17:04 jshay21

// app/libs/node.server.ts

import path from 'node:path';
export * as fs from 'node:fs';
export * as fsp from 'node:fs/promises';
export { path };

// route.tsx

import { fs } from '~/libs/node.server'

kiliman avatar Apr 14 '23 17:04 kiliman