Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Browserify require returns an empty object

Tags:

I have this code which, for reasons I can't understand, produces an empty object when using require(). My file structure is like this:

src |__ public     |__ javascript         |__ collections             |   categories.js             |   listings.js <-- Always an empty object         |__ models             |   category.js             |   employer.js             |   listing.js             |   location.js         |   routing         |   templates         |   tests         |   ui-components         |   views 

The problem file is collections/listings.js, which seems to simply output as an empty object when required like so:

var ListingsCollection = require('../collections/listings')

src/public/javascript/collections/listings.js looks like this:

var $        = require('jquery'),     _        = require('underscore'),     Backbone = require('backbone'),     Listing  = require('../models/listing');  Backbone.$ = $;  module.exports = Backbone.Collection.extend({     url: '/listings',      model: Listing,      parse: function (response) {         return response.listings;     } }); 

Here is an example of where things go wrong:

var $                  = require('jquery'),     _                  = require('underscore'),     Backbone           = require('backbone'),     LocationModel      = require('../models/location'),     ListingsCollection = require('../collections/listings');  Backbone.$ = $;  console.log(ListingsCollection); // > Object {}  module.exports = Backbone.Model.extend({      urlRoot: '/employers',      model: {         location: LocationModel,         listings: ListingsCollection     },      parse: function (response) {         var employer = response.employer;          // Create the child listings         employer.listings = new ListingsCollection;          return employer;     },      toJSON : function () {         var json = _.clone(this.attributes);          _.each(_.keys(this.model), function (child) {             if (this.get(child)) {                 json[child] = this.get(child).toJSON();             }         }.bind(this));          return json;     } }); 

So there it is - That collection never requires into the employer model such that it can be used to create a child collection for the parent model. I've looked at the source and researched this issue but I'm coming up with nothing so far... It's perplexing.

like image 607
Steve Adams Avatar asked Oct 19 '14 00:10

Steve Adams


People also ask

What is the use of Browserify Mcq?

What is Browserify? Browserify allows us to use node. js style modules in the browser. We define dependencies and then Browserify bundles it all up into a single neat and tidy JavaScript file.

What are some of the benefits of Browserify?

An additional advantage with Browserify is its use of transforms. Transforms work by injecting streams between resolved modules and content that is returned to transpile / convert code. Using transforms, you can support things like ES6 and JSX without having to precompile your code.

What is the use of Browserify?

Browserify is an open-source JavaScript bundler tool that allows developers to write and use Node. js-style modules that compile for use in the browser.

When should I use Browserify?

Browserify solves the problems of having too many JS files referenced in your HTML, inability to use Node modules in the browser, and inability to reference your own modules in your own code. Watchify streamlines the process of bundling your files and will make a change every time you change a JS file in your project.


1 Answers

Since my comment seems to have answered this issue, I thought I'd write it up formally.

When using Require.js you have to think about dependencies between modules. In some sense, this is the same issue as if you weren't using require. Let's pretend you have two files, A.js and B.js, which define an "A" function and a "B" function respectively:

// A.js window.A = function() {     // ... };  // B.js window.B = function() {     // ... }; 

You can add those files in any order to your page, and your code will work. But what if your definition of "B" depends on the definition of "A":

// B.js window.B = window.A || function() {     // ... }; 

Now, suddenly order matters: you have to include your B.js file after your A.js file or else B's code won't work. And if your A.js also depends on your B.js ...

// A.js window.A = window.B || function() {     // ... }; 

Then your code is fatally flawed, because B depends on A and A depends on B, and one has to be defined first. This is what is known as a "circular dependency".

Require has the same problem, only it's easier to miss because Require abstracts a lot of things from you. At the end of the day though Require (being JavaScript code) has to run sequentially, which means it has to define your modules in some order. If your module A depends on module B, and B depends on A, you'll have the same circular dependency issue.

Similarly if you have A that depends on B, and B that depends on C, and C that depends on A, you'll also have a circular dependency. Or if you have a C that depends on D that depends ... well you get the idea. Ultimately any module that depends on any other module has to ensure that neither the dependent module or any of its dependencies depend on the original module.

So how do you fix your code? The obvious way would be to remove the circular dependencies, which will certainly work, but there's also another option. Let's say your A depends on B, but only at run-time, not at load time. In other words instead of:

// A.js define(['B'], function(B) {     return B || function() {         // ...     }; }); 

you have:

// A.js define(['B'], function(B) {     return function() {         B();     }; }); 

In this case you can use the single argument "synchronous" form of require to avoid having to require "B" at the top of your file:

// A.js define([], function() {     return function() {         var B = require('B');         B();     }; }); 

Because we only use B after we've defined all our modules Require doesn't have to worry about A coming after B; it can define it whenever it wants because, by the time you actually want to use B, it will already be defined. Of course, this assumes that you have some module which actually does include "B" at the top (if you didn't require wouldn't even know that B exists).

Hope that helps.

like image 175
machineghost Avatar answered Oct 07 '22 04:10

machineghost