Skip to content
This repository was archived by the owner on Aug 4, 2021. It is now read-only.
This repository was archived by the owner on Aug 4, 2021. It is now read-only.

Lazy circular dependencies no longer work #105

@patrick-steele-idem

Description

@patrick-steele-idem

It looks like the changes that were part of #92 broke lazy circular dependencies. After investigating I found this to be the cause for #104

Lazy circular dependencies work with Node.js and other CommonJS module loaders/bundlers. I think it is important to maintain parity with the Node.js CommonJS module loader since this is breaking at least one library.

Given the following contrived setup where ./a.js lazily requires ./b.js and ./b.js requires ./a.js:

_./a.js:_

setTimeout(function() {
    var b = require('./b'); // ** Lazily require './b.js' inside `setTimeout()` callback **
    console.log(b);
}, 10);

module.exports = 'SUCCESS!';

_./b.js:_

module.exports = require('./a');

Running the following code under Node.js using node ./a.js will result in the following output:

SUCCESS!

However, running the code bundled up by rollup will output undefined.

Problem

Rollup produces the following code that eagerly loads each module:

(function() {
    'use strict';

    function createCommonjsModule(fn, module) {
        return module = {
            exports: {}
        }, fn(module, module.exports), module.exports;
    }

    var b = createCommonjsModule(function(module) {
        module.exports = a; // ** a is undefined at this point **
    });

    var a = createCommonjsModule(function(module) {
        setTimeout(function() {
            var b$$1 = b;
            console.log(b$$1);
        }, 10);

        module.exports = 'SUCCESS!';
    });

}());

Proposed solution

I propose that this plugin be updated to produce output code similar to the following:

(function() {
    'use strict';
    function defineCommonjsModule(fn) {
        var module = {
            exports: {}
        };

        var loaded;

        return function require() {
            if (!loaded) {
                loaded = true;
                fn(module, module.exports);
            }
            return module.exports;
        };
    }

    var $$require_b = defineCommonjsModule(function(module, exports) {
        module.exports = $$require_a();
    });

    var $$require_a = defineCommonjsModule(function(module, exports) {
        setTimeout(function() {
            var b = $$require_b();
            console.log(b);
        }, 10);

        module.exports = 'SUCCESS!';
    });

    $$require_a(); // ** Load the entry module **
}());

As a side benefit, the proposed code will be closer to the user's code while still being very concise and efficient.

Thoughts?

/cc @Rich-Harris @lohfu

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions