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 requirese llama a la función, restablece el thisobjeto a un objeto vacío y lo redefine modulenuevamente, lo que significa que no tiene que preocuparse por ninguna manipulación externa. Mientras su código esté cargado, estará a requiresalvo.
Sin embargo, esto se desmorona en el navegador, ya que cualquiera puede definirlo fácilmente modulepara 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 nombre moduleque tiene exportsdentro 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 thisobjeto es un objeto vacío, sin embargo, la modulevariable 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 moduleen el alcance global en el navegador, se colocará en el thisobjeto, lo que hará que la prueba falle, porque this.moduleserá el mismo objeto que el módulo. En el nodo, this.moduleno existe y moduleexiste 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 modulevariable se use libremente en el ámbito global, aún es posible evitar esto en el navegador creando un nuevo cierre y declarando moduledentro 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.