Existe uma convenção comum para dividir e modularizar o app.js
arquivo em um aplicativo Express.js ? Ou é comum manter tudo em um único arquivo?
Existe uma convenção comum para dividir e modularizar o app.js
arquivo em um aplicativo Express.js ? Ou é comum manter tudo em um único arquivo?
Respostas:
Eu tenho o meu dividido da seguinte forma:
~/app
|~controllers
| |-monkey.js
| |-zoo.js
|~models
| |-monkey.js
| |-zoo.js
|~views
| |~zoos
| |-new.jade
| |-_form.jade
|~test
| |~controllers
| |-zoo.js
| |~models
| |-zoo.js
|-index.js
Eu uso Exportações para retornar o que é relevante. Por exemplo, nos modelos que faço:
module.exports = mongoose.model('PhoneNumber', PhoneNumberSchema);
e se eu precisar criar um número de telefone, é tão simples como:
var PhoneNumber = require('../models/phoneNumber');
var phoneNumber = new PhoneNumber();
se eu precisar usar o esquema, então PhoneNumber.schema
(o que pressupõe que estamos trabalhando na pasta de rotas e precisamos ir 1 nível para cima e depois para baixo para os modelos)
O Express wiki possui uma lista de estruturas construídas sobre ele.
Desses, acho que o matador do Twitter está muito bem estruturado. Na verdade, usamos uma abordagem muito semelhante para carregar partes do aplicativo.
derby.js também parece extremamente interessante. É semelhante a meteoro sem todo o hype e realmente dá crédito onde o crédito é devido (notadamente, node e express).
Se você é fã do CoffeeScript (eu não sou) e reeeeaaaaaally quer o L&F do Rails, também existe o Tower.js .
Se você está familiarizado com Rails e não se importa com o sangramento de alguns conceitos, existe Locomotive . É uma estrutura leve construída no Express. Ele tem uma estrutura muito semelhante ao RoR e carrega alguns dos conceitos mais rudimentares (como roteamento).
Vale a pena conferir, mesmo se você não planeja usá-lo.
nodejs-express-mongoose-demo é muito semelhante a como eu estruturei o meu. Confira.
Aviso: referenciar o código que hackeado juntos para nocaute do nó, meio que funciona, mas está longe de ser elegante ou polido.
Para ser mais específico sobre a divisão, app.js
tenho o seguinte arquivo app.js
var express = require('express'),
bootstrap = require('./init/bootstrap.js'),
app = module.exports = express.createServer();
bootstrap(app);
Isso basicamente significa que coloco todo o meu bootstrap em um arquivo separado e, em seguida, inicializo o servidor.
Então, o que o bootstrap faz?
var configure = require("./app-configure.js"),
less = require("./watch-less.js"),
everyauth = require("./config-everyauth.js"),
routes = require("./start-routes.js"),
tools = require("buffertools"),
nko = require("nko"),
sessionStore = new (require("express").session.MemoryStore)()
module.exports = function(app) {
everyauth(app);
configure(app, sessionStore);
less();
routes(app, sessionStore);
nko('/9Ehs3Dwu0bSByCS');
app.listen(process.env.PORT);
console.log("server listening on port xxxx");
};
Bem, ele divide toda a configuração de inicialização do servidor em partes agradáveis. Especificamente
app.configure
)Por exemplo, vamos olhar para o arquivo de roteamento
var fs = require("fs"),
parseCookie = require('connect').utils.parseCookie;
module.exports = function(app, sessionStore) {
var modelUrl = __dirname + "/../model/",
models = fs.readdirSync(modelUrl),
routeUrl = __dirname + "/../route/"
routes = fs.readdirSync(routeUrl);
Aqui eu carrego todos os meus modelos e rotas como arrays de arquivos.
Aviso de isenção: readdirSync
só está ok quando chamado antes de iniciar o servidor http (antes .listen
). Chamar chamadas de bloqueio síncronas na hora de início do servidor apenas torna o código mais legível (é basicamente um hack)
var io = require("socket.io").listen(app);
io.set("authorization", function(data, accept) {
if (data.headers.cookie) {
data.cookie = parseCookie(data.headers.cookie);
data.sessionId = data.cookie['express.sid'];
sessionStore.get(data.sessionId, function(err, session) {
if (err) {
return accept(err.message, false);
} else if (!(session && session.auth)) {
return accept("not authorized", false)
}
data.session = session;
accept(null, true);
});
} else {
return accept('No cookie', false);
}
});
Aqui eu aperto o socket.io para realmente usar a autorização, em vez de deixar qualquer tom e jack falar com o meu servidor socket.io
routes.forEach(function(file) {
var route = require(routeUrl + file),
model = require(modelUrl + file);
route(app, model, io);
});
};
Aqui, começo minhas rotas passando o modelo relevante para cada objeto de rota retornado do arquivo de rota.
Basicamente, o objetivo é você organizar tudo em pequenos módulos legais e então ter algum mecanismo de bootstrapping.
Meu outro projeto (meu blog) tem um arquivo init com uma estrutura semelhante .
Aviso: o blog está quebrado e não constrói, estou trabalhando nisso.
Para uma organização de roteamento sustentável, você pode verificar este artigo sobre o módulo de nó express-routescan e testá-lo. Esta é a melhor solução para mim.
Eu tenho meus aplicativos construídos em cima da ferramenta Express-generator. Você pode instalá-lo executando npm install express-generator -g
e executando-o usando express <APP_NAME>
.
Para lhe dar uma perspectiva, uma das estruturas menores do meu aplicativo era assim:
~/
|~bin
| |-www
|
|~config
| |-config.json
|
|~database
| |-database.js
|
|~middlewares
| |-authentication.js
| |-logger.js
|
|~models
| |-Bank.js
| |-User.js
|
|~routes
| |-index.js
| |-banks.js
| |-users.js
|
|~utilities
| |-fiat-converersion.js
|
|-app.js
|-package.json
|-package-lock.json
Uma coisa legal que gosto nessa estrutura que acabo adotando para qualquer aplicação expressa que desenvolvo é a forma como as rotas são organizadas. Não gostei de ter que exigir cada arquivo de rota no app.js e app.use()
cada rota, especialmente à medida que o arquivo fica maior. Como tal, achei útil agrupar e centralizar todos os meus app.use()
em um arquivo ./routes/index.js.
No final, meu app.js será parecido com isto:
...
const express = require('express');
const app = express();
...
require('./routes/index')(app);
e meu ./routes/index.js será parecido com isto:
module.exports = (app) => {
app.use('/users', require('./users'));
app.use('/banks', require('./banks'));
};
Consigo simplesmente require(./users)
porque escrevi a rota dos usuários usando express.Router () que me permite "agrupar" várias rotas e depois exportá-las de uma vez, com o objetivo de tornar a aplicação mais modular.
Este é um exemplo do que você faria na minha rota ./routers/users.js:
const router = require('express').Router();
router.post('/signup', async (req, res) => {
// Signup code here
});
module.exports = router;
Esperançosamente, isso ajudou a responder sua pergunta! Boa sorte!