Posted on May 7, 2015 by Chris Harrington

Webpack with LESS and React

I’ve recently been playing around with Webpack and I really like it. It has the benefits of Browserify in that you can specify an entry point that’ll pull in all of your required modules into a single bundle with optional minification, while also letting you bundle your style together in your modules. For example, I can require a style file for a particular module right from the module itself, which allows me to somewhat limit the global nature of CSS rules. On top of that, Webpack allows us to leverage LESS in these included style files, too, that get compiled down to CSS. I’m a huge fan of this, as it allows us to create less coupled modules in that each style file can be tied directly to a module, and only gets pulled in when its required. Webpack also utilizes what they call “loaders”, which are basically preprocessors that perform various tasks. For example, there’s a LESS loader to convert LESS into CSS, and a JSX loader to perform a similar conversion for React classes.

Configuration

Webpack utilizes a configuration file that sits at the root of your application. It can be invoked in a number of ways: through the command line via the webpack utility, or through any number of build systems like gulp or grunt. I’ve been using gulp to great effect, and I’ll touch on how it works with Webpack a little later on. Here’s my current Webpack configuration:

var path = require("path"),
    webpack = require("webpack");

module.exports = {
    entry: "./src/index.js",
    output: {
        filename: "dist/bundle.js"
    },
    module: {
        loaders: [
            { test: /\.js$/, loader: "jsx-loader" },
            { test: /\.less$/, loader: "style!css!less" }
        ]
    },
    plugins: [
        new webpack.ResolverPlugin([
            new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin("bower.json", ["main"])
        ])
    ],
    resolve: {
        root: [path.join(__dirname, "bower_components"), path.join(__dirname, "./src")]
    }
};

So there’s a few things going on here. First, we’re specifying the entry point to the application. This is important, as Webpack will recursively check each of the files included from your entry file to build the bundle. For example, my entry point is located at src/index.js. In that file, I’m requiring a bunch of other modules, which Webpack will also pull in. Those modules require others, and so on, until Webpack has grabbed every source file, at which point it bundles them all together. Next, the output section allows us to specify the name of the bundle file that gets generated. Mine’s boringly called “bundle.js” in a dist folder.

Under the module section, we can specify loaders (among other things) that provide transformations and other functions to the bundle as it gets built. There are three options for loaders: preLoaders, which are applied first; then loaders, which come second; and finally postLoaders which come third. In this example, I’ve only got standard loaders because each loader is affecting a different subset of files. The first loader is responsible for transforming JSX files into raw JavaScript for the React side of things. Next, I’ve got a loader for transforming my LESS files into raw CSS files. Here, the syntax is a little weird; it indicates that the style loader should execute first, followed by the CSS loader, and then finally the LESS loader.

Note: Each of the loaders I’ve referenced need to be installed separately from Webpack. Here, I’m using a JSX loader, a style loader, a CSS loader and a LESS loader. They can all be installed via npm:

npm install jsx-loader style-loader css-loader less-loader --save-dev

After the module section, there’s a plugin section which (unsurprisingly) allows us to specify various plugins for the bundling process. I’m only using one plugin here, and it’s for compatibility with bower. Because of this section, I’m able to require modules that I’ve installed with bower. It’s very handy, and a large part of why I’m really enjoying Webpack. Browserify also supports this feature.

Finally, there’s the resolve section, which allows me to specify the root directory for requiring modules. This allows me to reference any components under the “src” directory in my require statements, and avoids the require("../../../../path/to/component.js") that so often happens in situations like this.

Example React Class

So how does all of this look in a real world example? I’ve built a small React class that shows off how to include various modules, plus the style for the class.

"use strict";

var React = require("react"),
	Module = require("custom-module");

require("./example-style.less");

module.exports = React.createClass({
	render: function() {
		return <div className="example">
			<Module>An example React class for Webpack and LESS.</Module>
		</div>;
	}
});

A quick run down of what’s going on here. First, I’m able to require both React and a custom module I’ve built excitingly entitled “custom-module”. There’s no relative pathing at work here because it’s hypothetically located under the src folder as specified in the configuration file above. Next, I’m including the style for the module by requiring “example-style.less”. I like this method of styling components, as each component can have its own style. So in this example, the Module class could require its own style that’s decoupled away from example-style.less. It’s very handy.

Gulp Integration

Webpack doesn’t support Gulp out of the box, but there are a few npm packages that’ll do the trick. I’m currently using the gulp-webpack-build module, which allows gulp to read the webpack.config.js file for configuration options, but also lets you override various options that may be beneficial. Here’s my gulp task for watching for webpack changes:

var gulp = require("gulp"),
webpack = require("gulp-webpack-build"),
path = require("path"),
gutil = require("gulp-util"),
moment = require("moment");

gulp.task("script", function() {
return _buildTask(false);
});

gulp.task("watch-script", function() {
return _buildTask(true);
});

function _buildTask(watch) {
return gulp.src(webpack.config.CONFIG_FILENAME)
.pipe(watch ? webpack.watch(_after) : webpack.compile(_after))
.pipe(gulp.dest("dist/"));
}

function _after(err, stats) {
if (err) {
gutil.beep();
_logErrors([err]);
} else if (stats.compilation.errors.length > 0) {
gutil.beep();
_logErrors(stats.compilation.errors);
} else
gutil.log("Scripts recompiled. Time elapsed: " + moment.duration(stats.endTime - stats.startTime).asSeconds() + "s");
}

function _logErrors(errors) {
for (var i = 0; i < errors.length; i++) gutil.log(gutil.colors.red(errors[i])); } [/code] I've created two gulp tasks, here: the first for a standard build, and the second for watching for changes and then building. Both of them use the Webpack node API, which is required at the top of the code section. The only real difference between the two tasks is a call to Webpack's "compile" vs "watch" method. Both of those methods take a callback to allow for custom messages for error and success messages and such. The gulp-webpack-build module provides a format method which shows a similar output to the Webpack command line tool, but I preferred to create my own messages.

Conclusion

So far, I'm enjoying how I can keep my style files modularized using Webpack, and it's relatively easy to use. Next up is running unit tests with Webpack bundles. Thanks for reading!

gisonline-me-gray