(Edited to greatly simplify)
On node I have the following server.js file.
var Backbone = require('backbone');
var Tweet = Backbone.Model.extend({});
var Tweets = Backbone.Collection.extend({
model : Tweet,
url: function () {
return 'http://search.twitter.com/search.json?q=backbone'
}
});
var myTweets = new Tweets();
myTweets.fetch();
When I run this, I get an error that says. "Cannot call method 'ajax' of undefined" (1359:14)
basically that is the result of $ being undefined. Why is it undefined? Well there are a number of intermediate steps but when the file is loaded, it is expecting "this" to be "window" in browser or "global" on server. executed on node "this" = {}.
So the question, "How do I set 'this' to global" inside the backbone.js file?
On Backbone >= 1.x, you can simply assign Backbone.$ rather than using Backbone.setDomLibrary.
Solution for Backbone < 0.9.9
The first issue you need to address is how you are running this on Node anyway. Nodejs is a server-side JS environment, but it does not include any logic for controlling a DOM. For that you need to load something like JSDom.
When you have some DOM environment set up, you can load jQuery and your code into it and it should work just like a browser.
To answer your question specifically though, loading jQuery into the global is a bit of an ugly way to do it. You should use Backbone's setDomLibrary function to set $ to what you want.
Try something like this:
if (typeof exports !== 'undefined') {
MyModels = exports;
Backbone.setDomLibrary(require('jquery'));
server = true;
} else {
MyModels = this.MyModels = {};
}
This will fail if you try to do any DOM functions though.
Related
I have a JS file code.js that will be loaded with a website containing code like the following:
window.someObject = window.someObject || {};
window.someObject.someFunction= function(aCondition) {
if (aCondition) someExternalObject.someFunc2();
};
setTimeout(window.someObject.someFunction, 1000);
I can't change this code.
I want to write a unit test for this, so my test file would look something like this:
const expect = require('chai').expect;
var rewire = require('rewire');
var codeModule = require('./path/to/file/code.js');
describe('Test code.js', () => { //Using Mocha.js
//Stub someObject.someFunction
//Test stub with expect()
})
//MORE CODE
This results in ReferenceError: window is not defined since there is no window object in Node.
The reason I'd want to import that module is that I'd want to mock someObject.someFunction for my test.
How can I deal with references to browser APIs like the window object when testing with Node?
Do I need to require a package like this before?
I'm pretty new to this so bear with me if I have some misconceptions here.
Before you import the file do this.
window = window || {}
It will define the window object in the global namespace, but of course with none of the good stuff you get in a browser.
I am building an electron app, where the mainWindow object is created following the quick start: http://electron.atom.io/docs/tutorial/quick-start/.
As per this quick start, it is created asynchronously. The problem that I run into, is that for instance when I want to send messages from main to renderer process, I need to reference the mainWindow object. If this happens to be in a module that I require, then I need a means to make this module know of the mainWindow object.
I could of course prepend it with global., but I know that this is very much advised against. So I wish to do it more elegantly.
I came across this post: Asynchronous nodejs module exports; which appears to offer a solution. Taking the main.js file from the quick start (see above link, it's explicitly shown there), it appears I would add to the createWindow function
if( typeof callback === 'function' ){
callback(mainWindow);
}
and export the main.js module as
module.exports = function(cb){
if(typeof mainWindow !== 'undefined'){
cb(mainWindow);
} else {
callback = cb;
}
}
Then, in a higher-level script, I would require as follows:
let main = require('./main.js');
let lib = require('./lib.js'); // Library where I need a mainWindow reference
main(function(window) {
lib.doSomething(window);
});
where lib.js looks like
module.exports.doSomething = function(window) {
// Do something with window object, like sending ipc messages to it
window.webContents.send('hello-from-main', "hi!");
}
Although the simple case in the original post 'Asynchronous nodejs module exports' works fine, I cannot get it to work like described above; running the app it complains Uncaught Exception: TypeError: Cannot read property 'webContents' of null. This is also the case if I directly require lib.js within main()'s callback (which I know is also advised against).
I confess that I do not fully understand the simple case of the post, as I am rather new to node. This prevents me from fixing my own implementation of it, which I agree is blunt copy/pasting which reasonably should be expected to fail. Could somebody help me with how to correct above method, or advise me of a different approach to make it work? Thank you!
I have created the npm package electron-main-window for the same.
Install:
$ npm install electron-main-window
or
$ yarn add electron-main-window
Usage:
// Import ES6 way
import { getMainWindow } from 'electron-main-window';
const mainWindow = getMainWindow();
// Import ES5 way
const mainWindow = require('electron-main-window').getMainWindow();
// e.g:
if(mainWindow !== null ){
mainWindow.webContents.send('mainWindowCommunication', "This is a test message");
}
Whooops! The devil is in the details... I had defined on top of main.js
let mainWindow = null, callback;
which caused the error! Should be
let mainWindow, callback;
then it works perfectly!
P.s. Instead of deleting my post, I opted for keeping it and answering myself for future reference of other people who need asynchronous exporting.
For testing purposes I am trying to remove some amd modules and reload updated versions from the server - with the goal of not refreshing the browser.
I am currently doing the following but the browser still doesn't reload the items from the network.
var scripts = document.getElementsByTagName('script');
var context = require.s.contexts['_'];
for (var key in context.defined) {
if(key.indexOf("tests")>-1){
requirejs.undef(key);
for (var i = scripts.length - 1; i >= 0; i--) {
var script = scripts[i];
var attr = script.getAttribute('data-requiremodule')
if (attr === key){
script.parentNode.removeChild(script);
}
}}
It deletes the references from the context and removes the script tags successfully.
But alas...
Does anyone know the mechanism to clear all the references from requirejs?
Any help much appreciated
We are currently trying out this implementation:
require.onResourceLoad = function(context, map)
{
require.undef(map.name);
};
No issues has surfaced so far.
Edit: IE doesn't care much about this fix. Chrome and FF is fine however.
Also, you should try live-edit in PhpStorm. Works like a charm. A demo can be seen here. Chrome only though.
this answer is similar to the user1903890 but i think its easy to follow making other implementation.
Basically we have to encapsulate in an init function the main.js requirejs controller specified in our index.html. Once it's defined, then we call to this init function to init requirejs normally
function init_requirejs(){
console.log("--------------------------- INIT requirejs:");
require([ "helpers/util"], function(util) {
var count=0;
$('#content').empty();
$('#content').append("<input type='button' id='increment_button' value='click to increment the counter'>");
$('#content').append("<h1 id='the_counter'>0</h1>");
$('#content').append("<br><br><input type='button' id='init_button' value='click to initialize requirejs files'>");
$('#increment_button').on('click', function(){
count++;
$('#the_counter').text(count);
});
$('#init_button').on('click', function(){
end();
init_requirejs();
});
util();
});
};
init_requirejs();
Also we need and use the require.onResourceLoad function to store all the files that participate in the requirejs app
var all=[];
require.onResourceLoad = function (context, map, depArray) {
all.push(map.name);
};
And we need a reset requirejs configuration function to delete the actual instance of requirejs, we will do it with the require.undef function:
function end(){
console.log("--------------------------- END requirejs:");
all.map(function(item){
require.undef(item);
});
};
That's all!
Later from our code we can force the reload app without reload the browser only calling to end() function and init_rquirejs() function. For example inside a jquery click event:
$('#init_button').on('click', function(){
end();
init_requirejs();
});
The code of the demo is in
https://github.com/juanantonioruz/requirejs-force-reload
And an online version
https://dl.dropboxusercontent.com/u/8688858/requirejs-force-reload/project.html
I hope this solution work for you!
Juan
How can I include a file, which contains classes definitions in my server.js file?
I don't want to use module.exports because I want to use this file in my client javascript code too.
Thank you!
If you want the module's contents to be available outside the scope of the file you have to use module.exports. Making the file also work in a browser just requires you to do some extra if/elses
For instance:
var self = {};
// Browser?
if(instanceof window !== 'undefined')
{
window['my_module_name'] = self;
}
// Otherwise assume Node.js
else
{
module.exports = self;
}
// Put the contents of this module in self
// For instance:
self.some_module_function = function() {
// Do stuff
}
Now if you're in Node.js you can reach the function like this:
my_module = require('my_module_name');
my_module.some_module_function(58);
Or if you're in a browser you can just call it directly since it's global:
my_module.some_module_function(58);
Otherwise I can recommend Stitch.js which allows you to develop JavaScript code using the CommonJS style require and modules, then compile it to also run in the browser with no code changes.
Require.js also allows for this type of functionality.
Here's another SO question about using the same code in node and browsers:
how to a use client js code in nodejs
I have a javascript lib, basically this is how it is structured so far:
var Ns = (function(){
var that = {};
// add stuff to 'that'
return that;
})();
//use Ns.foo() and Ns.bar()
The thing is that now, I wanted the same lib to be available with node and npm. So far this is what I could come up with:
this.Ns = (function(){ //same as previous snippet })()
//use Ns.foo() and Ns.bar()
The problem is that, while this works in the browser, in node I need to do this:
var Ns = require('ns').Ns
Problem: I'd love to be able to do var Ns = require('ns') but in order to do that I have to export this.foo and this.bar which will break the browser inclusion. Ideas?
// create local scope.
(function () {
var myModule = ...
// check for node module loader
if (typeof module !== "undefined" && typeof require !== "undefined") {
module.exports = myModule;
} else {
window["name"] = myModule;
}
})();
Creating a scope is probably the best route to go (so you don't have name collision issues), but an easier way to do this, by polluting the global scope, looks like this:
instead of
var x = require('x');
write
var x = (typeof require !== "undefined") ? require('x') : window;
and similarly, before added to exports, check if that object exists:
if (typeof exports !== "undefined)
exports.my_func = my_func;
The consequences of this, though, is that in the browser version everything gets dumped into global scope. Also, it assumes that the browser version loads the necessary scripts into the page. Easy to get working on a small scale... but I'm guessing it won't scale well.