ExpressJS jak skonstruować aplikację?
Używam frameworka internetowego ExpressJS dla NodeJS.
Ludzie korzystający z ExpressJS umieszczają swoje środowiska (rozwój, produkcja, test...), ich trasy Itp. na app.js
. Myślę, że to nie jest piękny sposób, ponieważ gdy masz dużą aplikację, aplikację.js jest za duży!
Chciałbym mieć taką strukturę katalogów:
| my-application
| -- app.js
| -- config/
| -- environment.js
| -- routes.js
Oto mój kod:
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);
Config / 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 !');
});
};
Mój kod działa dobrze i myślę, że struktura katalogów jest piękna. Jednak kod musiał zostać dostosowany i nie jestem pewien, czy jest dobry/piękny.
Czy lepiej użyć mojej struktury katalogów i dostosować kod, czy po prostu użyć jednego pliku (app.js)?
Dzięki za Rady!
18 answers
OK, minęło trochę czasu i jest to popularne pytanie, więc poszedłem do przodu i stworzył repozytorium github rusztowania z kodem JavaScript i długi README o tym, jak lubię struktury średniej wielkości express.aplikacja js.
Focusaurus / express_code_struktura jest repo z najnowszym kodem do tego. Zapraszamy do ściągania wniosków.
Oto migawka README, ponieważ stackoverflow nie lubi tylko odpowiedzi na link. Zrobię kilka aktualizacji, ponieważ jest to nowy projekt, który będę nadal aktualizować, ale ostatecznie repo github będzie up-to-date miejsce dla tych informacji.
Struktura Kodu
Ten projekt jest przykładem jak zorganizować średniej wielkości ekspres.aplikacja internetowa js.
Obecnie co najmniej express v4. 14 Grudzień 2016
Jak duża jest Twoja aplikacja?
Aplikacje internetowe nie są takie same, a nie ma, moim zdaniem, jednej struktury kodu, która powinna być stosowana do wszystkich express.aplikacje js.
Jeśli Twoja aplikacja jest mała, nie potrzebujesz tak głębokiej struktury katalogów, jak na przykładzie tutaj. Po prostu trzymaj to proste i przyklej garść .js
plików w katalogu głównym repozytorium i gotowe. Voila.
Jeśli Twoja aplikacja jest ogromna, w pewnym momencie musisz ją podzielić na odrębne pakiety npm. W ogóle węzeł.podejście js wydaje się faworyzować wiele małych Pakiety, przynajmniej dla bibliotek, i powinieneś zbudować swoją aplikację używając kilku pakietów npm, ponieważ zaczyna to mieć sens i uzasadniać narzut. Tak więc w miarę jak Twoja aplikacja rośnie i część kodu staje się wyraźnie nadająca się do wielokrotnego użytku poza Twoją aplikacją lub jest przejrzystym podsystemem, przenieś ją do własnego repozytorium git i przekształć w samodzielny pakiet npm.
Tak więc [56]} celem tego projektu jest zilustrowanie wykonalnej struktury dla średniej wielkości podanie.
Jaka jest Twoja ogólna Architektura
Istnieje wiele metod budowania aplikacji internetowych, takich jak]}- po stronie serwera MVC A la Ruby on Rails
- Single Page Application style a la MongoDB / Express/Angular / Node (MEAN)
- Podstawowa strona internetowa z niektórymi formularzami
- Models/Operations/Views/Events style a la MVC is dead, it ' s time to MOVE on
- i wiele innych zarówno obecnych jak i historyczne
Każdy z nich ładnie pasuje do innej struktury katalogów. Na potrzeby tego przykładu jest to tylko rusztowanie, a nie w pełni działająca aplikacja, ale zakładam następujące kluczowe punkty architektury:]}
- Strona ma kilka tradycyjnych statycznych stron / szablonów.]}
W 2007 roku, w ramach projektu" the world of Warcraft 2009", w ramach projektu "the world of Warcraft 2009", w ramach projektu "the world of Warcraft 2009".]}
Aplikacja wyświetla API stylu REST / JSON do przeglądarki.]}
- aplikacja modeluje prostą domenę biznesową, w tym przypadku jest to aplikacja do salonu samochodowego [86]}
A co z Ruby on Rails?
Będzie to motyw przewodni w tym projekcie, że wiele pomysłów zawartych w Ruby on Rails i decyzji "Convention over Configuration", które przyjęli, choć powszechnie akceptowane i używane, nie są w rzeczywistości zbyt pomocne i czasami są przeciwieństwem tego, co zaleca to repozytorium.
Moim głównym punktem jest to, że istnieją podstawy zasady organizowania kodu i oparte na tych zasadach konwencje Ruby on Rails mają sens (głównie) dla społeczności Ruby on Rails. Jednak po prostu bezmyślne aping te konwencje nie trafia w sedno. Po pogłębieniu podstawowych zasad, wszystkie twoje projekty będą dobrze zorganizowane i przejrzyste: skrypty powłoki, gry, aplikacje mobilne, projekty korporacyjne, a nawet katalog domowy.
Społeczność Rails chce mieć możliwość przełączania jednego programisty Rails z aplikacji na app to app i być zaznajomieni i wygodne z nim za każdym razem. Ma to wielki sens, jeśli jesteś 37 sygnały Lub kluczowe laboratoria, i ma korzyści. W świecie JavaScript po stronie serwera ogólny etos jest po prostu bardziej dziki zachód i tak naprawdę nie mamy z tym problemu. Tak się to robi. Przywykliśmy do tego. Nawet w ekspresowym.js, to bliski krewny Sinatry, a nie Rails, a branie konwenansów z Railsów zazwyczaj nic nie pomaga. Powiedziałbym nawet Zasady ponad Konwencję nad konfiguracją .
Podstawowe zasady i motywacje
- być opanowanym umysłowo
- mózg może poradzić sobie i myśleć tylko o niewielkiej liczbie powiązanych rzeczy na raz. Dlatego używamy katalogów. Pomaga nam radzić sobie ze złożonością, koncentrując się na małych porcjach.
- bądź odpowiedni dla rozmiaru
- Nie twórz "katalogów", w których jest tylko 1 plik, same 3 katalogi. Można to zobaczyć w The Ansible Best Practices that shames small projects into creating 10+ directories to hold 10+ files when 1 directory with 3 files would be much more appropriate. Nie jeździsz autobusem do pracy (chyba że jesteś kierowcą autobusu, ale nawet wtedy nie jeździsz autobusem w pracy), więc nie twórz struktur systemu plików, które nie są uzasadnione przez rzeczywiste pliki w nich zawarte.
- bądź modularny, ale pragmatyczny
- społeczność węzłów ogólnie faworyzuje małe moduły. Wszystko, co można całkowicie oddzielić od twojej aplikacji, powinno zostać wyodrębnione do modułu do użytku wewnętrznego lub opublikowane publicznie na npm. Jednak w przypadku średnich zastosowań, które są tutaj zakresem, narzut ten może dodać nudy do przepływu pracy bez proporcjonalnej wartości. Więc na czas, gdy masz jakiś kod, który jest uwzględniony, ale nie na tyle, aby uzasadnić całkowicie oddzielny moduł npm, po prostu rozważ go jako " proto-moduł" z oczekiwaniem, że gdy przekroczy jakiś próg wielkości, zostanie wyciągnięty.
- niektórzy ludzie, tacy jak @hij1nx zawierają nawet katalog
app/node_modules
i mają Plikipackage.json
w katalogachproto-module , aby ułatwić to przejście i działać jako przypomnienie.
- być łatwe do zlokalizowania kodu
- biorąc pod uwagę funkcję do zbudowania lub błąd do naprawienia, naszym celem jest, aby programista nie miał problemów z lokalizacją plików źródłowych.
- imiona mają znaczenie i dokładne Nie jest to jednak żaden problem, ponieważ nie jest on w stanie rozwiązać problemu.]}
- bądź przyjazny wyszukiwarkom
- cały kod źródłowy pierwszej strony jest w katalogu
app
, więc możeszcd
tam są uruchomione find / grep / xargs / ag / ACK / etc i nie być rozpraszanym przez dopasowania stron trzecich
- cały kod źródłowy pierwszej strony jest w katalogu
- Użyj prostego i oczywistego nazewnictwa
- npm wydaje się teraz wymagać nazw pakietów z małymi literami. Uważam, że to w większości straszne, ale muszę podążać za dlatego nazwy plików powinny używać
kebab-case
, chociaż nazwa zmiennej dla tego w JavaScript musi byćcamelCase
, ponieważ-
jest znakiem minus w JavaScript. - nazwa zmiennej pasuje do nazwy bazowej ścieżki modułu, ale z
kebab-case
przekształconą nacamelCase
- npm wydaje się teraz wymagać nazw pakietów z małymi literami. Uważam, że to w większości straszne, ale muszę podążać za dlatego nazwy plików powinny używać
- Grupa przez sprzężenie, nie przez funkcję
- jest to główne odejście od konwencji Ruby on Rails
app/views
,app/controllers
,app/models
, etc - funkcje są dodawane do pełnego stosu, więc chcę skupić się na pełnym stos plików, które są istotne dla mojej funkcji. Kiedy dodaję pole numer telefonu do modelu użytkownika, nie obchodzi mnie żaden kontroler inny niż kontroler użytkownika i nie obchodzi mnie żaden model inny niż model użytkownika.
- więc zamiast edytować 6 plików, które znajdują się we własnym katalogu i ignorować tony innych plików w tych katalogach, to repozytorium jest zorganizowane w taki sposób, że wszystkie pliki potrzebne do zbudowania funkcji są kolokowane
- z natury MVC, widok użytkownika jest połączony z kontrolerem użytkownika, który jest połączony z modelem użytkownika. Więc kiedy zmieniam model użytkownika, Te 3 pliki często zmieniają się razem, ale kontroler deals lub kontroler klienta są odsprzęgnięte, a zatem nie są zaangażowane. To samo dotyczy Zwykle projektów innych niż MVC.
- oddzielenie stylu MVC lub MOVE pod względem tego, który Kod wchodzi w który moduł jest nadal zachęcany, ale rozprzestrzenianie plików MVC do katalogów rodzeństwa jest po prostu denerwujące.
- tak więc każdy z moich routes files zawiera część tras, które posiada. Plik
routes.rb
W Stylu rails jest przydatny, jeśli chcesz mieć przegląd wszystkich tras w aplikacji, ale podczas tworzenia funkcji i naprawiania błędów dbasz tylko o trasy istotne dla zmienianego elementu.
- jest to główne odejście od konwencji Ruby on Rails
- przechowuj testy obok kodu
- to tylko przykład "grupy przez sprzężenie" , ale chciałem to konkretnie nazwać. Napisałem wiele projektów, w których testy działają pod równoległym systemem plików nazywa się "testy" i teraz, gdy zacząłem umieszczać moje testy w tym samym katalogu, co odpowiadający im kod, nigdy nie wrócę. Jest to bardziej modułowe i znacznie łatwiejsze do pracy w edytorach tekstu i łagodzi wiele"../../../ align = "left" / Jeśli masz wątpliwości, wypróbuj go na kilku projektach i sam zdecyduj. Nie zrobię nic poza tym, żeby przekonać cię, że tak jest lepiej.
- zmniejszyć sprzężenie przekrojowe ze zdarzeniami
- it ' s easy to think "OK, za każdym razem, gdy powstaje nowa umowa, chcę wysłać e-mail do wszystkich sprzedawców", a następnie po prostu umieścić kod, aby wysłać te e-maile w trasie, która tworzy umowy.
- jednak to połączenie w końcu zmieni Twoją aplikację w gigantyczną kulę błota.
- zamiast tego Model Deal powinien po prostu uruchomić Zdarzenie "create" i być całkowicie nieświadomy, co jeszcze system może zrobić w odpowiedzi na to.
- kiedy kodujesz w ten sposób, staje się o wiele bardziej możliwe, aby umieścić wszystkich użytkowników związanych kod do
app/users
, ponieważ nie ma w całym miejscu gniazda logiki biznesowej, która zanieczyszczałaby czystość bazy kodu użytkownika.
- przepływ kodu jest następujący
- Nie rób magicznych rzeczy. Nie ładuj automatycznie plików z katalogów magic w systemie plików. Nie bądź szyny. Aplikacja zaczyna się od
app/server.js:1
i możesz zobaczyć wszystko, co ładuje i wykonuje, postępując zgodnie z kodem. - nie rób DSL dla swoich tras. Nie rób głupiego metaprogramowania, gdy nie jest wezwany.
- jeśli Twoja aplikacja jest tak duża, że robienie
magicRESTRouter.route(somecontroller, {except: 'POST'})
to duża wygrana dla Ciebie ponad 3 podstawoweapp.get
,app.put
,app.del
, połączenia, prawdopodobnie budujesz monolityczną aplikację, która jest zbyt duża, aby skutecznie pracować. Ciesz się dużymi wygranymi, a nie konwersją 3 prostych linii na 1 złożoną linię.
Użyj nazw plików o małych rozmiarach
- ten format pozwala uniknąć problemów z rozróżnianiem wielkości liter na różnych platformach
- npm zabrania wielkich liter w nazwach nowych pakietów, i to działa dobrze z tym
Express.js specifics
Nie używaj app.configure
. Jest prawie całkowicie bezużyteczny i po prostu go nie potrzebujesz. Jest w wielu kotłach z powodu bezmyślnego copypasta.
- prawie każdy problem routingu, jaki widzę w stackoverflow, jest out-of-order Express middleware
- ogólnie rzecz biorąc, chcesz, aby Twoje trasy były rozdzielone i nie polegały na zamówieniu, które much
- Nie używaj
app.use
dla całej aplikacji, jeśli naprawdę potrzebujesz tylko tego middleware dla 2 tras (patrzę na Ciebie,body-parser
) - upewnij się, że kiedy wszystko zostanie powiedziane i zrobione, masz dokładnie tę kolejność:
- każda super ważna aplikacja middleware
- wszystkie trasy i różne trasy middlewares
- następnie obsługa błędów
server.js
i będzie jasne, jak są one uporządkowane. W przypadku średniej wielkości aplikacji, dzielenie rzeczy na oddzielne moduły tras jest przyjemne, ale wprowadza ryzyko out-of-order middleware [86]}
Sztuczka symboliczna aplikacji
Istnieje wiele podejść nakreślonych i omówionych przez społeczność w wielkim gist Better local require() paths for Node.js . Może wkrótce zdecyduję się wybrać albo " po prostu radzić sobie z wieloma ../../../.."lub użyć requiefrom modlue. Jednak w tej chwili używam sztuczki symbolicznej opisanej poniżej. Tak więc jednym ze sposobów na uniknięcie intra-projektu wymaganego przy irytujących ścieżkach względnych, takich jakrequire("../../../config")
, jest użycie następującej sztuczki:
- Utwórz dowiązanie symboliczne pod node_modules dla swojej aplikacji
- cd node_modules & & ln-nsf ../ app
- dodaj tylko łącze symboliczne node_modules / app , a nie cały folder node_modules, do git
- git add-f node_modules / app
- tak, nadal powinieneś mieć "node_modules" w pliku
.gitignore
- Nie, Nie powinieneś umieszczać "node_modules" w repozytorium git. Niektórzy ludzie polecą ci to zrobić. Są błędne.
- teraz możesz wymagać modułów wewnątrz projektu używając tego prefiksu
var config = require("app/config");
-
var DealModel = require("app/deals/deal-model")
;
- zasadniczo, to sprawia, że wewnątrz projektu wymaga pracy bardzo podobnie do Wymaga dla zewnętrznego npm Moduły.
- Przepraszamy, użytkownicy systemu Windows, musisz trzymać się ścieżek względnych katalogu nadrzędnego.
Konfiguracja
Ogólnie Moduły kodu i klasy oczekujące tylko podstawowego obiektu JavaScript options
przekazanego. Tylko app/server.js
powinien załadować moduł app/config.js
. Stamtąd może syntetyzować małe obiekty options
, aby skonfigurować podsystemy w razie potrzeby, ale łączenie każdego podsystemu z dużym globalnym modułem konfiguracyjnym pełnym dodatkowych informacji jest złym połączeniem.
Spróbuj centralizacja tworzenia połączeń DB i przekazywanie ich do podsystemów, w przeciwieństwie do przekazywania parametrów połączeń i samodzielnego wykonywania połączeń wychodzących przez podsystemy.
NODE_ENV
To kolejny kuszący, ale straszny pomysł przeniesiony z Rails. W Twojej aplikacji powinno znajdować się dokładnie 1 miejsceapp/config.js
, które odpowiada zmiennej środowiskowej NODE_ENV
. Wszystko inne powinno przyjmować jawną opcję jako argument konstruktora klasy lub konfiguracji modułu parametr.
Jeśli moduł e-mail ma opcję dostarczania wiadomości e-mail (SMTP, log do stdout, put in queue itp.), powinien przyjąć opcję podobną do {deliver: 'stdout'}
, ale absolutnie nie powinien sprawdzać NODE_ENV
.
Testy
Przechowuję teraz pliki testowe w tym samym katalogu co odpowiadający im kod i używam konwencji nazewnictwa rozszerzeń plików, aby odróżnić testy od kodu produkcyjnego.
-
foo.js
posiada kod modułu "foo" -
foo.tape.js
ma węzeł oparty testy na foo i mieszka w tym samym katalogu - Może być używany do testów, które muszą być wykonywane w środowisku przeglądarki.]}
Używam filesystem globs i polecenia find . -name '*.tape.js'
, aby uzyskać dostęp do wszystkich moich testów w razie potrzeby.
Jak uporządkować kod w każdym pliku .js
modułu
Zakres tego projektu polega głównie na tym, gdzie znajdują się pliki i katalogi, i nie chcę dodawać zbyt wielu innych obszarów, ale wspomnę tylko, że organizuję mój kod w 3 różne sekcje.
- otwarcie bloku CommonJS wymaga wywołania zależności stanu
- główny blok kodu pure-JavaScript. Nie ma tu częstych zanieczyszczeń. Nie odwołuj się do eksportu, modułu ani wymagań.
- Zamknięcie bloku CommonJS w celu skonfigurowania eksportu
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-15 20:01:49
UPDATE (2013-10-29) : proszę zobaczyć również moją inną odpowiedź, która ma JavaScript zamiast CoffeeScript według popularnego popytu, a także boilerplate github repo i obszerny README opisujący moje najnowsze zalecenia na ten temat.
Config
To, co robisz, jest w porządku. Lubię mieć własną przestrzeń nazw config ustawioną w pliku najwyższego poziomuconfig.coffee
z zagnieżdżoną przestrzenią nazw, taką jak ta.
#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}"
To jest przyjazne dla edycji sysadmin. Wtedy kiedy potrzebuję czegoś, na przykład informacji o połączeniu DB, to
require('./config').db.URL
Trasy / Kontrolery
Lubię zostawiać swoje trasy za pomocą kontrolerów i organizować je w podkatalogu app/controllers
. Potem mogę je załadować i pozwolić im dodać trasy, których potrzebują.
W moim app/server.coffee
pliku coffeescript robię:
[
'api'
'authorization'
'authentication'
'domains'
'users'
'stylesheets'
'javascripts'
'tests'
'sales'
].map (controllerName) ->
controller = require './controllers/' + controllerName
controller.setup app
Więc mam pliki typu:
app/controllers/api.coffee
app/controllers/authorization.coffee
app/controllers/authentication.coffee
app/controllers/domains.coffee
I np. w moim kontrolerze domen mam funkcję setup
jak to.
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
Views
Umieszczanie widoków w app/views
staje się zwyczajowym miejscem. Układam to w ten sposób.
app/views/layout.jade
app/views/about.jade
app/views/user/EditUser.jade
app/views/domain/EditDomain.jade
Pliki Statyczne
Przejdź do podkatalogu public
.
Github / Semver / npm
Put a README.md plik markdown w katalogu głównym git repo dla github.
Postaw paczkę.plik json z numerem wersji semantycznej w katalogu głównym git repo dla NPM.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-29 18:20:42
Poniżej znajduje się odpowiedź Petera Lyonsa dosłowna, przeniesiona do vanilla JS z Coffeescript, zgodnie z życzeniem kilku innych. Odpowiedź Piotra jest bardzo zdolna, a każdy głosujący nad moją odpowiedzią powinien głosować również na jego.
Config
To, co robisz, jest w porządku. Lubię mieć własną przestrzeń nazw config ustawioną w pliku najwyższego poziomuconfig.js
z zagnieżdżoną przestrzenią nazw, taką jak ta.
// 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}"
};
To jest przyjazne dla edycji sysadmin. Wtedy, gdy czegoś potrzebuję, podobnie jak DB connection info, jest to
require('./config').db.URL
Trasy / Kontrolery
Lubię zostawiać swoje trasy za pomocą kontrolerów i organizować je w podkatalogu app/controllers
. Potem mogę je załadować i pozwolić im dodać trasy, których potrzebują.
W moim app/server.js
pliku javascript robię:
[
'api',
'authorization',
'authentication',
'domains',
'users',
'stylesheets',
'javascripts',
'tests',
'sales'
].map(function(controllerName){
var controller = require('./controllers/' + controllerName);
controller.setup(app);
});
Więc mam pliki typu:
app/controllers/api.js
app/controllers/authorization.js
app/controllers/authentication.js
app/controllers/domains.js
I np. w moim kontrolerze domen mam funkcję setup
jak to.
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);
});
}
Views
Umieszczanie widoków w app/views
staje się zwyczajowym miejscem. Układam to w ten sposób.
app/views/layout.jade
app/views/about.jade
app/views/user/EditUser.jade
app/views/domain/EditDomain.jade
Pliki Statyczne
Przejdź do podkatalogu public
.
Github / Semver / npm
Put a README.md plik markdown w katalogu głównym git repo dla github.
Postaw paczkę.plik json z numerem wersji semantycznej w katalogu głównym git repo dla NPM.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-09 13:31:58
Moje pytanie zostało wprowadzone w kwietniu 2011 roku, jest spokojne stare. W tym czasie mogłem poprawić swoje doświadczenie z Express.js i jak zaprojektować aplikację napisaną przy użyciu tej biblioteki. Dzielę się więc tutaj moim doświadczeniem.
Oto moja struktura katalogów:
├── 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
Celem pliku app.js
jest uruchomienie aplikacji expressjs. Ładuje moduł konfiguracyjny, moduł rejestratora, oczekuje na połączenie z bazą danych, ..., i uruchomić ekspres serwer.
'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();
});
Trasy /
Katalog routes zawiera plik index.js
. Jego celem jest wprowadzenie pewnego rodzaju magii do ładowania wszystkich innych plików wewnątrz katalogu routes/
. Oto realizacja:
/**
* 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);
});
};
Dzięki temu modułowi tworzenie nowej definicji trasy i implementacja jest naprawdę prosta. Na przykład, hello.js
:
function hello(req, res) {
res.send('Hello world');
}
module.exports = function (app) {
app.get('/api/hello_world', hello);
};
Każdy moduł trasy jest samodzielny.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-01 09:56:32
Lubię używać globalnej "aplikacji", zamiast eksportować funkcję itp
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-08 14:36:07
Myślę, że to świetny sposób, aby to zrobić. Nie ogranicza się do express, ale widziałem sporo węzłów.projekty js na GitHubie robią to samo. Wyjmują parametry konfiguracyjne + mniejsze moduły (w niektórych przypadkach każdy URI) są uwzględniane w osobnych plikach.
Polecam przejrzeć konkretne projekty na GitHubie, aby uzyskać pomysł. IMO sposób w jaki robisz jest poprawny.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-25 12:56:17
Jest teraz koniec 2015 roku{[2] } i po rozwijaniu mojej struktury przez 3 lata oraz w małych i dużych projektach. Wniosek?
Nie rób jednego dużego MVC, ale rozdzielaj go w Moduły
Więc...
Dlaczego?
Zazwyczaj pracuje się na jednym module (np. produktach), który można zmieniać niezależnie.
-
Możesz ponownie wykorzystać Moduły
-
Możesz go przetestować oddzielnie
-
Jesteś w stanie aby zastąpić go oddzielnie
-
Mają przejrzyste (stabilne) interfejsy
- najpóźniej, jeśli pracowało wielu programistów, separacja modułów pomaga
Projekt nodebootstrap ma podobne podejście do mojej ostatecznej struktury. ( github )
Jak wygląda ta struktura?
-
Małe, otoczkowane Moduły , każdy z osobnym MVC
-
Każdy moduł ma paczka.json
-
Testowanie jako części struktury (w każdym module)
-
Konfiguracja globalna , biblioteki i usługi
-
Integrated Docker, Cluster, forever
Folderoverview (patrz folder lib dla modułów):
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-29 07:28:19
Minęło sporo czasu od ostatniej odpowiedzi na to pytanie, A Express również niedawno wydała wersję 4, która dodała kilka przydatnych rzeczy do organizowania struktury aplikacji.
Poniżej znajduje się długi, aktualny wpis na blogu o najlepszych praktykach dotyczących struktury aplikacji Express. http://www.terlici.com/2014/08/25/best-practices-express-structure.html
Istnieje również repozytorium GitHub stosujące porady zawarte w artykule. Jest zawsze na bieżąco z najnowszymi Wersja Express.
https://github.com/terlici/base-express
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-10 11:23:51
Nie sądzę, aby dodawanie tras do config było dobrym podejściem. Lepsza struktura może być coś takiego:
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...
Więc produkty.js i użytkowników.js będzie zawierać wszystkie trasy będzie wszystkie logiki wewnątrz.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-26 15:57:12
Cóż, Moje trasy umieszczam jako plik json, który czytałem na początku, i w pętli for w aplikacji.js ustawił trasy. Trasa.json zawiera widok, który ma być wywołany, oraz klucz dla wartości, które zostaną wysłane do trasy.
Działa to w wielu prostych przypadkach, ale musiałem ręcznie utworzyć kilka tras dla specjalnych przypadków.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-04 07:56:40
To może być interesujące:
Https://github.com/flatiron/nconf
Węzeł hierarchiczny.konfiguracja js z plikami, zmiennymi środowiskowymi, argumentami wiersza poleceń i scalaniem obiektów atomowych.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-06 03:21:39
Napisałem post dokładnie na ten temat. W zasadzie korzysta z routeRegistrar
, która iteracji poprzez pliki w folderze /controllers
wywołując swoją funkcję init
. Funkcja init
przyjmuje zmienną express app
jako parametr, dzięki czemu możesz rejestrować swoje trasy tak, jak chcesz.
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);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-14 12:35:18
1) Twój system plików Express project może wyglądać następująco:
/ ...
/lib
/node_modules
/public
/views
app.js
config.json
package.json
App.js-you global app container
2) Plik główny modułu (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) podłącz moduł w głównej aplikacji.js
...
var mymodule = require('mymodule');
app.use(mymodule);
4) przykładowa logika
lib/login
lib/db
lib/config
lib/users
lib/verify
lib/
/api/
...
lib/
/admin/
/users/
/settings/
/groups/
...
- najlepszy do testowania
- najlepsze dla skali
- Separate depends by module
- grupowanie trasy według funkcjonalności (lub modułów)
TJ mówi / Pokaż na Vimeo ciekawy pomysł jak modularize ekspresowa aplikacja - Modułowe aplikacje internetowe z węzłem.js i Express . Potężny i prosty.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:25
Http://locomotivejs.org / zapewnia sposób na strukturę aplikacji zbudowanej z węzła.js i Express.
Ze strony:
"Locomotive to web framework dla Node.js. Lokomotywa obsługuje MVC wzorców, tras RESTful i konwencji nad konfiguracją, podczas gdy bezproblemowa integracja z dowolnym silnikiem bazy danych i szablonów. Lokomotywa opiera się na Express, zachowując moc i prostotę oczekujesz od Node."
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-14 14:06:05
Podaję strukturę folderów w stylu MVC, proszę znaleźć poniżej .
Użyliśmy poniżej struktury folderów dla naszych dużych i średnich aplikacji internetowych .
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
Stworzyłem jeden moduł npm dla generation express mvc folder structurer.
Proszę znaleźć poniżej https://www.npmjs.com/package/express-mvc-generator
Proste kroki do wygenerowania i wykorzystania tych modułów .
I) install module npm install express-mvc-generator -g
Ii) sprawdź opcje express -h
Iii) Generowanie struktury express mvc express myapp
Iv) instalowanie zależności: npm install
:
V)otwórz konfigurację/bazę danych.js, proszę skonfigurować mongo db.
Vi) Uruchom aplikację node app
lub nodemon app
Vii) Sprawdź URL http://localhost:8042/signup lub http://yourip:8042/signup
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-05 06:45:28
Ostatnio przyjęłam Moduły jako niezależne mini-aplikacje.
|-- src
|--module1
|--module2
|--www
|--img
|--js
|--css
|--#.js
|--index.ejs
|--module3
|--www
|--bower_components
|--img
|--js
|--css
|--#.js
|--header.ejs
|--index.ejs
|--footer.ejs
Teraz dla dowolnego modułu (#.js), widoki (*.ejs), js, css i zasoby są obok siebie. routing podmodułów jest ustawiony w rodzicu #.js z dwoma dodatkowymi liniami
router.use('/module2', opt_middleware_check, require('./module2/#'));
router.use(express.static(path.join(__dirname, 'www')));
W ten sposób możliwe są nawet submodule.
Nie zapomnij ustawić widoku w katalogu src
app.set('views', path.join(__dirname, 'src'));
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-20 08:07:44
Tak wygląda większość struktury mojego projektu express.
Zazwyczaj robię express dirname
, aby zainicjować projekt, wybacz moje lenistwo, ale jest bardzo elastyczny i rozszerzalny. PS-musisz za to dostać express-generator
(dla tych którzy go szukają sudo npm install -g express-generator
, sudo bo instalujesz go globalnie)
|-- 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
Pewnie zastanawiasz się dlaczego .pliki env? Bo działają! Używam modułu dotenv
w moich projektach (ostatnio dużo) i działa! Wpisz te 2 wypowiedzi w app.js
lub www
var dotenv = require('dotenv');
dotenv.config({path: path.join(__dirname + "/.env")});
I kolejny wiersz do szybkiego ustawienia /bower_components
do serwowania statycznej zawartości pod zasobem /ext
app.use('/ext', express.static(path.join(__dirname, 'bower_components')));
Prawdopodobnie może być odpowiedni dla osób, które chcą używać Express i Angular razem, lub po prostu express bez tej hierarchii javascripts
oczywiście.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-04 19:40:03
Moja struktura express 4. https://github.com/odirleiborgert/borgert-express-boilerplate
Pakiety
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
Struktura
|-- app
|-- controllers
|-- helpers
|-- middlewares
|-- models
|-- routes
|-- services
|-- bin
|-- logs
|-- node_modules
|-- public
|-- components
|-- images
|-- javascripts
|-- stylesheets
|-- views
|-- .env
|-- .env-example
|-- app.js
|-- README.md
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-15 18:45:22