Electron-hot-loader
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: 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.