ExpressJS Как структурировать приложение?

Я использую веб-среду ExpressJS для NodeJS.

Люди, использующие ExpressJS, размещают свои среды (разработка, производство, тестирование...), их маршруты и т.д. на app.js. Я думаю, что это не красиво, потому что, когда у вас большое приложение, app.js слишком большой!

Я хотел бы иметь эту структуру каталогов:

| my-application
| -- app.js
| -- config/
     | -- environment.js
     | -- routes.js

Здесь мой код:

app.js

var express = require('express');
var app = module.exports = express.createServer();

require('./config/environment.js')(app, express);
require('./config/routes.js')(app);

app.listen(3000);

конфигурации /environment.js

module.exports = function(app, express){
    app.configure(function() {
    app.use(express.logger());
    });

    app.configure('development', function() {
    app.use(express.errorHandler({
        dumpExceptions: true,
        showStack: true
    }));
    });

    app.configure('production', function() {
    app.use(express.errorHandler());
    });
};

конфигурации /routes.js

module.exports = function(app) {
    app.get('/', function(req, res) {
    res.send('Hello world !');
    });
};

Мой код работает хорошо, и я думаю, что структура каталогов прекрасна. Однако код должен был быть адаптирован, и я не уверен, что он хороший/красивый.

Лучше ли использовать мою структуру каталогов и адаптировать код или просто использовать один файл (app.js)?

Спасибо за ваши советы!

Ответ 1

ОК, это было время, и это популярный вопрос, поэтому я пошел дальше и создал репозиторий github для лесов с кодом JavaScript и длинный README о том, как мне нравится структурировать приложение express.js среднего размера.

focusaurus/express_code_structure - это репо с последним кодом для этого. Приглашаем вас приветствовать.

Вот моментальный снимок README, поскольку stackoverflow не любит ответы только одной ссылки. Я сделаю некоторые обновления, так как это новый проект, который я буду продолжать обновлять, но в конечном итоге репозиторий github станет самым современным местом для этой информации.


Структура экспресс-кода

Этот проект является примером организации веб-приложения express.js среднего размера.

Текущее, по крайней мере, выражение v4.14 Декабрь 2016

Build Status

js-standard-style

Насколько велика ваша заявка?

Веб-приложения не все одинаковы, и, на мой взгляд, не существует единой структуры кода, которая должна применяться ко всем приложениям express.js.

Если ваше приложение мало, вам не нужна такая глубокая структура каталогов, как показано здесь. Просто держите его простым и вставьте несколько файлов .js в корень вашего репозитория, и все готово. Вуаля.

Если ваше приложение огромно, в какой-то момент вам нужно разбить его на отдельные пакеты npm. В целом подход node.js, похоже, относится ко многим небольшим пакетам, по крайней мере для библиотек, и вы должны создать свое приложение, используя несколько пакетов npm, поскольку это начинает иметь смысл и оправдывать накладные расходы. Так как ваше приложение растет, и некоторая часть кода становится явно повторно используемой за пределами вашего приложения или является ясной подсистемой, переместите ее в свой собственный репозиторий git и превратите его в автономный пакет npm.

Итак, фокус этого проекта состоит в том, чтобы проиллюстрировать работоспособную структуру для приложения среднего размера.

Какова ваша общая архитектура

Существует множество подходов к созданию веб-приложения, например

  • Серверная сторона MVC a la Ruby on Rails
  • Типовой стиль приложения a la MongoDB/Express/ Angular/Node (MEAN)
  • Основной веб-сайт с некоторыми формами
  • Модели/Операции/Представления/Стиль событий a la MVC мертв, время MOVE на
  • и многие другие как текущие, так и исторические

Каждый из них прекрасно вписывается в другую структуру каталогов. Для целей этого примера это просто строительные леса, а не полностью работающее приложение, но я предполагаю следующие ключевые точки архитектуры:

  • На сайте есть некоторые традиционные статические страницы/шаблоны
  • Часть "приложения" сайта разработана как стиль приложения с одной страницей.
  • Приложение предоставляет API стиля REST/JSON для браузера
  • Приложение моделирует простой бизнес-домен, в этом случае это приложение для автомобилей.

А как насчет Ruby on Rails?

Во всем этом проекте будет тема, согласно которой многие идеи, воплощенные в Ruby on Rails, и принятые ими решения "Конвенция по конфигурации", хотя и широко принятые и используемые, на самом деле не очень полезны, а иногда и противоположны что рекомендует этот репозиторий.

Мой главный смысл в том, что основополагающие принципы организации кода и основанные на этих принципах, соглашения Ruby on Rails имеют смысл (в основном) для сообщества Ruby on Rails. Тем не менее, просто бездумно перекликается с этими конвенциями. После того, как вы оцените основные принципы, ВСЕ ваши проекты будут хорошо организованы и понятны: оболочки, игры, мобильные приложения, корпоративные проекты, даже ваш домашний каталог.

Для сообщества Rails они хотят иметь один переключатель разработчика Rails из приложения в приложение в приложение и быть знакомым и комфортным с ним каждый раз. Это имеет большое значение, если вы 37 сигналов или Pivotal Labs, и имеет преимущества. В мире JavaScript на стороне сервера общий облик - это просто более дикий запад, и у нас действительно нет проблем с этим. Это как мы катимся. Мы привыкли к этому. Даже в express.js, это близкие родственники Sinatra, а не Rails, и принятие соглашений от Rails обычно ничего не помогает. Я бы даже сказал Принципы над Конформацией по конфигурации.

Основополагающие принципы и мотивы

  • Быть умственно управляемым
    • Мозг может заниматься только и думать о небольшом количестве связанных вещей сразу. Вот почему мы используем каталоги. Это помогает нам справляться со сложностью, сосредоточившись на небольших порциях.
  • Соответствие размера
    • Не создавайте "Mansion Directories", где только 1 файл отключает все 3 каталога. Вы можете увидеть это в Ansible Best Practices, который замалчивает небольшие проекты на создание 10 + каталогов для хранения 10+ файлов, когда 1 каталог с 3 файлами будет гораздо более уместным. Вы не управляете шиной, чтобы работать (если вы не водитель шины, но даже тогда ваша вождение автобуса AT работает, а не работа), поэтому не создавайте структуры файловой системы, которые не оправданы фактическими файлами внутри них.
  • Быть модульным, но прагматичным
    • Сообщество node в целом поддерживает небольшие модули. Все, что может быть полностью отделено от вашего приложения, должно быть извлечено в модуль либо для внутреннего использования, либо публично опубликован на npm. Однако для приложений среднего размера, которые являются областью действия здесь, накладные расходы на это могут добавить скуку в рабочий процесс без соразмерного значения. Таким образом, в течение времени, когда у вас есть какой-то код, который укомплектован, но недостаточно, чтобы оправдать полностью отдельный модуль npm, просто подумайте, что это " прото-модуль" с ожиданием того, что когда он пересечет некоторый порог размера, он будет извлечен.
    • Некоторые люди, такие как @hij1nx, даже включают каталог app/node_modules и имеют package.json файлы в прото-модуле /strong > , чтобы облегчить этот переход и действовать как напоминание.
  • Легко найти код
    • Учитывая возможность создания или исправление ошибки, наша цель состоит в том, что разработчик не имеет борьбы с поиском исходных файлов.
    • Имена являются значимыми и точными.
    • crfty code полностью удален, не оставлен в сиротском файле или просто прокомментирован
  • Будьте в поиске
    • весь исходный исходный код находится в каталоге app, поэтому вы можете cd запускать find/grep/xargs/ag/ack/etc и не отвлекаться на сторонние соответствия
  • Использовать простые и понятные имена
    • npm теперь, кажется, требует имена всех нижестоящих пакетов. Я считаю это главным образом ужасным, но я должен следовать за стадом, поэтому имена файлов должны использовать kebab-case, хотя имя переменной для JavaScript в JavaScript должно быть camelCase, потому что - является знаком минус в JavaScript.
    • имя переменной совпадает с базовым именем пути к модулю, но с kebab-case преобразуется в camelCase
  • Группировать по муфте, а не по функциям
    • Это существенный отход от соглашения Ruby on Rails app/views, app/controllers, app/models и т.д.
    • Функции добавляются в полный стек, поэтому я хочу сосредоточиться на полном стеке файлов, имеющих отношение к моей функции. Когда я добавляю поле номера телефона в пользовательскую модель, меня не интересует какой-либо контроллер, отличный от пользовательского контроллера, и мне не нужна никакая модель, кроме модели пользователя.
    • Таким образом, вместо того, чтобы редактировать 6 файлов, каждый из которых находится в своем собственном каталоге и игнорирует множество других файлов в этих каталогах, этот репозиторий организован таким образом, что все файлы, которые мне нужны для создания функции, размещаются
    • По характеру MVC пользовательский вид связан с пользовательским контроллером, который связан с пользовательской моделью. Поэтому, когда я меняю модель пользователя, эти 3 файла часто меняются вместе, но контроллер сделок или контроллер клиента развязаны и, следовательно, не задействованы. То же самое относится и к проектам, отличным от MVC.
    • Развязка стиля MVC или MOVE, с точки зрения которой идет код, в котором модуль по-прежнему поощряется, но распространение файлов MVC в родные каталоги просто раздражает.
    • Таким образом, каждый из моих файлов маршрутов имеет часть принадлежащих ему маршрутов. Файл routes.rb в стиле рельсов удобен, если вы хотите просмотреть все маршруты в приложении, но когда вы на самом деле создаете функции и исправляете ошибки, вы заботитесь только о маршрутах, относящихся к той части, которую вы меняете.
  • Хранить тесты рядом с кодом
    • Это всего лишь экземпляр "группы по связям", но я хотел назвать это специально. Я написал много проектов, где тесты живут под параллельной файловой системой под названием "тесты", и теперь, когда я начал сдавать свои тесты в том же каталоге, что и их соответствующий код, я никогда не вернусь. Это более модульное и гораздо более удобное в работе с текстовыми редакторами и облегчает много ошибок "../../..". Если вы сомневаетесь, попробуйте его в нескольких проектах и ​​решите сами. Я не собираюсь ничего делать за этим, чтобы убедить вас, что это лучше.
  • Уменьшить поперечное соединение с помощью событий
    • Легко думать "ОК, всякий раз, когда создается новый Сдел, я хочу отправить электронное письмо всем Продавцам", а затем просто поместите код для отправки этих писем на маршруте, который создает сделки.
    • Однако эта связь в конечном итоге превратит ваше приложение в гигантский шар грязи.
    • Вместо этого DealModel должен просто запустить событие "создать" и полностью не знать, что еще может сделать система в ответ на это.
    • Когда вы кодируете этот способ, становится гораздо более возможным поместить весь код, связанный с пользователем, в app/users, потому что там нет крысиного гнезда связанной бизнес-логики по всему месту, загрязняющего чистоту базы кода пользователя.
  • Поток кода следующий
    • Не делай волшебных вещей. Не производите автозагрузку файлов из магических каталогов в файловой системе. Не будьте Rails. Приложение начинается с app/server.js:1, и вы можете видеть все, что он загружает и выполняет, следуя коду.
    • Не делайте DSL для своих маршрутов. Не делайте глупое метапрограммирование, если оно не требуется.
    • Если ваше приложение настолько велико, что выполнение magicRESTRouter.route(somecontroller, {except: 'POST'}) является большой победой для вас по трем основным app.get, app.put, app.del, вызовам, вы, вероятно, строите монолитное приложение, которое слишком велико для эффективно работа сверху. Получите фантазию для БОЛЬШИХ выигрышей, а не для преобразования трех простых строк в одну сложную линию.
  • Использовать имена файлов нижнего кебаба

    • Этот формат позволяет избежать проблем с чувствительностью к файловой системе на разных платформах.
    • npm запрещает прописные буквы в именах новых пакетов, и это хорошо работает с этим

      особенности express.js

  • Не используйте app.configure. Это почти совершенно бесполезно, и вам это просто не нужно. Это во множестве шаблонов из-за бессмысленной copypasta.

  • ПОРЯДОК СРЕДНЕГО ОБРАЗОВАНИЯ И МАРШРУТЫ В ЭКСПРЕССНЫХ ВОПРОСАХ!!!
    • Почти каждая проблема маршрутизации, которую я вижу в stackoverflow, представляет собой промежуточное ПО вне очереди.
    • В общем, вы хотите, чтобы ваши маршруты были развязаны и не полагались на порядок.
    • Не используйте app.use для всего приложения, если вам действительно нужно только это промежуточное ПО для 2 маршрутов (я смотрю на вас, body-parser)
    • Убедитесь, что, когда все сказано и сделано, вы ТОЧНО этот заказ:
      • Любое супер-важное промежуточное ПО на уровне приложений.
      • Все ваши маршруты и сортированные маршруты.
      • THEN обработчики ошибок
  • К сожалению, будучи вдохновленным синатрой, express.js в основном предполагает, что все ваши маршруты будут в server.js, и будет ясно, как они упорядочены. Для приложений среднего размера, разбирая все на отдельные модули маршрутов, приятно, но это создает опасность для промежуточного программного обеспечения вне очереди.

Трюк с символикой приложения

Существует много подходов, которые подробно обсуждаются сообществом в большой gist Улучшенные локальные требования require() для node.js, Я скоро могу предпочесть либо "просто иметь дело с большим количеством.. /../../..", либо использовать requireFrom modlue. Однако на данный момент я использую трюк symlink, подробно описанный ниже.

Таким образом, один из способов избежать внутрипроекта требует раздражающих относительных путей, таких как require("../../../config"), использовать следующий трюк:

  • создать символическую ссылку в разделе node_modules для вашего приложения.
    • cd node_modules && & ln -nsf../app
  • добавьте только символическую ссылку node_modules/app, а не всю папку node_modules, на git
    • git add -f node_modules/app
    • Да, в файле .gitignore у вас должно быть "node_modules",
    • Нет, вы не должны помещать "node_modules" в ваш репозиторий git. Некоторые люди порекомендуют вам сделать это. Они неправильны.
  • Теперь вы можете потребовать внутрипроектные модули, используя этот префикс
    • var config = require("app/config");
    • var DealModel = require("app/deals/deal-model");
  • В принципе, это требует, чтобы внутрипроект работал очень аналогично требованиям для внешних модулей npm.
  • Извините, пользователи Windows, вам нужно придерживаться относительных путей родительского каталога.

Конфигурация

Обычно модули кода и классы ожидают, что передается только базовый объект JavaScript options. Только app/server.js должен загрузить модуль app/config.js. Оттуда он может синтезировать небольшие объекты options для настройки подсистем при необходимости, но связывать каждую подсистему с большим глобальным конфигурационным модулем, полным дополнительной информации, является плохая связь.

Попробуйте централизовать создание соединений БД и передать их в подсистемы, а не передавать параметры соединения, а подсистемы сами делают исходящие соединения.

NODE_ENV

Это еще одна заманчивая, но ужасная идея, перенесенная из Rails. В вашем приложении должно быть ровно 1 место, app/config.js, который смотрит на переменную среды NODE_ENV. Все остальное должно принимать явную опцию в качестве аргумента конструктора класса или параметра конфигурации модуля.

Если модуль электронной почты имеет возможность доставки сообщений электронной почты (SMTP, log to stdout, put in queue и т.д.), он должен иметь такую ​​возможность, как {deliver: 'stdout'}, но он не должен абсолютно не проверять NODE_ENV.

Испытания

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

  • foo.js имеет код "foo" модуля
  • foo.tape.js имеет теги node для foo и живет в одном каталоге
  • foo.btape.js может использоваться для тестов, которые необходимо выполнить в среде браузера.

Я использую файловые глобусы и команду find . -name '*.tape.js', чтобы получить доступ ко всем моим тестам по мере необходимости.

Как организовать код в каждом файле модуля .js

Эта область проекта в основном касается того, куда идут файлы и каталоги, и я не хочу добавлять много другой области, но я просто упомянул, что я упорядочиваю свой код на 3 различных раздела.

  • В открывшемся блоке CommonJS требуются вызовы в зависимости от состояний
  • Основной блок кода для чистого JavaScript. Здесь нет загрязнения CommonJS. Не ссылайтесь на экспорт, модуль или требуйте.
  • Закрывающий блок CommonJS для настройки экспорта

Ответ 2

ОБНОВЛЕНИЕ (2013-10-29). Также см. мой другой ответ, в котором JavaScript, а не CoffeeScript, пользуется большим спросом, а также шаблоном github repo и обширным README с подробными моими последними рекомендациями на эту тему.

Config

То, что вы делаете, прекрасно. Мне нравится иметь собственное пространство имен config, настроенное в файле верхнего уровня config.coffee с вложенным пространством имен, подобным этому.

#Set the current environment to true in the env object
currentEnv = process.env.NODE_ENV or 'development'
exports.appName = "MyApp"
exports.env =
  production: false
  staging: false
  test: false
  development: false
exports.env[currentEnv] = true
exports.log =
  path: __dirname + "/var/log/app_#{currentEnv}.log"
exports.server =
  port: 9600
  #In staging and production, listen loopback. nginx listens on the network.
  ip: '127.0.0.1'
if currentEnv not in ['production', 'staging']
  exports.enableTests = true
  #Listen on all IPs in dev/test (for testing from other machines)
  exports.server.ip = '0.0.0.0'
exports.db =
  URL: "mongodb://localhost:27017/#{exports.appName.toLowerCase()}_#{currentEnv}"

Это удобно для редактирования sysadmin. Тогда, когда мне нужно что-то, например, информация о соединении с DB, это `

require('./config').db.URL

<сильные > Маршруты/Контроллеры

Мне нравится оставлять свои маршруты с моими контроллерами и организовывать их в подкаталоге app/controllers. Затем я могу загрузить их и позволить им добавлять любые маршруты, в которых они нуждаются.

В моем файле app/server.coffee coffeescript я:

[
  'api'
  'authorization'
  'authentication'
  'domains'
  'users'
  'stylesheets'
  'javascripts'
  'tests'
  'sales'
].map (controllerName) ->
  controller = require './controllers/' + controllerName
  controller.setup app

Итак, у меня есть файлы вроде:

app/controllers/api.coffee
app/controllers/authorization.coffee
app/controllers/authentication.coffee
app/controllers/domains.coffee

И, например, в моем контроллере доменов, у меня есть функция setup, подобная этой.

exports.setup = (app) ->
  controller = new exports.DomainController
  route = '/domains'
  app.post route, controller.create
  app.put route, api.needId
  app.delete route, api.needId
  route = '/domains/:id'
  app.put route, controller.loadDomain, controller.update
  app.del route, controller.loadDomain, exports.delete
  app.get route, controller.loadDomain, (req, res) ->
    res.sendJSON req.domain, status.OK

Просмотры

Помещение просмотров в app/views становится обычным местом. Я излагаю это следующим образом.

app/views/layout.jade
app/views/about.jade
app/views/user/EditUser.jade
app/views/domain/EditDomain.jade

Статические файлы

Перейдите в подкаталог public.

Github/Semver/НМП

Поместите файл уценки README.md в свой корневой каталог git для github.

Поместите файл package.json с семантической версией в ваш git репозиционный корень для NPM.

Ответ 3

Ниже приводится ответ Петра Лайона на дословно, перенесенный на ванильный JS из Coffeescript, по просьбе нескольких других. Ответ Питера очень умен, и любой, кто голосовал по моему ответу, тоже проголосовал за него.


Config

То, что вы делаете, прекрасно. Мне нравится иметь собственное пространство имен config, настроенное в файле верхнего уровня config.js с вложенным пространством имен, подобным этому.

// Set the current environment to true in the env object
var currentEnv = process.env.NODE_ENV || 'development';
exports.appName = "MyApp";
exports.env = {
  production: false,
  staging: false,
  test: false,
  development: false
};  
exports.env[currentEnv] = true;
exports.log = {
  path: __dirname + "/var/log/app_#{currentEnv}.log"
};  
exports.server = {
  port: 9600,
  // In staging and production, listen loopback. nginx listens on the network.
  ip: '127.0.0.1'
};  
if (currentEnv != 'production' && currentEnv != 'staging') {
  exports.enableTests = true;
  // Listen on all IPs in dev/test (for testing from other machines)
  exports.server.ip = '0.0.0.0';
};
exports.db {
  URL: "mongodb://localhost:27017/#{exports.appName.toLowerCase()}_#{currentEnv}"
};

Это удобно для редактирования sysadmin. Тогда, когда мне нужно что-то, например, информация о соединении с DB, это `

require('./config').db.URL

<сильные > Маршруты/Контроллеры

Мне нравится оставлять свои маршруты с моими контроллерами и организовывать их в подкаталоге app/controllers. Затем я могу загрузить их и позволить им добавлять любые маршруты, в которых они нуждаются.

В моем app/server.js файле javascript я:

[
  'api',
  'authorization',
  'authentication',
  'domains',
  'users',
  'stylesheets',
  'javascripts',
  'tests',
  'sales'
].map(function(controllerName){
  var controller = require('./controllers/' + controllerName);
  controller.setup(app);
});

Итак, у меня есть файлы вроде:

app/controllers/api.js
app/controllers/authorization.js
app/controllers/authentication.js
app/controllers/domains.js

И, например, в моем контроллере доменов, у меня есть функция setup, подобная этой.

exports.setup = function(app) {
  var controller = new exports.DomainController();
  var route = '/domains';
  app.post(route, controller.create);
  app.put(route, api.needId);
  app.delete(route, api.needId);
  route = '/domains/:id';
  app.put(route, controller.loadDomain, controller.update);
  app.del(route, controller.loadDomain, function(req, res){
    res.sendJSON(req.domain, status.OK);
  });
}

Просмотры

Помещение просмотров в app/views становится обычным местом. Я излагаю это следующим образом.

app/views/layout.jade
app/views/about.jade
app/views/user/EditUser.jade
app/views/domain/EditDomain.jade

Статические файлы

Перейдите в подкаталог public.

Github/Semver/НМП

Поместите файл уценки README.md в свой корневой каталог git для github.

Поместите файл package.json с семантической версией в вашем корневом репо git для NPM.

Ответ 4

Мой вопрос был введен в апреле 2011 года, он тихий старый. В течение этого времени я мог бы улучшить свой опыт работы с Express.js и как архитектуру приложения, написанного с использованием этой библиотеки. Итак, я расскажу о своем опыте.

Здесь моя структура каталогов:

├── app.js   // main entry
├── config   // The configuration of my applications (logger, global config, ...)
├── models   // The model data (e.g. Mongoose model)
├── public   // The public directory (client-side code)
├── routes   // The route definitions and implementations
├── services // The standalone services (Database service, Email service, ...)
└── views    // The view rendered by the server to the client (e.g. Jade, EJS, ...)

App.js

Цель файла app.js - загрузить приложение expressjs. Он загружает модуль конфигурации, модуль журнала, ждет подключения к базе данных,... и запускает экспресс-сервер.

'use strict';
require('./config');
var database = require('./services/database');
var express = require('express');
var app = express();
module.exports = app;

function main() {
  var http = require('http');

  // Configure the application.
  app.configure(function () {
    // ... ... ...
  });
  app.configure('production', function () {
    // ... ... ...
  });
  app.configure('development', function () {
    // ... ... ...
  });

  var server = http.createServer(app);

  // Load all routes.
  require('./routes')(app);

  // Listen on http port.
  server.listen(3000);
}

database.connect(function (err) {
  if (err) { 
    // ...
  }
  main();
});

маршруты /

В каталоге маршрутов есть файл index.js. Его цель - ввести волшебство для загрузки всех других файлов внутри каталога routes/. Здесь реализация:

/**
 * This module loads dynamically all routes modules located in the routes/
 * directory.
 */
'use strict';
var fs = require('fs');
var path = require('path');

module.exports = function (app) {
  fs.readdirSync('./routes').forEach(function (file) {
    // Avoid to read this current file.
    if (file === path.basename(__filename)) { return; }

    // Load the route file.
    require('./' + file)(app);
  });
};

С помощью этого модуля создание нового определения маршрута и его реализация очень просты. Например, hello.js:

function hello(req, res) {
  res.send('Hello world');
}

module.exports = function (app) {
  app.get('/api/hello_world', hello);
};

Каждый модуль маршрута автономный.

Ответ 5

Мне нравится использовать глобальное "приложение", а не экспортировать функцию и т.д.

Ответ 6

Я думаю, что это отличный способ сделать это. Не ограничиваясь выражением, но я видел довольно много проектов node.js на github, делающих то же самое. Они извлекают параметры конфигурации + меньшие модули (в некоторых случаях каждый URI) учитываются в отдельных файлах.

Я бы порекомендовал проработать конкретные проекты на github, чтобы получить представление. ИМО так, как вы делаете, правильно.

Ответ 7

теперь конец 2015 года и после разработки моей структуры в течение 3 лет и в небольших и крупных проектах. Вывод?

Не делайте одного большого MVC, но разделяйте его в модулях

Итак...

Почему?

  • Обычно один работает на одном модуле (например, Products), который вы можете изменить самостоятельно.

  • Вы можете повторно использовать модули

  • Вы можете проверить его отдельно

  • Вы можете заменить его отдельно

  • У них четкие (стабильные) интерфейсы

    - В последнее время, если работало несколько разработчиков, разделение модулей помогает

Проект nodebootstrap имеет аналогичный подход к моей окончательной структуре. (github)

Как выглядит эта структура?

  • Маленькие, капсулированные модули, каждый с отдельным MVC

  • Каждый модуль имеет package.json

  • Тестирование как части структуры (в каждом модуле)

  • Глобальная конфигурация, библиотеки и службы

  • Интегрированный докер, кластер, навсегда

Folderoverview (см. папку lib для модулей):

nodebootstrap structure

Ответ 8

Я не думаю, что это хороший подход для добавления маршрутов в конфигурацию. Лучшая структура может быть примерно такой:

application/
| - app.js
| - config.js
| - public/ (assets - js, css, images)
| - views/ (all your views files)
| - libraries/ (you can also call it modules/ or routes/)
    | - users.js
    | - products.js
    | - etc...

Таким образом, products.js и users.js будут содержать все ваши маршруты, все логики внутри.

Ответ 9

Прошло совсем немного времени с момента последнего ответа на этот вопрос, и Express также недавно выпустил версию 4, в которой добавлено несколько полезных вещей для организации структуры вашего приложения.

Ниже приведено последнее сообщение в блоге о лучших методах структурирования вашего приложения Express. http://www.terlici.com/2014/08/25/best-practices-express-structure.html

Существует также репозиторий GitHub, применяющий рекомендации в статье. Это всегда актуально с последней версией Express.
https://github.com/terlici/base-express

Ответ 10

Ну, я поместил свои маршруты как json файл, который я прочитал в начале, и в for-loop в app.js настроил маршруты. Route.json включает в себя представление, которое должно быть вызвано, и ключ для значений, которые будут отправлены на маршрут.
Это работает для многих простых случаев, но мне пришлось вручную создавать маршруты для особых случаев.

Ответ 11

Я написал сообщение именно по этому вопросу. В основном он использует routeRegistrar, который выполняет итерацию через файлы в папке /controllers, вызывая ее функцию init. Функция init принимает переменную express app в качестве параметра, поэтому вы можете зарегистрировать свои маршруты так, как вы хотите.

var fs = require("fs");
var express = require("express");
var app = express();

var controllersFolderPath = __dirname + "/controllers/";
fs.readdirSync(controllersFolderPath).forEach(function(controllerName){
    if(controllerName.indexOf("Controller.js") !== -1){
        var controller = require(controllersFolderPath + controllerName);
        controller.init(app);
    }
});

app.listen(3000);

Ответ 12

Это может представлять интерес:

https://github.com/flatiron/nconf

Иерархическая конфигурация node.js с файлами, переменными среды, аргументами командной строки и слиянием атомных объектов.

Ответ 13

Я предоставляю структуру папок в стиле MVC, чтобы найти ниже.

Мы использовали следующую структуру папок для наших больших и средних веб-приложений.

 myapp   
|
|
|____app
|      |____controllers
|      |    |____home.js
|      |
|      |____models
|      |     |___home.js
|      |
|      |____views
|           |___404.ejs
|           |___error.ejs
|           |___index.ejs
|           |___login.ejs
|           |___signup.ejs
|   
|
|_____config
|     |___auth.js
|     |___constants.js
|     |___database.js
|     |___passport.js
|     |___routes.js
|
|
|____lib
|    |___email.js
|
|____node_modules
|
|
|____public.js
|    |____css
|    |    |__style.css
|    |    
|    |____js
|    |    |__script.js
|    |
|    |____img
|    |    |__img.jpg
|    |
|    |
|    |____uploads
|         |__img.jpg
|      
|   
|
|_____app.js
|
|
|
|_____package.json

Я создал один модуль npm для генерации выражений mvc.

См. Ниже https://www.npmjs.com/package/express-mvc[CN00длягенератора

Просто простые шаги для создания и использования этих модулей.

i) установить модуль npm install express-mvc-generator -g

ii) опции проверки express -h

iii) Генерировать выраженную mvc-структуру express myapp

iv) Установите зависимости: npm install:

v) Откройте ваш config/database.js, пожалуйста, настройте свой mongo db.

vi) Запустите приложение node app или nodemon app

vii) Проверьте URL-адрес http://localhost: 8042/signup ИЛИ http://yourip: 8042/signup

Ответ 15

1) Файловая система проекта Express может выглядеть так:

/ ...
/lib
/node_modules
/public
/views
      app.js
      config.json
      package.json

app.js - глобальный контейнер приложений

2) Основной файл модуля (lib/mymodule/index.js):

var express = require('express');    
var app = module.exports = express();
// and load module dependencies ...  

// this place to set module settings
app.set('view engine', 'jade');
app.set('views', __dirname + '/views');

// then do module staff    
app.get('/mymodule/route/',function(req,res){ res.send('module works!') });

3) Подключить модуль в главном app.js

...
var mymodule = require('mymodule');
app.use(mymodule);

4) Пример логики

lib/login
lib/db
lib/config
lib/users
lib/verify
lib/
   /api/ 
   ...
lib/
   /admin/
      /users/
      /settings/
      /groups/
...
  • Лучшее для тестирования
  • Лучшее для масштаба
  • Отдельно зависит от модуля
  • Группировка маршрута по функциональности (или модулям)

tj говорит/показывает на Vimeo интересную идею о том, как модульное экспресс-приложение - Модульные веб-приложения с Node.js и Express. Мощный и простой.

Ответ 16

http://locomotivejs.org/ предоставляет способ структурирования приложения, построенного с помощью Node.js и Express.

С веб-сайта:

"Локомотив - это веб-фреймворк для Node.js. Локомотив поддерживает MVC шаблоны, маршруты RESTful и соглашение по конфигурации, в то время как легко интегрируясь с любой базой данных и движком шаблонов. Локомотив строится на Экспрессе, сохраняя силу и простоту вы ожидаете от Node."

Ответ 17

Недавно я принял модули как независимые мини-приложения.

|-- src
  |--module1
  |--module2
     |--www
       |--img
       |--js
       |--css
     |--#.js
     |--index.ejs
  |--module3
  |--www
     |--bower_components
     |--img
     |--js
     |--css
  |--#.js
  |--header.ejs
  |--index.ejs
  |--footer.ejs

Теперь для любой маршрутизации модуля (#.js) представления (*.ejs), js, css и активы находятся рядом друг с другом. маршрутизация подмодулей устанавливается в родительском #.js с двумя дополнительными строками

router.use('/module2', opt_middleware_check, require('./module2/#'));
router.use(express.static(path.join(__dirname, 'www')));

Таким образом возможны даже подподмодули.

Не забудьте установить представление в каталог src

app.set('views', path.join(__dirname, 'src'));

Ответ 18

Вот как выглядит большая часть моей структуры каталога проекта.

Я обычно делаю express dirname, чтобы инициализировать проект, простить мою лень, но он очень гибкий и расширяемый. PS - вам нужно получить express-generator для этого (для тех, кто ищет его sudo npm install -g express-generator, sudo, потому что вы его устанавливаете по всему миру)

|-- bin
    |-- www //what we start with "forever"
|-- bower_components
|-- models
    |-- database.js
    |-- model1.js //not this exact name ofcourse.
    |-- .
|-- node_modules
|-- public
    |-- images
    |-- javascripts
        |-- controllers
        |-- directives
        |-- services
        |-- app.js
        |-- init.js //contains config and used for initializing everything, I work with angular a lot.
    |-- stylesheets
|-- routes
    |-- some
    |-- hierarchy
    .
    .
|-- views
    |-- partials
    |-- content
|-- .env
|-- .env.template
|-- app.js
|-- README.md

Вам должно быть интересно, почему .env файлы? Потому что они работают! Я использую модуль dotenv в своих проектах (много недавно), и он работает! Поп в этих двух операторах в app.js или www

var dotenv = require('dotenv');
dotenv.config({path: path.join(__dirname + "/.env")});

И еще одна строка, чтобы быстро установить /bower_components для обслуживания статического содержимого в ресурсе /ext

app.use('/ext', express.static(path.join(__dirname, 'bower_components')));

Вероятно, он может быть подходящим для людей, которые хотят использовать Express и Angular вместе или просто выразить без этой javascripts иерархии, конечно.

Ответ 19

Моя структура выражает 4. https://github.com/odirleiborgert/borgert-express-boilerplate

пакеты

View engine: twig
Security: helmet
Flash: express-flash
Session: express-session
Encrypt: bcryptjs
Modules: express-load
Database: MongoDB
    ORM: Mongoose
    Mongoose Paginate
    Mongoose Validator
Logs: winston + winston-daily-rotate-file
Nodemon
CSS: stylus
Eslint + Husky

Состав

|-- app
    |-- controllers
    |-- helpers
    |-- middlewares
    |-- models
    |-- routes
    |-- services
|-- bin
|-- logs
|-- node_modules
|-- public
    |-- components
    |-- images
    |-- javascripts
    |-- stylesheets
|-- views
|-- .env
|-- .env-example
|-- app.js
|-- README.md

Ответ 20

Простой способ структурирования ur express app:

  • В основном index.js должен поддерживаться следующий порядок.

    все app.set должны быть первыми.

    все app.use должны быть вторыми.

    а затем другой apis с их функциями или маршрутом - продолжить в других файлах

    Exapmle

    app.use("/password", passwordApi);

    app.use("/user", userApi);

    app.post("/token", passport.createToken);

    app.post("/logout", passport.logout)