it-swarm.com.de

ExpressJS Wie strukturiere ich eine Anwendung?

Ich verwende das ExpressJS-Webframework für NodeJS.

Benutzer, die ExpressJS verwenden, stellen ihre Umgebung (Entwicklung, Produktion, Test ...), ihre Routen usw. auf den app.js. Ich denke, das ist kein schöner Weg, denn wenn man eine große Anwendung hat, ist app.js zu groß!

Ich hätte gerne diese Verzeichnisstruktur:

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

Hier ist mein Code:

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

Mein Code funktioniert gut und ich denke, dass die Struktur der Verzeichnisse schön ist. Allerdings musste der Code angepasst werden und ich bin nicht sicher, ob er gut/schön ist.

Ist es besser, meine Verzeichnisstruktur zu verwenden und den Code anzupassen oder einfach eine Datei (app.js) zu verwenden?

Danke für deine Ratschläge!

488
Sandro Munda

UPDATE (2013-10-29): Bitte sehen Sie sich auch meine andere Antwort an, die auf Wunsch von JavaScript anstelle von CoffeeScript sowie einem Boilerplate-Github-Repo und einem ausführlichen README mit meinen neuesten Empfehlungen dazu vorliegt Thema.

Config

Was du tust, ist gut. Ich möchte, dass mein eigener Konfigurations-Namespace in einer config.coffee-Datei der obersten Ebene mit einem solchen verschachtelten Namespace eingerichtet wird.

#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}"

Dies ist für die Bearbeitung von Sysadmin-Dateien hilfreich. Wenn ich dann etwas brauche, wie zum Beispiel die DB-Verbindungsinformationen, dann ist es das

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

Routen/Controller

Ich lasse meine Routen gerne mit meinen Controllern und organisiere sie in einem app/controllers-Unterverzeichnis. Dann kann ich sie laden und sie die Routen hinzufügen lassen, die sie benötigen.

In meiner app/server.coffee coffeescript Datei mache ich:

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

Ich habe also Dateien wie:

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

Und zum Beispiel habe ich in meinem Domänencontroller eine setup-Funktion wie diese.

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

Ansichten

Das Einfügen von Ansichten in app/views wird zum üblichen Ort. Ich lege es so aus.

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

Statische Dateien

Gehen Sie in ein public-Unterverzeichnis.

Github/Semver/NPM

Legen Sie eine README.md-Markdown-Datei im git repo-Stammverzeichnis für github an.

Fügen Sie eine package.json-Datei mit einer semantic version -nummer in Ihr git-Repo-Stammverzeichnis für NPM ein.

154
Peter Lyons

Das Folgende ist die Antwort von Peter Lyons wörtlich, die von Coffeescript auf Vanilla JS übertragen wurde, wie von mehreren anderen verlangt. Peters Antwort ist sehr gut und jeder, der über meine Antwort abstimmt, sollte auch über ihn abstimmen.


Config

Was du tust, ist gut. Ich möchte, dass mein eigener Konfigurations-Namespace in einer config.js-Datei der obersten Ebene mit einem solchen verschachtelten Namespace eingerichtet wird.

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

Dies ist für die Bearbeitung von Sysadmin-Dateien hilfreich. Wenn ich dann etwas brauche, wie zum Beispiel die DB-Verbindungsinformationen, dann ist es das

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

Routen/Controller

Ich lasse meine Routen gerne mit meinen Controllern und organisiere sie in einem app/controllers-Unterverzeichnis. Dann kann ich sie laden und sie die Routen hinzufügen lassen, die sie benötigen.

In meiner app/server.js-Javascript-Datei mache ich:

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

Ich habe also Dateien wie:

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

Und zum Beispiel habe ich in meinem Domänencontroller eine setup-Funktion wie diese.

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

Ansichten

Das Einfügen von Ansichten in app/views wird zum üblichen Ort. Ich lege es so aus.

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

Statische Dateien

Gehen Sie in ein public-Unterverzeichnis.

Github/Semver/NPM

Legen Sie eine README.md-Markdown-Datei im git repo-Stammverzeichnis für github an.

Fügen Sie eine package.json-Datei mit einer semantic version -nummer in Ihr git-Repo-Stammverzeichnis für NPM ein.

50
dthree

Meine Frage wurde im April 2011 eingeführt, sie ist ziemlich alt. Während dieser Zeit konnte ich meine Erfahrung mit Express.js verbessern und die Architektur einer Anwendung, die mit dieser Bibliothek geschrieben wurde, verbessern. Also teile ich hier meine Erfahrung.

Hier ist meine Verzeichnisstruktur:

├── 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

Das Ziel der app.js-Datei besteht darin, die Anwendung expressjs zu booten. Es lädt das Konfigurationsmodul, das Logger-Modul, wartet auf die Datenbankverbindung, ... und führt den Express-Server aus.

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

routen/

Das Routenverzeichnis hat eine index.js-Datei. Ziel ist es, eine Art Magie einzuführen, um alle anderen Dateien in das Verzeichnis routes/ zu laden. Hier ist die Implementierung:

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

Mit diesem Modul ist das Erstellen einer neuen Routendefinition und -implementierung sehr einfach. Für Beispiele, hello.js:

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

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

Jedes Routenmodul ist Standalone .

42
Sandro Munda

Ich benutze gerne eine globale "App", anstatt eine Funktion etc

18
tjholowaychuk

Ich denke, es ist eine großartige Möglichkeit, dies zu tun. Nicht beschränkt auf den Ausdruck, aber ich habe schon eine Reihe von node.js-Projekten auf github gesehen, die dasselbe tun. Sie nehmen die Konfigurationsparameter heraus und kleinere Module (in manchen Fällen jeder URI) werden in separaten Dateien gespeichert.

Ich würde empfehlen, expressspezifische Projekte auf github durchzugehen, um eine Vorstellung zu bekommen. IMO die Art, wie Sie es tun, ist richtig.

17
neebz

es ist jetzt Ende 2015 und nachdem ich meine Struktur 3 Jahre lang sowie in kleinen und großen Projekten entwickelt habe. Fazit?

Mache keine großen MVC, sondern trenne sie in Modulen

So...

Warum?

  • Normalerweise arbeitet man mit einem Modul (z. B. Produkten), das Sie unabhängig voneinander ändern können. 

  • Sie können Module wiederverwenden

  • Sie können es separat testen

  • Sie können es separat austauschen

  • Sie haben klare (stabile) Schnittstellen

    Spätestens wenn mehrere Entwickler arbeiteten, hilft die Trennung der Module

Das Projekt nodebootstrap hat einen ähnlichen Ansatz wie meine endgültige Struktur. ( github )

Wie sieht diese Struktur aus?

  1. Kleine, gekapselte Module mit jeweils separaten MVC

  2. Jedes Modul hat eine package.json

  3. Testing als Teil der Struktur (in jedem Modul)

  4. Globale Konfiguration, Bibliotheken und Dienste

  5. Integrierter Docker, Cluster, für immer

Ordnerübersicht (siehe lib-Ordner für Module):

 nodebootstrap structure

14
Simon Fakir

Seit der letzten Antwort auf diese Frage ist eine Weile vergangen, und Express hat kürzlich auch Version 4 veröffentlicht, die einige nützliche Dinge für die Organisation Ihrer App-Struktur hinzugefügt hat.

Im Folgenden finden Sie einen aktuellen Blogeintrag mit bewährten Methoden zur Strukturierung Ihrer Express-App. http://www.terlici.com/2014/08/25/best-practices-express-structure.html

Es gibt auch ein GitHub-Repository, das die Ratschläge im Artikel anwendet. Es ist immer auf dem neuesten Stand mit der neuesten Express-Version.
https://github.com/terlici/base-express

7
Stefan

Ich denke nicht, dass es eine gute Methode ist, Routen zur Konfiguration hinzuzufügen. Eine bessere Struktur könnte so aussehen: 

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 und users.js enthalten also alle Ihre Routen und alle Logik.

7
ecdeveloper

Ich gebe MVC-Ordnerstruktur, bitte finden Sie unten.

Wir haben folgende Ordnerstruktur für unsere großen und mittleren Webanwendungen verwendet.

 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

Ich habe ein npm-Modul für die Generierung von Express-MVC-Ordnern erstellt.

Hier finden Sie den unten angegebenen https://www.npmjs.com/package/express-mvc-generator

Nur einfache Schritte zum Generieren und Verwenden dieser Module.

i) installiere das Modul npm install express-mvc-generator -g 

ii) Optionen prüfen express -h

iii) Express-MVC-Struktur erzeugen express myapp

iv) Abhängigkeiten installieren: npm install:

v) Öffnen Sie Ihre config/database.js. Bitte konfigurieren Sie Ihre Mongo-Datenbank.

vi) Führen Sie die Anwendung node app oder nodemon app aus. 

