5

I want to build an Electron app with ES6 import syntax so I can re-use modules between my Node.js and browser side JS without code duplication and found Electron is frustratingly behind the times on ES6 syntax support.

I learned about this magical solution only to discover it was no longer maintained.

So Babel to the rescue, or so I thought. Google isn't exactly fruitful on the topic of Babel + Electron tutorials. I also wanted to throw in Nodemon.

Here's my setup:

package.json

{
  "name": "infinitum",
  "version": "1.0.0",
  "description": "",
  "main": "compiled.js",
  "directories": {
    "test": "tests"
  },
  "scripts": {
    "start": " electron .",
    "compile": "nodemon --exec babel-node app.js --out-file compiled.js"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.12.10",
    "@babel/node": "^7.12.10",
    "@babel/preset-env": "^7.12.11",
    "electron": "^11.1.0",
    "nodemon": "^2.0.6"
  }
}

As you're going to see in the following output and debugging logs, the problem here is we're trying to compile the node module to use ES6 syntax, but any Electron app is dependent on the Electron module, which seems to not export in a traditional way, resolving the electron executable path (string) instead of a Node.js module. It's a circular problem.

app.js

import {app, BrowserWindow} from 'electron'
import 'url'
import 'path'

let win

function createWindow() {
   win = new BrowserWindow({width: 800, height: 600})
   win.loadURL(url.format ({
      pathname: path.join(__dirname, 'index.html'),
      protocol: 'file:',
      slashes: true
   }))
}

app.on('ready', createWindow)

.babelrc

{
  "presets": [
    "@babel/preset-env"
  ]
}

I'm running:

npm run compile

Which gives the error:

C:\Users\jonat\documents\github\infinitum\app.js:23
_electron.app.on('ready', createWindow);
              ^

TypeError: Cannot read property 'on' of undefined
    at Object.<anonymous> (C:\Users\jonat\documents\github\infinitum\/app.js:16:5)
    at Module._compile (internal/modules/cjs/loader.js:1076:30)
    at Module._compile (C:\Users\jonat\Documents\GitHub\infinitum\node_modules\pirates\lib\index.js:99:24)
    at Module._extensions..js (internal/modules/cjs/loader.js:1097:10)
    at Object.newLoader [as .js] (C:\Users\jonat\Documents\GitHub\infinitum\node_modules\pirates\lib\index.js:104:7)
    at Module.load (internal/modules/cjs/loader.js:941:32)
    at Function.Module._load (internal/modules/cjs/loader.js:782:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
    at Object.<anonymous> (C:\Users\jonat\Documents\GitHub\infinitum\node_modules\@babel\node\lib\_babel-node.js:172:21)
    at Module._compile (internal/modules/cjs/loader.js:1076:30)

So to debug I tried this app.js:

import electron from 'electron'
console.log("typeof electron:", typeof electron, "\nelectron:", electron)

Output:

typeof electron: string
electron: C:\Users\jonat\documents\github\infinitum\node_modules\electron\dist\electron.exe

And as further clarification, an app.js like this:

import * as name from 'electron'
console.log({ name })

logs:

{
  name: {
    default: 'C:\\Users\\jonat\\documents\\github\\infinitum\\node_modules\\electron\\dist\\electron.exe'
  }
}

I'm realizing this is probably because the "electron ." does something special in the parsing pipeline. But I've definitely heard of Babel being the solution to using ES6 import syntax in Electron, I just cant find an actual guide on doing it. So how can I use Babel with Electron?

J.Todd
  • 707
  • 1
  • 12
  • 34
  • IIRC I switched to electron-react-boilerplate after having an electron-forge debacle. I layered a bunch of stuff on top of it, but it solved the immediate issues--it may not be what you're looking for, but it's certainly a good starting point. – Dave Newton Dec 21 '20 at 18:10
  • @DaveNewton Thanks for the knowledge but if I have to use a module called electron-react-boilerplate in a project without react just to use ES6 import syntax I might just code the app in assembly instead. I'd be going through the same amount of time / trouble and save myself some dignity. – J.Todd Dec 21 '20 at 18:15
  • @J.Todd Funny, but untrue :) My point, as I stated, is that it's a good starting point to understand the setup, since it uses ES6. Maybe just pull out the React-related stuff. – Dave Newton Dec 21 '20 at 18:21
  • Webpack works good for me on electron projects using javascript or typescript. It may be worth to have a look. – Rhayene Dec 22 '20 at 13:04

1 Answers1

3

I think the problem is about your usage of babel-node. babel-node is a node cli clone that does babel transformations before executing JS code. It is not a compiler. There is no --out-file flag defined for this cli. It's a pity that it does not warn you for using an unrecognized flag.

In order to compile your ES6 files, you need to use babel cli. Replacing babel-node with babel at your compile task should do the trick.

Also you need to replace your imports to import * as ... from ... syntax:

import * as url from 'url'
import * as path from 'path'

You can also check Electron 12 previews. They support Node 14, which supports ES modules. So when Electron 12 is out, it should theoretically be possible to use ES modules without Babel.

infiniteRefactor
  • 1,940
  • 15
  • 22