Eu tenho um script que estou exigindo de um script Node.js, que desejo manter independente do mecanismo JavaScript.
Por exemplo, eu quero fazer exports.x = y;
apenas se estiver sendo executado em Node.js. Como posso realizar este teste?
Ao postar esta pergunta, eu não sabia que o recurso de módulos Node.js se baseia no CommonJS .
Para o exemplo específico que dei, uma pergunta mais precisa teria sido:
Como um script pode dizer se foi necessário como um módulo CommonJS?
javascript
node.js
commonjs
theosp
fonte
fonte
Respostas:
Ao procurar o suporte do CommonJS , é assim que a biblioteca Underscore.js faz isso:
Editar: para sua pergunta atualizada:
O exemplo aqui mantém o padrão do módulo.
fonte
Bem, não há uma maneira confiável de detectar a execução no Node.js. Como todo site pode facilmente declarar as mesmas variáveis, ainda assim, como não há
window
objeto no Node.js por padrão, você pode fazer o contrário e verificar se está executando dentro de um Node.js. Navegador.É isso que eu uso para bibliotecas que devem funcionar tanto em um navegador quanto em Node.js:
Ele ainda pode explodir caso
window
seja definido no Node.js, mas não há uma boa razão para alguém fazer isso, pois você precisaria explicitamente deixar de foravar
ou definir a propriedade noglobal
objeto.EDITAR
Para detectar se seu script foi necessário como um módulo CommonJS, isso também não é fácil. A única coisa que o commonJS especifica é que A: Os módulos serão incluídos por meio de uma chamada para a função
require
e B: Os módulos exportam itens por meio de propriedades noexports
objeto. Agora, como isso é implementado, é deixado para o sistema subjacente. O Node.js agrupa o conteúdo do módulo em uma função anônima:Consulte: https://github.com/ry/node/blob/master/src/node.js#L325
Mas não tente detectar isso por meio de
arguments.callee.toString()
coisas malucas , basta usar meu código de exemplo acima, que verifica o navegador. O Node.js é um ambiente muito mais limpo, por isso é improvável quewindow
seja declarado lá.fonte
window
na primeira linha do seu módulo, não deverá ter nenhum problema. Você também pode executar uma função anônima e verifique o[[Class]]
dethis
dentro dele (funciona apenas no modo não-estrito) Consulte "Classe" sob: bonsaiden.github.com/JavaScript-Garden/#typeoftypeof self === 'object'
pode ser mais seguro, poistypeof window === 'undefined'
falha no escopo dos trabalhadores da Web.No momento, deparei-me com uma detecção incorreta do nó que não está ciente do ambiente do nó no Electron devido a uma detecção enganosa de recursos. As soluções a seguir identificam o ambiente do processo explicitamente.
Identifique apenas o Node.js
Isso descobrirá se você está executando um processo de nó, pois
process.release
contém os "metadados relacionados à versão atual do [Node-]".Após o surgimento de io.js, o valor de
process.release.name
também pode se tornario.js
(consulte o documento do processo ). Para detectar corretamente um ambiente pronto para o nó, acho que você deve verificar da seguinte maneira:Identifique o nó (> = 3.0.0) ou io.js
Esta declaração foi testada com o Nó 5.5.0, Electron 0.36.9 (com Nó 5.1.1) e Chrome 48.0.2564.116.
Identifique o nó (> = 0.10.0) ou io.js
O comentário de @ daluege me inspirou a pensar em uma prova mais geral. Isso deve funcionar no Node.js> = 0.10 . Não encontrei um identificador exclusivo para versões anteriores.
Ps: Estou postando essa resposta aqui, pois a pergunta me levou até aqui, embora o OP estivesse procurando uma resposta para uma pergunta diferente.
fonte
process
eprocess.version
existe dentro do pacote, então eu adicionei uma verificação extra paraprocess.version
ondeprocess.release.node
é indefinido no lado do cliente, mas tem uma versão nó como um valor no lado do servidorprocess.version
variável (em react, webpack ou react-webpack). Gostaria muito de receber uma dica de onde a variável de versão está definida para adicioná-la à resposta. Dependendo das restrições release.node para o nó> = 3.xxfunction isNodejs() { return typeof "process" !== "undefined" && process && process.versions && process.versions.node; }
O problema de tentar descobrir em que ambiente seu código está executando é que qualquer objeto pode ser modificado e declarado, tornando quase impossível descobrir quais objetos são nativos do ambiente e quais foram modificados pelo programa.
No entanto, existem alguns truques que podemos usar para descobrir com certeza em que ambiente você está.
Vamos começar com a solução geralmente aceita usada na biblioteca de sublinhados:
typeof module !== 'undefined' && module.exports
Essa técnica é realmente perfeita para o servidor, pois quando a
require
função é chamada, ela redefine othis
objeto para um objeto vazio e redefinemodule
para você novamente, o que significa que você não precisa se preocupar com adulterações externas. Enquanto seu código estiver carregadorequire
, você estará seguro.No entanto, isso desmorona no navegador, pois qualquer um pode definir facilmente
module
para fazer parecer que é o objeto que você está procurando. Por um lado, esse pode ser o comportamento que você deseja, mas também determina quais variáveis o usuário da biblioteca pode usar no escopo global. Talvez alguém queira usar uma variável com o nomemodule
que possuiexports
dentro dele para outro uso. É improvável, mas quem somos nós para julgar quais variáveis alguém pode usar, apenas porque outro ambiente usa esse nome de variável?O truque, no entanto, é que, se estivermos assumindo que seu script está sendo carregado no escopo global (o que acontecerá se for carregado por meio de uma tag de script), uma variável não poderá ser reservada em um fechamento externo, porque o navegador não permite que . Agora lembre-se, no nó, o
this
objeto é um objeto vazio, mas amodule
variável ainda está disponível. Isso é porque é declarado em um fechamento externo. Assim, podemos corrigir a verificação do sublinhado adicionando uma verificação extra:this.module !== module
Com isso, se alguém declarar
module
no escopo global no navegador, ele será colocado nothis
objeto, o que fará com que o teste falhe, porquethis.module
será o mesmo objeto que o módulo. No nó,this.module
não existe emodule
existe dentro de um fechamento externo; portanto, o teste será bem-sucedido, pois não são equivalentes.Assim, o teste final é:
typeof module !== 'undefined' && this.module !== module
Nota: Embora agora isso permita que a
module
variável seja usada livremente no escopo global, ainda é possível ignorá-la no navegador, criando um novo fechamento e declarandomodule
dentro disso, carregando o script nesse encerramento. Nesse ponto, o usuário está replicando completamente o ambiente do nó e, esperançosamente, sabe o que está fazendo e está tentando fazer um estilo de nó exigir. Se o código for chamado em uma tag de script, ele ainda estará protegido contra novos fechamentos externos.fonte
Cannot read property 'module' of undefined
porque este é indefinido nos testes mocha por exemploO seguinte funciona no navegador, a menos que seja intencional e explicitamente sabotado:
Bam.
fonte
process+''
vez deprocess.toString()
?Object.prototype.toString.call(process)
var process = null;
causaria falha no segundo caso. Em Javascript e Java, a expressão'' + x
produz o mesmo quex.toString()
exceto quandox
é desagradável, o primeiro produz"null"
ou"undefined"
onde o último geraria um erro.Aqui está uma maneira bem legal de fazer isso:
Isso funciona porque em navegadores a variável global 'this' possui uma auto-referência chamada 'window'. Essa referência própria não existe no Nó.
Para interromper a verificação do navegador sugerida acima, você teria que fazer algo como o seguinte
antes de executar a verificação.
fonte
const isBrowser = this.window !== undefined
? E, em teoria, no nó eu posso fazerthis.window = this
para enganar a solução.Mais uma detecção de ambiente :
(Significado: a maioria das respostas aqui está correta.)
Um pouco paranóico, certo? Você pode tornar isso mais detalhado, verificando se há mais globais .
Mas NÃO!
Todos esses itens acima podem ser falsificados / simulados de qualquer maneira.
Por exemplo, para falsificar o
global
objeto:Isso não será anexado ao objeto global original do Nó, mas será anexado ao
window
objeto em um navegador. Portanto, isso implica que você está no Node env dentro de um navegador.A vida é curta!
Nos importamos se nosso ambiente é falso? Isso aconteceria quando algum desenvolvedor estúpido declarasse uma variável global chamada
global
no escopo global. Ou algum desenvolvedor mal injeta código em nosso ambiente de alguma forma.Podemos impedir que nosso código seja executado quando detectamos isso, mas muitas outras dependências do nosso aplicativo podem ficar presas a ele. Então, eventualmente, o código será quebrado. Se o seu código for bom o suficiente, você não deve se importar com todos os erros tolos que poderiam ter sido cometidos por outras pessoas.
E daí?
Se estiver direcionando 2 ambientes: Navegador e Nó;
"use strict"
; e simplesmente verifiquewindow
ouglobal
; e indique claramente nos documentos que o seu código suporta apenas esses ambientes. É isso aí!Se possível para o seu caso de uso; em vez de detecção de ambiente; faça a detecção de recurso síncrono dentro de um bloco try / catch. (isso levará alguns milissegundos para ser executado).
por exemplo
fonte
A maioria das soluções propostas pode realmente ser falsificada. Uma maneira robusta é verificar a
Class
propriedade interna do objeto global usando oObject.prototype.toString
. A classe interna não pode ser falsificada em JavaScript:fonte
Object.prototype.toString
que é realmente uma prática ruim.var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};
({}.toString.call(window))
é igual"[object global]"
.window.toString()
produz"[object Window]"
Que tal usar o objeto de processo e verificar execPath para
node
?fonte
window.process = {execPath: "/usr/local/bin/node"};
?Relacionado: para verificar se foi necessário como um módulo vs executar diretamente no nó, você pode verificar
require.main !== module
. http://nodejs.org/docs/latest/api/modules.html#accessing_the_main_modulefonte
Aqui está minha variação do que está acima:
Para usá-lo, você modifica o "House" na segunda última linha para ser o que você deseja que o nome do módulo esteja no navegador e publica o que você deseja que o valor do módulo seja (geralmente um construtor ou um objeto literal )
Nos navegadores, o objeto global é window e tem uma referência a si mesmo (há uma window.window que é == window). Parece-me que é improvável que isso ocorra, a menos que você esteja em um navegador ou em um ambiente que queira que você acredite que está em um navegador. Em todos os outros casos, se houver uma variável global 'module' declarada, ela será usada, caso contrário, será usada o objeto global.
fonte
Estou usando
process
para verificar se há node.js assimou
Documentado aqui
fonte
process.title
pode ser alteradoNo momento da redação deste artigo, essa resposta é mais uma opção "em breve", pois utiliza recursos muito novos do JavaScript.
o
runtime
valor seránode
ounot node
.Como mencionado, isso depende de alguns novos recursos JavaScript.
globalThis
é um recurso finalizado na especificação ECMAScript 2020. Encadeamento opcional / coalescência nula (a?
parte deglobalThis.process?.release?.name
) é suportado no mecanismo V8, que é fornecido com o Chrome 80. A partir de 8/4/2020, esse código funcionará no navegador, mas não funcionará no Nó, pois a ramificação do Nó 13 usa V8 7.9.xxx. Acredito que o Nó 14 (com lançamento previsto para 21/4/2020) deve usar o V8 8.x +.Essa abordagem vem com uma dose saudável das restrições atuais. Contudo; o ritmo em que os navegadores / Node são lançados, acabará sendo um one-liner confiável.
fonte
O Node.js possui um
process
objeto, desde que você não tenha nenhum outro script que o crie.process
Você pode usá-lo para determinar se o código é executado no Node.fonte
Essa é uma maneira bastante segura e direta de garantir a compatibilidade entre o javascript do lado do servidor e do lado do cliente, que também funcionará com o browserify, RequireJS ou CommonJS incluído no lado do cliente:
fonte
Editar : em relação à sua pergunta atualizada: "Como um script pode dizer se foi necessário como um módulo commonjs?" Eu não acho que pode. Você pode verificar se
exports
é um objeto (if (typeof exports === "object")
), já que a especificação exige que seja fornecida aos módulos, mas tudo o que indica é que ...exports
é um objeto. :-)Resposta original:
Tenho certeza de que há algum símbolo específico do NodeJS (
não, você precisa usarEventEmitter
talvezrequire
para obter o módulo de eventos; veja abaixo ) que você poderia procurar, mas, como David disse, o ideal é você detectar melhor o recurso (em vez ambiente) se faz algum sentido fazê-lo.Atualização : Talvez algo como:
Mas isso apenas indica que você está em um ambiente com
require
algo muito parecido com o NodeJSBuffer
. :-)fonte
window
variável dentro de um aplicativo NodeJS. :-)window
em um módulo NodeJS, para que eles pudessem incluir um código que dependia dewindow
ser o objeto global e não queria modificar esse código. Eu não faria, você não faria, mas aposto que alguém fez. :-) Ou eles costumavamwindow
significar algo completamente diferente.typeof process !== "undefined" && process.title === "node"
fonte
Da fonte do pacote de depuração:
https://github.com/visionmedia/debug/blob/master/src/index.js#L6
fonte
Pegue a fonte do node.js e altere-a para definir uma variável como
runningOnNodeJS
. Verifique essa variável no seu código.Se você não pode ter sua própria versão privada do node.js, abra uma solicitação de recurso no projeto. Peça que eles definam uma variável que fornece a versão do node.js em que você está executando. Em seguida, verifique essa variável.
fonte
window
global, acho que vou registrar uma solicitação de recurso nesse.var
instrução, pessoas que simplesmente a lançam no espaço de nomes global, então elas não entendem o conceito de módulos independentesPost muito antigo, mas eu apenas o resolvi envolvendo as instruções de solicitação em uma tentativa - captura
fonte