Circular dependencies not working as with ES modules
See original GitHub issueDemonstration
Reproducing this bug has been a bit tricky so I created a repository: https://github.com/isidrok/system-circular-dependencies-bug (Sorry for the size of the reproduction but I don’t know how to generate proper System code without Rollup).
The folders ‘system’ and ‘es’ contain the chunks generated by Rollup in its respective formats. As you can see, there is a circular dependency between ‘b.js’ and ‘c.js’.
Launching an http server (npm start
) and loading both pages (http://localhost:8080/system.html and http://localhost:8080/es.html) shows that the same code loads as ES format but fails as System.
If we eliminate the circular reference caused by the file ‘0\commonjsHelpers.js’ generated by @rollup/plugin-commonjs (nothing to do with this issue, just for the reproduction) by uncommenting line 17 of ‘rollup.config.js’ and building the app again (npm run build
) then both pages load without errors since there are no circular references.
Expected Behavior
Modules with circular references can be executed as its done using ES modules.
Actual Behavior
Modules with circular references fail to execute.
Edit: simplify reproduction
Issue Analytics
- State:
- Created 3 years ago
- Comments:5 (4 by maintainers)
@isidrok RollupJS System output does not support circular references and I don’t think it should. The argument for this is that chunk circular references always need to load together, so you should just make them the same chunk. There’s no real practical reason to separate chunks across circular reference boundaries.
Perhaps we could make a warning in this case.
Hi @isidrok, thanks for the clear description and repository demonstrating the issue.
The issue here is related to rollup, not to SystemJS. Here is the error in the browser console for the systemjs page:
The way that rollup plugin commonjs is using the
createCommonjsModule
function is by injecting it intoc.js
and then importing it from c into b.js.Regarding circular dependencies, the ES module spec first “links” the “hoisted exports” and then “instantiates” each module sequentially. The linking phase sets up the bindings for the exports and is what allows for the
createCommonjsModule
function to be available inside of b.js even before c.js has fully instantiated. All hoisted exports are available during initial execution of circular dependencies, but other exports are not.SystemJS supports “hoisted exports during the link phase” with the following syntax:
When rollup compiles to System.register format, it never does hoisted exports. You can see that this is the case by looking at this line: https://github.com/isidrok/system-circular-dependencies-bug/blob/b6e8ff9c7c4c1eddefa44d2aebc6987bd584bc03/system/c.js#L10.
To solve it, there are two options:
Solution 1
Don’t rely on hoisted exports / linking phase. To do this, you can remove the commonjs rollup plugin.
Example: https://github.com/isidrok/system-circular-dependencies-bug/pull/1
Solution 2
Make the
createCommonjsModule
function a hoisted export.Example: https://github.com/isidrok/system-circular-dependencies-bug/pull/2
I think that this solution is the ideal one, but it requires changes to rollup / rollup-plugin-commonjs. It might be best to open an issue up with rollup to look into it. If you do so, feel free to mention me in the rollup issue and I can help explain what needs to change.