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 el this
objeto a un objeto vacío y lo redefine module
nuevamente, lo que significa que no tiene que preocuparse por ninguna manipulación externa. Mientras su código esté cargado, estará a require
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 nombre module
que tiene exports
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, la module
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 el this
objeto, lo que hará que la prueba falle, porque this.module
será el mismo objeto que el módulo. En el 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 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 declarando module
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.