web-dev-qa-db-fra.com

ExpressJS Comment structurer une application?

J'utilise le framework Web ExpressJS pour NodeJS.

Les personnes utilisant ExpressJS placent leur environnement (développement, production, test ...), leurs itinéraires, etc. sur le app.js. Je pense que ce n'est pas une belle façon parce que quand vous avez une grosse application, app.js est trop grosse!

Je voudrais avoir cette structure de répertoire:

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

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

Mon code fonctionne bien et je pense que la structure des répertoires est belle. Cependant, le code devait être adapté et je ne suis pas sûr que ce soit bien/beau.

Est-il préférable d'utiliser ma structure de répertoires et d'adapter le code ou simplement d'utiliser un fichier (app.js)?

Merci pour vos conseils!

488
Sandro Munda

OK, cela fait longtemps et la question est populaire. J'ai donc créé un référentiel d'échafaudages github avec du code JavaScript et un long README sur la manière dont j'aime structurer un courrier express de taille moyenne. application js.

focusaurus/express_code_structure est le dépôt avec le dernier code pour cela. Les demandes de tirage sont les bienvenues.

Voici un instantané du README puisque le débordement de pile n'aime pas les réponses faites par un simple lien. Je ferai des mises à jour car il s'agit d'un nouveau projet que je continuerai à mettre à jour, mais au final, le dépôt github sera l'endroit à jour pour cette information.


Structure du code express

Ce projet montre comment organiser une application Web express.js de taille moyenne.

Courant pour exprimer au moins la v4.14 Décembre 2016

Build Status

js-standard-style

Quelle est la taille de votre application?

Les applications Web ne sont pas toutes identiques et il n’existe, à mon avis, pas de structure de code unique qui devrait être appliquée à toutes les applications express.js.

Si votre application est petite, vous n'avez pas besoin d'une structure de répertoire aussi détaillée que celle illustrée ici. Restez simple et collez une poignée de fichiers .js à la racine de votre référentiel et vous avez terminé. Voilà.

Si votre application est volumineuse, vous devez éventuellement la diviser en packages npm distincts. En général, l’approche node.js semble privilégier de nombreux petits packages, du moins pour les bibliothèques, et vous devez construire votre application en utilisant plusieurs packages npm, car cela commence à avoir un sens et à justifier les frais généraux. Ainsi, au fur et à mesure que votre application grandit et qu'une partie du code devient clairement réutilisable en dehors de votre application ou est un sous-système clair, déplacez-le dans son propre référentiel git et transformez-le en un package npm autonome.

Ainsi l'objectif de ce projet est d'illustrer une structure viable pour une application de taille moyenne.

Quelle est votre architecture globale

Il existe de nombreuses approches pour créer une application Web, telles que

  • MVC côté serveur à la Ruby sur Rails
  • Application simple page à la MongoDB/Express/Angulaire/Nœud (MEAN)
  • Site web basique avec quelques formulaires
  • Modèles/Opérations/Vues/Événements de style à la MVC est mort, il est temps d'activer
  • et beaucoup d'autres à la fois actuels et historiques

Chacun de ceux-ci s'intègre parfaitement dans une structure de répertoires différente. Pour les besoins de cet exemple, il s’agit simplement d’un échafaudage et non d’une application entièrement fonctionnelle, mais j’assume les points clés de l’architecture suivants:

  • Le site a quelques pages statiques/modèles traditionnels
  • La partie "application" du site est développée en tant que style d'application à une seule page.
  • L'application expose une API de style REST/JSON au navigateur
  • L'application modélise un domaine commercial simple. Dans ce cas, il s'agit d'une application d'un concessionnaire automobile.

Et que dire de Ruby sur Rails?

Tout au long de ce projet, le thème sera que beaucoup des idées contenues dans Ruby sur Rails et dans les décisions "Convention sur la configuration" qu'ils ont adoptées ne sont pas largement acceptées et utilisées. effectivement très utiles et sont parfois le contraire de ce que ce référentiel recommande.

