I don't know if I'm missing something here, but for some reason a configuration object I create is always undefined upon using:
gulpfile.config.js
var config = {
src_path: "Client/"
};
gulpfile.js
var config = require("./gulpfile.config.js");
gulp.task("test", function() {
util.log(config.src_path); // results in 'undefined'
});
Do objects have to be initialized within the scope of a gulp task or is there something wrong with the object declaration?
Add module.exports to your gulpfile.config.js, like so
# gulpfile.config.js
var config = {
src_path: "Client/"
};
module.exports = config
module.exports is the object that's returned as the result of a require call.
It does, indeed, look to me like you are redefining that variable, probably causing it to have the value true. Use the browser's JavaScript-console to be sure.
Related
I have the following simple test module (called testModule) in Screeps:
module.Exports = {
myProperty:'test'
};
In main, I try to output the contents of the module like so:
var x = require('testModule');
console.log("Value:" + JSON.stringify(x));
But all I get is an empty object ({});
As a result, x.myProperty is undefined. I have also tried making the module into a function, like so:
module.Exports = function(){
return {
myProperty:'test'
};
};
Then assigning it to x with var x = require('testModule')(); but I get the same result.
Obviously the game is still in development, so it is possible that this is a bug, but I'd like to rule out a mistake on my part first. Anyone been able to achieve what I'm trying to do? Anyone see what I'm doing wrong?
Edit
Interestingly, it gives me the same empty object even if I change the module to this:
module.Exports = 'test';
Surely this should be printing the string 'test' rather than an empty object? Is this a quirk of require js?
Just figured this out - I was using an uppercase E in module.exports. I have corrected the case and now it works fine:
module.exports = {
myProperty:'test'
};
I've been interested in prototypical programming with JavaScript, and I'm trying to figure out an efficient way of doing it with Node modules.
For example, I'd like to use a prototype to quickly create a debug object in each of my modules, which has a name property and a log method, constructed via:
custom_modules/debug.js
var settings = require('custom_modules/settings');
exports = function debug(name){
this.name = name;
this.log = function(message){
if (settings.debug == 'true'){
console.log("[Debug][" + name + "]: " + message);
}
}
}
So I'd like to know if I can use that module as a constructor, like so:
do_something.js
var debug = new require('custom_modules/debug')("Something Doer");
debug.log("Initialized"); // -> [Debug][Something Doer] : Initialized
Will it work? If not, what's the correct equivalent?
new doesn't care where the function comes from. So yes, the function can be the result of requireing a module.
However, the module must directly export the function. In your current code you are merely assigning a new value to the local exports variable, and we all know that assigning to a local variable doesn't have any effect outside of its scope.
The module will still export an empty object. You have to override the exports property of the module:
module.exports = function() {...};
As pointed out, there will be problems with precedence, so you would have to do
var debug = new (require('custom_modules/debug'))("Something Doer");
I think I'm badly misunderstanding how to use module.exports. It seems every module is overwriting what the last one spit out.
app.js:
var express = require("express")
, app = express()
, routes = require('routes')
, server = app.listen(1337, "0.0.0.0")
, io = require('socket.io').listen(server)
, redis = require("redis")
, client = redis.createClient();
var moduleA = require("./moduleA")(io, client); (need to pass socket.io and redis client)
var moduleB = require("./moduleB")(io, client); (same)
moduleA.js:
module.exports = function(io, client){
this.test = 'foo';
return this;
};
moduleB.js:
module.exports = function(io, client){
this.test = 'bar';
return this;
};
back to app.js:
console.log(moduleB.test); (prints "bar")
console.log(moduleA.test); (also prints "bar")
Could someone explain what I'm doing wrong? I can't think of any other way to do this, since the exports helper (?) itself doesn't seem to accept parameters.
You are exporting a constructor. You need to construct it, not call it.
Change
var moduleA = require("./moduleA")(io, client);
to
var moduleA = new (require("./moduleA"))(io, client);
or (for clarity)
var ModuleA = require("./moduleA");
var a = new ModuleA(io, client);
What you are seeing happen is the usual behavior when calling constructors as functions in sloppy mode: this references the global object. So of course modifying the global object from two locations will overwrite each other, and returning this will just return the global object. You can test this yourself: with your current code,
moduleA === moduleB === this === global
One way to prevent yourself from ever shooting yourself in the foot like this again is to use strict mode instead of sloppy mode. To do so, add the line
"use strict";
at the top of every module you write (before any other code). In strict mode, this for constructors called without new is undefined, so you will get an earlier and much easier-to-understand error.
Strict mode has many benefits of this sort; for an overview see [1], [2], [3].
An alternate solution is to stop using constructors altogether, but instead use factory functions. This would look like:
module.exports = function (io, client) {
var result = {};
result.test = "foo";
return result;
};
You seem to be trying to do something like this anyway, since you return this even though doing so in a constructor is entirely unnecessary. You could just stop using this and use an actual object under your control, instead of one whose semantics change depending on whether your function is being called or constructed.
I follow this pattern to organize my js application.
As that example says our application should has the single entry point. File application.js doing that work.
// Filename: application.js
var chat = {
// Create this closure to contain the cached modules
module: function() {
// Internal module cache.
var modules = {};
// Create a new module reference scaffold or load an
// existing module.
return function(name) {
// If this module has already been created, return it.
if (modules[name]) {
return modules[name];
}
// Create a module and save it under this name
return modules[name] = { Views: {} };
};
}()
};
// Using the jQuery ready event is excellent for ensuring all
// code has been downloaded and evaluated and is ready to be
// initialized. Treat this as your single entry point into the
// application.
jQuery(function($) {
$(document).ready(function(){
var foo = new Application.module('Chat').Collection();
});
});
// Filename: chat-module.js
(function(chat){
chat.Model = Backbone.Model.extend({ ... }),
chat.Collection = Backbone.Collection.extend({ ... }),
})(Application.module('Chat'));
It seems well but if try to define chat module for example and invoke it later I have the following error:
Uncaught TypeError: Property 'Collection' of object #<Object> is not a function
I think that error due jQuery ready invokes when chat-module.js not available yet.
How can I resolve that problem?
Your code creates an object and assigns it to the global variable chat, which has a module function as a property:
var chat = {
module: function...
};
...but then when you use it, you use Application.module rather than chat.module.
Application.module('Chat')
and
var foo = new Application.module('Chat').Collection();
It seems to me that your chat variable should be called Application.
Also note that you're using module in two different ways, both with new and without. Without would be the correct use based on your code. It will work both ways because module returns a function (which is an object), and so that will override the normal new behavior, but it means that using new serves no purpose and is misleading to someone reading the code.
I'm using Google's Closure Compiler in advanced mode, and I'm having a strange issue. Here is the uncompiled code, with returned log statement from the compiled version running:
goog.provide('frame.store');
goog.require('frame.storeBack.LocalStore');
goog.require('frame.storeBack.Mem');
frame.store = (function() {
/** prioritised list of backends **/
var backends = [
frame.storeBack.LocalStore,
frame.storeBack.Mem
];
frame.log(backends);
// [function rc(){}, function tc(){this.q={}}]
frame.log(frame.storeBack.LocalStore === backends[0]);
// true
frame.log(frame.storeBack.LocalStore.isAvailable === backends[0].isAvailable);
// false
frame.log(frame.storeBack.LocalStore.isAvailable);
// function sc(){try{return"localStorage"in window&&window.localStorage!==k}catch(a){return l}}
frame.log(backends[0].isAvailable);
// undefined
for (var i=0, len=backends.length; i<len; i++)
if (backends[i].isAvailable())
return new backends[i]();
// Uncaught TypeError: Object function rc(){} has no method 'Ga'
throw('no suitable storage backend');
})();
For some reason the static method isAvailable is not present when LocalStore is accessed via the backends array, and is present when it's accessed via it's global namespace.
Can anyone see why?
EDIT: for reference, here is the method declaration:
frame.storeBack.LocalStore.isAvailable = function() {
try {
return 'localStorage' in window && window['localStorage'] !== null;
}catch (e) {
return false;
}
};
Turn on --debug true to check your output and what frame.storeBack.LocalStore.isAvailable is renamed to.
Dump a variables name map to check whether frame.storeBack.LocalStore.isAvailable has been flattened.
For example, the Closure Compiler may flatten frame.storeBack.LocalStore.isAvailable first to frame$storeBack$LocalStore$isAvailable, then rename the whole thing to the global function "a" or something. This is called flattening of namespaces. Check the debug output to see whether your function declaration has been renamed to:
$frame$storeBack$LocalStore$isAvailable$$ = function() {
In such case, calling frame.storeBack.LocalStore.isAvailable() directly will still call the flattened global version, no prob here! However, you can't expact that isAvailable() exists in frame.storeBack.LocalStore (another object) any more. In the compiled output, frame.storeBack.LocalStore.isAvailable and frame.storeBack.LocalStore are now separated. This is the behavior of the compiler's namespace flattening, if it happens.
You're asking for trouble putting properties into a constructor function itself -- the compiler does a lot of optimizations on classes that you may not expect.
Check the debug output and variable names map to confirm. You may have to remove the closure wrapper function in order to see the actual names in the map file.
Not sure what your back ends are exactly...
But shouldn't you instantiate them?
var backends = { localStore : new frame.storeBack.LocalStore(),
mem: new frame.storeBack.Mem() };