Last active
May 10, 2016 02:15
-
-
Save ORESoftware/c05c4977a9e4b88cfbdc to your computer and use it in GitHub Desktop.
Hot reloading with React + RequireJS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
}); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
}); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | |
}; | |
}); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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