Mon point principal ici est qu’il existe des principes sous-jacents à l’organisation du code et que, sur la base de ces principes, les conventions Ruby sur Rails ont un sens (principalement) pour le Ruby sur Rails communauté. Cependant, il est inutile de singer ces conventions. Une fois que vous maîtriserez les principes de base, TOUS vos projets seront clairs et bien organisés: scripts Shell, jeux, applications mobiles, projets d’entreprise et même votre répertoire personnel.

Pour la communauté Rails, ils souhaitent pouvoir faire basculer un seul développeur Rails d'une application à une autre et en connaître le fonctionnement à chaque fois. Cela est tout à fait logique si vous utilisez 37 signaux ou laboratoires pivots et présente des avantages. Dans le monde JavaScript côté serveur, la philosophie générale est bien plus far west, et tout ce qui se passe ne pose pas de problème. C'est comme ça qu'on roule. Nous sommes habitués. Même dans express.js, c’est un proche parent de Sinatra, pas Rails, et prendre des conventions de Rails n’aide en général pas. Je dirais même Principes sur la convention sur la configuration .

Principes sous-jacents et motivations

  • Être mentalement gérable
    • Le cerveau ne peut que traiter et penser à un petit nombre de choses liées à la fois. C'est pourquoi nous utilisons des annuaires. Cela nous aide à gérer la complexité en nous concentrant sur de petites portions.
  • Soyez adapté à la taille
    • Ne créez pas de "répertoires de maisons" dans lesquels il n'y a qu'un fichier, trois répertoires isolés. Vous pouvez voir cela se produire dans le Ansible Best Practices qui modifie de petits projets en créant plus de 10 répertoires pour contenir plus de 10 fichiers lorsqu'un répertoire avec 3 fichiers serait beaucoup plus approprié. Vous ne conduisez pas un bus pour aller au travail (sauf si vous êtes chauffeur de bus, mais vous conduisez quand même un bus AT ne fonctionne pas.) Ne créez pas de structures de système de fichiers non justifiées. par les fichiers réels à l'intérieur d'eux.
  • Être modulaire mais pragmatique
    • La communauté de nœuds favorise globalement les petits modules. Tout ce qui peut être entièrement séparé de votre application doit être extrait dans un module pour un usage interne ou publié publiquement sur npm. Toutefois, pour les applications de taille moyenne visées ici, des frais supplémentaires peuvent alourdir votre flux de travail sans valeur correspondante. Donc, pour le moment où vous avez du code factorisé, mais pas suffisant pour justifier un module npm complètement séparé, considérez-le simplement comme un " proto-module "avec l’espoir que lorsqu’il dépassera un certain seuil de taille, il sera extrait.
    • Certaines personnes telles que @ hij1nx incluent même un répertoire app/node_modules et ont des fichiers package.json dans le proto-module des annuaires pour faciliter cette transition et servir de rappel.
  • Être facile à localiser le code
    • Étant donné une fonctionnalité à construire ou un bogue à corriger, notre objectif est qu'un développeur n'ait pas de difficulté à localiser les fichiers source impliqués.
    • Les noms sont significatifs et précis
    • le code crufty est complètement supprimé, n'est pas laissé dans un fichier orphelin ou simplement commenté
  • Soyez convivial pour les recherches
    • tout le code source première partie se trouve dans le répertoire app afin que vous puissiez cd exécuter find/grep/xargs/ag/ack/etc et ne pas être distrait par des correspondances avec des tiers
  • Utilisez des noms simples et évidents
    • npm semble maintenant exiger des noms de paquetages en minuscules. Je trouve cela généralement terrible, mais je dois suivre le troupeau. Les noms de fichiers doivent donc utiliser kebab-case même si le nom de la variable correspondant à cela en JavaScript doit être camelCase car - est un signe moins en JavaScript.
    • nom de variable correspond au nom de base du chemin de module, mais avec kebab-case transformé en camelCase
  • Groupe par couplage, pas par fonction
    • Ceci est un changement majeur par rapport à la convention Ruby sur Rails de app/views, app/controllers, app/models, etc.
    • Les fonctionnalités étant ajoutées à une pile complète, je souhaite donc me concentrer sur une pile complète de fichiers pertinents pour ma fonctionnalité. Lorsque j'ajoute un champ de numéro de téléphone au modèle utilisateur, je me fiche de tout contrôleur autre que le contrôleur utilisateur, et de n'importe quel modèle autre que le modèle utilisateur.
    • Ainsi, au lieu d'éditer 6 fichiers se trouvant chacun dans leur propre répertoire et d'ignorer des tonnes d'autres fichiers de ces répertoires, ce référentiel est organisé de manière à ce que tous les fichiers nécessaires à la création d'une fonctionnalité soient colocalisés.
    • De par la nature de MVC, la vue utilisateur est couplée au contrôleur utilisateur qui est couplé au modèle utilisateur. Ainsi, lorsque je change de modèle d'utilisateur, ces 3 fichiers changent souvent ensemble, mais le contrôleur d'offres ou le contrôleur client est découplé et n'est donc pas impliqué. Il en va de même pour les conceptions non-MVC.
    • Découplage de style MVC ou MOVE en ce qui concerne le code dans lequel le module est toujours recommandé, mais disperser les fichiers MVC dans des répertoires frères est simplement ennuyeux.
    • Ainsi, chacun de mes fichiers de routes contient la partie des routes qu’elle possède. Un fichier de style Rails routes.rb _ est pratique si vous souhaitez obtenir une vue d'ensemble de tous les itinéraires de l'application, mais lorsque vous créez des entités et corrigez des bugs, vous ne tenez compte que des itinéraires pertinents pour l'élément que vous modifiez.
  • Enregistrez les tests à côté du code
    • Ceci est juste une instance de "groupe par couplage", mais je voulais l'appeler spécifiquement. J'ai écrit de nombreux projets où les tests vivent sous un système de fichiers parallèle appelé "tests" et maintenant que j'ai commencé à mettre mes tests dans le même répertoire que le code correspondant, je ne vais jamais revenir en arrière. C’est plus modulaire et beaucoup plus facile à utiliser dans les éditeurs de texte et permet d’alléger un grand nombre des bêtises du chemin "../../ ..". Si vous avez des doutes, essayez quelques projets et décidez vous-même. Je ne ferai rien au-delà de cela pour vous convaincre que c'est mieux.
  • Réduit le couplage transversal avec les événements
    • Il est facile de penser "OK, chaque fois qu'un nouveau Deal est créé, je veux envoyer un email à tous les vendeurs", puis il suffit de mettre le code pour envoyer ces emails dans le chemin qui crée les deals.
    • Cependant, ce couplage finira par transformer votre application en une boule de boue géante.
    • Au lieu de cela, DealModel devrait simplement déclencher un événement "create" et ne pas savoir ce que le système pourrait faire d'autre en réponse à cela.
    • Lorsque vous codez de cette manière, il devient beaucoup plus possible de mettre tout le code lié à l'utilisateur dans app/users, car il n'y a pas un nid de logique métier couplée qui pollue la pureté de la base de code utilisateur.
  • Le flux de code est suivi
    • Ne fais pas de magie. Ne chargez pas automatiquement des fichiers à partir de répertoires magiques dans le système de fichiers. Ne soyez pas Rails. L'application commence à app/server.js:1 et vous pouvez voir tout ce qu'elle charge et exécuter en suivant le code.
    • Ne faites pas de DSL pour vos itinéraires. Ne faites pas de métaprogrammes stupides quand ce n’est pas nécessaire.
    • Si votre application est si volumineuse que magicRESTRouter.route(somecontroller, {except: 'POST'}) est une grande victoire pour 3 appels de base app.get, app.put, app.del, vous créez probablement une application monolithique trop volumineuse. travailler efficacement. Soyez chic pour les gros gains, pas pour convertir 3 lignes simples en 1 ligne complexe.
  • Utiliser les noms de fichiers de casse inférieure de kebab

    • Ce format évite les problèmes de sensibilité à la casse des systèmes de fichiers sur toutes les plateformes
    • npm interdit les majuscules dans les nouveaux noms de paquetages, ce qui fonctionne bien avec

      express.js spécificités

  • N'utilisez pas app.configure. C'est presque entièrement inutile et vous n'en avez tout simplement pas besoin. Il est souvent utilisé en raison d'un copypasta sans cervelle.

  • L'ORDRE DE MIDDLEWARE ET ITINÉRAIRES EN MATIÈRE EXPRESSE !!!
    • Presque tous les problèmes de routage que je vois sur stackoverflow sont des middleware express hors service
    • En général, vous voulez que vos itinéraires soient découplés et que vous ne vous fiez pas trop à l'ordre
    • N'utilisez pas app.use pour l'ensemble de votre application si vous n'avez vraiment besoin que de ce middleware pour 2 routes (je vous regarde, body-parser)
    • Assurez-vous quand tout est dit et fini que vous avez EXACTEMENT cette commande:
      1. Tout middleware super important à l'échelle de l'application
      2. Tous vos itinéraires et middlewares de route assortis
      3. ALORS les gestionnaires d'erreur
  • Malheureusement, express.js, inspiré par les sinatras, suppose généralement que tous vos itinéraires seront dans server.js et que la manière dont ils sont commandés sera claire. Pour une application de taille moyenne, répartir les choses en modules de routage distincts est agréable, mais cela présente un risque de middleware hors service.

Le truc des liens symboliques

Il existe de nombreuses approches décrites et discutées en détail par la communauté dans le grand Gist Mieux des chemins locaux requis () pour Node.js . Je pourrais bientôt décider de préférer soit "simplement traiter avec beaucoup de ../../../ .." ou utiliser le requireFrom modlue. Cependant, pour le moment, j'utilise l'astuce de lien symbolique décrite ci-dessous.

Ainsi, un moyen d'éviter les intrusions dans des projets avec des chemins relatifs gênants comme require("../../../config") consiste à utiliser le truc suivant:

  • créer un lien symbolique sous node_modules pour votre application
    • cd node_modules && ln -nsf ../app
  • ajoutez uniquement le lien symbolique node_modules/app lui-même , et non le dossier entier node_modules, à git
    • git add -f node_modules/app
    • Oui, vous devriez toujours avoir "node_modules" dans votre fichier .gitignore
    • Non, vous ne devriez pas mettre "node_modules" dans votre dépôt git. Certaines personnes vous recommanderont de le faire. Ils sont incorrects.
  • Vous pouvez maintenant avoir besoin de modules intra-projet utilisant ce préfixe
    • var config = require("app/config");
    • var DealModel = require("app/deals/deal-model");
  • Fondamentalement, cela rend les travaux intra-projet très similaires à ceux des modules npm externes.
  • Désolé, utilisateurs de Windows, vous devez vous en tenir aux chemins relatifs du répertoire parent.

