React does a really interesting thing with its build process that I haven't seen elsewhere.
React uses what appears to be CommonJS syntax in its files. For example, in ReactDOM.js:
var ReactDescriptor = require('ReactDescriptor'); var ReactDescriptorValidator = require('ReactDescriptorValidator'); var ReactLegacyDescriptor = require('ReactLegacyDescriptor'); var ReactDOMComponent = require('ReactDOMComponent');
However, in CommonJS, a non-relative import (that is, one that doesn't start with
./) is supposed to indicate a package, not a module within the same package. For example, if I do
require('react') in a traditional Browserify project, it'll look for a module in
None of those imported modules are in separate packages, but are within the React repo. Not only that, but they're not even in the same folder - this file is in
src/browser/ReactDOM.js, but ReactDescriptor is within
I knew that React eventually used Browserify to build its global bundle, so I dug in a bit further and found that before that, the
jsx Grunt task builds each file to JSX and moves it to
build/modules. And when I say moved, I mean it ends up as a totally flat structure -
src/browser/ReactDOM.js is built to
src/core/ReactDescriptor.js is built to
build/modules/ReactDOM.js. The JSX task also adds a prepending
./ to imports to make them relative.
At this point, the React build process creates a Browserify bundle from
build/modules. However, when published to NPM,
build/modules actually becomes the
I can think of a few advantages to having this "flat" structure:
- Folder organization is independent of your the module system's structure, so you can move files around all you want without breaking anything
- In CommonJS, you avoid having complex relational lookups (e.g. no
I wonder whether the added complexity in the build step is because of those advantages, or whether Facebook has an internal build tool that uses this flat structure? I imagine it's the latter, since while the advantages are nice, they don't seem nice enough to add this extra complexity. Leaving the
./ off of each import path is also a sign that React wasn't originally written with "traditional" CJS in mind.