Show Buttons
Share On Facebook
Share On Twitter
Share On Google Plus
Share On Linkdin
Share On Reddit
Share On Stumbleupon
Contact us
Hide Buttons

Configure reactjs with webpack and grunt

So, you wanna bun­dle your react com­po­nents using web­pack? How about a grunt task that con­tin­u­ously watches the changes that you make to your jsx files and auto­mat­i­cally com­piles them before web­pack bun­dles them together?

In this post, we are going to do exactly that.

The entire source code for this project is avail­able at github here .

Direc­tory Structure

The project has 3 main parts
– app.js: A sim­ple nodejs http server that lit­er­ally does noth­ing but server your sta­tic pages.
– public/js/src: The direc­tory where we will keep all our .js and .jsx files.
– public/js/build: The direc­tory where the com­piled form of our jsx files are placed and then bun­dled.
– Two basic html pages: public/index.html , public/anotherPage.html, just to demon­strate how to con­fig­ure web­pack to cre­ate one bun­dle per page.

rootd directory structure

Set­ting up your package.json
You can look at the package.json file from the github repos­i­tory. Else, if you are adding it to an exist­ing project, you can run the fol­low­ing com­mands from your project root to get your dev depen­den­cies right.

npm install --save-dev expose-loader grunt grunt-browserify grunt-cli grunt-contrib-watch grunt-react grunt-webpack webpack nodemon

If you haven’t installed react, you will need to do that as well

npm install --save react

The public/js/src direc­tory
Sicne React mainly deals with com­po­nents, its nice to have a direc­tory in which you keep all of your com­po­nents. Here’s how our stuff is orga­nized within the public/js/src direc­tory
components/common : As the name sug­gests, keep any com­po­nents reused on mul­ti­ple pages here.
components/index : Com­po­nents spe­cific to the index page.
components/index/Page.jsx: The top level React com­po­nent for the index page.

components/anotherPage: Com­po­nents spe­cific to the anoth­er­Page page.
components/anotherPage/Page.jsx: The top level React com­po­nent for the anoth­er­Page page.

Con­fig­u­ra­tion

The grunt con­fig­u­ra­tion
We are going to keep our grunt file sim­ple by split­ting the con­fig­u­ra­tion of each task into their own files and them require them as modules.

rootd directory structure

module.exports = function(grunt) {

  grunt.initConfig({});

  grunt.config( 'webpack', require('./grunt/webpack.js') );
  grunt.config( 'react', require('./grunt/react.js') );
  grunt.config( 'watch', require('./grunt/watch.js') );

  grunt.loadNpmTasks('grunt-webpack');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-react');

  grunt.registerTask('default', ['react']);

};

Also, make a note of how the keys in the grunt con­fig file are related to the names of the exported files. This is what lets you cre­ate dif­fer­ent files for dif­fer­ent sources.

rootd directory structure

The react task configuration

module.exports = {
    jsx: {
        files: [{
            expand: true,
            cwd: 'public/js/src', // Source Directory
            src: ['**/*.jsx','**/*.js'], // Files to compile
            dest: 'public/js/build', // Destination dir after compile
            ext: '.js'
        }]
    }
};

Web­pack configuration

var path = require('path');

module.exports = {
  dev: {
    entry: {
        index: './grunt/webpack_entries/index.js',
        anotherPage: './grunt/webpack_entries/anotherPage.js',
    },
    output: {
        path: path.join(__dirname,'../public/js/build'),
        filename: 'bundle-[name].js'
    },
    stats: {
        // Configure the console output
        colors: true,
        modules: true,
        reasons: true
    },
    progress: true,
    keepalive: true
  }
};

And finally the con­fig­u­ra­tion for the watch that keeps an eye on file changes
Watch task configuration

module.exports = {
  scripts: {
    files: ['public/js/**/*.jsx', 'public/js/**/*.js'],
    tasks: ['react', 'webpack']
  }
};

As icing on the cake, if you are usng nodejs, you can con­fig­ure a script in your package.json to run your first run your tasks and then restart your nodejs application.

package.json

"scripts": {
    "build": "grunt react && grunt webpack",
    "dev": "grunt watch & nodemon app"
  },

Using the gen­er­ated bun­dles in your html pages
Now that our bun­dles are gen­er­ated, open public/index.html and add a script tag with the src prop­erty js/build/bundle-index.js since that’s the bun­dle that is gen­er­ated for your index. Sim­i­lary, in anotherPage.html, set the script tag’s src prop­erty to js/build/bundle-index.js

NOTE
One prob­lem that I encoun­tered when I set this up was that the react dev tools plu­gin did not show up in chrome. Turns out, you need to expose React as a global object for the plu­gin to work. In order to do that, in our webpack_entires/index.js and webpack_entries/anothePage.js I included a line expose react. Thats the rea­son why we have expose-loader in our depen­dency list.

require('expose?React!react');

That’s all there is to the setup. Now all you gotta do is run npm run dev from your project root and then stop wor­ry­ing about hav­ing to com­pile and bun­dle your changes and restart­ing your nodejs server after every save.

Ryan Sukale

Ryan is a UX engineer living in San Francisco, California.

You may also like...

  • Евгений Куртов

    thank you for the writeup and git repo!

    • tuto­ri­al­hori­zon

      Actu­ally yes. Web­pack has a com­mon­sChunkPlu­gin that lets you do that. I am gonna shortly pub­lish a sig­nif­i­cantly refac­tored ver­sion of this project along with a tuto­r­ial with a much cleaner code orga­ni­za­tion and some web­pack good­ies like the opti­miza­tion that you mentioned

    • tuto­ri­al­hori­zon

      Ive finally updated the project. Its much cleaner and your wepack con­fig is now optimized.

      Check it out and let me know if you have any questions

      https://github.com/tutorialhorizon/react-webpack-setup/releases/tag/v1.0