Configuration

Généralement, les modules et les classes de code n'attendent qu'un objet JavaScript options de base transmis. Seul app/server.js doit charger le module app/config.js. À partir de là, il peut synthétiser de petits objets options pour configurer les sous-systèmes selon les besoins, mais le couplage de chaque sous-système à un grand module de configuration global contenant des informations supplémentaires est un couplage incorrect.

Essayez de centraliser la création de connexions à la base de données et de les transférer dans des sous-systèmes, par opposition à la transmission de paramètres de connexion et à la création de connexions sortantes par les sous-systèmes.

NODE_ENV

Ceci est une autre idée séduisante mais terrible reportée de Rails. Il devrait y avoir exactement 1 place dans votre application, app/config.js qui examine la variable d’environnement NODE_ENV. Tout le reste devrait prendre une option explicite comme argument de constructeur de classe ou paramètre de configuration de module.

Si le module e-mail a une option sur la manière de distribuer les e-mails (SMTP, se connecter à stdout, mettre en file d'attente, etc.), il devrait prendre une option comme {deliver: 'stdout'} mais il ne devrait absolument pas vérifier NODE_ENV.

Des tests

Je garde maintenant mes fichiers de test dans le même répertoire que le code correspondant et utilise les conventions de dénomination des extensions de nom de fichier pour distinguer les tests du code de production.

  • foo.js a le code du module "foo"
  • foo.tape.js possède les tests basés sur les noeuds pour foo et réside dans le même répertoire
  • foo.btape.js peut être utilisé pour les tests devant être exécutés dans un environnement de navigateur

J'utilise les fichiers globs du système de fichiers et la commande find . -name '*.tape.js' pour accéder à tous mes tests, si nécessaire.

Comment organiser le code dans chaque fichier de module .js

La portée de ce projet concerne principalement l'emplacement des fichiers et des répertoires, et je ne veux pas en ajouter beaucoup d'autres, mais je mentionnerai simplement que j'organise mon code en 3 sections distinctes.

  1. Le bloc d'ouverture de CommonJS nécessite des appels aux dépendances d'état
  2. Bloc de code principal de JavaScript pur. Aucune pollution CommonJS ici. Ne faites pas référence aux exportations, aux modules ou aux besoins.
  3. Bloc de fermeture de CommonJS pour configurer les exportations
291
Peter Lyons

UPDATE (2013-10-29): Veuillez vous reporter à mon autre réponse également, qui a JavaScript à la place de CoffeeScript à la demande générale, ainsi qu'un référentiel passe-partout github et un document détaillé README détaillant mes dernières recommandations. sur ce sujet.

Config

Ce que tu fais est bien. J'aime avoir mon propre espace de noms de configuration configuré dans un fichier config.coffee de niveau supérieur avec un espace de noms imbriqué comme celui-ci.

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

C'est convivial pour l'édition par l'administrateur système. Ensuite, lorsque j’ai besoin de quelque chose, comme les informations de connexion à la base de données,

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

Routes/Controllers

J'aime laisser mes routes avec mes contrôleurs et les organiser dans un sous-répertoire app/controllers. Ensuite, je peux les charger et les laisser ajouter les itinéraires dont ils ont besoin.

Dans mon fichier app/server.coffee coffeescript, je fais:

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

J'ai donc des fichiers comme:

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

Et par exemple dans mon contrôleur de domaines, j'ai une fonction setup comme celle-ci.

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

Vues

Mettre des vues dans app/views devient le lieu habituel. Je le pose comme ça.

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

Fichiers statiques

Allez dans un sous-répertoire public.

Github/Semver/NPM

Placez un fichier de marquage README.md à la racine de votre dépôt Git pour github.

Placez un fichier package.json avec un numéro version sémantique dans votre racine de dépôt git pour NPM.

154
Peter Lyons

Ce qui suit est la réponse textuelle de Peter Lyons, transférée de Coffeescript à Vanilla JS, comme demandé par plusieurs autres. La réponse de Peter est très efficace et quiconque vote pour ma réponse devrait également voter pour la sienne.


Config

Ce que tu fais est bien. J'aime avoir mon propre espace de noms de configuration configuré dans un fichier config.js de niveau supérieur avec un espace de noms imbriqué comme celui-ci.

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

C'est convivial pour l'édition par l'administrateur système. Ensuite, lorsque j’ai besoin de quelque chose, comme les informations de connexion à la base de données,

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

Routes/Controllers

J'aime laisser mes routes avec mes contrôleurs et les organiser dans un sous-répertoire app/controllers. Ensuite, je peux les charger et les laisser ajouter les itinéraires dont ils ont besoin.

Dans mon fichier javascript app/server.js je fais:

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

J'ai donc des fichiers comme:

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

Et par exemple dans mon contrôleur de domaines, j'ai une fonction setup comme celle-ci.

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

Vues

Mettre des vues dans app/views devient le lieu habituel. Je le pose comme ça.

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

Fichiers statiques

Allez dans un sous-répertoire public.

Github/Semver/NPM

Placez un fichier de marquage README.md à la racine de votre dépôt Git pour github.

Placez un fichier package.json avec un numéro version sémantique dans votre racine de dépôt git pour NPM.

50
dthree

Ma question a été introduite en avril 2011, elle est ancienne. Pendant ce temps, je pouvais améliorer mon expérience avec Express.js et comment architecturer une application écrite à l'aide de cette bibliothèque. Donc, je partage ici mon expérience.

Voici ma structure de répertoire:

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

L'objectif du fichier app.js est d'amorcer l'application Expressjs. Il charge le module de configuration, le module de journalisation, attend la connexion à la base de données, ... et exécute le serveur express.

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

itinéraires/

Le répertoire routes a un fichier index.js. Son but est d'introduire une sorte de magie pour charger tous les autres fichiers dans le répertoire routes/. Voici la mise en œuvre:

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

Avec ce module, créer une nouvelle définition et implémentation de route est vraiment facile. Par exemple, hello.js:

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

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

Chaque module de route est autonome .

42
Sandro Munda

J'aime utiliser une "application" globale plutôt que d'exporter une fonction, etc.

18
tjholowaychuk

Je pense que c'est une excellente façon de le faire. Non limité à exprimer mais j'ai vu pas mal de projets node.js sur github faisant la même chose. Ils suppriment les paramètres de configuration + les modules plus petits (dans certains cas, tous les URI) sont factorisés dans des fichiers séparés.

Je recommanderais de passer par des projets spécifiques à github pour avoir une idée. OMI la façon dont vous faites est correcte.

17
neebz

c'est maintenant Fin 2015 et après avoir développé ma structure pendant 3 ans et dans des projets de toutes tailles. Conclusion?

Ne faites pas un grand MVC, mais le séparez en modules

Alors...

Pourquoi?

  • On travaille généralement sur un module (par exemple, Produits), que vous pouvez modifier indépendamment. 

  • Vous pouvez réutiliser des modules

  • Vous pouvez le tester séparément

  • Vous pouvez le remplacer séparément

  • Ils ont des interfaces claires (stables)

    -Au plus tard, s'il y avait plusieurs développeurs travaillant, la séparation des modules aide

Le projet nodebootstrap a une approche similaire à ma structure finale. ( github )

A quoi ressemble cette structure?

  1. Petits modules encapsulés, chacun avec MVC séparé

  2. Chaque module a un package.json

  3. Test dans le cadre de la structure (dans chaque module)

  4. Configuration globale, bibliothèques et services

  5. Docker intégré, cluster, pour toujours

Folderoverview (voir le dossier lib pour les modules):

 nodebootstrap structure

14
Simon Fakir

Cela faisait longtemps que la dernière réponse à cette question n’était pas passée et Express a récemment publié la version 4, qui ajoute quelques éléments utiles pour l’organisation de la structure de votre application.

Vous trouverez ci-dessous un long article de blog présentant les meilleures pratiques pour structurer votre application Express http://www.terlici.com/2014/08/25/best-practices-express-structure.html

Il existe également un référentiel GitHub appliquant les conseils de l'article. Il est toujours à jour avec la dernière version d'Express.
https://github.com/terlici/base-express

7
Stefan

Je ne pense pas que ce soit une bonne approche pour ajouter des routes à la configuration. Une meilleure structure pourrait être quelque chose comme ceci: 

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

Ainsi, products.js et users.js contiendront tous vos itinéraires et toute leur logique.

7
ecdeveloper

Je donne la structure de dossier de style MVC s'il vous plaît trouver ci-dessous.

Nous avons utilisé la structure de dossiers ci-dessous pour nos applications Web grandes et moyennes.

 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

J'ai créé un module npm pour la génération du classeur de dossiers mvc express.

Veuillez trouver ci-dessous https://www.npmjs.com/package/express-mvc-generator

Juste des étapes simples pour générer et utiliser ces modules.

i) installer le module npm install express-mvc-generator -g 

