ExpressJS如何构建应用程序?

时间:2011-04-25 12:18:34

标签: node.js express

我正在使用NodeJS的ExpressJS Web框架。

使用ExpressJS的人将他们的环境(开发,生产,测试......),他们的路线等放在app.js上。我认为这不是一个很好的方式,因为当你有一个很大的应用程序时,app.js太大了!

我想要这个目录结构:

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

这是我的代码:

app.js

var express = require('express');
var app = module.exports = express.createServer();

require('./config/environment.js')(app, express);
require('./config/routes.js')(app);

app.listen(3000);

配置/ environment.js

module.exports = function(app, express){
    app.configure(function() {
    app.use(express.logger());
    });

    app.configure('development', function() {
    app.use(express.errorHandler({
        dumpExceptions: true,
        showStack: true
    }));
    });

    app.configure('production', function() {
    app.use(express.errorHandler());
    });
};

配置/ routes.js

module.exports = function(app) {
    app.get('/', function(req, res) {
    res.send('Hello world !');
    });
};

我的代码效果很好,我认为目录的结构很漂亮。但是,代码必须进行调整,我不确定它是好还是漂亮。

使用我的目录结构并调整代码或只使用一个文件(app.js)会更好吗?

感谢您的建议!

20 个答案:

答案 0 :(得分:155)

更新(2013-10-29):请参阅我的其他答案,其中包含JavaScript而不是CoffeeScript的热门需求以及样板github repo和详细的README详细说明我的最新建议关于这个话题。

<强>配置

你做得很好。我喜欢在顶级config.coffee文件中设置我自己的config命名空间,并使用嵌套的命名空间。

#Set the current environment to true in the env object
currentEnv = process.env.NODE_ENV or 'development'
exports.appName = "MyApp"
exports.env =
  production: false
  staging: false
  test: false
  development: false
exports.env[currentEnv] = true
exports.log =
  path: __dirname + "/var/log/app_#{currentEnv}.log"
exports.server =
  port: 9600
  #In staging and production, listen loopback. nginx listens on the network.
  ip: '127.0.0.1'
if currentEnv not in ['production', 'staging']
  exports.enableTests = true
  #Listen on all IPs in dev/test (for testing from other machines)
  exports.server.ip = '0.0.0.0'
exports.db =
  URL: "mongodb://localhost:27017/#{exports.appName.toLowerCase()}_#{currentEnv}"

这对系统管理员编辑很友好。然后当我需要某些东西时,比如数据库连接信息,它就是

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

<强>路线/控制器

我喜欢将我的路线留给我的控制器并将它们组织在app/controllers子目录中。然后我可以加载它们并让它们添加它们需要的任何路径。

在我的app/server.coffee coffeescript文件中:

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

所以我有以下文件:

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

例如在我的域控制器中,我有一个setup函数。

exports.setup = (app) ->
  controller = new exports.DomainController
  route = '/domains'
  app.post route, controller.create
  app.put route, api.needId
  app.delete route, api.needId
  route = '/domains/:id'
  app.put route, controller.loadDomain, controller.update
  app.del route, controller.loadDomain, exports.delete
  app.get route, controller.loadDomain, (req, res) ->
    res.sendJSON req.domain, status.OK

<强>视图

app/views中添加观点正在成为习惯性的地方。我这样躺着。

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

静态文件

进入public子目录。

<强> Github上/ Semver / NPM

将一个README.md降价文件放在你的git repo root用于github。

将一个带有semantic version号码的package.json文件放在你的git repo root中,用于NPM。

答案 1 :(得分:50)

以下是Peter Lyons的逐字回答,按照其他几个人的要求从Coffeescript移植到香草JS。彼得的答案很有能力,任何对我的答案投票的人都应该投票给他。


<强>配置

你做得很好。我喜欢在顶级config.js文件中设置我自己的config命名空间,并使用嵌套的命名空间。

// Set the current environment to true in the env object
var currentEnv = process.env.NODE_ENV || 'development';
exports.appName = "MyApp";
exports.env = {
  production: false,
  staging: false,
  test: false,
  development: false
};  
exports.env[currentEnv] = true;
exports.log = {
  path: __dirname + "/var/log/app_#{currentEnv}.log"
};  
exports.server = {
  port: 9600,
  // In staging and production, listen loopback. nginx listens on the network.
  ip: '127.0.0.1'
};  
if (currentEnv != 'production' && currentEnv != 'staging') {
  exports.enableTests = true;
  // Listen on all IPs in dev/test (for testing from other machines)
  exports.server.ip = '0.0.0.0';
};
exports.db {
  URL: "mongodb://localhost:27017/#{exports.appName.toLowerCase()}_#{currentEnv}"
};

