Parcel: fs.readFileSync - Cannot statically evaluate fs argument

Created on 5 Dec 2018  ยท  21Comments  ยท  Source: parcel-bundler/parcel

๐Ÿ› bug report

๐ŸŽ› Configuration (.babelrc, package.json, cli command)

{
  "your": { "config": "here" }
}

๐Ÿค” Expected Behavior

๐Ÿ˜ฏ Current Behavior

๐Ÿ’ Possible Solution

๐Ÿ”ฆ Context

๐Ÿ’ป Code Sample

https://github.com/mytee306/marked-intro

๐ŸŒ Your Environment

| Software | Version(s) |
| ---------------- | ---------- |
| Parcel | latest
| Node | latest
| npm/Yarn | latest
| Operating System | linux mint

Good First Issue Feature

Most helpful comment

just tell parcel you're running in a node environment with the target flag

e.g. parcel app.js --target node

All 21 comments

You did this:

const markdown = require("./markdown.md");

const md = fs.readFileSync(markdown, { encoding: "UTF-8" });

Just do this:

const md = fs.readFileSync("./markdown.md", { encoding: "UTF-8" });

thanks for your answer, but writing
fs.readFileSync("./markdown.md", { encoding: "UTF-8" });
resulted in ~
cannot find __dirname/src/markdown.md

Does the file src/markdown.md exist?
If it's in the parent folder, then you need to use ../markdown.md.

it's there indeed, you may find it here

@mischnic Have you been able to replicate the issue?

Yes, I am.

This is the folder structure

 |- index.html
 |- index.js
 |- markdown.md

but inside index.js only fs.readFileSync("./src/markdown.md"); works. I would expect the path to behave like require (relative to the current file).

Yes, I am.

This is the folder structure

 |- index.html
 |- index.js
 |- markdown.md

but inside index.js only fs.readFileSync("./src/markdown.md"); works. I would expect the path to behave like require (relative to the current file).

Awesome, it worked! Although, I agree that it would make more if the src folder would count as the current folder to build a relative path off of. Just like when importing your javascript file in index.html.

I agree that it would make more if the src folder would count as the current folder to build a relative path off of

Yes, I would call the current behaviour a bug

Hello! I'm a first-time contributor, and I'd like to dig into this issue. Am I understanding it correctly that what's proposed here is that within a build, the behaviour should work as if process.cwd() was set to the directory that the entry file resides in?

So, given this structure:

 |- package.json
 |- src/
     |- index.html
     |- index.js
     |- a/
         |- a.js
     |- b/
         |- b.md

If src/a/a.js included this snippet:

fs.readFileSync('./b/b.md');

And parcel was run like parcel src/index.js, then it would correctly find b.md? That would be somewhat consistent with Node in the sense that all modules share the same working directory, but it would be inconsistent when comparing these:

node src/index.js # process.cwd() == "/the/project/"
parcel src/index.js # process.cwd() == "/the/project/src"

The current (?) behaviour makes it work exactly like Node, in this sense:

node src/a/a.js # ๐Ÿšซ "/the/project/b/b.md" not found!
parcel src/a/a.js # ๐Ÿšซ "/the/project/b/b.md" not found!

cd src
node a/a.js # โœ… "/the/project/src/b/b.md" found
parcel a/a.js # โœ… "/the/project/src/b/b.md" found

Also, in your case @mytee306 you can do:

const md = fs.readFileSync(require.resolve("./markdown.md"), { encoding: "UTF-8" });
node src/index.js # process.cwd() == "/the/project/"
parcel src/a/a.js # ๐Ÿšซ "/the/project/b/b.md" not found!

The current (?) behaviour makes it work exactly like Node

The issue with this comparison is that process.cwd() doesn't exist on the web.
(fs.readFileSync doesn't get replaced with --target node)

node src/a/a.js # ๐Ÿšซ "/the/project/b/b.md" not found!
parcel src/a/a.js # ๐Ÿšซ "/the/project/b/b.md" not found!

cd src
node a/a.js # โœ… "/the/project/src/b/b.md" found
parcel a/a.js # โœ… "/the/project/src/b/b.md" found

And failing to build depending on the current directory is even worse.

The issue with this comparison is that process.cwd() doesn't exist on the web.
(fs.readFileSync doesn't get replaced with --target node)

You're correct of course, but many of us develop JavaScript for the server and the browser simultaneously, and sometimes modules are shared across those bundles. So having the same piece of JavaScript have two different behaviours in these two context (when they can work the same) seems confusing to me.

Again, the predictable, stable solution to this problem in particular is doing this:

const md = fs.readFileSync(require.resolve("./markdown.md"), { encoding: "UTF-8" });

The issue with this comparison is that process.cwd() doesn't exist on the web.
(fs.readFileSync doesn't get replaced with --target node)

You're correct of course, but many of us develop JavaScript for the server and the browser simultaneously, and sometimes modules are shared across those bundles. So having the same piece of JavaScript have two different behaviours in these two context (when they can work the same) seems confusing to me.

Again, the predictable, stable solution to this problem in particular is doing this:

const md = fs.readFileSync(require.resolve("./markdown.md"), { encoding: "UTF-8" });

thanks for replying, you have a good point however making the above proposed changes results in

src/index.js:20:27: Cannot statically evaluate fs argument
  18 | });
  19 |
> 20 | const md = fs.readFileSync(require.resolve("./markdown.md"), { encoding: "UTF-8" });
     |                           ^
  21 |
  22 | document.querySelector(".app").innerHTML = marked(md);

Reference

@mytee306 Oh! Now this is something that can be improved I think. Parcel should be able to evaluate require.resolve calls statically. Then piping it into fs.readFileSync should make that work too. Maybe modify the issue or create a new one to address this?

I'll change this into a feature request as require.resolve should probably be supported as it's pretty much what parcel currently does (without adding it explicitly).

However process.cwd() can not really be statically evaluated (at least not reliable).

Apologies if I've misread anything, went over this thread rather quickly.

@emilniklas Also see #1661 for some of my thoughts here with the "fake" readFileSync in a browser context.

just tell parcel you're running in a node environment with the target flag

e.g. parcel app.js --target node

@codeshifu That is all it takes!

@codeshifu's tip makes perfect sense and worked perfectly.

just tell parcel you're running in a node environment with the target flag

e.g. parcel app.js --target node

can you please tell me how to do it ??

node_modules/mime/mime.js:52:32: Cannot statically evaluate fs argument
50 | // Read file and split into lines
51 | var map = {},

52 | content = fs.readFileSync(file, 'ascii'),
| ^
53 | lines = content.split(/[\r\n]+/);
54 |
55 | lines.forEach(function(line) {

how can i fix this please

Was this page helpful?
0 / 5 - 0 ratings

Related issues

will-stone picture will-stone  ยท  3Comments

jzimmek picture jzimmek  ยท  3Comments

Niggler picture Niggler  ยท  3Comments

oliger picture oliger  ยท  3Comments

humphd picture humphd  ยท  3Comments