facebookarchive / prepack

A JavaScript bundle optimizer.
http://prepack.io
Other
14.21k stars 424 forks source link

Bad serialization output when Prepacking Immutable.js #2555

Closed trueadm closed 6 years ago

trueadm commented 6 years ago

Take the input: https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.2/immutable.js

When we try to Prepack the code, we end up with variables used before being declared:

screen shot 2018-09-18 at 22 39 06

trueadm commented 6 years ago

It looks like it's an issue with residual function holding bindings/references to other functions. Here's a minimal repro @NTillmann @cblappert if you have any ideas:

(function() {

  function createClass(ctor, superClass) {
    if (superClass) {
      ctor.prototype = Object.create(superClass.prototype);
    }
    ctor.prototype.constructor = ctor;
  }

  function mixin(ctor, methods) {
    var keyCopier = function(key) {
      ctor.prototype[key] = methods[key];
    };
    Object.keys(methods).forEach(keyCopier);
    Object.getOwnPropertySymbols && Object.getOwnPropertySymbols(methods).forEach(keyCopier);
    return ctor;
  }

  function Iterable(value) {}
  function Iterator(next) {}

  createClass(Seq, Iterable);
  function Seq(value) {}

  createClass(IndexedSeq, Seq);
  function IndexedSeq(value) {}

  createClass(SetSeq, Seq);
  function SetSeq(value) {
    indexedSeqFromValue;
  }

  SetSeq.prototype.toSetSeq = function() {
    return this;
  };

  Seq.isSeq = isSeq;
  Seq.Set = SetSeq;
  Seq.Indexed = IndexedSeq;

  createClass(ArraySeq, IndexedSeq);
  function ArraySeq(array) {}

  createClass(IterableSeq, IndexedSeq);
  function IterableSeq(iterable) {}

  createClass(IteratorSeq, IndexedSeq);
  function IteratorSeq(iterator) {}

  createClass(ToIndexedSequence, IndexedSeq);
  function ToIndexedSequence(iter) {}

  Iterable.Iterator = Iterator;

  mixin(Iterable, {
    foo: function() {
      ToIndexedSequence;
    },
  });

  function isSeq(maybeSeq) {}

  function indexedSeqFromValue(value) {
    maybeIndexedSeqFromValue;
  }

  function seqFromValue(value) {
    ObjectSeq;
  }

  function maybeIndexedSeqFromValue(value) {
    ArraySeq;
    IteratorSeq;
    IterableSeq;
  }

  global.foo = Iterable;
})();
NTillmann commented 6 years ago

I'll be looking at it today.

NTillmann commented 6 years ago

More minimal repro:

(function() {
    function A() { B; }
    function B() {}

    let p = Object.create(A.prototype);
    B.prototype = Object.create(p);

    global.foo = p;
})();