Create-react-app: Using FS in CRA + Electron

Created on 9 Apr 2019  路  14Comments  路  Source: facebook/create-react-app

Is this a bug report?

Unsure.

I'm trying to use create-react-app + electron.js to make a cross-platform desktop app. In that app, I want to save and load the user's files, like Word or Excel. To do so, I need believe I need to use node.js's fs module, which I believe is somehow blocked in CRA, but I also need to use electron.js's dialog as well. Requiring that module throws an error when electron itself can't use fs.

I don't know if this is an error in how I'm thinking about the app, an error in how I've configured my app, an error in react, create-react-app, or electron, or if it's something else. Any help would be appreciated.

I have not ejected the app.

Did you try recovering your dependencies?

Yes. I rebuilt the project essentially from scratch here: https://github.com/arcandio/fstest2

Which terms did you search for in User Guide?

I've looked for

  • react fs empty
  • react electron fs
  • react use fs
  • create-react-app fs

Environment

System:
OS: Windows 10
CPU: x64 AMD FX(tm)-8350 Eight-Core Processor
Binaries:
Yarn: 1.15.2 - C:\Users\arcan\AppData\Roaming\npmyarn.CMD
npm: 5.6.0 - C:\Program Files (x86)\nodejs\npm.CMD
Browsers:
Edge: 44.17763.1.0
Internet Explorer: 11.0.17763.1
npmPackages:
react: ^16.8.4 => 16.8.6
react-dom: ^16.8.4 => 16.8.6
react-scripts: 2.1.8 => 2.1.8
npmGlobalPackages:
create-react-app: Not Found

Steps to Reproduce

(Write your steps here:)

  1. clone or download repo https://github.com/arcandio/fstest2
  2. run npm run electron-dev
  3. observe error inside electron when attempting to access electron's dialog via the remote

Expected Behavior

Expected no error on require: https://electronjs.org/docs/api/dialog, as that documentation indicates that const { dialog } = require('electron').remote should be valid outside electron's main process.

Actual Behavior

App throws an error:

TypeError: fs.existsSync is not a function
getElectronPath
F:/freelance/repos/creative-ontology-editor/node_modules/electron/index.js:8
   5 | var pathFile = path.join(__dirname, 'path.txt');
   6 | 
   7 | function getElectronPath() {
>  8 |   if (fs.existsSync(pathFile)) {
   9 |     var executablePath = fs.readFileSync(pathFile, 'utf-8');
  10 | 
  11 |     if (process.env.ELECTRON_OVERRIDE_DIST_PATH) {

image

Reproducible Demo

https://github.com/arcandio/fstest2

question

All 14 comments

Pretty certain you'll need to eject. The relevant line is here; we mock out fs because it's not available in the browser. This _probably_ will not change; create-react-app is built for running in a normal browser environment. But I feel your pain, as our electron app at work uses ejected cra :')

So the proposed solution is to eject and remove that line that mocks out the one module that I need? I assume then that there's no way to override CRA's webpack configuration, since that's the point of CRA managing the configuration of the project, is that right?

Also, if I eject my actual project, what do I need to know about that? Will things break? Do I need to learn all of webpack?

Or should I change what preset wepack uses in my package.json?

For this particular issue, I think removing that one line would fix it. As you said, there's no way to configure webpack with stock CRA, but there are some alternatives.

Ejecting is honestly rough as it puts you in-charge of a very complex webpack setup. However, the web moves fast, and most of your application code will be relatively build system agnostic if you stick close to CRA's conservative feature set. We ejected back in v1 and it continues to work for us. Webpack has become much more sane in later versions, so touching it to once every six months hasn't been bad.

There are some other projects that purport to make CRA configurable, though I'm not very familiar with them. The react-app-rewired repo may be a good starting place. Here's a page from the docs that talks about alternatives to ejecting. And there are other projects that are similar to CRA but allow more configuration. I've heard of next.js but am not at all familiar. Good luck!

I ejected and commented out line 653, but no luck, somehow. The error is different, but on the same subject/line/problem:

./node_modules/electron/index.js
Module not found: Can't resolve 'fs' in 'F:\freelance\repos\cra electron fs\fstest2\node_modules\electron'

I don't think I know enough about webpack to figure out what's going wrong where on this. I committed up to the test repo, just in case: https://github.com/arcandio/fstest2/tree/ejected

Since my react code is separate from the project configuration, would it be plausible to come at this the other way by starting with an electron app and adding in react? I understand doing so this might not be relevant to the CRA project.

Sorry I missed your reply! Have you tried changing target to electron-renderer? From looking at this issue. The crux is that webpack will inline require statements (its whole job as a bundler), but you really need the require statement to stay as-is and resolve at runtime. I _think_ changing the target will make this happen naturally, but honestly it's been over a year since I've touched our webpack config. Let me know!

How would I do that, concretely? I don't know what target you're talking about, and I can't find "target" in webpack.config.js or package.json, aside from the final build package. Is that what you mean?

Just add it as a key at the top level of your webpack config. Here's the documentation on target.

Alright, tried adding

const options = {
  target: 'electron-renderer'
};

but still no luck.

@arcandio do you have found anyone solution?

@agat Check the pr I sent on their repo.

@arcandio, @heyimalex I found solution without eject, with https://www.npmjs.com/package/@craco/craco.

craco.config.js

module.exports = {
    webpack: {
        configure: {
            target: 'electron-renderer'
        }
    }
};

And check that BrowserWindow has nodeIntegration: true property:

new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
        nodeIntegration: true
    }
});

Thanks guys. @heyimalex's PR seems to have fixed the issue.

Follow #5498 for the final solution

Was this page helpful?
0 / 5 - 0 ratings

Related issues

alleroux picture alleroux  路  3Comments

xgqfrms-GitHub picture xgqfrms-GitHub  路  3Comments

JimmyLv picture JimmyLv  路  3Comments

fson picture fson  路  3Comments

jnachtigall picture jnachtigall  路  3Comments