javascript – How to detect if my code is running in Node.js but not in a browser without using new Function ()?

Question:

This answer explains how to tell if your JavaScript is running in Node.js or in the browser, but it depends on using new Function() , which doesn't work in a browser if you use a CSP without unsafe-eval (and that's important in my project).

I know that there are several sensible forms, but fallible as well as it can be to see if window or process.versions.node are defined but it is easy to define these variables to fool the program.

Is there some other foolproof way to detect if I'm in the browser or in Node.js without using new Function() ?

I guess I can at least try that in a try {} and if I'm in Node.js I can be for sure, and if not I can use a less foolproof way.

Answer:

There is a solution based on localStorage (which transforms the stored integers into "strings"). I didn't find a way to cheat detection from node because you can't catch adding a key you don't know what it will be.

The isDOM function returns true in a browser (that supports localStorage or all modern ones) and returns false in node.js

function isDOM(){
    try{
        var key;
        while(localStorage[key='detect-dom-'+Math.random()]) ;
        localStorage[key]=1;
        return localStorage[key]!==1;
    }catch(err){
        return false;
    }
}

console.log('isDOM', isDOM());

if(!isDOM()){
    global.localStorage=[];
    Object.observe(global.localStorage, function(changes){
        changes.forEach(function(change){
            if(typeof change.object[change.name] != "string" && change.name=='add' || change.name=='update'){
                change.object[change.name] = ""+change.object[change.name];
            }
            console.log(change, JSON.stringify(change.object[change.name]));
        });
    });
}

console.log('cheat isDOM', isDOM());

The attempt to cheat is with Object.observe but being asynchronous it doesn't work. Maybe it can be cheated in the future with Proxy (in Mozilla) but in node 4 it doesn't work


my previous answer based on the above idea:

There is a version that does the same. But it is not perfect (it is better than the function with new Function which is also not perfect because it does not detect global.window = global executed in node).

Let's analyze your need.

It all depends on what your conflict hypothesis is.

If what you are looking for is to detect someone in node who wants to make you believe that you are in the DOM to falsify the detection, I at least did not find a solution.

If what you are looking for is to detect the best possible if it is the DOM or Node, for example looking if windows === this but you are afraid that someone has accidentally written in some module global.window = global for something strange, you can try clearing global.window . My tests go:

function isDOM(){
    try{
      if(typeof window !== "undefined" && this === window){
        if(window.window === window){
          try{
            window.temporarySaveWindow = window.window;
            delete window.window;
            if(window.window){
              delete window.temporarySaveWindow;
              return true;
            }
            global.window = window.temporarySaveWindow;
            delete window.temporarySaveWindow;
            return false;
          }catch(err){
            delete window.temporarySaveWindow;
            return false;
          }
        }
      }else{
        return false;
      }
    }catch(err){
      return false;
    }
}

var isDOM2=new Function("try {return this===window;}catch(e){ return false;}");

console.log('isDOM', isDOM());

if(!isDOM()){
    global.window = global;
    Object.defineProperty(global, 'window', {configurable: false});
}

console.log('cheat isDOM', isDOM());
Scroll to Top