vii) Überprüfen Sie die URL http: // localhost: 8042/signup OR http: // yourip: 8042/signup .

Nun, ich stelle meine Routen als Json-Datei, die ich am Anfang gelesen habe, und richtete die Routen in einer for-Schleife in app.js ein. Die route.json enthält die Ansicht, die aufgerufen werden soll, und den Schlüssel für die Werte, die in die Route gesendet werden.
Dies funktioniert für viele einfache Fälle, aber für spezielle Fälle musste ich einige Routen manuell erstellen.

6
TiansHUo

Ich habe genau zu diesem Thema einen Beitrag geschrieben. Es verwendet im Wesentlichen eine routeRegistrar, die Dateien im Ordner /controllers durchläuft, die ihre Funktion init aufrufen. Die Funktion init nimmt die Variable express app als Parameter, damit Sie Ihre Routen wie gewünscht registrieren können.

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);
6
Renato Gama

Dies kann von Interesse sein:

https://github.com/flatiron/nconf

Hierarchische node.js-Konfiguration mit Dateien, Umgebungsvariablen, Befehlszeilenargumenten und Zusammenführen von atomaren Objekten.

5
Ulysses V

http://locomotivejs.org/ bietet eine Möglichkeit, eine mit Node.js und Express erstellte App zu strukturieren.

Von der Website:

"Locomotive ist ein Web - Framework für Node.js. Locomotive unterstützt MVC Patterns, RESTful - Routen und Konventionen über die Konfiguration. Die Integration von Nahtlos in jede Datenbank - und Template - Engine ..__ Kraft und Einfachheit Sie erwarten von Node. "

4
Ben Mordue

1) Ihr Express-Projekt-Dateisystem mag vielleicht wie folgt aussehen:

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

app.js - Ihr globaler App-Container

2) Modulhauptdatei (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) Schließen Sie das Modul in der Hauptanwendung an

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

4) Beispiellogik 

lib/login
lib/db
lib/config
lib/users
lib/verify
lib/
   /api/ 
   ...
lib/
   /admin/
      /users/
      /settings/
      /groups/
...
  • Am besten zum Testen
  • Am besten für die Skalierung
  • Getrennt hängt von Modul ab
  • Route nach Funktionalität (oder Modulen) gruppieren

tj sagt/zeige auf Vimeo eine interessante Idee, wie man Expressanwendungen modularisiert. - Modulare Webanwendungen mit Node.js und Express . Kraftvoll und einfach.

4
diproart

Ich habe kürzlich Module als unabhängige Mini-Apps angenommen.

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

Für jedes Modul-Routing (# .js) liegen jetzt Ansichten (* .ejs), js, css und Assets nebeneinander. Das Routing des Submoduls ist in den übergeordneten # .js mit zwei zusätzlichen Zeilen eingerichtet

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

Auf diese Weise sind sogar Submodule möglich.

Vergessen Sie nicht, view auf das src-Verzeichnis zu setzen

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

So sieht der größte Teil meines Express-Projektverzeichnisses aus.

Normalerweise mache ich einen express dirname, um das Projekt zu initialisieren, meine Faulheit zu vergeben, aber es ist sehr flexibel und erweiterbar. PS - du musst express-generator dafür bekommen (für diejenigen, die danach suchen Sudo npm install -g express-generator, Sudo, weil du es global installierst)

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

Sie müssen sich fragen, warum .env-Dateien? Weil sie arbeiten! Ich verwende dotenv Modul in meinen Projekten (vor kurzem viel) und es funktioniert! Pop in diesen beiden Anweisungen in app.js oder www

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

Und noch eine Zeile, um schnell /bower_components für statische Inhalte unter der Ressource /ext festzulegen.

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

Es kann wahrscheinlich für Leute geeignet sein, die Express und Angular zusammen verwenden möchten, oder einfach nur ohne diese javascripts-Hierarchie.

1
Nitesh Oswal

Meine Struktur Express 4 . https://github.com/odirleiborgert/borgert-express-boilerplate

Pakete

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

Struktur

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

Eine einfache Möglichkeit, Ihre Express-App zu strukturieren:

  • In main index.js sollte die folgende Reihenfolge beibehalten werden.

    alle app.set sollte an erster Stelle stehen.

    all app.use sollte an zweiter Stelle stehen.

    gefolgt von anderen apis mit ihren Funktionen oder route-continue in anderen Dateien

    Beispiel

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

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

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

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

0
Snivio