OK, já faz um tempo e essa é uma pergunta popular, então criei um repositório de github para andaimes com código JavaScript e um README longo sobre como eu gosto de estruturar um aplicativo express.js de tamanho médio.
focusaurus / express_code_structure é o repositório com o código mais recente para isso. Solicitações pull bem-vindas.
Aqui está um instantâneo do README, já que o stackoverflow não gosta de respostas apenas por um link. Farei algumas atualizações, pois este é um novo projeto que continuarei atualizando, mas no final o repositório do github será o local atualizado para essas informações.
Estrutura do código expresso
Este projeto é um exemplo de como organizar um aplicativo Web express.js de tamanho médio.
Atual para pelo menos expressar v4.14 de dezembro de 2016
Qual é o tamanho da sua aplicação?
Os aplicativos da Web não são todos iguais e, na minha opinião, não existe uma única estrutura de código que deva ser aplicada a todos os aplicativos express.js.
Se seu aplicativo for pequeno, você não precisará de uma estrutura de diretórios tão profunda como exemplificada aqui. Apenas mantenha a simplicidade e cole alguns .js
arquivos na raiz do seu repositório e pronto. Voilà.
Se seu aplicativo for enorme, em algum momento você precisará dividi-lo em pacotes npm distintos. Em geral, a abordagem node.js parece favorecer muitos pacotes pequenos, pelo menos para bibliotecas, e você deve criar seu aplicativo usando vários pacotes npm, pois isso começa a fazer sentido e justificar a sobrecarga. Assim, à medida que seu aplicativo cresce e parte do código se torna claramente reutilizável fora do aplicativo ou é um subsistema claro, mova-o para seu próprio repositório git e faça-o em um pacote npm independente.
Portanto, o foco deste projeto é ilustrar uma estrutura viável para um aplicativo de tamanho médio.
Qual é a sua arquitetura geral
Existem muitas abordagens para criar um aplicativo Web, como
- MVC do lado do servidor no Ruby on Rails
- Estilo de aplicativo de página única no MongoDB / Express / Angular / Node (MEAN)
- Site básico com alguns formulários
- Modelos / Operações / Vistas / Eventos no estilo MVC está morto, é hora de seguir em frente
- e muitos outros atuais e históricos
Cada um deles se encaixa perfeitamente em uma estrutura de diretórios diferente. Para os fins deste exemplo, é apenas um andaime e não um aplicativo totalmente funcional, mas estou assumindo os seguintes pontos principais da arquitetura:
- O site possui algumas páginas / modelos estáticos tradicionais
- A parte "aplicativo" do site é desenvolvida como um estilo de aplicativo de página única
- O aplicativo expõe uma API de estilo REST / JSON ao navegador
- O aplicativo modela um domínio comercial simples, neste caso, é um aplicativo de concessionária de carros
E o Ruby on Rails?
Será um tema ao longo deste projeto que muitas das idéias incorporadas no Ruby on Rails e as decisões da "Convenção sobre configuração" que eles adotaram, embora amplamente aceitas e usadas, não são realmente muito úteis e às vezes são o oposto do que esse repositório recomenda.
Meu ponto principal aqui é que existem princípios subjacentes à organização do código e, com base nesses princípios, as convenções Ruby on Rails fazem sentido (principalmente) para a comunidade Ruby on Rails. No entanto, apenas imitar essas convenções sem pensar perde o objetivo. Depois de conhecer os princípios básicos, TODOS os seus projetos serão bem organizados e claros: shell scripts, jogos, aplicativos móveis, projetos corporativos e até o diretório inicial.
Para a comunidade Rails, eles desejam ter um único desenvolvedor de Rails alternando de aplicativo para aplicativo e se familiarizar e se familiarizar com ele a cada vez. Isso faz muito sentido se você tiver 37 sinais ou o Pivotal Labs e tiver benefícios. No mundo JavaScript do lado do servidor, o ethos geral é apenas muito mais a oeste, e não temos realmente nenhum problema com isso. É assim que nós fazemos. Estamos acostumados a isso. Mesmo no express.js, é um parente próximo do Sinatra, não do Rails, e aceitar convenções do Rails geralmente não ajuda em nada. Eu diria até Princípios sobre Convenção sobre Configuração .
Princípios e motivações subjacentes
O truque de link simbólico do aplicativo
Existem muitas abordagens descritas e discutidas em profundidade pela comunidade na grande essência Melhor locais exigem caminhos () para Node.js . Em breve, posso decidir preferir "apenas lidar com lotes de ../../../ .." ou usar o modulo requireFrom. No entanto, no momento, eu tenho usado o truque de link simbólico detalhado abaixo.
Portanto, uma maneira de evitar o intraprojeto exige caminhos relativos irritantes, como require("../../../config")
é usar o seguinte truque:
- crie um link simbólico em node_modules para seu aplicativo
- cd node_modules && ln -nsf ../app
- adicione apenas o link simbólico node_modules / app , não toda a pasta node_modules, ao git
- git add -f node_modules / app
- Sim, você ainda deve ter "node_modules" em seu
.gitignore
arquivo
- Não, você não deve colocar "node_modules" em seu repositório git. Algumas pessoas recomendam que você faça isso. Eles estão incorretos.
- Agora você pode exigir módulos intraprojetos usando esse prefixo
var config = require("app/config");
var DealModel = require("app/deals/deal-model")
;
- Basicamente, isso faz com que o intraprojeto exija um trabalho muito semelhante ao exigido para módulos npm externos.
- Desculpe, usuários do Windows, você precisa seguir os caminhos relativos do diretório pai.
Configuração
Geralmente codifique módulos e classes para esperar apenas a options
passagem de um objeto JavaScript básico . Somente o app/server.js
carregamento deve ser carregado app/config.js
. A partir daí, ele pode sintetizar options
objetos pequenos para configurar subsistemas, conforme necessário, mas o acoplamento de cada subsistema a um grande módulo de configuração global cheio de informações extras é um acoplamento ruim.
Tente centralizar a criação de conexões com o banco de dados e passe-as para os subsistemas, em vez de passar os parâmetros de conexão e fazer com que os subsistemas façam as próprias conexões de saída.
NODE_ENV
Essa é outra idéia atraente, mas terrível, herdada do Rails. Deve haver exatamente um lugar no seu aplicativo, app/config.js
que analisa a NODE_ENV
variável de ambiente. Tudo o resto deve ter uma opção explícita como argumento do construtor de classe ou parâmetro de configuração do módulo.
Se o módulo de e-mail tiver uma opção de como enviar e-mails (SMTP, log para stdout, colocar na fila etc.), deve ser uma opção como {deliver: 'stdout'}
essa, mas absolutamente não deve ser verificada NODE_ENV
.
Testes
Agora, mantenho meus arquivos de teste no mesmo diretório que o código correspondente e uso as convenções de nomenclatura de extensão de nome de arquivo para distinguir testes de código de produção.
foo.js
tem o código do módulo "foo"
foo.tape.js
possui os testes baseados em nós para foo e vive no mesmo diretório
foo.btape.js
pode ser usado para testes que precisam ser executados em um ambiente de navegador
Uso globs do sistema de arquivos e o find . -name '*.tape.js'
comando para obter acesso a todos os meus testes, conforme necessário.
Como organizar o código dentro de cada .js
arquivo de módulo
O escopo deste projeto é principalmente para onde os arquivos e diretórios vão, e não quero adicionar muito outro escopo, mas mencionarei apenas que organizo meu código em três seções distintas.
- O bloco de abertura do CommonJS requer chamadas para dependências de estado
- Bloco de código principal de JavaScript puro. Nenhuma poluição do CommonJS aqui. Não faça referência a exportações, módulos ou exigências.
- Bloco de fechamento do CommonJS para configurar exportações