Pregunta ¿Cómo verificar si un script se está ejecutando bajo node.js?


Tengo un script que estoy solicitando de un script node.js, que quiero mantener el motor de JavaScript independiente.

Entonces, por ejemplo, quiero hacer:

exports.x = y;

solo si se está ejecutando bajo node.js. ¿cómo puedo realizar esta prueba?

Editar: Al publicar esta pregunta, no sabía que la función de módulos node.js se basa en Commonjs.

Para el ejemplo específico que di una pregunta más precisa, habría sido:

¿Cómo puede un script decir si se ha requerido como un módulo commonjs?


122
2017-11-19 11:41


origen


Respuestas:


Así es como el Underscore.js la biblioteca lo hace (buscando el soporte CommonJS):

Editar: a su pregunta actualizada:

(function () {

    // Establish the root object, `window` in the browser, or `global` on the server.
    var root = this; 

    // Create a reference to this
    var _ = new Object();

    var isNode = false;

    // Export the Underscore object for **CommonJS**, with backwards-compatibility
    // for the old `require()` API. If we're not in CommonJS, add `_` to the
    // global object.
    if (typeof module !== 'undefined' && module.exports) {
            module.exports = _;
            root._ = _;
            isNode = true;
    } else {
            root._ = _;
    }
})();

El ejemplo aquí conserva el patrón de Módulo.


71
2018-03-04 17:34



Bueno, no hay una manera confiable de detectar la ejecución en Node.js ya que cada sitio web podría declarar fácilmente las mismas variables, sin embargo, dado que no hay window objeto en Node.js de forma predeterminada puede ir al revés y comprobar si se está ejecutando dentro de un navegador.

Esto es lo que uso para libs que deberían funcionar tanto en un navegador como en Node.js:

if (typeof window === 'undefined') {
    exports.foo = {};

} else {
    window.foo = {};
}

Todavía podría explotar en caso de que window se define en Node.js pero no hay bueno razón por la cual alguien hace esto, ya que explícitamente tendrías que dejar de lado var o establecer la propiedad en el global objeto.

EDITAR

Para detectar si su script ha sido requerido como un módulo CommonJS, de nuevo no es fácil. Lo único que commonJS especifica es que A: los módulos se incluirán a través de una llamada a la función require y B: los módulos exportan cosas a través de propiedades en el exports objeto. Ahora cómo se implementa eso se deja al sistema subyacente. Node.js envuelve el contenido de los módulos en una función anónima.