ii) options de vérification express -h

iii) Générer une structure express mvc express myapp

iv) Dépendances d'installation: npm install:

v) Ouvrez votre fichier config/database.js, veuillez configurer votre base de données mongo.

vi) Lancer l'application node app ou nodemon app 

vii) URL de vérification http: // localhost: 8042/inscription OR http: // yourip: 8042/inscription

Eh bien, je mets mes itinéraires en tant que fichier JSON, que je lis au début, et dans une boucle for dans app.js, configurez les itinéraires. Le fichier route.json indique la vue à appeler et la clé des valeurs qui seront envoyées dans la route.
Cela fonctionne pour de nombreux cas simples, mais je devais créer manuellement des itinéraires pour des cas particuliers.

6
TiansHUo

J'ai écrit un post exactement à ce sujet. Fondamentalement, il utilise une routeRegistrar qui parcourt les fichiers du dossier /controllers en appelant sa fonction init. La fonction init prend la variable express app en tant que paramètre afin que vous puissiez enregistrer vos itinéraires comme vous le souhaitez.

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

Cela peut être intéressant:

https://github.com/flatiron/nconf

Configuration node.js hiérarchique avec les fichiers, les variables d'environnement, les arguments de ligne de commande et la fusion d'objet atomique.

5
Ulysses V

