Live code editing with Browserify and React.
Hot reloading is de facto in today's front-end scene but unfortunately there isn't any decent implementation for Browserify yet. This is shame because (in my opinion) Browserify is the best bundling tool at the moment.
Hence the goal of this project is to bring the hot reloading functionality to Browserify by honoring its principles: simplicity and modularity.
LiveReactload can be used as a normal Browserify plugin. When applied to the bundle, it modifies the Browserify bundling pipeline so that the created bundle becomes "hot-reloadable".
- LiveReactload starts the reloading server which watches the bundle changes and sends the changed contents to the browser via WebSocket.
- When the changes arrive to the browser, LiveReactload client (included automatically in the bundle) analyzes the changes and reloads the changed modules
Starting from version 2.0.0
LiveReactload utilizes Dan Abramov's
babel-plugin-react-transform and
react-proxy, which means that hot-reloading
capabilities are same as in Webpack.
And because one photo tells more than a thousand words, see the following video to see LiveReactload in action:
If you are a Webpack user, you probably want to check react-transform-boilerplate.
If you want to stick with browserify, but use the Hot Module Reloading API (like webpack), you could use: browserify-hmr, babel-plugin-react-transform and react-transform-hmr
LiveReactload requires watchify
, babelify
and react >= 0.13.x
in order to
work.
ATTENTION: these instructions are meant for Babel 6.x. If you are using Babel 5.x, please see the Babel 5.x example.
Install pre-requirements (if not already exist)
npm i --save react
npm i --save-dev watchify
Install babelify
and its dependencies
npm i --save babelify babel-preset-es2015 babel-preset-react
Install React proxying components and LiveReactload
npm i --save-dev livereactload [email protected] babel-plugin-react-transform
Create .babelrc
file into project's root directory (or add react-transform
extra
if the file already exists). More information about .babelrc
format and options
can be found from babel-plugin-react-transform.
{
"presets": ["es2015", "react"],
"env": {
"development": {
"plugins": [
["react-transform", {
"transforms": [{
"transform": "livereactload/babel-transform",
"imports": ["react"]
}]
}]
]
}
}
}
And finally use LiveReactload as a Browserify plugin with watchify
. For example:
node_modules/.bin/watchify site.js -t babelify -p livereactload -o static/bundle.js
That's it! Now just start (live) coding! For more detailed example, please see the basic usage example.
Ideally your client code should be completely unaware of the reloading. However,
some libraries like redux
require a little hack for hot-reloading. That's why
LiveReactload provides module.onReload(..)
hook.
By using this hook, you can add your own custom functionality that is executed in the browser only when the module reload occurs:
if (module.onReload) {
module.onReload(() => {
... do something ...
// returning true indicates that this module was updated correctly and
// reloading should not propagate to the parent components (if non-true
// value is returned, then parent module gets reloaded too)
return true
});
}
For more details, please see the redux example.
LiveReactload is build system agnostic. It means that you can use LiveReactload with all build systems having Browserify and Watchify support. Please see build systems example for more information.
Well... if you hide your state inside the modules then the reloading will lose the state. For example the following code will not work:
// counter.js
const React = require('react')
let totalClicks = 0
export default React.createClass({
getInitialState() {
return {clickCount: totalClicks}
},
handleClick() {
totalClicks += 1
this.setState({clickCount: totalClicks})
},
render() {
return (
<div>
<button onClick={this.handleClick}>Increment</button>
<div>{this.state.clickCount}</div>
</div>
)
}
})
You can configure the LiveReactload Browserify plugin by passing some options
to it (-p [ livereactload <options...> ]
, see Browserify docs for more information
about config format).
LiveReactload supports the following configuration options
Prevents reload server startup. If you are using LiveReactload plugin with Browserify (instead of watchify), you may want to enable this so that the process won't hang after bundling. This is not set by default.
Starts reload server to the given port and configures the bundle's client to
connect to the server using this port. Default value is 4474
Configures the reload client to use the given hostname when connecting to the
reload server. You may need this if you are running the bundle in an another device.
Default value is localhost
Omits the reload client from the generated bundle.
Overrides the default reload client implementation with your custom one. This can be either a global module or local module path relative to the bundle's entry file.
Example usage:
-p [ livereactload --client './customClient' ]
And the custom client code:
// customClient.js
export default function client(scope, callbacks) {
const {change} = callbacks
const ws = new WebSocket("ws://my.custom.livereactload.server.path:port")
ws.onmessage = m => {
const msg = JSON.parse(m.data)
if (msg.type === "change") {
change(msg)
}
}
}
MIT
Please create a Github issue if problems occur. Pull request are also welcome
and they can be created to the development
branch.