这对系统管理员编辑很友好。然后当我需要某些东西时,比如数据库连接信息,它就是

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

<强>路线/控制器

我喜欢将我的路线留给我的控制器并将它们组织在app/controllers子目录中。然后我可以加载它们并让它们添加它们需要的任何路径。

在我的app/server.js javascript文件中:

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

所以我有以下文件:

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

例如在我的域控制器中,我有一个setup函数。

exports.setup = function(app) {
  var controller = new exports.DomainController();
  var route = '/domains';
  app.post(route, controller.create);
  app.put(route, api.needId);
  app.delete(route, api.needId);
  route = '/domains/:id';
  app.put(route, controller.loadDomain, controller.update);
  app.del(route, controller.loadDomain, function(req, res){
    res.sendJSON(req.domain, status.OK);
  });
}

<强>视图

app/views中添加观点正在成为习惯性的地方。我这样躺着。

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

静态文件

进入public子目录。

<强> Github上/ Semver / NPM

将一个README.md降价文件放在你的git repo root用于github。

将一个带有semantic version号码的package.json文件放在你的git repo root中,用于NPM。

答案 2 :(得分:42)

我的问题是在2011年4月推出的,它很安静。在此期间,我可以改善使用Express.js的体验以及如何构建使用此库编写的应用程序。所以,我在这里分享我的经验。

这是我的目录结构:

├── app.js   // main entry
├── config   // The configuration of my applications (logger, global config, ...)
├── models   // The model data (e.g. Mongoose model)
├── public   // The public directory (client-side code)
├── routes   // The route definitions and implementations
├── services // The standalone services (Database service, Email service, ...)
└── views    // The view rendered by the server to the client (e.g. Jade, EJS, ...)

<强> App.js

app.js文件的目标是引导expressjs应用程序。它加载配置模块,记录器模块,等待数据库连接,...,并运行快速服务器。

'use strict';
require('./config');
var database = require('./services/database');
var express = require('express');
var app = express();
module.exports = app;

function main() {
  var http = require('http');

  // Configure the application.
  app.configure(function () {
    // ... ... ...
  });
  app.configure('production', function () {
    // ... ... ...
  });
  app.configure('development', function () {
    // ... ... ...
  });

  var server = http.createServer(app);

  // Load all routes.
  require('./routes')(app);

  // Listen on http port.
  server.listen(3000);
}

database.connect(function (err) {
  if (err) { 
    // ...
  }
  main();
});

<强>路由/

routes目录有一个index.js文件。它的目标是引入一种魔法来加载routes/目录中的所有其他文件。这是实施:

/**
 * This module loads dynamically all routes modules located in the routes/
 * directory.
 */
'use strict';
var fs = require('fs');
var path = require('path');

module.exports = function (app) {
  fs.readdirSync('./routes').forEach(function (file) {
    // Avoid to read this current file.
    if (file === path.basename(__filename)) { return; }

    // Load the route file.
    require('./' + file)(app);
  });
};

使用该模块,创建新的路由定义和实现非常简单。例如,hello.js

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

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

每个路线模块独立

答案 3 :(得分:18)

我喜欢使用全局“app”,而不是导出函数等

答案 4 :(得分:17)

我认为这是一个很好的方式。不仅限于表达,但我在github上看到了很多相同的node.js项目。他们取出配置参数+较小的模块(在某些情况下,每个URI)都被分解在不同的文件中。

我建议在github上通过特定于快递的项目来获得一个想法。 IMO你的方式是正确的。

答案 5 :(得分:14)

现在 2015年底,经过3年的开发和小型和大型项目。结论

不要做一个大型MVC,而是将其分开模块

因此...

<强>为什么吗

  • 通常可以在一个模块(例如产品)上工作,您可以单独更改。

  • 您可以重复使用模块

  • 您可以分开测试

  • 您可以分开更换

  • 他们有明确的(稳定的)接口

    - 最近,如果有多个开发人员在工作,模块分离有帮助