http://locomotivejs.org/ fournit un moyen de structurer une application construite avec Node.js et Express.

Sur le site:

"Locomotive est un cadre Web pour Node.js. Locomotive prend en charge les modèles MVC , Les itinéraires RESTful et la convention sur la configuration, tout en puissance et simplicité .__ vous attendez de Node. "

4
Ben Mordue

1) Votre système de fichiers de projet Express ressemble peut-être à:

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

app.js - votre conteneur d'applications global

2) Fichier principal du module (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) Connecter le module dans app.js principal

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

4) Exemple de logique 

lib/login
lib/db
lib/config
lib/users
lib/verify
lib/
   /api/ 
   ...
lib/
   /admin/
      /users/
      /settings/
      /groups/
...
  • Meilleur pour les tests
  • Meilleur pour la balance
  • Séparer dépend par module
  • Regroupement des itinéraires par fonctionnalité (ou modules)

tj dit/montre sur Vimeo idée intéressante comment modularise une application express - Applications Web modulaires avec Node.js et Express . Puissant et simple.

4
diproart

J'ai récemment adopté des modules en tant que mini-applications indépendantes.

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

Désormais, pour tout routage de module (# .js), les vues (* .ejs), js, css et les actifs sont côte à côte.

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

De cette façon, même les sous-modules sont possibles.

N'oubliez pas de définir la vue dans le répertoire src

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

Voici à quoi ressemble la plupart de mes structures de répertoires de projets express.

Je fais habituellement un express dirname pour initialiser le projet, pardonnez-moi ma paresse, mais c'est très flexible et extensible. PS - vous devez obtenir express-generator pour cela (pour ceux qui le recherchent Sudo npm install -g express-generator, Sudo car vous l'installez globalement)

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

Vous devez vous demander pourquoi les fichiers .env? Parce qu'ils travaillent! J'utilise le module dotenv dans mes projets (beaucoup récemment) et ça marche! Pop dans ces 2 instructions dans app.js ou www

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

Et une autre ligne pour définir rapidement /bower_components afin de servir du contenu statique sous la ressource /ext

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

Cela peut probablement convenir aux personnes qui souhaitent utiliser Express et Angular ensemble, ou simplement exprimer sans cette hiérarchie javascripts bien sûr.

1
Nitesh Oswal

Ma structure express 4 . https://github.com/odirleiborgert/borgert-express-boilerplate

Paquets

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

Structure

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

Un moyen simple de structurer votre application express:

  • Dans index.js principal, l’ordre suivant devrait être maintenu.

    all app.set devrait être le premier.

    tout app.use devrait être deuxième.

    suivi par d'autres apis avec leurs fonctions ou route-continue dans d'autres fichiers

    Exapmle

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

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

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

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

0
Snivio