Як структурувати програму express.js?


102

Чи існує загальна умова розбиття та модуляції app.jsфайлу в додатку Express.js ? Або звичайно зберігати все в одному файлі?


3
Там люди розбивали їх на маршрути. Також ви можете поглянути на експрес-ресурси.
BRampersad

@Brandon_R Ви спробували ресурси? Я поглянув на це і подумав, що це виглядає акуратно, просто ще не поцупив шини.
Шанс

1
Трохи пізно, але я нещодавно відкрив джерело маршрутизатора для експресу, який дозволяє розбити app.js чудово введення контролерів + перегляди тощо. Див.: Github.com/kishorenc/road
jeffreyveon

Відповіді:


82

У мене розбив так:

~/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

Я використовую Експорт для повернення релевантного. Наприклад, у моделях, які я роблю:

module.exports = mongoose.model('PhoneNumber', PhoneNumberSchema);

і тоді, якщо мені потрібно створити номер телефону, це так просто, як:

var PhoneNumber = require('../models/phoneNumber');
var phoneNumber = new PhoneNumber();

якщо мені потрібно використовувати схему, то PhoneNumber.schema

(що передбачає, що ми працюємо з папки маршрутів і нам потрібно перейти на 1 рівень вгору, а потім вниз до моделей)


РЕДАКТ 4

Експрес вики містить список структур , побудованих на ньому.

З них я вважаю, що матадор Twitter дуже добре структурований. Ми фактично використовували дуже подібний підхід до того, як вони завантажують частини програми.

derby.js також виглядає надзвичайно цікаво. Метеор схожийбез будь-якого шуму і насправді дає кредит там, де належить кредит (зокрема, вузол та експрес).


EDIT 3

Якщо ви шанувальник CoffeeScript (я не є) і reeeeaaaaaally бажаєте L&F Rails, також є Tower.js .


EDIT 2

Якщо ви знайомі з рейками і не заперечуєте проти кровотеч деяких понять, є Локомотив . Це легкий каркас, побудований на Express. Він має дуже схожу структуру, як RoR і містить деякі більш рудиментарні поняття (наприклад, маршрутизація).

Варто перевірити, навіть якщо ви не плануєте ним користуватися.


РЕДАКТ 1

nodejs-express-мангуста-демон дуже схожа на те, як я структурував шахту. Перевір.


2
Куди йде логіка бізнесу? Чи використовуєте ви коли-небудь помічників для таких речей, як аутентифікація?
Ерік Червоний

@ErictheRed, якщо ви знайомі з MVC Pattern (рейки, Asp.Net mvc тощо), то я вважаю, що "Мої маршрути" є моїми контролерами, і все подібне стає на місце після цього. Бізнес-логіка йде в моделях (хоча у мене виникають труднощі з валідацією та мангустом). Для помічників я використовую Експорт у простій внутрішній бібліотеці утиліт, яку я збираю для себе для речей, які я повторно використовую.
Шанс

Класно було б завантажити зразок налаштування в github, щоб ми подивилися. Що йде в папку / файли Routes?
chovy

1
@chovy Я додав посилання на github.com/qed42/nodejs-express-mongoose-demo, що має дуже схожу структуру
Шанс

Я рекомендую уникати будь-яких роздутих каркасів, побудованих на вершині експресу
Райнос

9

Увага: посилаючись на код, який я зламав разом для вибивання вузла, він начебто працює, але далеко не елегантний або відшліфований.

Щоб бути більш конкретним щодо розбиття, у app.jsмене є такий файл app.js

var express = require('express'),
    bootstrap = require('./init/bootstrap.js'),
    app = module.exports = express.createServer();

bootstrap(app);

Це в основному означає, що я розміщую всі свої завантажувальні програми в окремий файл, а потім завантажую сервер.

Отже, що робить завантажувальна машина ?

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");
};

Добре це розбиває всі налаштування ініціалізації сервера в хороші шматки. Конкретно

  • У мене є шматок, який налаштовує всі мої віддалені аутентифікації OAuth, використовуючи Everyauth.
  • У мене є шматок, який налаштовує мою програму (в основному викликає app.configure)
  • У мене є трохи коду, який пробиває менше, тому він перекомпілює будь-який з моїх менших місць у css під час виконання.
  • У мене є код, який встановлює всі мої маршрути
  • Я називаю цей маленький модуль nko
  • Нарешті я запускаю сервер, слухаючи порт.

Для прикладу розглянемо файл маршрутизації

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);

Тут я завантажую всі свої моделі та маршрути як масиви файлів.

Відмова від відповідальності: readdirSync це нормально лише тоді, коли викликається перед запуском http-сервера (раніше .listen). Виклик синхронного блокування дзвінків у час запуску сервера просто робить код більш читабельним (це в основному хак)

    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);
        }
    });

Тут я пробиваю socket.io, щоб фактично використовувати авторизацію, а не дозволяти кому-небудь tom і jack розмовляти зі своїм сервером socket.io

    routes.forEach(function(file) {
        var route = require(routeUrl + file),
            model = require(modelUrl + file);

        route(app, model, io);
    });
};

Тут я починаю свої маршрути, передаючи відповідну модель у кожен об’єкт маршруту, повернутий з файлу маршруту.

В основному суть полягає в тому, що ви впорядковуєте все в маленькі приємні модулі, а потім маєте якийсь механізм завантаження.

Мій інший проект (мій блог) має файл init із подібною структурою .

Відмова: блог зламаний і не будується, я над ним працюю.



0

У мене є додатки, створені на основі інструмента експрес-генератора. Ви можете встановити його, запустивши npm install express-generator -gта запустивши його express <APP_NAME>.

Щоб дати вам перспективу, одна з менших структур мого додатка виглядала так:

~/
|~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

Один класний предмет, який мені подобається в цій структурі, я закінчую прийняттям для будь-якої експрес-програми, яку я розробляю, - це спосіб організації маршрутів. Мені не сподобалося вимагати кожного файлу маршруту в app.js і app.use()кожного маршруту, тим більше, що файл стає більшим. Як таке, мені здалося корисним згрупувати та централізувати все своєapp.use() у файлі ./routes/index.js.

Зрештою, мій app.js буде виглядати приблизно так:

...
const express = require('express');
const app = express();

...
require('./routes/index')(app);

і мій ./routes/index.js буде виглядати приблизно так:

module.exports = (app) => {
  app.use('/users', require('./users'));
  app.use('/banks', require('./banks'));
};

Я вмію просто require(./users)тому, що я написав маршрут користувачів за допомогою express.Router (), який дозволяє мені "групувати" кілька маршрутів і потім експортувати їх відразу, з метою зробити додаток більш модульним.

Це приклад того, що ви могли б штрафувати на моєму маршруті ./routers/users.js:


const router = require('express').Router();

router.post('/signup', async (req, res) => {
    // Signup code here
});

module.exports = router;

Сподіваємось, це допомогло відповісти на ваше запитання! Удачі!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.