nodebootstrap项目与我的最终结构有类似的方法。 (github

此结构如何?

  1. 小型封装模块,每个模块都有单独的MVC

  2. 每个模块都有一个package.json

  3. 测试作为结构的一部分(在每个模块中)

  4. 全局配置,图书馆和服务

  5. 集成Docker,群集,永远

  6. Folderoverview(参见模块的lib文件夹):

    nodebootstrap structure

答案 6 :(得分:7)

我认为将路由添加到配置是一种不错的方法。更好的结构可能是这样的:

application/
| - app.js
| - config.js
| - public/ (assets - js, css, images)
| - views/ (all your views files)
| - libraries/ (you can also call it modules/ or routes/)
    | - users.js
    | - products.js
    | - etc...

所以products.js和users.js将包含你所有逻辑内的所有路径。

答案 7 :(得分:7)

我给MVC风格的文件夹结构请在下面找。

我们在大中型网络应用程序中使用了波纹管文件夹结构。

 myapp   
|
|
|____app
|      |____controllers
|      |    |____home.js
|      |
|      |____models
|      |     |___home.js
|      |
|      |____views
|           |___404.ejs
|           |___error.ejs
|           |___index.ejs
|           |___login.ejs
|           |___signup.ejs
|   
|
|_____config
|     |___auth.js
|     |___constants.js
|     |___database.js
|     |___passport.js
|     |___routes.js
|
|
|____lib
|    |___email.js
|
|____node_modules
|
|
|____public.js
|    |____css
|    |    |__style.css
|    |    
|    |____js
|    |    |__script.js
|    |
|    |____img
|    |    |__img.jpg
|    |
|    |
|    |____uploads
|         |__img.jpg
|      
|   
|
|_____app.js
|
|
|
|_____package.json

我为generation express mvc文件夹结构创建了一个npm模块。

请找到下面的https://www.npmjs.com/package/express-mvc-generator

生成和使用此模块的简单步骤。

i)安装模块npm install express-mvc-generator -g

ii)检查选项express -h

iii)生成明确的mvc结构express myapp

iv)安装依赖项:npm install

v)打开你的config / database.js,请配置你的mongo db。

vi)运行应用程序node appnodemon app

vii)检查网址http://localhost:8042/signuphttp://yourip:8042/signup

答案 8 :(得分:7)

自问题的最后一个答案以来已经有一段时间了,Express最近还发布了第4版,它为组织应用程序结构添加了一些有用的东西。

以下是一篇关于如何构建Express应用程序的最佳实践的最新博客文章。 http://www.terlici.com/2014/08/25/best-practices-express-structure.html

还有一个GitHub存储库应用了本文中的建议。它始终与最新的Express版本保持同步 https://github.com/terlici/base-express

答案 9 :(得分:6)

好吧,我将我的路由作为json文件,我在开头读取,并在app.js中的for循环中设置路由。 route.json包括应该调用的视图,以及将发送到路由中的值的键 这适用于许多简单的情况,但我必须为特殊情况手动创建一些路径。

答案 10 :(得分:6)

我已经写了一篇关于此事的文章。它基本上使用routeRegistrar来遍历调用其函数/controllers的文件夹init中的文件。函数init将快速app变量作为参数,以便您可以按照自己的方式注册路线。

var fs = require("fs");
var express = require("express");
var app = express();

var controllersFolderPath = __dirname + "/controllers/";
fs.readdirSync(controllersFolderPath).forEach(function(controllerName){
    if(controllerName.indexOf("Controller.js") !== -1){
        var controller = require(controllersFolderPath + controllerName);
        controller.init(app);
    }
});

app.listen(3000);

答案 11 :(得分:5)

这可能是有意义的:

https://github.com/flatiron/nconf

  

具有文件,环境变量,命令行参数和原子对象合并的分层node.js配置。

答案 12 :(得分:4)

http://locomotivejs.org/提供了一种构建使用Node.js和Express构建的应用程序的方法。

来自网站:

  

&#34;机车是Node.js的Web框架。机车支持MVC   模式,RESTful路由和约定优于配置   与任何数据库和模板引擎无缝集成。   机车以Express为基础,保留了动力和简洁性   你对Node有所期待。&#34;

答案 13 :(得分:4)

1)您的Express项目文件系统可能如下:

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

app.js - 您是全球应用容器

2)模块主文件(lib / mymodule / index.js):

var express = require('express');    
var app = module.exports = express();
// and load module dependencies ...  

// this place to set module settings
app.set('view engine', 'jade');
app.set('views', __dirname + '/views');

// then do module staff    
app.get('/mymodule/route/',function(req,res){ res.send('module works!') });

3)在主app.js中连接模块

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

4)示例逻辑

lib/login
lib/db
lib/config
lib/users
lib/verify
lib/
   /api/ 
   ...
lib/
   /admin/
      /users/
      /settings/
      /groups/
