I'm working on a project that uses Node.js. I'm familiar with JavaScript, but not great. As part of that, I've run into a challenge that I'm not sure how to overcome.
I need to share some code on the server (Node.js) and my client-side (browser) app. I want to be able to access this code by typing the following:
myCompany.myProject.myFunction(someValue);
or just
myProject.myFunction(someValue);
In an attempt to do this, I have the following:
'use strict';
var myCompany = myCompany || {};
var myProject = myCompany.myProject || {};
myProject.myFunction= function(someValue) {
console.log(someValue);
};
Inside of myFunction, I want to one thing if I'm running on the server (Node.js) and something different if I'm running in the browser. However, I'm not sure how to do that. I reviewed this post and this SO question, yet I still don't understand it.
Thank you for your help!
You need something like this:
function someFunctionName() {
// Common functional
if (typeof module !== 'undefined' && module.exports) {
// Do something only in Node.JS
} else {
// Do something else in the browser
}
// Common functional
}
Related
I have a webapp which will run on a website and as a standalone Electron instance (.exe for Windows).
I'd like to tell via JavaScript if the webapp is running inside ElectronJS or not, in order to display some extra features for the online version. Is there any way to detect the Electron framework instance? I'd like to avoid writing two slightly different versions of the webapp.
Just use this code (got it from is-electron "library")
function isElectron() {
// Renderer process
if (typeof window !== 'undefined' && typeof window.process === 'object' && window.process.type === 'renderer') {
return true;
}
// Main process
if (typeof process !== 'undefined' && typeof process.versions === 'object' && !!process.versions.electron) {
return true;
}
// Detect the user agent when the `nodeIntegration` option is set to true
if (typeof navigator === 'object' && typeof navigator.userAgent === 'string' && navigator.userAgent.indexOf('Electron') >= 0) {
return true;
}
return false;
}
Based on electron issue:
For main scripts, they're running as a Node process, so use process.versions.hasOwnProperty('electron') or equivalent
For renderer scripts, they're running in the browser, so use /electron/i.test(navigator.userAgent) or equivalent
Electron exposes full access to Node.js both in the main and the renderer process.
Source: Electron Application Architecture
This means that in your renderer thread (i.e. the user-facing part of your application) you can access NodeJS native modules such as fs.
I would recommend adopting a similar approach to browsers: avoid user-agent-based conditionals and prefer a is-this-feature-available? model if you can:
// renderer.js
try {
const fs = require('fs');
// test something (quick) that only the `fs` module can do
} catch (e) {
// probably not an electron app
}
However please do read https://www.electronjs.org/docs/tutorial/security first!
Further thoughts
Presumably you must somehow derive two artefacts from one single codebase: a web app and a desktop app.
You could perhaps consider injecting/exposing an environment variable during the build process assuming you can run two different build configurations.
you can use for simplicity a library named is-electron
I am trying to setup an interface, where I can write one js file that can be used on the server (nodejs) and on the client (javascript).
An example file would be a Vector object, that I would like to use on both the client and the server, as I am creating a multiplayer game.
In node.js, I know that you can use the following syntax to require source files...
var Vector = require('./vector');
Then you can access its module.exports by typing in Vector.
The problem here is that for the server I need an extra bit of code at the end of the file...
module.exports = Vector;
... which is not necessary on the client.
Is it possible to maybe require source code, something like the following?
var data = (...) // get data from vector.js file
var Vector = require_code(data + 'module.exports = Vector');
If not, there might be another way of doing what I am trying to accomplish.
That might sound a little confusing, but help is greatly appreciated!
Thanks in advance,
David.
Sounds like you are looking for UMDs - Universal Module Definitions.
(function (root, factory) {
if (typeof define === "function" && define.amd) {
define(["jquery", "underscore"], factory);
} else if (typeof exports === "object") {
module.exports = factory(require("jquery"), require("underscore"));
} else {
root.Requester = factory(root.$, root._);
}
}(this, function ($, _) {
// this is where I defined my module implementation
var Requester = { // ... };
return Requester;
}));
You'll need to change the name in root.Requestor to be the name of your module. root picks up the value of this which will be the global object or what you normally call window on the browser.
This particular example looks for jQuery and underscore as example dependencies, but they are easy enough to factor out if you need.
I've got a relatively simple JavaScript file (call it foo.js) that has 3 functions that are being called by a second JS file in the browser. There are a few other functions in foo.js, but they are only used internally.
Now foo.js also needs to be able to be used by a JS file running in node.js. Same thing, only needs to access the three basic functions.
So I added module.exports around these three functions like so:
module.exports = {
init_foo: function (bar){
return JSON.parse(bar);
},
export_foo: function (foobar){
return JSON.stringify(foobar);
},
switch_foo: function (boofar){
switch(boofar)
{
case 'A':
return 1;
case 'B':
return 2;
default:
return 3;
}
}
};
So now my node.js file can get the code by using
var foo = require('./foo.js');
But of course the browser code can't use it anymore, gives an error. When looking for a solution I found browserify but I can't seem to get it to work (keeps returning an empty file even when doing the suggested tutorial, guessing it's something to do with the set up of the system I am using, just not sure what), and it seems like it's more complex then I need anyway (don't want to browserify the entire browser JavaScript code, but can't browserify foo.js, have to make a new JS file that requires foo.js and uses it then browserify that, effectively adding a middle man that wasn't needed before).
Seeing as how the code I want to access with both node.js and from the browser is relatively simple is there an easy way to do this? (Just writing the code twice isn't a solution, it is simple code but I want to only have to edit it once for changes to propagate to both locations).
It is probably the best to use a specialized packet like browserify but for a small thing like yours the following might be a better fit. (I used it in my primesieve module)
var myModule = (function() {
return {
init_foo: function (bar){
return JSON.parse(bar);
},
export_foo: function (foobar){
return JSON.stringify(foobar);
},
switch_foo: function (boofar){
switch(boofar)
{
case 'A':
return 1;
case 'B':
return 2;
default:
return 3;
}
}
};
})();
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
module.exports = myModule;
} else {
if (typeof define === 'function' && define.amd) {
define([], function() {
return myModule;
});
} else {
window.myModule = myModule;
}
}
There have been some time passed since and better methods might have evolved but it is small and simple and worked for me.
Welp, one thing you can do is only assign a property of 'module' if it exists. And hope that no other JavaScript has introduced that to your browser environment as a global variable.
(function() {
var exports
...
if (this.hasOwnProperty('module'))
module.exports = exports
})()
Note that the this there is the global object.
I'm trying to do a pretty basic example using meteor js.
In my lib folder (shared by client and server) i have the following code
if (typeof hair === 'undefined') {
hair = {};
}
if (!hair.dao) {
hair.dao = {};
}
hair.dao.store = (function() {
return new Meteor.Collection('store');
})();
In folder server/libs i have this code
Meteor.startup(function() {
console.log(hair.dao.store.find().fetch());
});
(Which log one element)
In my client/libs folder i have this code
var cursorStores;
cursorStores = hair.dao.store.find();
console.log(cursorStores.fetch());
(Which logs no element)
It used to work, but now it stops.
Just to be clear i'm running on windows, and i removed and added again the autopublish package.
The data probably hasn't reached the client yet when you do that find. Try wrapping those 3 lines of client code in a Deps.autorun
I think find needs to take an argument. See http://docs.meteor.com/#find
If you are wanting the first element there are other ways of getting it. http://docs.meteor.com/
Try find({}) with empty curly braces
I recently tried to import a file into my existing node.js project. I know this should be written with a module but i include my external javascript file like this:
eval(fs.readFileSync('public/templates/simple.js')+'')
The contents of simple.js looks like this:
if (typeof examples == 'undefined') { var examples = {}; }
if (typeof examples.simple == 'undefined') { examples.simple = {}; }
examples.simple.helloWorld = function(opt_data, opt_sb) {
var output = opt_sb || new soy.StringBuilder();
output.append('Hello world!');
return opt_sb ? '' : output.toString();
};
(Yes, google closure templates).
I can now call the template file using:
examples.simple.helloWorld();
Everything is working like expected. However I'm not able to figure out what the scope of these functions is and where I could possibly access the examples object.
Everything is running in a node.js 0.8 server and like I said its working...I just dont quite know why?
Thanks for clarification.
eval() puts variables into the local scope of the place where you called it.
It's as if the eval() was replaced by the code in the string argument.
I suggest to change the content of the files to:
(function() {
...
return examples;
})();
That way, you can say:
var result = eval(file);
and it will be obvious where everything is/ends up.
Note: eval() is a huge security risk; make sure you read only from trusted sources.