Using React With Webpack and ES6 in a Grunt Task

Grunt has fallen out of fashion as the preferred JavaScript task runner but it’s still powerful nonetheless and millions of people are still using it and making modules for it. Like other technologies before it there have been new tools developed and adopted by the community but both Grunt and Gulp are both used by a large portion of the Node community. Normally when we talk about Webpack we’d assume a configuration where the project uses Gulp as their task runner. Today I want to show you how to create a React app using Grunt tasks to run your scripts through Webpack, Babel to support JSX, and add support for ES6 syntax.

Suppose your in a situation like I am where I develop my simple static sites using Grunt and my more complex web apps using Gulp. You’d start off with a simple Grunt file that did things like transpire LESS, run a JS linter, a simple local server. Now imagine your simple static site could benefit from some simple React components. What do you do now? Refactor all of your code and configs to use Gulp instead? There’s an easier way. Just use Webpack and React’s suggested setup.

This is exactly what I’m doing with my TapTempo app. It started out as a simple one script, jQuery based, single page app. After looking at the structure of my markup I decided it would be a good idea to turn it into a React application. This would make it easier to add features in the future and there are a lot of features I can think of that this app will need beyond it’s simple “tap to calculate tempo” functionality.

Where to begin

First, we just go through the normal React installation procedures. Assuming your project is an NPM module (you ran npm init when you started your project, right?) you can start by installing React

Install Webpack and Babel

In this section we’re going to enable ES6 and Babel support.

npm install webpack --save-dev

The Webpack docs tell you to create config files and such. Ignore that. We’re going to use Grunt to configure out Webpack installation. I personally install Webpack both locally and globally. The above command installs a local copy to your project while this will install it globally: npm install -g webpack.

Next we install Babel with npm install --save-dev babel-loader babel-core.

Install the Webpack Grunt task

npm install grunt-webpack --save-dev

Installing React

npm install --save react react-dom

We need Webpack and Grunt to understand React syntax so we install a couple more modules.

npm install --save-dev babel-cli babel-preset-react

npm install --save-dev babel-cli babel-preset-es2015

Integrate React, Webpack, and all it’s dependencies into your Grunt task

Now we install the Grunt module that’ll take our React JSX and ES6 code and turn it into something browsers understand.

npm install grunt-webpack --save-dev

Now we’re ready to use Grunt to have Webpack transpile our code.

Suppose we have a Gruntfile that looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
module.exports = function(grunt) {

  // Time your grunt tasks and never need to loadGruntTask again
  require('time-grunt')(grunt);
  require('load-grunt-tasks')(grunt);

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    project: {
      dev: 'src',
      dist: 'dist',
      build: '<%= grunt.template.today("yyyymmdd") %>'
    },

    // local server
    connect: {
      server: {
        options: {
          host: 'localhost',
          port: process.env.PORT || '9000',
          base: '<%= project.dev %>/'
        }
      }
    },

    // watch for file changes
    watch: {
      styles: {
        files: ['<%= project.dev %>/less/**/*.less'],
        tasks: ['less:dev'],
        options: {
          livereload: true
        }
      },
      scripts: {
        files: ['<%= project.dev %>/js/**/*.js', 'Gruntfile.js'],
        tasks: ['webpack:build', 'jshint:dev'], // !important
        options: {
          livereload: true,
          reload: true
        }
      }
    },

    // compile less
    less: {
      dev: {
        files: {
          '<%= project.dev %>/css/style.css': ['<%= project.dev %>/less/style.less']
        }
      }
    },

    // lint js
    jshint: {
      options: {
        reporter: require('jshint-stylish')
      },
      dev: ['<%= project.dev %>/js/**/*.js', '<%= project.dev %>/js/scripts.js']
    },

    // copy
    copy: {
      setup: {
        expand: true,
        cwd: '<%= project.dev %>/vendor/font-awesome/fonts/',
        src: ['*.{otf,ttf,svg,eot,woff,woff2}'],
        dest: '<%= project.dev %>/fonts/'
      }
    },

    // webpack !pay attention to this task!
    webpack: {
      build: {
        entry: ['./src/js/scripts.js'],
        output: {
          path: 'src/js/',
          filename: 'build.js'
        },
        stats: {
          colors: false,
          modules: true,
          reasons: true
        },
        storeStatsTo: 'webpackStats',
        progress: true,
        failOnError: true,
        watch: true,
        module: {
          loaders: [
            { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
          ]
        }
      }
    }
  });

  // Tasks
  grunt.registerTask('default', ['develop']);
  grunt.registerTask('develop', [
    'connect:server',
    'watch'
    ]);

  grunt.registerTask('setup', ['copy:setup']);
};

This task serves a static HTML file from src/index.html. Within that file we reference our JavaScripts as /js/build.js. We write our React and ES6 code in scripts.js and it gets transpiled into src/js/build.js. See that webpack task? All of the Webpack options can be used within that object. That’s why you don’t need to create a Webpack config file.

How it all works together

When you run grunt a local static server is run. It serves up static files in the src/ folder. Whenever src/js/scripts.js changes we run the scripts.js file through Webpack, it gets transpiled into build.js and that gets listed and referenced within the HTML. Now you can create React components and update your Grunt config as needed as you add more JSX/React files.

I used to be a Gulp + Webpack user as they’re a little easier to wrap your mind around – at least for me as a Gulp user for the past year (it’s been a while since I did anything complex with Grunt) – but Grunt and Webpack essentially do the same thing and React supports both and even has documentation on setting them up. The React docs are more thorough but the downside is that you need to visit a lot of different websites read lots of docs before you can get up and running. My goal here was to put all the information you needed in one place so you didn’t need to switch tabs and possible get lost like I almost did my first few times around.

So check this out and remember: as long as a tool is being actively maintained there’s someone out there using it and you can get a job off those skills. You can have your preferences but dip your toes into other tech every now and then so you can understand the pros and cons of each, how they differ, and what they’re best uses are.

That’s that. How to use Webpack with Grunt to build a React application using ES6 and Babel. Let me know if I skipped a step as I’m writing this on a Friday evening, tired from a long work week.

Web development

« Why developers hate being called by recruiters Do you even microservice, bro? »

Comments