React and jspm

#jspm#react

Tim Kye

I've been tinkering with React a lot lately; I am really loving it. Since I still believe that jspm offers a better development and bundling experience than WebPack (unless you need hot module reloading), I spend some time this week getting a solid project template down for React and jspm.

Directory Structure

Let's just jump straight to the solution, and then break down the reasons.

Project
|--assets/
|    |--css/
|    |--fonts/
|    |--images/
|    +--stylus/
|--dist/
    +--built.js
|--node_modules/
|--jspm_packages/
|--src/
|--jspm.config.js
+--server.js

Assets

I like to keep this stuff seperate from the code that will end up going into src. I find myself going into these folders for very different reasons, and the fewer things I have to look for the easier it is to find them. It also feels like a natural seperation to me.

The css directory is going to contain any external css, like the kind a 3rd party widget or plugin might need, as well as the compiled css generated by Stylus, my favorite css pre-processor. The stylus directory will obviously contain these pre-processed files.

Dist

This will contain the build JavaScript files. It's in a seperate directory so that when production goes to host files, it can switch from hosting src to hosting dist. This stops uncompiled source code from being hosted, without the server needing to know which file exactly needs to be provided (in case I am datestamping on the fillename to cache bust).

3rd Part Code and Src

Both node_modules and jspm_packages are at the root to keep them out of the src folder. When I try to Find all, having my code and only my code in a single folder saves me from digging through a lot of giant, minified results. I want all 3rd party code seperated from my app's code.

jspm.config.js

To get bundling to work alongside development hosting with the jspm_packages folder outside the src folder, I use the following config.

paths: {
    "*": "src/*",
    "github:*": "jspm_packages/github/*",
    "npm:*": "jspm_packages/npm/*"
}

This allows my ES6 imports to reference app code without the src/ prefix.

server.js

To ensure bunlding works alongside development, jspm_packages needs to get served at /jspm_packages. jspm.config.js also needs to be served, preferably from the root. I don't want to just host everything in __dirname though; I only want to host what the public needs access to. Luckily express makes setting up multiple static directories easy.

var port = process.env.PORT || 9000,
    ip = process.env.IP || "0.0.0.0",
    isProduction = process.env.NODE_ENV == 'production',
    clientDir = __dirname + (isProduction ? '/dist/' : '/src/'),
    assetDir = __dirname + '/assets',
    jspmConfigName = '/jspm.config.js',
    jspmConfig = __dirname + jspmConfigName,
    jspmDir = __dirname + '/jspm_packages/',
    express = require('express'),
    app = express();

//Configure
app.use('/jspm_packages', express.static(jspmDir));
app.use('/assets', express.static(assetDir));
app.use('/src', express.static(clientDir));
app.use(jspmConfigName, express.static(jspmConfig));

Yeoman

I've packaged all of this into a Yeoman generator: https://www.npmjs.com/package/generator-react-jspm