Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[@rollup/plugin-commonjs] Circular dependency is not resolved optimally by plugin-commonjs for protobufjs causing runtime error #988

@kskalski

Description

@kskalski
  • 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.js has a hard dependency at top var util = require("./util");,
  • namespace.js has hard dedepdency at top var ReflectionObject = require("./object");
  • while util.js has only loose dependencies on type.js (and also enum.js and root.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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions