Modulele JS recursive nu sunt găsite

Nu sunt sigur dacă fac eu ceva greșit, dacă e un bug în… nici nu știu unde sau altceva. Am încercat să fac pack și cu webpack și cu browserify (ca să exclud vreun bug în packer) și am exact aceeași problemă: dacă fac require la un modul recursiv, nu îl găsește (îmi întoarce un obiect gol).

Ce vreau eu să fac: pentru moment, vreau să generez liste (UL/LI) dintr-un obiect nested.

Ce se întâmplă: când sunt la prima iterație (sau nu sunt copii), totul e ok. Copiii sunt cei care aduc problemele (hmmm, asta sună aiurea) pentru că UL-ul nu mai există:

Object {}
Uncaught TypeError: UL is not a constructor

Problema cea mai ciudată este că se rezolvă dacă fac require în metoda addChildren


Codul care reproduce toată povestea:

// app.js
var UL = require('./ul.js');
var LI = require('./li.js');
var col = require('./col.js');

var c = new col([{}, {children: [{},{},{}]}, {}]);

var u = new UL({
  collection: c
});
// model.js
module.exports = Backbone.Model.extend({ defaults : { children: 0 } });
// col.js
var model = require('./model.js');
module.exports = Backbone.Collection.extend({ model : model });
// ul.js
var LI = require('./li.js');

module.exports = Backbone.View.extend({
  initialize: function(){
    this.collection.each(this.renderItems, this);
    return this;
  },

  renderItems: function(model, i){
    var item = new LI({ model: model }).render().$el;
    this.$el.append(item);
  },
});
// li.js
var UL = require('./ul.js');
var col = require('./col.js');

module.exports = Backbone.View.extend({
  initialize: function(){
    if (this.model.get('children').length) { this.addChildren(); }
    return this;
  },

  addChildren: function(){
    var list = new UL({ collection: new col(this.model.get('children')) });
  },
});
1 Like

Am reușit să replic totul fără backbone, ci doar cu module chioare:

// app
var a = require('./a.js');
var b = require('./b.js');

a();
//a
var b = require('./b.js');
module.exports = function(){ b(); };
//b
var a = require('./a.js');
module.exports = function(){ a(); };

Atât codul generat de webpack cât și cel generat de browserify îmi spun că a is not a function la a doua iterație (mă aștept să intre într-un loop infinit…)

1 Like

Cu ajutorul lui @navaru am reușit să înțeleg problema: se numește circular dependencies și se rezolvă așa.

2 Likes

Jesus Christ Superstar!

Poți detalia? Mulțumesc.

Incercam sa-mi imaginez o aplicatie care are nevoie de “a” si “span” si “div”. Poate chiar si niste “table”, “tr”, “td”, nebunii d-astea.

// app.js var UL = require('./ul.js'); var LI = require('./li.js'); var col = require('./col.js'); var A = require('./a.js'); var SPAN = require('./span.js'); var TABLE = require('./table.js'); var DIV= require('./div.js'); // de-aici incolo sky is the limit ...

De aia ii multumeam lui Jesus Christ Superstar ca nu lucrez cu node/backbone/newest-js-framework-care-rupe-si-fara-case-nu-poti-sa-faci-absolut-nimic-pentru-ca-e-vitala-daca-zice-addy-osmani-sau-chiar-facebook, nu cred ca sunt pregatit pentru o asijderea complexitate a unei aplicatii :slight_smile:

1 Like

Credeam că e evident că am eliminat tot ce era irelevant și am simplificat cât am putut…

Codul final nu arată chiar așa. :slight_smile:

1 Like

@iamntz:

Cred ca cel mai bine ar fi sa incerci sa eviti situatiile legate de circular dependencies. Un alt articol care vorbeste despre asta e aici: http://selfcontained.us/2012/05/08/node-js-circular-dependencies/

Am avut si eu o situatie de genul asta, in care am aplicat varianta “delay invocation of dependency until runtime”, de ex:

var a;

function b() {
  a = a || require('./a');
 
  a();
}

Arata destul de urat, oricum. Cel mai bine e sa faci un refactoring si sa impiedici treaba asta. In cazul in care nu e posibil, varianta cu delay functioneaza.

1 Like

Am vazut ca ai rezolvat problema. Dar sunt curios ce voiai sa faci. Ceva de genul liste care sa contina subliste? Greseala e evidenta in li.js. Ideal ar trebui ca view-ul respectiv sa fie responsabil de rendarea propriului model si atat. orice alta sub lista cred ca trebuie initializata in afara listei parinte si apoi adaugata ca un element de sine statator.

Bafta!

1 Like

Inițial am aplicat hack-ul din link-ul de mai sus. În final însă am renunțat la module, la browserify la tot. Rezultatul? Mai puțini nervi, totul terminat în câteva ore.

Probabil voi relua toată povestea la un alt proiect, unde voi avea ceva mai mult timp. :slight_smile:

1 Like

Asta se intampla frecvent mai ales in ultima vreme de cand cu browserify, webpack, react, jsx, babel, es2015 samd…