Search code examples
reactjsecmascript-6electronbabeljs

export/import custom JSX components (ES6 Modules) in Electron 1.5


I have an Electron 1.5 application, with some JSX components that I wrote. I want the components in a seperate file (module).

Given that Electron supports Node 7.4 and Chromium 54, I figured I could use ES6 module syntax, with export. But I am getting errors with the export command.

This note indicates that ES6 might have issues in Electron: ES6 syntax import Electron (require..)

export class Welcome extends React.Component {
  render() {
    return <h1>Hello Again, {this.props.name}</h1>;
  }
}

export class CountWidget extends React.Component {
  render() {
    return (
      <div>
        <h1>{this.props.value}</h1>
        <button onClick={this.props.onIncrement}>+</button>
        <button onClick={this.props.onDecrement}>-</button>
      </div>);
  }
}

Do I require, or import in the main program:

import {Welcome} from 'componenets\widgets'

I am currently using VSCODE for my IDE, and I have a Babel watch process running that is with the react and es2016 presets running. I tried a es2015 preset, but Electron is not happy with the require syntax that babel uses.

  "babel": {
    "sourceMaps": "inline",
    "presets": [
      "react",
      "es2016"
    ]
  }

UPDATE

I tried using babel-presets-es2016-node5

It still complains of:

Uncaught ReferenceError: exports is not defined(…)

It generated this at the end of the Counter.js file, which is where it complains.

exports.Welcome = Welcome;
exports.CountWidget = CountWidget;

Solution

  • Needed to make a few changes, but Aluan Haddad is basically correct. You cannot use the es2015 preset, you need the es2015-node5 preset. Or I tried both babel-preset-node6 and babel-preset-node7 and they worked for my Electron work.

    Counter.jsx (output will be in ./jsx/Counter.js

    const React = require('react');
    const ReactDOM = require('react-dom')
    
    export class Welcome extends React.Component {
      render() {
        return <h1>Hello Again, {this.props.name}</h1>;
      }
    }
    
    export class CountWidget extends React.Component {
      render() {
        return (
          <div>
            <h1>{this.props.value}</h1>
            <button onClick={this.props.onIncrement}>+</button>
            <button onClick={this.props.onDecrement}>-</button>
          </div>);
      }
    }
    

    Window.js (which imports)

    const {ipcRenderer, remote} = require('electron')
    const {createStore} = require('redux')
    const { composeWithDevTools } = require('redux-devtools-extension')
    const {Welcome, CountWidget} = require('./jsx/Counter.js')
    const React = require('react');
    const ReactDOM = require('react-dom')
    
    
    document.addEventListener("DOMContentLoaded", render)
    //$.ready(creator);
    
    const reducer = (state = 0, action) => {
        switch (action.type) {
            case 'INCREMENT':
                return state + 1;
            case 'DECREMENT':
                return state - 1;
            default:
                return state;
        }
    }
    
    const store = createStore(reducer, composeWithDevTools())
    store.subscribe(render)
    
    function welcome() {
        return React.createElement(Welcome, { name: 'Sara' })
    }
    function widget() {
        var state = store.getState()
        return (
            React.createElement(CountWidget, {
                value: state,
                onIncrement: () => store.dispatch({
                    type: 'INCREMENT'
                }),
                onDecrement: () => store.dispatch({
                    type: 'DECREMENT'
                })
            }))
    }
    
    function render() {
        version()
        ReactDOM.render(welcome(), document.getElementById('root'))
        ReactDOM.render(widget(), document.getElementById('reduxer'))
    }
    
    function version() {
        let ver = remote.getGlobal('MAIN').nodeVersion;
        $('#status span').text(ver);
    }