Posted by & filed under Javascript, Work.

About two months ago our Core team at Teradek has switched front-end to a single-page application on a new stack. Previous stack included server-side templates, Require.js, Underscore, Backbone, Handlebars for JavaScript and HTML, and Compass for CSS. Current stack is a little different: one static HTML file, Require.js, Lodash, Backbone + Chaplin + React for JS and HTML, and Stylus for CSS.

This short post is about React.js — not my opinion of it as a library, but about building it, giving you some tips and how-to’s.

File structure

Before incorporating building React files (JSX), we had a folder for views inside JS directory. We had an alias for “views” pointing to the respective folder for Require.js, and all references to JSX dependencies were using this alias. JS source folder looked somewhat like this:

But building JSX files required us to use another folder for JSX files. The fix was quite trivial: /app/views was moved two levels up and renamed it to /jsx. Also, we have changed all file extensions in /jsx from .js to .jsx. Latter step is not necessary, I did this to emphasize different file type even more. New file structure looks as follows:

Tip: Do not mix files of other types with JSX files in the above folder, keep it for React files only, and always begin them with /** @jsx React.DOM */.

Building with Grunt

First we tried using grunt-react npm module as described in their README, both with and without grunt-browserify. It never worked because grunt-react could not resolve Require.js dependencies, as most of them were using aliases from Require’s config. I did not find a workaround to this, and did not want to change dependencies from aliases to relative paths in lots of files. So I tried native React.js’ build tool explained here. And Great Success — it worked like a charm!

Now, here’s the how-to:

Install command line jsx tool:

This tool will translate your source JSX files with inline XML syntax for DOM components to native JavaScript files.

npm install -g react-tools — you must add -g flag, otherwise it will not work.

Add Grunt task:

To run JSX compiler, we use grunt-shell and the Grunt task looks like this:

Above shell command iterates through all .jsx files in JSX source folder (flag -x jsx tells compiler to look for .jsx files instead of default .js files). But as I mentioned above, this step is not necessary and you do not need to change file extensions to .jsx as a required step.

Second part of the shell command removes a hidden folder .module-cache/ created by jsx compiler. Alternatively you can add --no-cache-dir flag to jsx command.

Now when you run grunt jsx, compiler will convert your JSX files under src/jsx/ and place converted files to your regular JS directory.

Tip: you would not do this exactly like this in production. You should not put compiled files to your sources directory. Or at least you do not need to commit them to your repository.

But because we have not yet finished with the entire build routine for our static assets, JSX files are compiled to source JS folder in order to be compiled by grunt-contrib-requirejs later.

Optimizing for Require.js:

If you also use Require.js in your project, you might want to, if not already, optimize your JavaScript files using r.js. But if you are building JSX files to regular JS files as explain in this post, you must remember that you do not need to run non-JSX files through JSX Transformer if you use them as dependencies, e.g. as in the following example:

Now that grunt jsx task already translated your JSX files to native JS, using jsx! pre-processor is an extra step, so when you optimize your JS files using grunt-contrib-requirejs, you want to remove “jsx!” from your dependency definitions. In order to do this, add onBuildWrite config option.

Above will effectively remove all “jsx!” substrings from all compiled JS files for your project.

I hope you found this information helpful. Please comment if you have any questions of suggestions.

3 Responses to “Building React.js with Grunt”

  1. t_-

    Just wanted to thank you for a great writeup, I ran into the same issue with grunt-react and this solved the problem. One additional function I had to add to the require-js configuration was to duplicate the onBuildWrite to onBuildRead, esprima was throwing errors:

    onBuildRead: function (moduleName, path, contents) {
    return contents.replace(/jsx!/g, ”);
    }

    Reply
    • Alexander

      Hi, thanks for your comment. I guess that depends more on what you have in your JSX files. When I run this grunt task, it doesn’t fail if my ‘build-jsx’ shell command fails, so it looks like grunt-contrib-requirejs succeeded but in fact all of my JSX views are not there. That not cool, but not directly related to requirejs builds.

      Reply

Trackbacks/Pingbacks

  1.  Automating building RequireJS modules with Grunt | Alexander Farennikov

Leave a Reply

  • (will not be published)