Czy istnieje wspólna konwencja podziału i modularyzacji app.js
pliku w aplikacji Express.js ? A może często trzyma się wszystko w jednym pliku?
Czy istnieje wspólna konwencja podziału i modularyzacji app.js
pliku w aplikacji Express.js ? A może często trzyma się wszystko w jednym pliku?
Odpowiedzi:
Mój rozpadł się w następujący sposób:
~/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
Korzystam z eksportu, aby zwrócić to, co jest istotne. Na przykład w modelach, które wykonuję:
module.exports = mongoose.model('PhoneNumber', PhoneNumberSchema);
a jeśli muszę utworzyć numer telefonu, jest to tak proste, jak:
var PhoneNumber = require('../models/phoneNumber');
var phoneNumber = new PhoneNumber();
jeśli muszę użyć schematu, to PhoneNumber.schema
(co zakłada, że pracujemy z folderu tras i musimy przejść 1 poziom w górę, a następnie w dół do modeli)
Express wiki ma listę struktur zbudowanych na wierzchu.
Spośród nich myślę, że matador na Twitterze ma całkiem dobrą strukturę. W rzeczywistości zastosowaliśmy bardzo podobne podejście do sposobu ładowania części aplikacji.
derby.js również wygląda niezwykle interesująco. Jest to podobne do meteor bez całego szumu i faktycznie przypisuje kredyt tam, gdzie należy się kredyt (zwłaszcza węzeł i ekspres).
Jeśli jesteś fanem CoffeeScript (ja nie jestem) i naprawdę chcesz L&F Railsów, jest też Tower.js .
Jeśli jesteś zaznajomiony z Railsami i nie przeszkadza ci wykrwawianie niektórych koncepcji, to jest Lokomotywa . Jest to lekki framework oparty na Express. Ma bardzo podobną strukturę jak RoR i przenosi niektóre z bardziej podstawowych pojęć (takich jak routing).
Warto to sprawdzić, nawet jeśli nie planujesz z niego korzystać.
nodejs-express-mongoose-demo jest bardzo podobne do mojej struktury. Sprawdź to.
Ostrzeżenie: odnośnik do kodu, który zhakowałem razem w celu usunięcia węzłów, trochę działa, ale nie jest elegancki ani dopracowany.
Aby być bardziej szczegółowym na temat podziału, app.js
mam następujący plik app.js
var express = require('express'),
bootstrap = require('./init/bootstrap.js'),
app = module.exports = express.createServer();
bootstrap(app);
Zasadniczo oznacza to, że umieszczam cały proces ładowania początkowego w osobnym pliku, a następnie uruchamiam serwer.
Więc co robi bootstrap ?
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");
};
Cóż, dzieli całą konfigurację inicjalizacji serwera na ładne fragmenty. konkretnie
app.configure
)Spójrzmy na przykład na plik routingu
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);
Tutaj ładuję wszystkie moje modele i trasy jako tablice plików.
Zastrzeżenie: readdirSync
jest ok tylko wtedy, gdy zostanie wywołane przed uruchomieniem serwera http (wcześniej .listen
). Wywołanie synchronicznych wywołań blokujących w czasie uruchamiania serwera sprawia, że kod jest bardziej czytelny (jest to w zasadzie 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);
}
});
Tutaj uderzam socket.io, aby faktycznie używał autoryzacji, a nie pozwalając jakiemukolwiek tomowi i jackowi rozmawiać z moim serwerem socket.io
routes.forEach(function(file) {
var route = require(routeUrl + file),
model = require(modelUrl + file);
route(app, model, io);
});
};
Tutaj rozpoczynam moje trasy od przekazania odpowiedniego modelu do każdego obiektu trasy zwróconego z pliku trasy.
Zasadniczo chodzi o to, że organizujesz wszystko w ładne małe moduły, a następnie masz pewien mechanizm ładowania początkowego.
Mój inny projekt (mój blog) ma plik init o podobnej strukturze .
Zastrzeżenie: blog jest zepsuty i nie tworzy się, pracuję nad tym.
Dla zarządzalny organizacji routingu można sprawdzić ten artykuł o tej wyraźnej-routescan modułu węzła i spróbować. To dla mnie najlepsze rozwiązanie.
Moje aplikacje są tworzone w oparciu o narzędzie ekspresowego generatora. Możesz go zainstalować, uruchamiając npm install express-generator -g
i uruchamiając za pomocą express <APP_NAME>
.
Aby dać ci perspektywę, jedna ze struktur mojej mniejszej aplikacji wyglądała następująco:
~/
|~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
Jedną fajną rzeczą, którą lubię w tej strukturze, którą ostatecznie dostosowuję do każdej rozwijanej przeze mnie aplikacji ekspresowej, jest sposób organizacji tras. Nie podobało mi się, że muszę wymagać plików tras w pliku app.js i app.use()
każdej trasy, zwłaszcza gdy plik się powiększa. W związku z tym uznałem za pomocne zgrupowanie i scentralizowanie wszystkich moich app.use()
plików w pliku ./routes/index.js.
Ostatecznie mój plik app.js będzie wyglądał mniej więcej tak:
...
const express = require('express');
const app = express();
...
require('./routes/index')(app);
a mój ./routes/index.js będzie wyglądał mniej więcej tak:
module.exports = (app) => {
app.use('/users', require('./users'));
app.use('/banks', require('./banks'));
};
Jestem w stanie to zrobić po prostu require(./users)
dlatego, że napisałem trasy użytkowników przy użyciu express.Router (), który pozwala mi „grupować” wiele tras, a następnie eksportować je jednocześnie, w celu uczynienia aplikacji bardziej modułową.
To jest przykład tego, co możesz dobrze na mojej trasie ./routers/users.js:
const router = require('express').Router();
router.post('/signup', async (req, res) => {
// Signup code here
});
module.exports = router;
Mamy nadzieję, że pomogło to odpowiedzieć na Twoje pytanie! Powodzenia!