SodiumFRP / sodium-typescript

Typescript/Javascript implementation of Sodium FRP (Functional Reactive Programming) library
126 stars 17 forks source link

TypeError: Cannot read property 'requestRegen' of null #98

Open ziriax opened 5 years ago

ziriax commented 5 years ago

I'm trying to port my old sodium-frp-react-demo to the latest versions of SodiumJS and ReactJS, but I get a crash when running, any idea what this might be? I'm creating cell loops, so I do this inside Transaction.Run, but this crashes in the latest version, works fine in the very old version I was using.

Stack trace:

Stream.listen_
c:/dev/sodium-frp-react/node_modules/sodiumjs/dist/sodium.esm.js:1984
  1981 | Stream.prototype.listen_ = function (target, h, suppressEarlierFirings) {
  1982 |   var _this = this;
  1983 | 
> 1984 |   if (this.vertex.register(target)) Transaction.currentTransaction.requestRegen();
       | ^  1985 |   var listener = new Listener(h, target);
  1986 |   this.listeners.push(listener);
  1987 | 
View compiled
Source.register_
c:/dev/sodium-frp-react/node_modules/sodiumjs/dist/sodium.esm.js:1620
  1617 | var out = new StreamWithSend();
  1618 | var left = new Vertex("merge", 0, []);
  1619 | left.sources.push(new Source(this.vertex, function () {
> 1620 |   return _this.listen_(left, function (a) {
       | ^  1621 |     out.send_(a);
  1622 |   }, false);
  1623 | }));
View compiled
Source.register
c:/dev/sodium-frp-react/node_modules/sodiumjs/dist/sodium.esm.js:245
  242 | 
  243 | if (!this.registered) {
  244 |   this.registered = true;
> 245 |   if (this.register_ !== null) this.deregister_ = this.register_();else {
      | ^  246 |     // Note: The use of Vertex.NULL here instead of "target" is not a bug, this is done to create a
  247 |     // rank-independent source. (see note at constructor for more details.). The origin vertex still gets
  248 |     // added target vertex's children for the memory management algorithm.
View compiled
Vertex.incRefCount
c:/dev/sodium-frp-react/node_modules/sodiumjs/dist/sodium.esm.js:328
  325 | var anyChanged = false;
  326 | 
  327 | if (this.refCount() == 0) {
> 328 |   for (var i = 0; i < this.sources.length; i++) this.sources[i].register(this);
      | ^  329 | }
  330 | 
  331 | this.targets.push(target);
View compiled
Vertex.increment
c:/dev/sodium-frp-react/node_modules/sodiumjs/dist/sodium.esm.js:420
  417 | };
  418 | 
  419 | Vertex.prototype.increment = function (referrer) {
> 420 |   return this.incRefCount(referrer);
      | ^  421 | };
  422 | 
  423 | Vertex.prototype.decrement = function (referrer) {
View compiled
Vertex.register
c:/dev/sodium-frp-react/node_modules/sodiumjs/dist/sodium.esm.js:314
  311 | };
  312 | 
  313 | Vertex.prototype.register = function (target) {
> 314 |   return this.increment(target);
      | ^  315 | };
  316 | 
  317 | Vertex.prototype.deregister = function (target) {
View compiled
Source.register_
c:/dev/sodium-frp-react/node_modules/sodiumjs/dist/sodium.esm.js:1625
  1622 |   }, false);
  1623 | }));
  1624 | out.vertex.sources = out.vertex.sources.concat([new Source(left, function () {
> 1625 |   left.register(out.vertex);
       | ^  1626 |   return function () {
  1627 |     left.deregister(out.vertex);
  1628 |   };
View compiled
Source.register
c:/dev/sodium-frp-react/node_modules/sodiumjs/dist/sodium.esm.js:245
  242 | 
  243 | if (!this.registered) {
  244 |   this.registered = true;
> 245 |   if (this.register_ !== null) this.deregister_ = this.register_();else {
      | ^  246 |     // Note: The use of Vertex.NULL here instead of "target" is not a bug, this is done to create a
  247 |     // rank-independent source. (see note at constructor for more details.). The origin vertex still gets
  248 |     // added target vertex's children for the memory management algorithm.
View compiled
Vertex.incRefCount
c:/dev/sodium-frp-react/node_modules/sodiumjs/dist/sodium.esm.js:328
  325 | var anyChanged = false;
  326 | 
  327 | if (this.refCount() == 0) {
> 328 |   for (var i = 0; i < this.sources.length; i++) this.sources[i].register(this);
      | ^  329 | }
  330 | 
  331 | this.targets.push(target);
View compiled
Vertex.increment
c:/dev/sodium-frp-react/node_modules/sodiumjs/dist/sodium.esm.js:420
  417 | };
  418 | 
  419 | Vertex.prototype.increment = function (referrer) {
> 420 |   return this.incRefCount(referrer);
      | ^  421 | };
  422 | 
  423 | Vertex.prototype.decrement = function (referrer) {
View compiled
Vertex.register
c:/dev/sodium-frp-react/node_modules/sodiumjs/dist/sodium.esm.js:314
  311 | };
  312 | 
  313 | Vertex.prototype.register = function (target) {
> 314 |   return this.increment(target);
      | ^  315 | };
  316 | 
  317 | Vertex.prototype.deregister = function (target) {
View compiled
StreamWithSend.Stream.listen_
c:/dev/sodium-frp-react/node_modules/sodiumjs/dist/sodium.esm.js:1984
  1981 | Stream.prototype.listen_ = function (target, h, suppressEarlierFirings) {
  1982 |   var _this = this;
  1983 | 
> 1984 |   if (this.vertex.register(target)) Transaction.currentTransaction.requestRegen();
       | ^  1985 |   var listener = new Listener(h, target);
  1986 |   this.listeners.push(listener);
  1987 | 
View compiled
Source.register_
c:/dev/sodium-frp-react/node_modules/sodiumjs/dist/sodium.esm.js:1643
  1640 | var out = new StreamWithSend();
  1641 | var coalescer = new CoalesceHandler(f, out);
  1642 | out.vertex.sources = out.vertex.sources.concat([new Source(this.vertex, function () {
> 1643 |   return _this.listen_(out.vertex, function (a) {
       | ^  1644 |     coalescer.send_(a);
  1645 |   }, false);
  1646 | })]).concat(toSources(Lambda2_deps(f)));
View compiled
Source.register
c:/dev/sodium-frp-react/node_modules/sodiumjs/dist/sodium.esm.js:245
  242 | 
  243 | if (!this.registered) {
  244 |   this.registered = true;
> 245 |   if (this.register_ !== null) this.deregister_ = this.register_();else {
      | ^  246 |     // Note: The use of Vertex.NULL here instead of "target" is not a bug, this is done to create a
  247 |     // rank-independent source. (see note at constructor for more details.). The origin vertex still gets
  248 |     // added target vertex's children for the memory management algorithm.
View compiled
Vertex.incRefCount
c:/dev/sodium-frp-react/node_modules/sodiumjs/dist/sodium.esm.js:328
  325 | var anyChanged = false;
  326 | 
  327 | if (this.refCount() == 0) {
> 328 |   for (var i = 0; i < this.sources.length; i++) this.sources[i].register(this);
      | ^  329 | }
  330 | 
  331 | this.targets.push(target);
View compiled
Vertex.increment
c:/dev/sodium-frp-react/node_modules/sodiumjs/dist/sodium.esm.js:420
  417 | };
  418 | 
  419 | Vertex.prototype.increment = function (referrer) {
> 420 |   return this.incRefCount(referrer);
      | ^  421 | };
  422 | 
  423 | Vertex.prototype.decrement = function (referrer) {
View compiled
Vertex.register
c:/dev/sodium-frp-react/node_modules/sodiumjs/dist/sodium.esm.js:314
  311 | };
  312 | 
  313 | Vertex.prototype.register = function (target) {
> 314 |   return this.increment(target);
      | ^  315 | };
  316 | 
  317 | Vertex.prototype.deregister = function (target) {
View compiled
StreamWithSend.Stream.listen_
c:/dev/sodium-frp-react/node_modules/sodiumjs/dist/sodium.esm.js:1984
  1981 | Stream.prototype.listen_ = function (target, h, suppressEarlierFirings) {
  1982 |   var _this = this;
  1983 | 
> 1984 |   if (this.vertex.register(target)) Transaction.currentTransaction.requestRegen();
       | ^  1985 |   var listener = new Listener(h, target);
  1986 |   this.listeners.push(listener);
  1987 | 
View compiled
(anonymous function)
C:/dev/sodium-frp-react-demo/node_modules/sodiumjs/dist/sodium.esm.js:1386
  1383 |   // that might have happened during this transaction will be suppressed.
  1384 |   last_ca = ca;
  1385 |   if (kill2 !== null) kill2();
> 1386 |   kill2 = Operational.value(ca).listen_(out.getVertex__(), function (a) {
       | ^  1387 |     return out.send_(a);
  1388 |   }, false);
  1389 | }, false);
View compiled
Entry.action
C:/dev/sodium-frp-react-demo/node_modules/sodiumjs/dist/sodium.esm.js:2067
  2064 | Transaction.currentTransaction.inCallback++;
  2065 | 
  2066 | try {
> 2067 |   h(a);
       | ^  2068 |   Transaction.currentTransaction.inCallback--;
  2069 | } catch (err) {
  2070 |   Transaction.currentTransaction.inCallback--;
View compiled
Transaction.close
C:/dev/sodium-frp-react-demo/node_modules/sodiumjs/dist/sodium.esm.js:108
  105 |   if (this.prioritizedQ.isEmpty()) break;
  106 |   var e = this.prioritizedQ.dequeue();
  107 |   this.entries.remove(e);
> 108 |   e.action();
      | ^  109 | }
  110 | 
  111 | var sq = this.sampleQ;
View compiled
Function.Transaction.run
C:/dev/sodium-frp-react-demo/node_modules/sodiumjs/dist/sodium.esm.js:189
  186 | var a = f();
  187 | 
  188 | if (transWas === null) {
> 189 |   Transaction.currentTransaction.close();
      | ^  190 |   Transaction.currentTransaction = null;
  191 | 
  192 |   if (Transaction.collectCyclesAtEnd) {
View compiled
Module.transactional
C:/dev/sodium-frp-react-demo/src/circuits/helpers.ts:16
  13 | }
  14 | 
  15 | export function transactional<T>(action: () => T): T {
> 16 |     return S.Transaction.currentTransaction
  17 |         ? action()
  18 |         : S.Transaction.run(action);
  19 | }
View compiled
Function.create
C:/dev/sodium-frp-react-demo/src/circuits/document.ts:29
  26 | 
  27 |     public static create(storage: Storage = window.localStorage, key = "state") {
  28 |         // When using Sodium loops, a circuit must be constructed inside an explicit transaction
> 29 |         return H.transactional(() => new Document$(storage, key));
  30 |     }
  31 | }
  32 | 
View compiled
new App
C:/dev/sodium-frp-react-demo/src/containers/App.tsx:5
  2 | import * as C from "../circuits"
  3 | import * as V from "../views"
  4 | 
> 5 | export class App extends React.PureComponent {
  6 | 
  7 |   private readonly doc = C.Document$.create();
  8 | 
View compiled
▶ 23 stack frames were collapsed.
Module../src/index.tsx
C:/dev/sodium-frp-react-demo/src/index.tsx:6
  3 | import { App } from './containers/App';
  4 | import * as serviceWorker from './serviceWorker';
  5 | 
> 6 | ReactDOM.render(<App />, document.getElementById('root'));
  7 | 
  8 | // If you want your app to work offline and load faster, you can change
  9 | // unregister() to register() below. Note this comes with some pitfalls.
View compiled
__webpack_require__
C:/dev/sodium-frp-react-demo/webpack/bootstrap:781
  778 | };
  779 | 
  780 | // Execute the module function
> 781 | modules[moduleId].call(module.exports, module, module.exports, hotCreateRequire(moduleId));
      | ^  782 | 
  783 | // Flag the module as loaded
  784 | module.l = true;
ziriax commented 5 years ago

Mmm, it seems a similar errors occurs when reverting the SodiumJS 1.1.3 (send being called before listeners are attached, and that gets rethrown), so this problem must have been introduced by upgrading other packages.

With the latest version (3.0.5) this send being called error is not thrown, but the code crashes as reported above.

clinuxrulz commented 5 years ago

I wonder if sodium-frp-react library has bundled its own sodiumjs with its own global scope separate from the global scope of sodium-frp-react-demo. Sort of like the library is loaded twice and it is passing sodium objects between the two sodium libraries.

In other words one sodium lib currentTransaction is not null, and the other bundled sodium lib currentTransaction is null.

Like #50.

clinuxrulz commented 5 years ago

Might have to try:

export const sodium = window["sodium"] as typeof import("sodiumjs");

On both and include sodium initially in a script tag. Bit messy though.

clinuxrulz commented 5 years ago

Similar issue here with angular. https://github.com/webpack/webpack/issues/2134

This guy has a solution. https://github.com/webpack/webpack/issues/2134#issuecomment-192579511

(Make sodiumjs a "peerDependency" in sodium-frp-react)

ziriax commented 5 years ago

Ah! Thanks a lot, I will try that