DRY, Browserify

In my last post, I discussed some of the biggest lessons I learned while building my first component in ReactJS. One of those lessons revolved around Browserify, and how it was the best way to leverage component reuse.

As I moved closer to production, I realized there was one particularly nasty side effect to Browserify. Take the following code for example:

var React = require("react");
var ReactDOM = require("react-dom");

// Custom React Component
var RecipeTabs = require("components/RecipeTabs.js");

function initPage()
{
	ReactDOM.render(
	  React.createElement(RecipeTabs),
	  document.getElementById('recipeTabs')
	);
}

Browserify lets us use CommonJS require syntax even though browsers don’t natively support it. One way it does this is by inlining the entire contents of your require’d JavaScript into your script. So, in the example above, our 13-line script will suddenly grow to include all of React, all of ReactDOM and all of the code for RecipeTabs.

If we blindly require React in this manner inside every JavaScript file on our site, then we end up with a bunch of duplicate inlined code. Even worse, we are forcing users to download the same code over and over. The browser only sees unique file names and sizes — it isn’t smart enough to realize that inside those files are large chunks of repeated code. What we really want is one file that contains all of our common code, and reuse that file on every page. That way, the browser only downloads the code once; every other page load uses a cached copy.

Thankfully, Browserify natively provides a solution to this issue.

The trick is to create a single file that contains all JavaScript requires used site-wide. This single bundle can then be included on all of your pages.

Browserify gives us an easy way to do this. For example, using gulp:

gulp.task('browserify-global', function() {
	return browserify()
		.require(['react','react-dom'])
		.transform(envify)
		.bundle()
		.pipe(source('exports.js'))
		.pipe(gulp.dest('./js'));
});

This creates an exports.js file which is a bundle of React and ReactDOM. We can now include this on every page of our site — the browser will download it once and then cache it for every subsequent page.

But we still have a problem. Browserify doesn’t know about exports.js when it processes the rest of the site’s JavaScript. It will go ahead and inline React and ReactDOM as usual wherever it’s require’d.

The second piece to make this work is to tell Browserify to not inline certain require’d libraries:

gulp.task('browserify-custom', function() {
    return glob('./src/**/*.js', function(err, files) {
        if(!err) {
	        var tasks = files.map(function(entry) {
	            return browserify({ entries: [entry] })
	                .external(['react','react-dom'])
	                .bundle()
	                .pipe(source(entry))
	                .pipe(gulp.dest('./js'));
	        });
		}
	});	
});

Now, whenever Browserify encounters a require for ‘react’ or ‘react-dom’, it won’t inline the script. But, as long as we include the exports.js generated in the previous step, the reference will resolve, and it will be able to execute any React or ReactDOM code.

This isn’t limited to third-party JavaScript libraries either. If you have your own code that is referenced across the entire site, then you can include it:

.require(['react','react-dom', {file: './src/pn.js', expose: 'pn'}])

The expose property specifies the name to use in your require statements. In this case, whenever I need to reference code in pn.js, I can simply require(‘pn’).

In the second step, we can now specify pn as an external library:

.external(['react','react-dom','pn'])

ReactJS: What I Learned From My First Component

Today marks an important milestone — I’m blogging about a JavaScript library!

Ever since I took a deep-dive JavaScript boot camp a few months ago, I’ve been eager to start a project that would let me hone my newly-acquired skills. To that end, I’ve been refactoring ProjectNom’s (poorly-coded) JavaScript so that it conforms to best practices.

That’s low-hanging fruit though. What I really wanted to sink my teeth into was something like AngularJS — a modern JavaScript framework that takes the language to another level, opening up entirely new ways of rendering a website (e.g. SPA).

But the problem with Angular is that it’s a full MVC framework, and an opinionated one at that. To truly get the most out of it, I’d have to build ProjectNom from scratch – which I had just finished doing for other reasons, and didn’t want to do again so soon.

At work, it has been proposed that we use ReactJS for any front-end development so that components could be shared and re-used across projects. I didn’t know anything about React except the name, so when I had some free time, I decided to research it.

I started to get really excited. Not only did the philosophy of the framework sound right up my alley, but it was also designed in such a way that it could slot easily into an existing project. After a tutorial or two, I made the decision to take it for a spin on ProjectNom. What follows are my experiences and takeaways as I moved from the perfect world of tutorials to a real world use case.

To be clear, this post is not a tutorial. There are many of those already, including on React’s own website. I include a quick introduction to the theory of React in the next section, but after that I will assume you know the basics of how React works so that we can dig a little deeper.

So what is React?

Let’s imagine for a moment that standard HTML elements — div, ul, input, etc — are like LEGO bricks. They each have a function and purpose; but, on their own, they aren’t very interesting or useful.

React gives us a way to define components. A React component is like a LEGO set – it specifies the pieces and assembly instructions to create an interesting, complex object. It’s easy to define your own component, but there are also a large number of ready-made React components available. Either way, once a component is defined, all you have to do is ask React for it, and it’s ready to use on a web page.

Of course, a static collection of HTML elements is only slightly more interesting than a single HTML element. Most web pages are driven by the data that flows through it, and that’s where React’s power is fully realized. Each React component contains a state and this state defines how the component should look or behave. You can specify an initial state when you first ask React for a component, but that state can be modified at any time in response to new data. You could think of it like a LEGO set that specifies exactly which minifigs should go where, but providing the flexibility to move them around later.

If this sounds as interesting to you as it does to me, then I encourage you to check out a tutorial or two. Feel free to come back here once you understand the basics.

Continue reading