Hot reloading for React components in electron without babel nor webpack
Clone or download
Pull request Compare This branch is 7 commits ahead of geowarin:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
src
test-integration
test
.editorconfig
.gitignore
.travis.yml
CHANGELOG.md
README.md
appveyor.yml
compiler.js
package.json

README.md

Electron-hot-loader

npm Build Status Build status

Hot reloading for React components in electron without babel nor webpack

This package leverages react-proxy and electron's access to the file system to enable hot reloading on React components at really high speed.

Demo of electron-hot-boilerplate

Demo: electron-hot-boilerplate

Setup

Put the following code at the top of index.js, the javascript entry point of your application in the browser. It is generally included in your index.html.

if (process.env.NODE_ENV === 'development') {
    const electronHot = require('electron-hot-loader');
    electronHot.install();
    electronHot.watchJsx(['src/**/*.jsx']);
    electronHot.watchCss(['src/assets/**/*.css']);
}

// We can now require our jsx files, they will be compiled for us
require('./index.jsx');

// In production you should not rely on the auto-transform.
// Pre-compile your react components with your build system instead.

// But, you can do this if your really want to:
// require('electron-hot-loader').install({doNotInstrument: true});

The index.jsx file is just the classic React initialization:

const React = require('react');
const ReactDOM = require('react-dom');
const App = require('./ui/App.jsx');

ReactDOM.render(<App/>, document.getElementById('root'));

electron-hot-loader will instrument all your React components and wrap them in proxies. When a file is updated on your disk, the proxies will update and a render will be forced on the root component.

This is very similar to what react-transform-hmr does but without dependencies to babel or webpack.

For your tests you can add this to your mocha config, it will compile your jsx without instrumenting them:

-u bdd
--recursive ./test/**/*.jsx
--full-trace
--reporter spec
--require electron-hot-loader/compiler

Higher order components

A higher order component is a function that takes a component and returns another, decorated, component.

Some libraries (like Redux with connect) use higher-order components. With only access to the AST, it is impossible to find out if a function will return a component or not.

So you will need to explicitly register the names of the higher order components when installing electron-hot-loader:

electronHot.install({higherOrderFunctions: ['connect']});

A demo of electron-hot-loader working with redux is available on the redux branch of electron-hot-boilerplate.

Goal

Since electron is both node and a browser, I figured we could try experimenting hot reloading without webpack in this context.

In its latest versions, node has access to a lot of ES2015 features. There seems to be little need for a babel transpilation... If you can live with the lack of es6 modules and spread operators!

In exchange, you will get a much better developer experience. Not much overhead or config and very fast reloads. Also, as soon as those features land in V8, we'll get them for free!

Principle

Installing electron-hot-loader will use require extensions (don't pay attention to the deprecation warning, it's just for development, right?) to compile JSX files as your require them in your application.

Since we have access to all the compiled components, we can use esprima to get the AST of each one.

The ReactDOM.render method has a distinctive signature that we can use to identify the root of our application.

When a user component is included in a JSX file, it is compiled to React.createElement(). We can wrap all those calls in a register() method, keep track of all the components created that way, and wrap them with react-proxy.

Then, it is just a matter of watching the file system to know which components have been updated and force a re-render on them.

The application will keep all its state and you will get unprecedented productivity.

Disclaimer

This is still a POC. I plan to use it in my current project where I was a little upset with the overhead of using webpack in electron so I will be the first to eat my own dog food.

Critiques and ideas are warmly welcomed so do not hesitate to open issues and sumit pull requests.

Roadmap

  • Write some tests
  • Write some more tests
  • Welcome feedback and ideas
  • Support source maps

Example

Have a look at electron-hot-boilerplate for a complete example.

Thanks

Dan Abramov and the other commiters for their incredible work on react-proxy.

Gurdas Nijor for his inspirational talk at ReactJS 2015 and his repo demonstrating esprima tranforms for React.