Tengo un script que necesito de un script Node.js, que quiero mantener el motor de JavaScript independiente.
Por ejemplo, quiero hacerlo exports.x = y;
solo si se ejecuta en Node.js. ¿Cómo puedo realizar esta prueba?
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?
javascript
node.js
commonjs
theosp
fuente
fuente
Respuestas:
Al buscar el soporte de CommonJS , así es como lo hace la biblioteca Underscore.js :
Editar: a su pregunta actualizada:
El ejemplo aquí retiene el patrón del Módulo.
fuente
Bueno, no hay una forma 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 ningún
window
objeto en Node.js de manera predeterminada, puede dar la vuelta y verificar 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:
Todavía podría explotar en caso de que
window
esté definido en Node.js, pero no hay una buena razón para que alguien haga esto, ya que explícitamente necesitaría omitirvar
o establecer la propiedad en elglobal
objeto.EDITAR
Para detectar si su script ha sido requerido como un módulo CommonJS, eso tampoco es fácil. Lo único que CommonJS especifica es que A: los módulos se incluirán mediante una llamada a la función
require
y B: los módulos exportan cosas a través de propiedades en elexports
objeto. Ahora, cómo se implementa eso se deja al sistema subyacente. Node.js envuelve el contenido del módulo en una función anónima:Ver: https://github.com/ry/node/blob/master/src/node.js#L325
Pero no intente detectar eso a través de algunas
arguments.callee.toString()
cosas locas , solo use mi código de ejemplo anterior que verifica el navegador. Node.js es un entorno mucho más limpio, por lo que es poco probable quewindow
se declare allí.fuente
window
en la primera línea de su módulo, no debería tener ningún problema. También puede ejecutar una función anónima y comprobar el[[Class]]
dethis
su interior (sólo funciona en modo no estricto) Ver "clase" en: bonsaiden.github.com/JavaScript-Garden/#typeoftypeof self === 'object'
podría ser más seguro ya quetypeof window === 'undefined'
falla en el alcance de los trabajadores web.Actualmente me topé con una detección incorrecta de Node que no conoce el entorno de Node en Electron debido a una detección de características engañosa. Las siguientes soluciones identifican el entorno del proceso explícitamente.
Identificar solo Node.js
Esto descubrirá si está ejecutando un proceso Node, 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 llegar a serio.js
(ver el documento de proceso ). Para detectar correctamente un entorno preparado para Nodo, supongo que debe verificar lo siguiente:Identificar nodo (> = 3.0.0) o io.js
Esta declaración se probó con el Nodo 5.5.0, Electrón 0.36.9 (con el Nodo 5.1.1) y Chrome 48.0.2564.116.
Identificar nodo (> = 0.10.0) o io.js
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.
PD: Estoy publicando esa respuesta aquí ya que la pregunta me llevó aquí, aunque el OP estaba buscando una respuesta a una pregunta diferente.
fuente
process
yprocess.version
existe dentro del paquete, por lo que agregué una verificación adicional deprocess.version
dóndeprocess.release.node
está indefinido en el lado del cliente pero tiene una versión de nodo como valor en el lado del servidorprocess.version
variable (en react, webpack o react-webpack). Agradecería cualquier pista donde se define la variable de versión para agregarla a la respuesta. Dependiendo de las restricciones de release.node al nodo> = 3.xxfunction isNodejs() { return typeof "process" !== "undefined" && process && process.versions && process.versions.node; }
El problema al tratar de averiguar en qué entorno se está ejecutando su código es que cualquier objeto puede modificarse y declararse, por lo que es casi imposible descubrir qué objetos son nativos del entorno y cuáles han sido modificados por el programa.
Sin embargo, hay algunos trucos que podemos usar para determinar con seguridad en qué entorno se encuentra.
Comencemos con la solución generalmente aceptada que se usa en la biblioteca de subrayado:
typeof module !== 'undefined' && module.exports
Esta técnica es realmente perfecta para el lado del servidor, ya que cuando
require
se llama a la función, restablece elthis
objeto a un objeto vacío y lo redefinemodule
nuevamente, lo que significa que no tiene que preocuparse por ninguna manipulación externa. Mientras su código esté cargado, estará arequire
salvo.Sin embargo, esto se desmorona en el navegador, ya que cualquiera puede definirlo fácilmente
module
para que parezca que es el objeto que está 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. Quizás alguien quiera usar una variable con el nombremodule
que tieneexports
dentro para otro uso. Es poco probable, pero ¿quiénes somos para juzgar qué variables puede usar otra persona, solo porque otro entorno usa ese nombre de variable?Sin embargo, el truco es que si asumimos que su script se está cargando en el ámbito global (que será si se carga a través de una etiqueta de script), una variable no se puede reservar en un cierre externo, porque el navegador no permite que . Ahora recuerde que en el nodo, el
this
objeto es un objeto vacío, sin embargo, lamodule
variable aún está disponible. Eso es porque se declara en un cierre exterior. Entonces podemos arreglar 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 elthis
objeto, lo que hará que la prueba falle, porquethis.module
será el mismo objeto que el módulo. En el nodo,this.module
no existe ymodule
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 que la
module
variable se use libremente en el ámbito global, aún es posible evitar esto en el navegador creando un nuevo cierre y declarandomodule
dentro de eso, luego cargando el script dentro de ese cierre. En ese momento, el usuario está replicando completamente el entorno del nodo y, con suerte, sabe lo que está haciendo y está tratando de hacer un estilo de nodo requerido. Si se llama al código en una etiqueta de script, seguirá estando a salvo de cualquier cierre externo nuevo.fuente
Cannot read property 'module' of undefined
porque esto no está definido en las pruebas de mocha, por ejemploLo siguiente funciona en el navegador a menos que se haya saboteado intencionalmente y explícitamente:
Bam
fuente
process+''
lugar deprocess.toString()
?Object.prototype.toString.call(process)
var process = null;
causaría que el segundo caso falle. Tanto en Javascript como en Java, la expresión'' + x
produce lo mismo que,x.toString()
excepto cuandox
es desagradable, la primera produce"null"
o"undefined"
donde la segunda arrojaría un error.Aquí hay una manera genial de hacerlo también:
Esto funciona porque en los navegadores la variable global 'this' tiene una referencia propia llamada 'ventana'. Esta auto referencia no existe en el Nodo.
Para romper la comprobación de navegador sugerida anteriormente, tendría que hacer algo como lo siguiente
antes de ejecutar el cheque.
fuente
const isBrowser = this.window !== undefined
? Y en teoría en el nodo que puedo hacerthis.window = this
para engañar a la solución.Otra detección más del entorno :
(Significado: la mayoría de las respuestas aquí están bien).
Un poco paranoico, ¿verdad? Puede hacer esto más detallado al buscar más globales .
Pero NO!
Todos estos anteriores pueden ser falsificados / simulados de todos modos.
Por ejemplo para falsificar el
global
objeto:Esto no se adjuntará al objeto global original del Nodo, pero se adjuntará al
window
objeto en un navegador. Por lo tanto, implicará que estás en Node env dentro de un navegador.¡La vida es corta!
¿Nos importa si nuestro entorno es falso? Ocurriría cuando algún desarrollador estúpido declare una variable global llamada
global
en el ámbito global. O algún malvado desarrollador inyecta código en nuestro entorno de alguna manera.Podemos evitar que nuestro código se ejecute cuando detectemos 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 debe preocuparse por todos y cada uno de los errores tontos que podrían haber cometido otros.
¿Y qué?
Si apunta a 2 entornos: navegador y nodo;
"use strict"
; y ya sea simplemente verificarwindow
oglobal
; e indique claramente que en los documentos su código solo admite estos entornos. ¡Eso es!Si es posible para su caso de uso; en lugar de la 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
fuente
La mayoría de las soluciones propuestas pueden ser falsificadas. Una forma robusta es verificar la
Class
propiedad interna del objeto global utilizandoObject.prototype.toString
. La clase interna no se puede falsificar en JavaScript:fuente
Object.prototype.toString
cual es una práctica realmente mala.var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};
({}.toString.call(window))
es igual"[object global]"
.window.toString()
produce"[object Window]"
¿Qué pasa con el uso del objeto del proceso y comprobar execPath para
node
?fuente
window.process = {execPath: "/usr/local/bin/node"};
?Relacionado: para verificar si se ha requerido como un módulo vs ejecutar directamente en el nodo, puede verificar
require.main !== module
. http://nodejs.org/docs/latest/api/modules.html#accessing_the_main_modulefuente
Aquí está mi variación sobre lo que está arriba:
Para usarlo, modifique la "Casa" en la segunda última línea para que sea lo que quiera que sea el nombre del módulo en el navegador y publique lo que quiera que sea el valor del módulo (generalmente un constructor o un objeto literal )
En los navegadores, el objeto global es window, y tiene una referencia a sí mismo (hay una window.window que es == window). Me parece que esto es poco probable que ocurra a menos que esté en un navegador o en un entorno que quiera que crea que está en un navegador. En todos los demás casos, si se declara una variable global de 'módulo', la usa de lo contrario, usa el objeto global.
fuente
Estoy usando
process
para verificar node.js asío
Documentado aquí
fuente
process.title
se puede cambiarAl momento de escribir este artículo, esta respuesta es más una opción "próximamente", ya que aprovecha las características muy nuevas de JavaScript.
El
runtime
valor seránode
onot node
.Como se mencionó, esto se basa en algunas características nuevas de JavaScript.
globalThis
es una característica finalizada en la especificación ECMAScript 2020. El motor V8, que se entrega con Chrome 80, admite el encadenamiento opcional / fusión nula (?
parte deglobalThis.process?.release?.name
). A partir del 8/04/2020, este código funcionará en el navegador pero no en el Nodo ya que la rama del Nodo 13 usa V8 7.9.xxx. Creo que el Nodo 14 (que se lanzará el 21/04/2020) debe usar V8 8.x +.Este enfoque viene con una buena dosis de restricciones actuales. Sin embargo; el ritmo al que se lanzan los navegadores / Node, con el tiempo será una línea confiable.
fuente
Node.js tiene un
process
objeto, por lo tanto, siempre y cuando no tenga ningún otro script queprocess
pueda crear , puede usarlo para determinar si el código se ejecuta en Node.fuente
Esta es una forma bastante segura y directa de garantizar la compatibilidad entre javascript del lado del servidor y del lado del cliente, que también funcionará con browserify, RequireJS o CommonJS incluidos en el lado del cliente:
fuente
Editar : Con respecto a su pregunta actualizada: "¿Cómo puede un script saber si se ha requerido como módulo commonjs?" No creo que pueda. Puede verificar si
exports
es un objeto (if (typeof exports === "object")
), ya que la especificación requiere que se proporcione a los módulos, pero todo lo que le dice es que ...exports
es un objeto. :-)Respuesta original:
Estoy seguro de que hay algún símbolo específico de NodeJS (
no, debe usarloEventEmitter
tal vezrequire
para obtener el módulo de eventos; ver más abajo ) que puede verificar, pero como dijo David, lo ideal es que detecte la función (más bien que el medio ambiente) si tiene sentido hacerlo.Actualización : tal vez algo como:
Pero eso solo te dice que estás en un entorno con
require
algo muy, muy parecido a NodeJSBuffer
. :-)fuente
window
Igualmente puedo romper su verificación definiendo una variable dentro de una aplicación NodeJS. :-)window
en un módulo NodeJS, por lo que podrían incluir código que se basara enwindow
ser el objeto global y no quisiera modificar ese código. Yo no lo haría, tú no, pero apuesto a que alguien lo ha hecho. :-) O simplementewindow
significaban algo completamente diferente.typeof process !== "undefined" && process.title === "node"
fuente
Desde la fuente del paquete de depuración:
https://github.com/visionmedia/debug/blob/master/src/index.js#L6
fuente
Tome la fuente de node.js y cámbiela para definir una variable como
runningOnNodeJS
. Verifique esa variable en su código.Si no puede tener su propia versión privada de node.js, abra una solicitud de función en el proyecto. Pídales que definan una variable que le proporcione la versión de node.js en la que se está ejecutando. Luego, verifique esa variable.
fuente
window
global, supongo que presentaré una solicitud de función en ese.var
declaración, las personas que simplemente la filtran en el espacio de nombres global, bueno, entonces no entienden el concepto de módulos autónomosPublicación muy antigua, pero la resolví envolviendo las declaraciones requeridas en un intento - captura
fuente