Estou criando um pequeno aplicativo com um cliente JavaScript (executado no navegador) e um servidor Node.js., comunicando-se usando o WebSocket.
Eu gostaria de compartilhar código entre o cliente e o servidor. Eu apenas comecei o Node.js e meu conhecimento do JavaScript moderno está um pouco enferrujado, para dizer o mínimo. Então, eu ainda estou tentando entender a função requireJS do CommonJS. Se estou criando meus pacotes usando o objeto 'export', não consigo ver como poderia usar os mesmos arquivos JavaScript no navegador.
Desejo criar um conjunto de métodos e classes usados nas duas extremidades para facilitar a codificação e decodificação de mensagens e outras tarefas espelhadas. No entanto, os sistemas de empacotamento Node.js / CommonJS parecem me impedir de criar arquivos JavaScript que podem ser usados nos dois lados.
Também tentei usar o JS.Class para obter um modelo OO mais rígido, mas desisti porque não conseguia descobrir como fazer com que os arquivos JavaScript fornecidos funcionassem com require (). Há algo que estou perdendo aqui?
fonte
Respostas:
Se você deseja escrever um módulo que possa ser usado no lado do cliente e no servidor, tenho uma pequena postagem no blog sobre um método rápido e fácil: Escrever para o Node.js e o navegador , essencialmente o seguinte (onde
this
é o mesmowindow
) :Como alternativa, existem alguns projetos que visam implementar a API do Node.js. no lado do cliente, como os gemini de Marak .
Você também pode estar interessado no DNode , que permite expor uma função JavaScript para que possa ser chamada de outra máquina usando um protocolo de rede baseado em JSON simples.
fonte
O Epeli tem uma boa solução aqui http://epeli.github.com/piler/ que até funciona sem a biblioteca, basta colocar isso em um arquivo chamado share.js
No lado do servidor, basta usar:
E no lado do cliente, basta carregar o arquivo js e usar
fonte
Faça o check-out do código-fonte do jQuery que faz isso funcionar no padrão do módulo Node.js., AMD e global no navegador:
fonte
Não esqueça que a representação em cadeia de uma função JavaScript representa o código-fonte dessa função. Você pode simplesmente escrever suas funções e construtores de maneira encapsulada para que eles possam ser toString () 'enviados para o cliente.
Outra maneira de fazer isso é usar um sistema de compilação, colocar o código comum em arquivos separados e incluí-los nos scripts do servidor e do cliente. Estou usando essa abordagem para um jogo simples de cliente / servidor via WebSockets, onde o servidor e o cliente executam essencialmente o mesmo ciclo de jogo e o cliente sincroniza com o servidor a cada tick para garantir que ninguém trapaceie.
Meu sistema de compilação para o jogo é um script Bash simples que executa os arquivos através do pré-processador C e, em seguida, através do sed para limpar algumas folhas indesejadas de cpp, para que eu possa usar todo o material pré-processador normal, como #include, #define, #ifdef etc.
fonte
Eu recomendaria olhando para o adaptador RequireJS para Node.js . O problema é que o padrão do módulo CommonJS que o Node.js usa por padrão não é assíncrono, o que bloqueia o carregamento no navegador da web. O RequireJS usa o padrão AMD, que é assíncrono e compatível com o servidor e o cliente, desde que você use o
r.js
adaptador.fonte
Talvez isso não esteja totalmente de acordo com a pergunta, mas pensei em compartilhar isso.
Eu queria disponibilizar algumas funções simples de utilitário de cadeia de caracteres, declaradas em String.prototype, para o nó e o navegador. Eu simplesmente mantenho essas funções em um arquivo chamado utilities.js (em uma subpasta) e posso referenciá-lo facilmente a partir de uma tag de script no código do meu navegador e usando o require (omitindo a extensão .js) no meu script Node.js. :
my_node_script.js
my_browser_code.html
Espero que seja uma informação útil para alguém que não seja eu.
fonte
utilites.js
com uma única linhamodule.exports = require('./static/js/utilities');
. Dessa forma, você só precisa atualizar um caminho se embaralhar as coisas.utilities.js
está nashared
pasta sob o projeto. Usandorequire('/shared/utilities')
me deu o erroCannot find module '/shared/utilities'
. Eu tenho que usar algo assimrequire('./../../shared/utilities')
para fazer funcionar. Portanto, ele sempre sai da pasta atual e sobe até a raiz e depois desce.Se você usar os bundlers de módulo, como o webpack para agrupar arquivos JavaScript para uso em um navegador, basta reutilizar o módulo Node.js. para o frontend em execução em um navegador. Em outras palavras, seu módulo Node.js. pode ser compartilhado entre o Node.js. e o navegador.
Por exemplo, você tem o seguinte código sum.js:
Módulo Node.js normal: sum.js
Use o módulo no Node.js
Reutilize-o no frontend
fonte
O servidor pode simplesmente enviar arquivos de origem JavaScript para o cliente (navegador), mas o truque é que o cliente precisará fornecer um mini ambiente de "exportação" antes de poder
exec
codificar e armazená-lo como um módulo.Uma maneira simples de criar esse ambiente é usar um fechamento. Por exemplo, digamos que seu servidor forneça arquivos de origem via HTTP, como
http://example.com/js/foo.js
. O navegador pode carregar os arquivos necessários por meio de um XMLHttpRequest e carregar o código da seguinte forma:A chave é que o cliente pode agrupar o código externo em uma função anônima para ser executada imediatamente (um fechamento) que cria o objeto "exporta" e o retorna para que você possa atribuí-lo onde quiser, em vez de poluir o espaço para nome global. Neste exemplo, ele é atribuído ao atributo de janela
fooModule
que conterá o código exportado pelo arquivofoo.js
.fonte
window.fooModule = {}; (new Function('exports', xhr.responseText))(window.fooModule)
.Nenhuma das soluções anteriores traz o sistema do módulo CommonJS para o navegador.
Conforme mencionado nas outras respostas, existem soluções de gerenciamento / empacotador de ativos, como Browserify ou Piler, e soluções de RPC, como dnode ou nowjs .
Mas não consegui encontrar uma implementação do CommonJS para o navegador (incluindo um
require()
função eexports
/module.exports
objetos etc.). Então escrevi o meu, apenas para descobrir depois que alguém o havia escrito melhor do que eu: https://github.com/weepy/brequire . Chama-se Brequire (abreviação de Browser exigem).A julgar pela popularidade, os gerentes de ativos atendem às necessidades da maioria dos desenvolvedores. No entanto, se você precisar de uma implementação de navegador do CommonJS, o Brequire provavelmente será adequado.
Atualização de 2015: não uso mais o Brequire (ele não é atualizado há alguns anos). Se estou escrevendo um pequeno módulo de código aberto e quero que alguém possa usá-lo facilmente, seguirei um padrão semelhante à resposta de Caolan (acima) - escrevi um post sobre isso alguns anos atrás.
No entanto, se estou escrevendo módulos para uso privado ou para uma comunidade padronizada no CommonJS (como a comunidade Ampersand ), escreverei no formato CommonJS e utilizarei o Browserify .
fonte
now.js também vale a pena dar uma olhada. Ele permite que você chame as funções do lado do servidor e do lado do servidor.
fonte
Se você deseja escrever seu navegador no estilo Node.js., você pode tentar dualizar .
Não há compilação de código do navegador, portanto você pode escrever seu aplicativo sem limitações.
fonte
Escreva seu código como módulos RequireJS e seus testes como testes Jasmine .
Dessa forma, o código pode ser carregado em qualquer lugar com o RequireJS e os testes podem ser executados no navegador com jasmine-html e jasmine-node no Node.js sem a necessidade de modificar o código ou os testes.
Aqui está um exemplo de trabalho para isso.
fonte
Caso de uso: compartilhe a configuração do seu aplicativo entre o Node.js e o navegador (esta é apenas uma ilustração, provavelmente não é a melhor abordagem, dependendo do seu aplicativo).
Problema: você não pode usar
window
(não existe no Node.js) nemglobal
(não existe no navegador).Solução:
Arquivo config.js:
No navegador (index.html):
Agora você pode abrir as ferramentas de desenvolvimento e acessar a variável global
config
No Node.js (app.js):
Com Babel ou TypeScript:
fonte
shared.js
ehelpers.js
-shared.js
usa funções dehelpers.js
, portanto, precisaconst { helperFunc } = require('./helpers')
na parte superior, para que funcione no lado do servidor. O problema está no cliente, queixa-se derequire
não ser uma função, mas se eu envolver a linha de solicitaçãoif (typeof module === 'object') { ... }
, o servidor diz que helperFunc () não está definido (fora da instrução if). Alguma idéia para fazê-lo funcionar em ambos?shared.js
:helperFunc = (typeof exports === 'undefined') ? helperFunc : require('./helpers').helperFunc;
- Infelizmente, será necessária uma linha para cada função exportada, mas espero que seja uma boa solução?Eu escrevi um módulo simples , que pode ser importado (usando require no Nó ou tags de script no navegador), que você pode usar para carregar módulos do cliente e do servidor.
Exemplo de uso
1. Definindo o módulo
Coloque o seguinte em um arquivo
log2.js
, dentro da pasta estática de arquivos da web:Simples assim!
2. Usando o módulo
Por ser um carregador de módulo bilateral , podemos carregá-lo de ambos os lados (cliente e servidor). Portanto, você pode fazer o seguinte, mas não precisa fazer as duas coisas ao mesmo tempo (muito menos em uma ordem específica):
No Node, é simples:
Isso deve retornar
2
.Se o seu arquivo não estiver no diretório atual do Node, lembre-se de chamar
loader.setRoot
o caminho para a pasta estática de arquivos da Web (ou onde quer que esteja o seu módulo).Primeiro, defina a página da web:
Certifique-se de não abrir o arquivo diretamente no seu navegador; Como ele usa o AJAX, sugiro que você dê uma olhada no
http.server
módulo do Python 3 (ou seja, qual for a sua solução de implantação de servidor da Web super rápida, de linha de comando e pasta).Se tudo correr bem, isso aparecerá:
fonte
Eu escrevi isso, é simples de usar se você deseja definir todas as variáveis para o escopo global:
fonte