Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Environment detection: node.js or browser

I'm developping a JS-app that needs to work both on the client side and the server side (in Javascript on a browser and in Node.js), and I would like to be able to reuse the parts of the code that are used for both sides.

I have found out that window was a variable only accessible on Browsers, and global in node, so I can detect in which environment the code is executing (assuming that no script declares the window variable)

They are two problems.

  1. How should I detect in which browser the code is running. For example, is this code OK. (This code is inline, meaning that it is surrounded by some global code, reused for both environments)

    if window?     totalPath= "../examples/#{path}" else     totalPath= "../../examples/#{path}" 
  2. How can I use global variables for both environments ? Now, I'm doing the following, but this really doesn't feel right.

    if window?     window.DocUtils = {}     window.docX = []     window.docXData= [] else     global.DocUtils= {}     global.docX = []     global.docXData = [] 
like image 732
edi9999 Avatar asked Jul 10 '13 16:07

edi9999


People also ask

Does node JS run in the browser environment?

js is a server-side JavaScript run-time environment. It's open-source, including Google's V8 engine, libuv for cross-platform compatibility, and a core library. Notably, Node. js does not expose a global "window" object, since it does not run within a browser.

What is difference between node JS and browser?

Unlike the browser where Javascript is sandboxed for your safety, node. js has full access to the system like any other native application. This means you can read and write directly to/from the file system, have unrestricted access to the network, can execute software and more.

Does node js need environment variables?

Environment variables are a fundamental part of developing with Node. js, allowing your app to behave differently based on the environment you want them to run in. Wherever your app needs configuration, you use environment variables.

Is node js a framework or environment?

js is actually not a framework or a library, but a runtime environment, based on Chrome's V8 JavaScript engine.


2 Answers

NOTE: This question had two parts, but because the title was "Environment detection: node.js or browser" - I will get to this part first, because I guess many people are coming here to look for an answer to that. A separate question might be in order.

In JavaScript variables can be redefined by the inner scopes, thus assuming that environment has not created variables named as process, global or window could easily fail, for example if one is using node.js jsdom module, the API usage example has

var window = doc.defaultView; 

After which detecting the environment based on the existence of window variable would systematically fail by any module running under that scope. With the same logic any browser based code could easily overwrite global or process, because they are not reserved variables in that environment.

Fortunately there is a way of requiring the global scope and testing what it is - if you create a new function using a new Function() constructor, the execution scope of this is bound to the global scope and you can compare the global scope directly to the expected value. *)

So to create a function check if the global scope is "window" would be

var isBrowser=new Function("try {return this===window;}catch(e){ return false;}");  // tests if global scope is bound to window if(isBrowser()) console.log("running under browser"); 

And function to test if global scope is bound to "global" would be

var isNode=new Function("try {return this===global;}catch(e){return false;}");  // tests if global scope is bound to "global" if(isNode()) console.log("running under node.js"); 

the try... catch -part will makes sure that if variable is not defined, false is returned.

The isNode()could also compare this.process.title==="node" or some other global scope variable found inside node.js if you will, but comparing to the global should be enough in practice.

http://jsfiddle.net/p6yedbqk/

NOTE: detecting the running environment is not recommended. However, it can be useful in a specific environment, like development and testing environment which has some known characteristics for the global scope.

Now - the second part of the answer. after the environment detection has been done, you can select which environment based strategy you want to use (if any) to bind your variable which are "global" to your application.

The recommended strategy here, in my opinion, would be to use a singleton pattern to bind your settings inside a class. There is a good list of alternatives already in SO

Simplest/cleanest way to implement a singleton in JavaScript

So, it may turn out if you do not need a "global" variable, and you do not need the environment detection at all, just use the singleton pattern to defined a module, which will store the values for you. OK, one can argue that the module itself is a global variable, which in JavaScript it actually is, but at least in theory it looks a bit cleaner way of doing it.

*) https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function

Note: Functions created with the Function constructor do not create closures to their creation contexts; they always are created in the global scope. When running them, they will only be able to access their own local variables and global ones, not the ones from the scope in which the Function constructor was called.

like image 90
Tero Tolonen Avatar answered Sep 18 '22 15:09

Tero Tolonen


Since apparently Node.js could have both (w/ NW.js?), my personnal way to do it is by detecting if the node entry exists in process.versions object.

var isNode = false;     if (typeof process === 'object') {   if (typeof process.versions === 'object') {     if (typeof process.versions.node !== 'undefined') {       isNode = true;     }   } } 

The multilevel of conditions is to avoid errors while searching into an undefined variable due to some browsers limitations.

Reference: https://nodejs.org/api/process.html#process_process_versions

like image 42
Dan. B. Avatar answered Sep 18 '22 15:09

Dan. B.