plugins: [@rollup/plugin-commonjs] Circular dependency is not resolved optimally by plugin-commonjs for protobufjs causing runtime error
- Rollup Plugin Name: plugin-commonjs
- Rollup Plugin Version: 20.0.0
- Rollup Version: 2.56.3
- Operating System (or Browser): Windows / Chrome
- Node Version: v12.20.1
- Link to reproduction: https://github.com/kskalski/rollup-protobufjs
Expected Behavior
Code runs without error, in particular code from protobufjs object.js is executed before its reference in field.js thus avoiding use of uninitialized variable ReflectionObject
Circular dependency reported during build, but resolved in favor of executing required (unconditionally specified at root of the module) dependencies first before “loose” dependencies (requires placed in function bodies / conditionals?)
Actual Behavior
Error during runtime
field.js:6 Uncaught TypeError: Cannot read property 'prototype' of undefined
at field.js:6
at index.umd.js:4
at index.umd.js:5
The order of circular dependency resolution is not optimal, since modules that are not on critical path are executed before those on critical path.
Additional Information
In particular I tracked the offending cycle as node_modules\protobufjs\src\object.js -> node_modules\protobufjs\src\util.js -> node_modules\protobufjs\src\type.js -> node_modules\protobufjs\src\namespace.js -> node_modules\protobufjs\src\object.js
however:
object.jshas a hard dependency at topvar util = require("./util");,namespace.jshas hard dedepdency at topvar ReflectionObject = require("./object");- while
util.jshas only loose dependencies ontype.js(and alsoenum.jsandroot.js), like those:
util.decorateType = function decorateType(ctor, typeName) {
...
if (!Type)
Type = require("./type");
...
}
...
Object.defineProperty(util, "decorateRoot", {
get: function() {
return roots["decorated"] || (roots["decorated"] = new Root());
}
});
so in fact the optimal breaking of the cycle would be something like:
type.js -> namespace.js -> object.js -> util.js
(util.js thus executed first, type.js last)
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 32 (6 by maintainers)
@lukastaegert I just wanted to chime in and mention that the beta version of the commonjs plugin fixed a circular dependency issue for me!
I was attempting to build a third-party React package with Rollup. The package uses styled-components, and it was crashing when it hit circular dependencies. I was able to build the package with webpack but not Rollup. Updating to the beta version allowed me to build the package with Rollup.
Thanks for the great work!
I think I fixed the issue now. I assume it was caused by some premature optimizations I built into the original algorithm. Instead of trying to debug this, I switched now to a much simpler cycle detection algorithm that does not try to cache too much. I worked fine for the example given (and also in a complex project of my own). Published as @rollup/plugin-commonjs@22.0.0-2 and also updated the “beta” tag.
I’d also like to chime in with another example. I tried switching a CRA project to Vite and encountered it breaking in the production build because of this bug happening to xmlbuilder.
https://github.com/dantman/rollup-commonjs-circular-xmlbuilder-bug
I tested it with the beta and it fixed the issue. So I am encouraged there is a solution to it and ~~all it requires is Vite to update a package.
However, I am extremely discouraged by the fact that this confirmed fix for a bug that makes rollup unusable to users of certain libraries has been “beta” for 3.5 months. I can’t report this as a bug and ask them to bump the package, because the package doesn’t even have an official release. And because it’s a major and the dependency is indie Vite I can’t even workaround this by installing the beta in my package as Vite will continue to use the older version.
Edit:
It appears that Vite doesn’t actually use@rollup/plugin-commonjsthis may be a bug in vite or esbuild, I got confused by the fact that Vite does use this package as a dev dependency and I can reproduce the exact same error with a minimal rollup reproduction.Edit2: I retract my retraction. Vite does use
@rollup/plugin-commonjs, it’s just compiled into thevitepackage using rollup. So it’s not even possible to use something like patch-package to replace the@rollup/plugin-commonjsversion. Additionally I tried outdynamicRequireTargetswhich appears to be the official workaround. However it doesn’t work at all as addingxmlbuildertodynamicRequireTargetsresults injsx-xml(the middle package that actually usesxmlbuilder) having a “Could not dynamically require” error, and adding bothxmlbuilderandjsx-xmlleads to either a build time error (because the named imports are now on a default import object) or a “require is not defined” error if I fix that.According to the prompted https://github.com/mmacfadden/rollup-protobufjs#notes I alias to dist/protobuf.min.js to solved this problem.
However the code generated by commonjs plugin begs for a question whether it should actually use dynamic import in cases where
requireis called inside a function (and conditionally). Right now for the original codethe plugin generates a top level imports block with
and
require$$5is used like this:I suppose conversion of requires into imports should be done per scope (top-level vs functions) and for the latter might need to use dynamic import e.g.
and in that case the sorting of modules could better resolve the araising circular dependencies, since actually the static imports do not have a cycle here, it’s only the dynamic imports that create them.