Ludwig Magnusson
Ludwig Magnusson

Reputation: 14399

Browserifying react with addons to a standalone component, usable by plugins

I am experementing a bit with react and browserify and have these wishes:

I have managed to do the things described above but I ran into this specific situation:

In some places of my code I want to use react with addons and as such require it like this: var React = require('react/addons). I don't do this in all parts of my code and it is not done in 3rd party dependencies such as react-router. This seems to create a conflict. Either the browserified bundle will only be available through var React = require('react/addons) which breaks 3rd party dependencies, or I will have to bundle react both with or without addons which menas that react is bundled and downloaded twice.

I tried to use aliasify and make react an alias for react/addons but I couldn't make it work. Should this be possible?

Another acceptable solution would be to bundle just the addons in a separate bundle and through that make both react and react/addons available through calls to require. Is any of this possible?

Addition As a comment to the first comment by BrandonTilley, this is not just applicable to React and addons. Lodash also comes with a number of different distributions and I would like to be able to choose the version to use in my webapp in this case as well.

Upvotes: 7

Views: 1765

Answers (3)

Sebastien Lorber
Sebastien Lorber

Reputation: 92190

Notice that what you want to achieve is documented here: Browserify partitionning

I'm packaging my app in 2 parts: appLibs.js and app.js. I've done this for caching too but I choose to put all the code that does not change often in a single bundle instead of splitting it like you want, but you can use the same trick.

Here's the code that might interest you:

var libs = [
    "react",
    "react/addons", // See why: https://github.com/substack/node-browserify/issues/1161
    ... other libs
];

gulp.task('browserify-libs', function () {
    var b = browserify(...);
    libs.forEach(function(lib) {
        b.require(lib);
    });
    return b.bundle().......
});
gulp.task('browserify',['browserify-libs'],function () {
    var b = browserify(...);
    libs.forEach(function(lib) {
        b.external(lib);
    });
    return b.bundle().......
});

This way, React is only bundled once in appLibs.js and can be required inside app.js using both react and react/addons

If you really want to bundle your libs in separate files, bundle then with b.require("myLib"), but in this case be sure to check that the libraries do not have direct dependencies. If a lib to bundle has a dependency in React, this means that lib will be packaged in the bundle, potentially leading to multiple bundles having React inside them (and making weird failures at runtime). The library should rather use peerDependencies so that b.require does not try to package these dependencies

Upvotes: 2

Ludwig Magnusson
Ludwig Magnusson

Reputation: 14399

Thanks for all suggestions but the solution I have chosen is a "shim" if that is the correct term. Looks like this:

  1. Browserify react/addons into it's own file
  2. Create my own file (called shim) only containing this: module.exports = require('react/addons');
  3. Browserify my shim and use the expose option, exposing it as react

Now, either if react or react/addons is required I get react/addons

Upvotes: 0

mantoni
mantoni

Reputation: 1622

Sounds like the perfect use case for factor-bundle.

From the browserify handbook:

factor-bundle splits browserify output into multiple bundle targets based on entry-point. For each entry-point, an entry-specific output file is built. Files that are needed by two or more of the entry files get factored out into a common bundle.

Upvotes: 0

Related Questions