Skip to content

Instantly share code, notes, and snippets.

@ORESoftware
Last active May 10, 2016 02:15
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ORESoftware/c05c4977a9e4b88cfbdc to your computer and use it in GitHub Desktop.
Save ORESoftware/c05c4977a9e4b88cfbdc to your computer and use it in GitHub Desktop.
Hot reloading with React + RequireJS
define(['require'],function(require){ // 'require' is a reserved dependency keyword in RequireJS
var module = require('someModule'); //if we know for sure that someModule is already loaded, then we can load it here synchrounously
});
var gulp = require('gulp');
var socketio = require('socket.io');
var EE = require('events').EventEmitter;
var react = require('gulp-react');
var io = socketio.listen('3002', function (err, msg) {
if (err) {
console.error(err);
}
});
io.on('connection', function (socket) {
console.log('a client connected');
socket.on('disconnect', function () {
console.log('a client disconnected');
});
});
gulp.watch('./public/static/app/js/views/**/*.js').on('change', function (file) {
var reconciledPath = reconcilePathForRequireJS(file); //you need to do some work to reconcile RequireJS paths with your front-end app
var ee = transpileJSX();
ee.on('error', function (err) {
io.sockets.emit('.jsx transform error', JSON.stringify(err))
});
ee.on('end', function () {
io.sockets.emit('hot-reload (.jsx)', reconciledPath);
});
});
function transpileJSX() {
var ee = new EE();
gulp.src('./public/static/app/js/views/**/*.js')
.pipe(react({harmony: false})).on('error', function (err) { //we absolutely need error handling, so front-end doesn't croak if we make mistakes writing our JSX
ee.emit('error',err);
})
.pipe(gulp.dest('./public/static/app/js/jsx')).on('error', function (err) {
ee.emit('error',err);
}).on('end', function () {
ee.emit('end');
});
return ee;
}
define(function () {
function hotReloadSimple(item, callback) {
require.undef(item); // nullifies module identified by string 'item'
require([item], function (module) { //RequireJS will now look on the filesystem for the module of the same name since it no longer exists in the browser runtime
callback(null, module);
});
}
return {
hotReloadSimple:hotReloadSimple
}
});
define([
'socketio',
'#allCollections',
'#allCSS',
'#hotReload',
'app/js/cssAdder'
],
function (io, collections, allCSS, hotReload, cssAdder) {
var socketHotReload = null;
function getConnection() {
if (socketHotReload == null) {
socketHotReload = io.connect('http://127.0.0.1:3002');
//you should implement io.on 'error', on 'connect' and on 'disconnect' etc
socketHotReload.on('.jsx transform error', function (data) {
throw new Error(data)); //you need to implement window.onerror to prevent error from crashing front-end
});
socketHotReload.on('hot-reload (.jsx)', function (data) {
hotReload.hotReloadSimple(data,function(err,result){
if(err){
alert(err);
return;
}
var filename = reconcilePath(data); //you need to implement reconcilePath
require(['#allViews'],function(allViews){ //I have a module '#allViews' that contains all my front-end views
allViews[filename] = result;
Backbone.history.loadUrl(Backbone.history.fragment); //reload the current page (don't need to worry about any other pages)
});
});
});
}
return socketHotReload;
}
return {
getConnection: getConnection,
};
});
// RequireJS loads all dependencies outline in the config file before starting the app, this allows us to predefine certain dependences so that we can later use *synchronous* require calls
// the synchronous require calls will allow us to do hot reloading with React and Backbone
requirejs.config({
enforceDefine: false,
waitSeconds: 6,
baseUrl: '/static', //Node.js Express server makes the public folder basically into the root, so we start at 'static' as in public/static/*
paths: {
'async': 'vendor/async',
'jquery': 'vendor/jquery',
'ejs': 'vendor/ejs',
'flux': 'vendor/Flux',
'text': 'vendor/text', //important RequireJS plugin for text files CSS & HTML templates
'underscore': 'vendor/underscore-min',
'backbone': 'vendor/backbone',
'bootstrap': 'vendor/bootstrap',
'react':'vendor/react-with-addons',
'socketio': 'vendor/socketio',
'events': 'vendor/events-amd',
'#patches': 'app/js/patches',
'#allTemplates': 'app/js/meta/allTemplates',
'#allViews': 'app/js/meta/allViews',
'#allModels': 'app/js/meta/allModels',
'#allCollections': 'app/js/meta/allCollections',
'#appState': 'app/js/appState', //the # syntax is my own to identify that it's my own module and a singleton
'#viewState': 'app/js/viewState',
'#allControllers': 'app/js/meta/allControllers',
'#allDispatchers': 'app/js/meta/allDispatchers',
'#BaseCollection': 'app/js/collections/BaseCollection',
'@AppDispatcher': 'app/js/flux/dispatcher/AppDispatcher',
'#allCSS': 'app/js/meta/allCSS',
'#allFluxActions': 'app/js/meta/allFluxActions',
'#allFluxConstants': 'app/js/meta/allFluxConstants',
'#SuperController' : 'app/js/controllers/SuperController'
},
'shim': {
'underscore': {
'exports': '_'
},
'backbone': {
'deps': ['jquery', 'underscore'],
'exports': 'Backbone'
},
'handlebars': {
'exports': 'Handlebars'
},
ejs: {
exports: "ejs"
}
}
});
require(['app/js/application'], function (Application) {
Application.start();
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment