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());
});
};
Config / routes.js
module.exports = function(app) {
app.get('/', function(req, res) {
res.send('Hello world !');
});
};
Мой код работает хорошо, и я думаю, что структура каталогов прекрасна. Тем не менее, код должен быть адаптирован, и я не уверен, что это хорошо / красиво.
Лучше использовать мою структуру каталогов и адаптировать код или просто использовать один файл (app.js)?
Спасибо за ваши советы!
18 ответов
Хорошо, это было давно, и это популярный вопрос, поэтому я решил создать репозиторий github для скаффолдинга с кодом JavaScript и длинным README о том, как мне нравится структурировать приложение express.js среднего размера.
https://github.com/focusaurus/express_code_structure - это репозиторий с последним кодом для этого. Потяните запросы приветствуются.
Вот снимок README, так как stackru не любит ответы типа "просто ссылка". Я сделаю некоторые обновления, так как это новый проект, который я буду продолжать обновлять, но в конечном итоге репозиторий github станет актуальным местом для получения этой информации.
Экспресс структура кода
Этот проект является примером того, как организовать веб-приложение express.js среднего размера.
Текущий хотя бы экспресс v4.14 декабрь 2016
Насколько велико ваше приложение?
Веб-приложения не все одинаковы, и, на мой взгляд, не существует единой структуры кода, которая должна применяться ко всем приложениям express.js.
Если ваше приложение маленькое, вам не нужна такая глубокая структура каталогов, как показано здесь. Просто будь проще и придерживайся горстки.js
файлы в корне вашего хранилища, и все готово. Вуаля.
Если ваше приложение огромно, в какой-то момент вам нужно разбить его на отдельные пакеты npm. В целом подход node.js, по-видимому, предпочтителен для множества небольших пакетов, по крайней мере, для библиотек, и вы должны собрать свое приложение, используя несколько пакетов npm, так как это начинает иметь смысл и оправдывает накладные расходы. Так как ваше приложение растет, и некоторая часть кода становится многократно используемой за пределами вашего приложения или становится чистой подсистемой, переместите его в собственный репозиторий git и превратите в отдельный пакет npm.
Таким образом, цель этого проекта - проиллюстрировать работоспособную структуру для приложения среднего размера.
Какова ваша общая архитектура
Существует много подходов к созданию веб-приложения, таких как
- Серверная сторона MVC а-ля Ruby on Rails
- Стиль одностраничного приложения в стиле MongoDB/Express/Angular/Node (MEAN)
- Основной веб-сайт с некоторыми формами
- Модели / Операции / Виды / Стиль событий а-ля MVC мертв, пора MOVE на
- и многие другие, как современные, так и исторические.
Каждый из них хорошо вписывается в другую структуру каталогов. Для целей этого примера это просто строительные леса, а не полностью работающее приложение, но я предполагаю следующие ключевые моменты архитектуры:
- На сайте есть несколько традиционных статических страниц / шаблонов.
- "Приложение" часть сайта разрабатывается как стиль одностраничного приложения
- Приложение предоставляет браузеру API в стиле REST/JSON.
- Приложение моделирует простой бизнес-домен, в данном случае это приложение для автосалона.
А как насчет Ruby on Rails?
На протяжении всего проекта будет темой, что многие идеи, воплощенные в Ruby on Rails, и принятые ими решения "Convention over Configuration", хотя они широко приняты и используются, на самом деле не очень полезны, а иногда являются противоположностью тому, что в этом хранилище. рекомендую.
Здесь я хочу сказать, что существуют основополагающие принципы организации кода, и, основываясь на этих принципах, соглашения Ruby on Rails имеют смысл (в основном) для сообщества Ruby on Rails. Тем не менее, просто бездумно придерживаясь этих соглашений, теряет смысл. Как только вы освоите основные принципы, ВСЕ ваши проекты будут хорошо организованы и понятны: сценарии оболочки, игры, мобильные приложения, корпоративные проекты, даже ваш домашний каталог.
Сообщество Rails хочет иметь возможность иметь одного разработчика Rails, переключающегося с одного приложения на другое, и быть знакомым с ним каждый раз. Это имеет большой смысл, если у вас 37 сигналов или Pivotal Labs, и имеет свои преимущества. В мире JavaScript на стороне сервера общий идеал просто гораздо более дикий запад, и у нас на самом деле нет проблем с этим. Вот так мы катимся. Мы к этому привыкли. Даже в express.js это близкий родственник Синатры, а не Rails, и получение соглашений от Rails обычно ничего не помогает. Я бы даже сказалПринципы над Конвенцией над Конфигурацией.
Основные принципы и мотивы
- Быть умственно управляемым
- Мозг может иметь дело только с небольшим количеством связанных вещей и думать о них одновременно. Вот почему мы используем каталоги. Это помогает нам справляться со сложностью, сосредотачиваясь на небольших порциях.
- Быть подходящим по размеру
- Не создавайте "Каталоги Mansion", где есть только 1 файл, один на три каталога вниз. Вы можете увидеть это в Ansible Best Practices, которая заставляет небольшие проекты создавать более 10 каталогов для хранения более 10 файлов, когда 1 каталог с 3 файлами будет гораздо более подходящим. Вы не едете на работу на автобусе (если вы не водитель автобуса, но даже если вы ездите на автобусе, AT не работает), поэтому не создавайте структуры файловой системы, которые не оправданы фактическими файлами внутри них.,
- Будь модульным, но прагматичным
- В целом сообщество узлов предпочитает небольшие модули. Все, что может быть чисто отделено от вашего приложения целиком, должно быть извлечено в модуль для внутреннего использования или опубликовано на npm. Тем не менее, для приложений среднего размера, которые здесь входят в объем, накладные расходы могут добавить утомление вашему рабочему процессу без соответствующей стоимости. Так что на тот момент, когда у вас есть некоторый код, который выровнен, но недостаточен для оправдания совершенно отдельного модуля npm, просто считайте его "прото-модулем", ожидая, что, когда он пересечет некоторый порог размера, он будет извлечен.
- Некоторые люди, такие как @hij1nx, даже включают
app/node_modules
каталог и естьpackage.json
файлы в каталогах протомодуля, чтобы облегчить этот переход и служить напоминанием.
- Быть легко найти код
- Нашей целью является сборка или исправление ошибки, наша цель состоит в том, чтобы у разработчика не было проблем с поиском исходных файлов.
- Имена значимы и точны
- Неправильный код полностью удален, не оставлен в бесхозном файле или просто закомментирован
- Быть дружественным к поиску
- весь исходный код первого лица находится в
app
каталог, чтобы вы моглиcd
запускайте find/grep/xargs/ag/ack/etc и не отвлекайтесь на сторонние совпадения
- весь исходный код первого лица находится в
- Используйте простые и понятные названия
- Теперь для npm требуются имена в нижнем регистре. Я нахожу это главным образом ужасным, но я должен следовать за стадом, таким образом, имена файлов должны использовать
kebab-case
хотя имя переменной для этого в JavaScript должно бытьcamelCase
так как-
это минус в JavaScript. - имя переменной совпадает с базовым именем пути модуля, но с
kebab-case
преобразован вcamelCase
- Теперь для npm требуются имена в нижнем регистре. Я нахожу это главным образом ужасным, но я должен следовать за стадом, таким образом, имена файлов должны использовать
- Группировка по соединению, а не по функции
- Это серьезный отход от конвенции Ruby on Rails
app/views
,app/controllers
,app/models
, так далее - Функции добавляются в полный стек, поэтому я хочу сосредоточиться на полном стеке файлов, которые имеют отношение к моей функции. Когда я добавляю поле телефонного номера в модель пользователя, мне не важен какой-либо контроллер, кроме пользовательского контроллера, и меня не волнует какая-либо модель, кроме пользовательской модели.
- Таким образом, вместо редактирования 6 файлов, каждый из которых находится в своем собственном каталоге, и игнорирования множества других файлов в этих каталогах, этот репозиторий организован так, что все файлы, которые мне нужны для создания функции, размещаются в одном месте.
- По своей природе MVC, пользовательский вид связан с пользовательским контроллером, который связан с пользовательской моделью. Поэтому, когда я изменяю модель пользователя, эти 3 файла часто меняются вместе, но контроллер сделок или контроллер клиента разъединяются и, следовательно, не участвуют. То же самое относится и к проектам не-MVC, как правило.
- Разъединение в стиле MVC или MOVE с точки зрения того, какой код идет, какой модуль все еще поощряется, но распространение файлов MVC в одноуровневые каталоги просто раздражает.
- Таким образом, каждый из моих файлов маршрутов имеет часть маршрутов, которыми он владеет. В стиле рельсов
routes.rb
Файл полезен, если вы хотите получить обзор всех маршрутов в приложении, но при создании объектов и исправлении ошибок вам важны только маршруты, относящиеся к изменяемой части.
- Это серьезный отход от конвенции Ruby on Rails
- Хранить тесты рядом с кодом
- Это всего лишь пример "группировка по связям", но я хотел конкретно это назвать. Я написал много проектов, в которых тесты живут в параллельной файловой системе, называемой "тестами", и теперь, когда я начал размещать свои тесты в том же каталоге, что и соответствующий им код, я больше никогда не вернусь. Это более модульное решение, с которым гораздо проще работать в текстовых редакторах, и оно избавляет от большого количества бессмысленного пути "../../..". Если вы сомневаетесь, попробуйте несколько проектов и решите сами. Я не собираюсь делать ничего, кроме этого, чтобы убедить вас, что это лучше.
- Уменьшите сквозную связь с событиями
- Легко подумать: "Хорошо, всякий раз, когда создается новая сделка, я хочу отправить электронное письмо всем продавцам", а затем просто введите код для отправки этих электронных писем по маршруту, который создает сделки.
- Однако эта связь в конечном итоге превратит ваше приложение в гигантский шарик грязи.
- Вместо этого DealModel должен просто вызвать событие "create" и не знать, что еще может сделать система в ответ на это.
- Когда вы кодируете таким образом, становится намного более возможным поместить весь пользовательский код в
app/users
потому что нет повсюду гнезда связанной бизнес-логики, загрязняющей чистоту базы кода пользователя.
- Поток кода отслеживается
- Не делай волшебных вещей. Не загружайте файлы из магических каталогов в файловой системе. Не будь Rails. Приложение начинается с
app/server.js:1
и вы можете увидеть все, что он загружает и выполняет, следуя коду. - Не делайте DSL для ваших маршрутов. Не делайте глупого метапрограммирования, когда это не требуется.
- Если ваше приложение настолько велико, что делает
magicRESTRouter.route(somecontroller, {except: 'POST'})
это большая победа для вас более 3 основныхapp.get
,app.put
,app.del
звонки, вы, вероятно, создаете монолитное приложение, которое слишком велико для эффективной работы. Получите фантазию для БОЛЬШИХ выигрышей, а не для преобразования 3 простых линий в 1 сложную линию.
- Не делай волшебных вещей. Не загружайте файлы из магических каталогов в файловой системе. Не будь Rails. Приложение начинается с
Используйте имена файлов в нижнем регистре
- Этот формат позволяет избежать проблем чувствительности к регистру файловой системы на разных платформах.
- npm запрещает использование заглавных букв в новых именах пакетов, и это хорошо работает
особенности express.js
Не использовать
app.configure
, Это почти полностью бесполезно, и вам просто не нужно это. Это во многих шаблонах из-за бессмысленного копирования.- ПОРЯДОК СРЕДНЕГО ОБОРУДОВАНИЯ И МАРШРУТОВ ПО ЭКСПРЕССАМ!!!
- Почти каждая проблема маршрутизации, которую я вижу в stackru, является неупорядоченным экспресс-промежуточным ПО
- В общем, вы хотите, чтобы ваши маршруты были разделены и не полагались на порядок
- Не использовать
app.use
для всего вашего приложения, если вам действительно нужно это промежуточное ПО только для 2 маршрутов (я смотрю на вас,body-parser
) - Убедитесь, что, когда все сказано и сделано, у вас точно такой заказ:
- Любое очень важное промежуточное программное обеспечение для всего приложения
- Все ваши маршруты и различные промежуточные программы маршрутов
- ТО обработчики ошибок
- К сожалению, будучи вдохновленным синатрой, express.js в основном предполагает, что все ваши маршруты будут
server.js
и будет понятно, как они заказаны. Для приложений среднего размера разделение элементов на отдельные модули маршрутов - это хорошо, но оно представляет опасность неработающего промежуточного программного обеспечения.
Трюк с символической ссылкой на приложение
Существует множество подходов, подробно изложенных и обсужденных сообществом в большой сути. Лучшие локальные пути require() для Node.js. Вскоре я могу предпочесть либо "просто иметь дело с большим количеством../../../..", либо использовать модуль requireFrom. Однако в данный момент я использую трюк с символьными ссылками, подробно описанный ниже.
Таким образом, один из способов избежать внутрипроектного требует раздражающих относительных путей, таких как require("../../../config")
это использовать следующий трюк:
- создайте символическую ссылку под node_modules для вашего приложения
- cd node_modules && ln -nsf ../app
- добавьте в git только символическую ссылку node_modules/app, а не всю папку node_modules
- git add -f node_modules/app
- Да, вы все еще должны иметь "node_modules" в вашем
.gitignore
файл - Нет, вы не должны помещать "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, вход в stdout, очередь и т. Д.), Необходимо выбрать такую опцию, как {deliver: 'stdout'}
но это не должно абсолютно проверять NODE_ENV
,
тесты
Теперь я храню свои тестовые файлы в том же каталоге, что и соответствующий им код, и использую соглашения об именах расширений файлов, чтобы отличать тесты от производственного кода.
foo.js
имеет код модуля "foo"foo.tape.js
имеет основанные на узлах тесты для foo и живет в том же каталогеfoo.btape.js
может использоваться для тестов, которые необходимо выполнить в среде браузера
Я использую глобусы файловой системы и find . -name '*.tape.js'
Команда, чтобы получить доступ ко всем моим тестам по мере необходимости.
Как организовать код внутри каждого .js
файл модуля
Область действия этого проекта в основном о том, куда идут файлы и каталоги, и я не хочу добавлять много других областей, но я просто упомяну, что я организовал свой код в 3 отдельных раздела.
- Для открытия блока CommonJS требуются вызовы зависимостей состояний
- Основной блок кода из чистого JavaScript. Никакого загрязнения CommonJS здесь. Не ссылаться на экспорт, модуль или требовать.
- Закрытие блока CommonJS для настройки экспорта
ОБНОВЛЕНИЕ (2013-10-29): Пожалуйста, ознакомьтесь с моим другим ответом, в котором есть популярный спрос на JavaScript вместо CoffeeScript, а также репозиторий github и подробный README с подробным изложением моих последних рекомендаций по этой теме.
конфиг
То, что вы делаете, прекрасно. Мне нравится настраивать свое собственное пространство имен конфигурации на верхнем уровне 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}"
Это удобно для редактирования системного администратора. Затем, когда мне нужно что-то, как информация о подключении к БД, это
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.
Ниже приводится дословный ответ Питера Лайонса, перенесенный на vanilla JS из Coffeescript, по просьбе нескольких других. Ответ Питера очень удачный, и любой, кто голосует за мой ответ, должен голосовать и за него.
конфиг
То, что вы делаете, прекрасно. Мне нравится настраивать свое собственное пространство имен конфигурации на верхнем уровне 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}"
};
Это удобно для редактирования системного администратора. Затем, когда мне нужно что-то, как информация о подключении к БД, это
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.
Мой вопрос был введен в апреле 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);
};
Каждый модуль маршрута является автономным.
Мне нравится использовать глобальное "приложение", а не экспортировать функцию и т. Д.
Я думаю, что это отличный способ сделать это. Не ограничивается выражением, но я видел довольно много проектов node.js на github, делающих одно и то же. Они извлекают параметры конфигурации + меньшие модули (в некоторых случаях каждый URI) располагаются в отдельных файлах.
Я бы порекомендовал пройтись по специальным проектам на github, чтобы получить представление. ИМО, как вы делаете это правильно.
Сейчас конец 2015 года, и после того, как я разработал свою структуру в течение 3 лет, а также в малых и крупных проектах. Заключение?
Не делайте один большой MVC, но разделяйте его на модули
Так...
Зачем?
Обычно один работает над одним модулем (например, "Продуктами"), который вы можете изменить самостоятельно.
Вы можете повторно использовать модули
Вы можете проверить это отдельно
Вы можете заменить его отдельно
У них есть четкие (стабильные) интерфейсы
-Последнее, если работало несколько разработчиков, разделение модулей помогает
Проект http://nodebootstrap.io/ похож на мою окончательную структуру. ( Github)
Как выглядит эта структура?
Маленькие капсулированные модули, каждый с отдельным MVC
У каждого модуля есть package.json
Тестирование как часть структуры (в каждом модуле)
Глобальная конфигурация, библиотеки и сервисы
Интегрированный докер, кластер, навсегда
Folderoverview (см. Папку lib для модулей):
Я даю структуру папок в стиле 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-generator
Просто простые шаги для создания и использования этих модулей.
я) установить модуль npm install express-mvc-generator -g
II) проверить параметры express -h
iii) Создать экспресс-структуру MVC express myapp
iv) Установить зависимости: npm install
:
v) Откройте ваш config / database.js, пожалуйста, настройте вашу базу данных mongo.
vi) Запустите приложение node app
или же nodemon app
vii) Проверьте URL-адрес http://localhost:8042/signup или http://yourip:8042/signup
Я не думаю, что это хороший подход для добавления маршрутов в конфигурации. Лучшая структура может быть примерно такой:
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 будут содержать все ваши маршруты, и вся логика будет внутри.
Прошло много времени с момента последнего ответа на этот вопрос, и Express также недавно выпустила версию 4, в которой добавлено несколько полезных вещей для организации структуры вашего приложения.
Ниже приведен длинный актуальный пост в блоге о лучших методах структурирования вашего приложения Express. http://www.terlici.com/2014/08/25/best-practices-express-structure.html
Существует также репозиторий GitHub, в котором применяются рекомендации из этой статьи. Он всегда в курсе последних версий Express.
https://github.com/terlici/base-express
Ну, я поместил мои маршруты в файл json, который я прочитал в начале, и в цикле for в app.js установил маршруты. В файле route.json указывается, какой вид следует вызвать, и ключ для значений, которые будут отправлены в маршрут.
Это работает для многих простых случаев, но мне пришлось вручную создавать некоторые маршруты для особых случаев.
Я написал пост именно по этому вопросу. Это в основном использует routeRegistrar
который перебирает файлы в папке /controllers
вызывая свою функцию init
, функция init
принимает экспресс 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);
http://locomotivejs.org/ предоставляет способ структурировать приложение, созданное с помощью Node.js и Express.
С веб-сайта:
"Locomotive - это веб-фреймворк для Node.js. Locomotive поддерживает шаблоны MVC, маршруты RESTful и соглашения о конфигурации, в то же время беспрепятственно интегрируясь с любой базой данных и механизмом шаблонов. Locomotive опирается на Express, сохраняя мощь и простоту, которую вы ожидаете с узла ".
Это может представлять интерес:
https://github.com/flatiron/nconf
Иерархическая конфигурация node.js с файлами, переменными среды, аргументами командной строки и объединением атомарных объектов.
Структура Sails.js мне кажется красивой и чистой, поэтому я использую структуру стиля MVC для своих экспресс-проектов, аналогичную sails.js.
project_root
|
|_ _ app
|_ _ |_ _ controllers
|_ _ |_ _ |_ _ UserController.js
|_ _ |_ _ middlewares
|_ _ |_ _ |_ _ error.js
|_ _ |_ _ |_ _ logger.js
|_ _ |_ _ models
|_ _ |_ _ |_ _ User.js
|_ _ |_ _ services
|_ _ |_ _ |_ _ DatabaseService.js
|
|_ _ config
|_ _ |_ _ constants.js
|_ _ |_ _ index.js
|_ _ |_ _ routes.js
|
|_ _ public
|_ _ |_ _ css
|_ _ |_ _ images
|_ _ |_ _ js
|
|_ _ views
|_ _ |_ _ user
|_ _ |_ _ |_ _ index.ejs
Папка приложения - содержит общий логин для приложения.
Папка config - содержит конфигурации приложения, константы, маршруты.
Общая папка - содержит стили, изображения, скрипты и т. Д.
Папка просмотров - содержит виды для каждой модели (если есть)
Проект Boilerplate можно найти здесь,
https://github.com/abdulmoiz251/node-express-rest-api-boilerplate
Я сталкивался с этой структурой MVC http://www.travisglines.com/web-coding/a-simple-mvc-setup-in-node-js
Я недавно принял модули как независимые мини-приложения.
|-- 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 и assets находятся рядом друг с другом. подмодульная маршрутизация настроена в родительском #.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'));
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/
...
- Лучший для тестирования
- Лучший по масштабу
- Отдельно зависит от модуля
- Группировка маршрута по функциональности (или модулям)
tjholowaychuk говорит / показывает на Vimeo интересную идею о том, как модульное экспресс-приложение - модульные веб-приложения с Node.js и Express. Мощный и простой.
Так выглядит большая часть структуры моего экспресс-проекта.
Я обычно делаю express dirname
чтобы инициализировать проект, простите мою лень, но он очень гибкий и расширяемый. PS - нужно получить express-generator
для этого (для тех, кто ищет это sudo npm install -g express-generator
Судо, потому что вы устанавливаете его во всем мире)
|-- 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
модуль в моих проектах (много в последнее время) и он работает! Поп в эти 2 заявления в 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
иерархия конечно.
Моя структура экспресс 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
Простой способ структурировать приложение ur express:
В main index.js должен поддерживаться следующий порядок.
все app.set должно быть первым.
все app.use должно быть вторым.
а затем другие apis с их функциями или route-continue в других файлах
Exapmle
app.use ("/ пароль", passwordApi);
app.use ("/ user", userApi);
app.post ("/ token", passport.createToken);
app.post ("/ logout", passport.logout)
Лучший способ создания структуры MVC для проекта ExpressJs с помощью руля и Passportjs
- app
-config
-passport-setup.js
-controllers
-middleware
-models
-routes
-service
-bin
-www
-configuration.js
-passport.js
-node_modules
-views
-handlebars page
-env
-.gitignore
-package.json
-package-lock.json