function (exports, require, module, __filename, __dirname) { 

Ver: https://github.com/ry/node/blob/master/src/node.js#L325

Pero no lo hagas ir allí tratando de detectar eso a través de un loco arguments.callee.toString() cosas, en su lugar, simplemente use mi código de ejemplo anterior que comprueba el navegador, Node.js es un medio ambiente mucho más limpio, por lo que es poco probable que window será declarado allí.


69
2017-11-19 11:51



El problema al tratar de averiguar en qué entorno se está ejecutando su código es que cualquier objeto puede modificarse y declararse, lo que hace casi imposible determinar qué objetos son nativos del entorno y cuáles han sido modificados por el programa.

Sin embargo, hay algunos trucos que podemos usar para averiguar con certeza en qué entorno se encuentra.

Comencemos con la solución generalmente aceptada que se usa en la biblioteca de guiones bajos:

typeof module !== 'undefined' && module.exports

Esta técnica en realidad está perfectamente bien para el lado del servidor, como cuando el require función se llama, se restablece el this objetar a un objeto vacío, y redefine module para ti otra vez, lo que significa que no tienes que preocuparte por ninguna manipulación externa. Siempre que su código se cargue con require, estás seguro.

Sin embargo, esto se desmorona en el navegador, ya que cualquiera puede definir fácilmente modulepara que parezca que es el objeto que estás buscando. Por un lado, este podría ser el comportamiento que desea, pero también dicta qué variables puede usar el usuario de la biblioteca en el ámbito global. Tal vez alguien quiera usar una variable con el nombre module que tiene exports dentro de ella para otro uso. Es poco probable, pero ¿quiénes somos para juzgar qué variables puede usar otra persona, simplemente porque otro entorno usa ese nombre de variable?

El truco, sin embargo, es que si asumimos que su script se está cargando en el ámbito global (que será si se carga mediante una etiqueta de script) una variable no se puede reservar en un cierre externo, porque el navegador no permite eso . Ahora recuerda en el nodo, el this objeto es un objeto vacío, sin embargo, el module variable todavía está disponible. Eso es porque está declarado en un cierre exterior. Entonces podemos corregir el cheque de subrayado agregando un cheque adicional:

this.module !== module

Con esto, si alguien declara module en el alcance global en el navegador, se colocará en el this objeto, lo que hará que la prueba falle, porque this.module, será el mismo objeto que el módulo. En nodo, this.module no existe, y module existe dentro de un cierre externo, por lo que la prueba tendrá éxito, ya que no son equivalentes.

Por lo tanto, la prueba final es:

typeof module !== 'undefined' && this.module !== module

Nota: Si bien esto ahora permite el module variable que se utilizará libremente en el ámbito global, aún es posible omitir esto en el navegador creando un nuevo cierre y declarando module dentro de eso, luego carga la secuencia de comandos dentro de ese cierre. En ese momento, el usuario está replicando por completo el entorno del nodo y, con un poco de suerte, sabe lo que está haciendo e intenta hacer que un estilo de nodo lo requiera. Si se llama al código en una etiqueta de script, seguirá a salvo de cualquier nuevo cierre externo.


25
2017-08-11 23:06



Lo siguiente funciona en el navegador a menos que intencionalmente, saboteado explícitamente:

if(typeof process === 'object' && process + '' === '[object process]'){
    // is node
}
else{
    // not node
}

Bam.


21
2018-06-18 07:34



Actualmente tropecé con una detección incorrecta de Node que es no consciente del entorno del nodo en Electrón debido a una detección de funciones engañosa. Las siguientes soluciones identifican explícitamente el proceso-entorno.


Identificar solamente Node.js

(typeof process !== 'undefined') && (process.release.name === 'node')

Esto descubrirá si está ejecutando en un proceso de nodo, ya que process.release contiene los "metadatos relacionados con la versión actual [Node-]".

Después del engendro de io.js El valor de process.release.name también puede convertirse io.js (ver el proceso-doc) Para detectar adecuadamente un entorno preparado para Nodo, supongo que debe verificar lo siguiente:

Identificar nodo (> = 3.0.0) o io.js

(typeof process !== 'undefined') &&
(process.release.name.search(/node|io.js/) !== -1)

Esta afirmación se probó con el nodo 5.5.0, Electron 0.36.9 (con el nodo 5.1.1) y Chrome 48.0.2564.116.

Identificar nodo (> = 0.10.0) o io.js

(typeof process !== 'undefined') &&
(typeof process.versions.node !== 'undefined')

El comentario de @ daluege me inspiró a pensar en una prueba más general. Esto debería funcionar desde Node.js> = 0.10. No encontré un identificador único para versiones anteriores.


P.s .: Estoy publicando esa respuesta aquí ya que la pregunta me condujo aquí, aunque el OP estaba buscando una respuesta a una pregunta diferente.


20
2018-03-05 10:46



La mayoría de las soluciones propuestas en realidad pueden ser falsificadas. Una forma robusta es verificar la interna Class propiedad del objeto global utilizando el Object.prototype.toString. La clase interna no se puede fingir en JavaScript:

var isNode = 
    typeof global !== "undefined" && 
    {}.toString.call(global) == '[object global]';

9
2017-08-05 11:53



Aún otra detección de ambiente:

(Significado: la mayoría de las respuestas aquí están bien.)

function isNode() {
    return typeof global === 'object'
        && String(global) === '[object global]'
        && typeof process === 'object'
        && String(process) === '[object process]'
        && global === global.GLOBAL // circular ref
        // process.release.name cannot be altered, unlike process.title
        && /node|io\.js/.test(process.release.name)
        && typeof setImmediate === 'function'
        && setImmediate.length === 4
        && typeof __dirname === 'string'
        && Should I go on ?..
}

Un poco paranoico ¿verdad? Puede hacer que esto sea más detallado al buscar más globals.

¡Pero NO!

Todos estos anteriores pueden ser simulados / falsos de todos modos.

Por ejemplo, para falsificar global objeto:

global = {
    toString: function () {
        return '[object global]';
    },
    GLOBAL: global,
    setImmediate: function (a, b, c, d) {}
 };
 setImmediate = function (a, b, c, d) {};
 ...

Esto no se adjuntará al objeto global original del Nodo pero se adjuntará al window objeto en un navegador. Entonces implicará que estás en Node env dentro de un navegador.

¡La vida es corta!

¿Nos importa si nuestro entorno es falso? Sucedería cuando algún desarrollador estúpido declare una variable global llamada global en el alcance global. O algún dev malvado inyecta código en nuestro env de alguna manera.

Podemos evitar que nuestro código se ejecute cuando captemos esto, pero muchas otras dependencias de nuestra aplicación podrían quedar atrapadas en esto. Entonces eventualmente el código se romperá. Si su código es lo suficientemente bueno, no debería preocuparse por todos y cada uno de los errores tontos que podrían haber cometido otros.

¿Y qué?

Si se orienta a 2 entornos: navegador y nodo;
"use strict"; y simplemente verifique window o global; e indique claramente que en los documentos su código solo admite estos entornos. ¡Eso es!

var isBrowser = typeof window !== 'undefined'
    && ({}).toString.call(window) === '[object Window]';

var isNode = typeof global !== "undefined" 
    && ({}).toString.call(global) === '[object global]';

Si es posible para su caso de uso; en lugar de detección del entorno; hacer detección de características sincrónicas dentro de un bloque try / catch. (estos tardarán unos milisegundos en ejecutarse).

p.ej.

function isPromiseSupported() {
    var supported = false;
    try {
        var p = new Promise(function (res, rej) {});
        supported = true;
    } catch (e) {}
    return supported;
}

9
2017-08-07 15:38



Aquí hay una forma genial de hacerlo también:

const isBrowser = this.window === this;

Esto funciona porque en los navegadores la variable global 'this' tiene una autorreferencia llamada 'ventana'. Esta autorreferencia no existe en Node.

  • En el navegador 'this' es una referencia al objeto global, llamado 'ventana'.
  • En el nodo 'this' es una referencia al module.exports objeto.
    • 'esto es no una referencia al objeto global Nodo, llamado 'global'.
    • 'esto es no una referencia al espacio de declaración de variables del módulo.

Para romper el control de navegador sugerido anteriormente, tendría que hacer algo como lo siguiente

this.window = this;

antes de ejecutar el cheque.


8
2018-01-25 23:21



¿Qué hay de usar el objeto de proceso y verificar execPath para node?

process.execPath

Este es el absoluto   ruta de acceso del ejecutable que   comenzó el proceso.

Ejemplo:

/ usr / local / bin / node


4
2017-11-21 14:14