Search code examples
javascriptrequirejslodashbroccolijs

Error building two different files from same tree with broccoli-requirejs


I'm trying to compile two different JS files using broccoli-requirejs. A logical way to go about this seemed to be to run the requireJs filter on my scripts tree twice, with two different configurations. Doing so produces some really strange errors that, to me, resembles a race condition or something.

See below for Broccoli config and error output.

var compileCoffee = require("broccoli-coffee"),
    compileStatic = require("broccoli-static-compiler"),
    mergeTrees    = require("broccoli-merge-trees"),
    requireJs     = require("broccoli-requirejs"),
    _             = require("lodash");

var scripts = compileStatic("app/coffee", {
    srcDir: "/",
    destDir: "scripts"
});
scripts = compileCoffee(scripts, {bare: true});

var rjsOptions = {
    baseUrl: "scripts",
    inlineText: true,
    optimize: "uglify",
    stubModules: ["text"],
    paths: {
        knockout: "empty:"
    }
};

var fooScript = requireJs(scripts, {
    requirejs: _.extend(rjsOptions, {
        include: ["foo"],
        insertRequire: ["main"],
        mainConfigFile: "scripts/main.js",
        name: "main",
        out: "scripts/main.js"
    })
});

var barScript = requireJs(scripts, {
    requirejs: _.extend(rjsOptions, {
        insertRequire: ["bar"],
        mainConfigFile: "scripts/main.js",
        name: "bar",
        out: "scripts/bar.js"
    })
});

module.exports = mergeTrees([
    fooScript,
    barScript
]);

I get the following error when building this:

$ broccoli build build
Error: Merge error: file scripts/bar.js exists in /home/fredrik/app/tmp/require_js_filter-tmp_dest_dir-yMHQNi3F.tmp and /home/fredrik/app/tmp/require_js_filter-tmp_dest_dir-C8Wv970J.tmp
Pass option { overwrite: true } to mergeTrees in order to have the latter file win.
  at mergeRelativePath (/home/fredrik/app/node_modules/broccoli-merge-trees/index.js:98:21)
  at mergeRelativePath (/home/fredrik/app/node_modules/broccoli-merge-trees/index.js:122:17)
  at /home/fredrik/app/node_modules/broccoli-merge-trees/index.js:23:5
  at $$$internal$$tryCatch (/home/fredrik/app/node_modules/broccoli-merge-trees/node_modules/promise-map-series/node_modules/rsvp/dist/rsvp.js:490:16)
  at $$$internal$$invokeCallback (/home/fredrik/app/node_modules/broccoli-merge-trees/node_modules/promise-map-series/node_modules/rsvp/dist/rsvp.js:502:17)
  at $$$internal$$publish (/home/fredrik/app/node_modules/broccoli-merge-trees/node_modules/promise-map-series/node_modules/rsvp/dist/rsvp.js:473:11)
  at Object.$$rsvp$asap$$flush [as _onImmediate] (/home/fredrik/app/node_modules/broccoli-merge-trees/node_modules/promise-map-series/node_modules/rsvp/dist/rsvp.js:1581:9)
  at processImmediate [as _immediateCallback] (timers.js:345:15)


Build failed

And if I do pass {overwrite: true} to the mergeTrees call, I get the output of the first requireJs call (ie. the scripts/main.js), but with the filename bar.js.


Solution

  • It seems my problem was totally unrelated to both Broccoli and broccoli-requirejs. It's my call to _.extend that overwrites rjsConfig object. And since the actual r.js optimization with its of the config object doesn't happen before the trees are merged, the result of the second _.extend call is passed in twice.

    Simply changing the order of the arguments passed to _.extend made it work as expected:

    var fooScript = requireJs(scripts, {
        requirejs: _.extend({
            include: ["foo"],
            insertRequire: ["main"],
            mainConfigFile: "scripts/main.js",
            name: "main",
            out: "scripts/main.js"
        }, rjsOptions)
    });