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!

Author: Ondrej Slinták, 2011-04-25

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

Stan Budowy

js-standard-style

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ą Pliki package.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żesz cd tam są uruchomione find / grep / xargs / ag / ACK / etc i nie być rozpraszanym przez dopasowania stron trzecich
  • 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ą na camelCase
  • 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.
  • 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 podstawowe app.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.

  • KOLEJNOŚĆ POŚREDNIKÓW I TRAS W SPRAWACH EKSPRESOWYCH!!!
    • 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ść:
      1. każda super ważna aplikacja middleware
      2. wszystkie trasy i różne trasy middlewares
      3. następnie obsługa błędów
  • / Align = "left" / js przeważnie zakłada, że wszystkie Twoje trasy 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 jak require("../../../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 miejsce app/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.

    1. otwarcie bloku CommonJS wymaga wywołania zależności stanu
    2. główny blok kodu pure-JavaScript. Nie ma tu częstych zanieczyszczeń. Nie odwołuj się do eksportu, modułu ani wymagań.
    3. Zamknięcie bloku CommonJS w celu skonfigurowania eksportu
     261
    Author: Peter Lyons,
    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 poziomu config.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.

     154
    Author: Peter Lyons,
    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 poziomu config.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.

     50
    Author: dthree,
    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.

     41
    Author: Sandro Munda,
    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

     18
    Author: tjholowaychuk,
    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.

     17
    Author: neebz,
    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?

    1. Małe, otoczkowane Moduły , każdy z osobnym MVC

    2. Każdy moduł ma paczka.json

    3. Testowanie jako części struktury (w każdym module)

    4. Konfiguracja globalna , biblioteki i usługi

    5. Integrated Docker, Cluster, forever

    Folderoverview (patrz folder lib dla modułów):

    struktura nodebootstrap

     13
    Author: Simon Fakir,
    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

     7
    Author: Stefan,
    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.

     7
    Author: ecdeveloper,
    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.

     6
    Author: TiansHUo,
    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.

     5
    Author: Ulysses V,
    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);
    
     5
    Author: Renato Gama,
    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.

     4
    Author: diproart,
    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."

     4
    Author: Ben Mordue,
    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

     4
    Author: Raja Rama Mohan Thavalam,
    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'));
    
     1
    Author: zevero,
    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.

     0
    Author: Nitesh Oswal,
    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
    
     0
    Author: Odirlei Borgert,
    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