...
  • 最适合测试
  • 最适合规模
  • 分开取决于模块
  • 按功能(或模块)分组路由

tj说/在Vimeo上展示有趣的想法如何模块化表达应用 - Modular web applications with Node.js and Express。功能强大而简单。

答案 14 :(得分:2)

我最近将模块视为独立的迷你应用程序。

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

现在,对于任何模块路由(#.js),视图(* .ejs),js,css和资产彼此相邻。 子模块路由在父#Riz中设置,并带有两行额外的行

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

这样甚至可以使用子子模块。

不要忘记将视图设置为src目录

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

答案 15 :(得分:1)

这就是我的大部分快递项目目录结构的外观。

我通常做一个express dirname初始化项目,原谅我的懒惰,但它非常灵活和可扩展。 PS - 你需要获得express-generator(对于那些正在寻找它的人sudo npm install -g express-generator,sudo因为你在全球安装它)

|-- bin
    |-- www //what we start with "forever"
|-- bower_components
|-- models
    |-- database.js
    |-- model1.js //not this exact name ofcourse.
    |-- .
|-- node_modules
|-- public
    |-- images
    |-- javascripts
        |-- controllers
        |-- directives
        |-- services
        |-- app.js
        |-- init.js //contains config and used for initializing everything, I work with angular a lot.
    |-- stylesheets
|-- routes
    |-- some
    |-- hierarchy
    .
    .
|-- views
    |-- partials
    |-- content
|-- .env
|-- .env.template
|-- app.js
|-- README.md

你一定想知道为什么.env文件?因为他们工作!我在我的项目中使用dotenv模块(最近很多)并且它有效!在app.jswww

中的这两个语句中弹出
var dotenv = require('dotenv');
dotenv.config({path: path.join(__dirname + "/.env")});

另一行快速设置/bower_components以在资源/ext下提供静态内容

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

它可能适合那些希望一起使用Express和Angular的人,或者只是在没有javascripts层次结构的情况下表达。

答案 16 :(得分:1)

我的结构表达4。 https://github.com/odirleiborgert/borgert-express-boilerplate

<强>包

View engine: twig
Security: helmet
Flash: express-flash
Session: express-session
Encrypt: bcryptjs
Modules: express-load
Database: MongoDB
    ORM: Mongoose
    Mongoose Paginate
    Mongoose Validator
Logs: winston + winston-daily-rotate-file
Nodemon
CSS: stylus
Eslint + Husky

<强>结构

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

答案 17 :(得分:1)

Sails.js结构对我来说看起来很干净整洁,所以我在快递项目中使用MVC样式结构,类似于sails.js。

project_root  
|  
|_ _ app  
|_ _ |_ _ controllers  
|_ _ |_ _ |_ _ UserController.js  
|_ _ |_ _ middlewares  
|_ _ |_ _ |_ _ error.js  
|_ _ |_ _ |_ _ logger.js  
|_ _ |_ _ models  
|_ _ |_ _ |_ _ User.js  
|_ _ |_ _ services  
|_ _ |_ _ |_ _ DatabaseService.js  
|  
|_ _ config  
|_ _ |_ _ constants.js  
|_ _ |_ _ index.js  
|_ _ |_ _ routes.js  
|  
|_ _ public  
|_ _ |_ _ css  
|_ _ |_ _ images  
|_ _ |_ _ js  
|  
|_ _ views  
|_ _ |_ _ user  
|_ _ |_ _ |_ _ index.ejs  

应用文件夹-包含应用的整体登录信息。
配置文件夹-包含应用配置,常量,路由。
公共文件夹-包含样式,图像,脚本等。
视图文件夹-包含每种模型的视图(如果有)

样板项目可以在这里找到,
https://github.com/abdulmoiz251/node-express-rest-api-boilerplate

答案 18 :(得分:0)

构建ur express应用的简单方法:

  • 在main index.js中,应保持以下顺序。

      

    所有 app.set 应该是第一个。

         

    所有 app.use 应该排第二。

         

    其他api及其功能或在其他文件中继续路由

         

    示例

         

    app.use(“ / password”,passwordApi);

         

    app.use(“ / user”,userApi);

         

    app.post(“ / token”,护照.createToken);

         

    app.post(“ /登出”,护照。登出)

答案 19 :(得分:0)

使用车把和Passportjs的ExpressJs项目的MVC结构的最佳方法

>>>"War" in "Love is War"
true
>>>"War" in "LoveIsWar"
true
>>>"Warfalse" in "Love is War"
false