Skip to content

CrossChunkCodeMotion introduces JS runtime error in ES2015+ #3752

Closed
@DavidANeil

Description

@DavidANeil

Given the following code:

// main.js
goog.module('_main');

const LocalConstant = {a: 5};

class Base {
    constructor() {
        console.log(LocalConstant);
    }
}

exports.Base = Base;

console.log(LocalConstant);
// other.js
goog.module('_other');

const main_1 = goog.require('_main');

class Child extends main_1.Base {
    constructor() {
        super();
    }
}

exports.Child = Child;

goog.global.sideeffect = new Child();

Compiling into ES2015

$ java -jar closure-compiler-v20201102.jar --language_out ECMASCRIPT_2015 --emit_use_strict false --compilation_level ADVANCED_OPTIMIZATIONS --formatting PRETTY_PRINT --js_output_file=mainout.js --chunk mainout:2 --chunk otherout:1:mainout ~/github/closure-library/closure/goog/base.js main.js other.js 

Produces the following output:
mainout.js:

var a = this || self;
const c = {a:5};
console.log(c);

otherout.js:

var d = class {
  constructor() {
    console.log(c);
  }
};
a.b = new class extends d {
  constructor() {
    super();
  }
};

As you can see, the class Base (d) from main.js has been moved to a different chunk, since it is unused in its own chunk.
Unfortunately the LocalConstant (c) is not available in the context of otherout.js, because it is declared with const in mainout.js.
If main.js is adjusted to include a exports.LocalConstant = LocalConstant; then const c becomes var c and therefore is available in the other module.
Before ES2015 const did not exist, so this worked without error.

There are 2 possible fixes, I am not sure which is preferred:

  1. Change the CrossChunkCodeMotion CompilerPass to not move the Base class out of its chunk, because it is tied to the local variable, and therefore a part of the global cycle created by the side-effect of logging the constant.
  2. Change some other (?which?) CompilerPass to synthesize the exports.LocalConstant = LocalConstant;

I am going to start looking into the first of those as a contribution, mostly just because it seems easier.

Metadata

Metadata

Assignees

Labels

triage-doneHas been reviewed by someone on triage rotation.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions