All Projects → ORESoftware → Hr4r

ORESoftware / Hr4r

Example project - "Hot Reloading 4 RequireJS" front-end web applications & some extra code demonstrating hot-reloading for Node.js Express servers

Programming Languages

javascript
184084 projects - #8 most used programming language
typescript
32286 projects

Projects that are alternatives of or similar to Hr4r

bs-dynamic-import
📦🚀 BuckleScript dynamic import interop on JavaScript environment
Stars: ✭ 31 (+10.71%)
Mutual labels:  dynamic, code-splitting, lazy-loading
systemjs-tools
(dev)tools for working with SystemJS
Stars: ✭ 41 (+46.43%)
Mutual labels:  hot-reloading, hot-reload
untool
JavaScript tooling platform that focuses on universal React applications. Supports advanced features such as hot-reloading, static and dynamic server side rendering and code splitting.
Stars: ✭ 18 (-35.71%)
Mutual labels:  hot-reloading, code-splitting
Redux Dynamic Modules
Modularize Redux by dynamically loading reducers and middlewares.
Stars: ✭ 874 (+3021.43%)
Mutual labels:  code-splitting, dynamic
Preact Lazy Route
Lazy load preact route components
Stars: ✭ 12 (-57.14%)
Mutual labels:  code-splitting, lazy-loading
guide-to-async-components
📖 Guide To JavaScript Async Components
Stars: ✭ 79 (+182.14%)
Mutual labels:  code-splitting, lazy-loading
hot-reload
Hot reload development for Go
Stars: ✭ 72 (+157.14%)
Mutual labels:  hot-reloading, hot-reload
Jet Live
c++ hot code reload for linux and macos
Stars: ✭ 283 (+910.71%)
Mutual labels:  hot-reloading, hot-reload
flutter dynamic
The flutter_dynamic is a library that create flutter application dynamic.
Stars: ✭ 66 (+135.71%)
Mutual labels:  dynamic, hot-reload
isomorphic-react-redux-saga-ssr
Isomorphic, React, Redux, Saga, Server Side rendering, Hot Module Reloading, Ducks, Code Splitting
Stars: ✭ 19 (-32.14%)
Mutual labels:  hot-reloading, code-splitting
Playgrounds
Better playgrounds that work both for Objective-C and Swift
Stars: ✭ 2,586 (+9135.71%)
Mutual labels:  hot-reloading, hot-reload
Crx Hotreload
Chrome Extension Hot Reloader
Stars: ✭ 545 (+1846.43%)
Mutual labels:  hot-reloading, hot-reload
Systemjs Hot Reloader
reloads your modules as needed so that you can have satisfyingly fast feedback loop when developing your app
Stars: ✭ 215 (+667.86%)
Mutual labels:  hot-reloading, hot-reload
Systemjs Hmr
Hot Module Replacement for SystemJS
Stars: ✭ 24 (-14.29%)
Mutual labels:  hot-reloading, hot-reload
Cssfx
Allow runtime modification of JavaFX CSS
Stars: ✭ 95 (+239.29%)
Mutual labels:  hot-reloading, hot-reload
Require Vuejs
RequireJS plugin to async and dynamic load and parse .vue components
Stars: ✭ 143 (+410.71%)
Mutual labels:  requirejs, dynamic
React Redux Universal Boilerplate
An Universal ReactJS/Redux Boilerplate
Stars: ✭ 165 (+489.29%)
Mutual labels:  code-splitting, hot-reload
React Pwa
An upgradable boilerplate for Progressive web applications (PWA) with server side rendering, build with SEO in mind and achieving max page speed and optimized user experience.
Stars: ✭ 2,433 (+8589.29%)
Mutual labels:  code-splitting, hot-reload
active reloader rb
Rails gem that reloads browser as soon as any file is changed
Stars: ✭ 11 (-60.71%)
Mutual labels:  hot-reloading, hot-reload
Vueniverse
Full stack, user based, PWA, Vue template.
Stars: ✭ 339 (+1110.71%)
Mutual labels:  code-splitting, hot-reload

#hr4R

client-side hot-reloading is much more useful than server-side hot-reloading - both can save you time - but client hot-reloading can save you lots more time, and make designers' lives much better.

######the steps for clientside hot-reloading are:

  1. gulp.js watchers listen for filesystem changes
  2. socket.io server in gulpfile sends a message to all browser clients with the path of the file that changed
  3. client deletes cache representing that file/module, and re-requires it (using AJAX to pull it from the server filesystem)
  4. front-end app is configured / designed to re-evaluate all references to the modules that it wishes to hot-reload, in this case, only JS views, templates and CSS are available to hot reload - the router, controllers, datastores (Backbone Collections and Models) are not configured yet. I do suspect all files could be hot reloaded with the only exception being data stores.

RequireJS makes this all very easy to do since it's an asynchronous module loading system - you don't need to run a build or an incremental build to get the client code in the air - and you may easily require a nominal file on the fly. In production, you can use r.js to build optimized (concatenated, minified) deployment files, and your requires essentially become synchronous instead of asynchronous. RequireJS is the real deal. Thanks RequireJS.

####Clientside hot-reloading

to run this Express server, you should have a local MongoDB instance running with this command

ulimit -n 1024 && mongod --dbpath /some/path/anywhere/you/want/mongodb_dev_data --replSet rs0

start the node.js Express server with

gulp nodemon

this runs Nodemon, after running some other important gulp tasks. Nodemon is a must-have, and it should be configured to ignore changes to your client code - in this case, nodemon only looks for server changes and ignores changes that we make to the client code in the public directory. On the other hand - our front-end hot-reloading process will listen exclusively to files in the public directory.

we run a couple tasks before starting nodemon - we transpile JSX and then run a metadata generator that I wrote that allows RequireJS to require entire directories, this is very useful for controllers and views, especially controllers that follow some path convention. Without a controller path convention I know of no possible way from keeping your front-end router files from getting enormous.

next up, let's talk about the gulpfile.js at the root of the project

gulpfile.js contains this code at the bottom of the file:

gulp.task('metagen:all', ['transpile-jsx'], function (done) {
    runAllMetagens(done);
});


gulp.task('nodemon', ['metagen:all', 'watch:hot-reload-front-end', 'watch:hot-reload-back-end'], function () {

    nodemon({

        script: 'bin/www.js',
        ext: 'js',
        ignore: ['public/*', '*.git/*', '*.idea/*', 'routes/*', 'gulpfile.js'],     //nodemon monitors our server for changes, but ignores changes to client code in public directory
        args: ['--use_socket_server', '--use_hot_reloader'],
        nodeArgs: [],
        env: {'NODE_ENV': 'development'}

    }).on('restart', []);

});

you should look into what the 'watch:hot-reload-front-end' task does - it sends a socket.io message to the browser, however many browsers you have open on your development machine, sometimes I have 2 or 3 and I need all browser windows to receive an update, of course they all do, thanks to websockets, thanks Socket.io.

in the client code (all client code is in the ./public directory) we have a hotReloadHandler, which is a socket.io client

there's some extra ugly code in there that resolves paths that I wish to simplify but essentially the code looks like this

socketHotReload.on('hot-reload (.jsx)', function (data) {

    updateProgressBar(40);

    hotReloader.hotReload(data,function(err,result){              // deletes the cached module reference

        if(err){
            alert(err);
            return;
        }

        updateProgressBar(60);

        var filename = deCapitalizeFirstLetter(reconcilePath1(data,'jsx'));

        require(['#allViews'],function(allViews){                  // AJAX is used to re-require the file
            allViews[filename] = result;                           // new file is loaded and we update the singleton "allViews" that holds the references to every view in the app
            updateProgressBar(80);
            Backbone.history.loadUrl(Backbone.history.fragment);   // we re-render all views in sight, via the Backbone router (this does not refresh the page!)
            updateProgressBar(100);
        });
    });
});

the above calls the following module, which does all the reloading, for .js, templates and CSS

  define(function () {

        var hotReloadSimple = function (item, callback) {
            require.undef(item);
            require([item], function (file) {
                callback(null, file);
            });
        };

        return {
            hotReload:hotReloadSimple
        }

    });

that's pretty much it for client-side hot-reloading
...next up we have serverside hot-reloading

hot-reloading Node.js Express server code

I debated whether to include this portion of serverside reloading, but I think it's actually easier to reload servercode and then when you get the idea, you can try the clientside second.

in our canonical app.js, at the root of the project, we have this:

var runRoute = null;

if (app.get('env') === 'development') {
    runRoute = function (path) {   //this hot reloads all file in the routes dir (serverside hot-reloading - less time waiting for server to restart with nodemon)
        return function (req, res, next) {
            require(path)(req, res, next);
        };
    }
}
else {
    runRoute = function (path) {  //for production and test environments, runRoute function resolves modules immediately
        return require(path);
    }
}

//ROUTES
app.use('/', runRoute('./routes/index'));


as you can see, if we are in the development environment, runRoute is function that returns a function (known as functor for all you academics), which means that every time a route is hit, it re-evaluates the require statement - so if we reload a file, it will re-evaluate the require pulling in the new file and avoiding re-referencing the old file. DON'T WORRY. If the file is already cached it will not slow down your development server, at all. If you delete the cache, only then will it have to do the extra work of re-requiring the file. It does not have to re-require everytime. Just to be sure you get that.

Got it? pretty straightforward

we don't need socket.io for serverside reloading - because we already have an HTTP server listening for stuff

so in development mode we just need to add a route that can handle hot-reload requests like so:

if (app.get('env') === 'development') {
    app.post('/hot-reload', function (req, res, next) {  //route to handle serverside hot-reloading of files in our /routes dir
        var path = req.body.path;
        path = require.resolve(path);
        if (path.indexOf('node_modules') < 0 && path.indexOf('routes') > 0) {
            try {
                delete require.cache[path];
                res.send({success: 'successfully deleted cache with keyname: ' + path});
            }
            catch (err) {
                res.send({error: String(err)});
            }
        }
    });
}

as you can see, I configured it to ignore anything in /node_modules/ directory and made sure only the /routes directory was being listened to; I could have just used '/routes/' but just in case there was some node_module with '/routes/' in the path, I added that clause. Not as fail proof as I would like, but should work for now.

the final part of the equation is similar to front-end reloading - we use gulp to listen to the filesystem - like so:

gulp.task('watch:hot-reload-back-end', function () {

    //if route file changes, we just reload that one route, it works

    gulp.watch('./routes/**/*.js').on('change', function (file) {

        request({
                method: 'POST',
                json: {
                    path: file.path
                },
                uri: 'http://localhost:3000/hot-reload'
            },
            function (err, response, body) {
                if (err) {
                    console.log(colors.red(ijson.parse(err).error));
                }
                else {
                    console.log(colors.blue(ijson.parse(body).success));
                }
            });
    });
});

if you have any questions you can open an issue, thanks!

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].