ExpressJS如何构建应用程序?


526

我正在为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);

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

我的代码运行良好,我认为目录的结构很漂亮。但是,必须对代码进行修改,但我不确定代码是否良好/美观。

使用我的目录结构并修改代码还是只使用一个文件(app.js)更好?

感谢您的建议!


这样做的性能问题是否仍然存在?我记得在某处(也许是快递小组)读过,当您将所有此类内容分开时,会损失很多性能。像您的请求/秒之类的东西会下降很多,几乎就像是一个错误。
AntelopeSalad

2
它来自Express Google小组。这是链接: groups.google.com/group/express-js/browse_thread/thread/…–
AntelopeSalad

52
不,这是非常不真实的
tjholowaychuk 2011年

Answers:


306

好的,已经有一段时间了,这是一个很普遍的问题,所以我继续前进,创建了一个带有JavaScript代码的脚手架github存储库,以及有关我喜欢如何构建一个中型express.js应用程序的自述文件。

focusaurus / express_code_structure是具有最新代码的存储库。拉请求欢迎。

这是自述文件的快照,因为stackoverflow不喜欢仅链接的答案。我将进行一些更新,因为这是我将继续更新的新项目,但是最终github回购将是此信息的最新信息。


快速代码结构

该项目是如何组织中型express.js Web应用程序的示例。

当前至少要表达v4.14 2016年12月

建立状态

js-标准样式

您的应用程序有多大?

Web应用程序并不完全相同,在我看来,没有一种代码结构可以应用于所有express.js应用程序。

如果您的应用程序很小,则不需要此处所示的深层目录结构。只需保持简单,然后将少量.js文件粘贴到存储库的根目录即可。Voilà。

如果您的应用程序很大,则有时需要将其分解为不同的npm软件包。通常,node.js方法似乎倾向于使用许多小型软件包,至少对于库而言是如此,并且您应该通过使用几个npm软件包来构建应用程序,因为这开始变得有意义并证明了开销。因此,随着您的应用程序的增长以及部分代码在您的应用程序外部或作为清晰的子系统可以清楚地重用,请将其移至其自己的git存储库中,并将其放入独立的npm包中。

因此,该项目的重点是说明中型应用程序的可行结构。

你的整体架构是什么

有多种构建Web应用程序的方法,例如

  • 服务器端MVC和Ruby on Rails
  • 单页应用程序样式为MongoDB / Express / Angular / Node(MEAN)
  • 具有某些形式的基本网站
  • MVC的模型/操作/视图/事件样式已死,现在该进行MOVE了
  • 和许多其他当前和历史

这些都很好地适合于不同的目录结构。就本示例而言,它只是脚手架,而不是功能全面的应用程序,但是我假设以下关键体系结构要点:

  • 该网站有一些传统的静态页面/模板
  • 该站点的“应用程序”部分被开发为“单页应用程序”样式
  • 该应用程序向浏览器公开REST / JSON样式的API
  • 该应用程序为一个简单的业务领域建模,在这种情况下,它是一个汽车经销商应用程序

Ruby on Rails呢?

在整个项目中,将成为一个主题,Ruby on Rails中体现的许多想法及其采纳的“配置公约”决定尽管被广泛接受和使用,但实际上并没有什么帮助,有时与该存储库相反推荐。

我的主要观点是组织代码具有一些基本原则,基于这些原则,Ruby on Rails约定(大多数情况下)对Ruby on Rails社区有意义。但是,仅仅不加思索地修改这些约定就没有意义。一旦掌握了基本原理,您的所有项目都将井井有条,清晰:shell脚本,游戏,移动应用程序,企业项目,甚至您的主目录。

对于Rails社区,他们希望能够有一个Rails开发人员从一个应用程序切换到另一个应用程序,并且每次都熟悉并满意。如果您是37个信号机或Pivotal Labs,这非常有意义,并且会有所帮助。在服务器端JavaScript世界中,总体上来说,风风雨雨无处不在,我们对此并不存在任何疑问。我们就是这样滚动的。我们已经习惯了。即使在express.js中,它也是Sinatra的近亲,而不是Rails,从Rails取得约定通常无济于事。我什至会说原则优于约定而不是配置

基本原理和动机

  • 在精神上易于管理
    • 大脑只能一次处理并思考少量相关事物。这就是为什么我们使用目录。通过专注于小部分,它可以帮助我们应对复杂性。
  • 尺寸合适
    • 不要创建“ Mansion Directories”,其中只有1个文件,仅3个目录向下。您可以在Ansible Best Practices中看到这种情况,该做法会使小型项目蒙羞地创建10个以上的目录来容纳10个以上的文件,而1个目录和3个文件更合适。您不会开车去上班(除非您是公共汽车司机,但是即使您在工作时开车去上班也不能上班),所以也不要创建文件系统结构,该文件系统结构不能由其中的实际文件来证明。
  • 模块化但务实
    • 节点社区总体上偏爱小型模块。任何可以从您的应用程序中完全分离出来的内容都应提取到模块中,以供内部使用或在npm上公开发布。但是,对于此处适用的中型应用程序,此操作的开销可能会使乏味的添加到您的工作流中而没有相应的价值。因此,当您有一些代码被分解但不足以证明一个完全独立的npm模块的时间时,只需将其视为“ 原型模块 ”,并期望当它超过某个大小阈值时,它将被提取出来。
    • 诸如@ hij1nx之类的某些人甚至包括app/node_modules目录,并package.json原型模块目录中包含文件,以促进该过渡并起到提醒作用。
  • 易于查找代码
    • 给定要构建的功能或要修复的错误,我们的目标是使开发人员可以轻松地找到所涉及的源文件。
    • 名称有意义且准确
    • 杂乱无章的代码已完全删除,没有留在孤立文件中或仅被注释掉了
  • 易于搜索
    • 所有第一方源代码都在app目录中,因此您可以cd运行find / grep / xargs / ag / ack / etc并不受第三方匹配的干扰
  • 使用简单明了的命名
    • npm现在似乎要求使用全小写的软件包名称。我觉得这主要是可怕的,但我必须随大流,这样的文件名应该使用kebab-case,即使必须是对JavaScript中的变量名camelCase,因为-在JavaScript中有一个减号。
    • 变量名称与模块路径的基本名称匹配,但已kebab-case转换为camelCase
  • 按耦合分组,而不按功能分组
    • 这是从的Ruby on Rails的惯例是一大飞跃app/viewsapp/controllersapp/models,等
    • 功能已添加到完整堆栈中,因此我想重点关注与功能相关的完整文件堆栈。当我在用户模型中添加电话号码字段时,除了用户控制器外,我不在乎任何控制器,除了用户模型外,我也不在乎任何模型。
    • 因此,与其编辑每个目录中的6个文件并忽略这些目录中的其他文件,不如将这个存储库组织起来,以便将我需要构建功能的所有文件都放在同一位置
    • 通过MVC的性质,用户视图耦合到与用户模型耦合的用户控制器。因此,当我更改用户模型时,这3个文件通常会一起更改,但是交易控制器或客户控制器是分离的,因此不涉及。通常,非MVC设计也是如此。
    • MVC或MOVE样式的去耦在哪个代码进入哪个模块方面仍然受到鼓励,但是将MVC文件散布到同级目录只是令人讨厌。
    • 因此,我的每个路由文件都具有其拥有的部分路由。routes.rb如果想要了解应用程序中所有路线的概述,则使用Rails样式的文件很方便,但是在实际构建功能和修复错误时,您只关心与要更改的零件相关的路线。
  • 将测试存储在代码旁边
    • 这只是“通过耦合进行分组”的一个实例,但我想特别指出。我已经编写了许多项目,这些测试都存在于名为“ tests”的并行文件系统下,并且现在我开始将测试与相应代码放在同一目录中,我再也不会回头。这更加模块化,并且在文本编辑器中更易于使用,并且减轻了许多“ ../../ ..”路径的胡扯。如果您有疑问,请尝试几个项目并自己决定。除此以外,我不会做任何其他事情来使您相信它会更好。
  • 减少与事件的跨领域耦合
    • 容易想到“确定,每当创建新交易时,我都想向所有销售人员发送电子邮件”,然后只需将代码发送到创建交易的路径中即可。
    • 但是,这种耦合最终会将您的应用程序变成一个巨大的泥泞球。
    • 取而代之的是,DealModel应该只触发一个“ create”事件,并且完全不知道系统可能会对此做出什么反应。
    • 当您以这种方式进行编码时,将所有与用户相关的代码放入app/users其中的可能性变得更大,因为到处都是耦合业务逻辑的棘手问题,这污染了用户代码库的纯度。
  • 代码流是可遵循的
    • 不要做魔术。不要从文件系统中的魔术目录自动加载文件。不要成为Rails。该应用程序始于,app/server.js:1您可以按照以下代码查看加载和执行的所有内容。
    • 不要为您的路由创建DSL。当不需要它时,不要执行愚蠢的元编程。
    • 如果你的应用程序是如此之大,这样做magicRESTRouter.route(somecontroller, {except: 'POST'})是一个巨大的胜利为你在3个基本app.getapp.putapp.del,电话,你可能会建立一个整体的应用程序,是太大了有效工作的。赢得大笔大奖,而不是将3条简单的线转换为1条复杂的线。
  • 使用小写字母的文件名

    • 这种格式避免了跨平台的文件系统区分大小写的问题
    • npm禁止在新的程序包名称中使用大写字母,这很适合

      express.js的细节

  • 不要使用app.configure。它几乎完全没有用,您只是不需要它。由于无意识的复制,它的样板很多。

  • 紧急情况下中途和路线的顺序!!!
    • 我在stackoverflow上看到的几乎每个路由问题都是乱序的快速中间件
    • 通常,您希望您的路线解耦,而不是太依赖顺序
    • app.use如果您确实只需要2条路由的中间件,则不要用在您的整个应用程序中(我在看着您,body-parser
    • 确定说完所有步骤后,您便拥有以下命令:
      1. 任何超重要的应用程序范围的中间件
      2. 您的所有路线和各种路线中间件
      3. 然后错误处理程序
  • 可悲的是,受到sinatra的启发,express.js大多假设您的所有路线都将进入server.js,并且将清楚如何排序它们。对于中型应用程序,将内容分解为单独的路由模块是不错的选择,但它的确引入了乱序中间件的风险

应用程序符号链接技巧

社区在针对Node.js的更好的本地更好的require()路径中概述并讨论了许多方法。我可能很快会决定选择“只处理大量的../../../ ..”还是使用requireFrom模块。但是,此刻,我一直在使用下面详述的symlink技巧。

因此,避免require("../../../config")使用类似恼人的相对路径来避免项目内需求的一种方法是使用以下技巧:

  • 在您的应用程序的node_modules下创建符号链接
    • cd node_modules && ln -nsf ../app
  • 加上刚刚node_modules /应用程序符号链接本身,而不是整个文件夹node_modules,到混帐
    • git add -f node_modules / app
    • 是的,您的.gitignore文件中仍应包含“ node_modules”
    • 不,您不应将“ node_modules”放入git存储库。有人会建议您这样做。他们是不正确的。
  • 现在您可以要求使用此前缀的项目内模块
    • var config = require("app/config");
    • var DealModel = require("app/deals/deal-model");
  • 基本上,这使得项目内需求与外部npm模块的需求非常相似。
  • 抱歉,Windows用户需要坚持父目录的相对路径。

组态

通常,代码模块和类仅期望options传入基本的JavaScript 对象。仅app/server.js应加载app/config.js模块。从那里可以options根据需要合成小对象以配置子系统,但是将每个子系统耦合到一个充满额外信息的大型全局配置模块上,则是不好的结合。

尝试集中创建数据库连接并将其传递到子系统中,而不是传递连接参数并让子系统自己进行传出连接。

NODE_ENV

这是Rails提出的另一个诱人但可怕的想法。您的应用中应该恰好有1个位置,app/config.js它可以查看NODE_ENV环境变量。其他所有内容都应采用显式选项作为类构造函数参数或模块配置参数。

如果电子邮件模块具有关于如何传递电子邮件的选项(SMTP,登录到stdout,放入队列等),则应采用类似的选项,{deliver: 'stdout'}但绝对不要选中NODE_ENV

测验

现在,我将测试文件与其对应的代码保存在同一目录中,并使用文件扩展名命名约定将测试与生产代码区分开。

  • foo.js 具有模块“ foo”的代码
  • foo.tape.js 具有针对foo的基于节点的测试,并位于同一目录中
  • foo.btape.js 可以用于需要在浏览器环境中执行的测试

我使用文件系统全局文件和find . -name '*.tape.js'命令来根据需要访问所有测试。

如何在每个.js模块文件中组织代码

这个项目的范围主要是关于文件和目录的位置,并且我不想添加其他范围,但是我只想提到我将代码组织为3个不同的部分。

  1. CommonJS的开放块要求调用状态依赖项
  2. 纯JavaScript的主要代码块。这里没有CommonJS污染。不要引用导出,模块或要求。
  3. 关闭CommonJS以设置导出

1
如果只有很少的路由使用它,应该使用什么代替bodyParser?
Ilan Frumer 2014年

3
我发现我一直在寻找的位置:stackoverflow.com/questions/12418372/...
宜兰Frumer

1
@wlingke,请访问gist.github.com/branneman/8048520,以详细讨论该问题的可用方法。
彼得·里昂斯

@peterLyons感谢您的分享。阅读完之后,我想我会写一个启动脚本。谢谢!
wlingke

2
至于在该应用程序的符号链接技巧,有这样的小模块,这使得所有的问题消失
海科科里

157

更新(2013-10-29):也请参阅我的其他答案,该书具有受大众欢迎的JavaScript而不是CoffeeScript的代码,以及样板的github存储库和详尽的自述文件,详细介绍了我在该主题上的最新建议。

设定档

你在做什么很好。我喜欢在具有config.coffee嵌套名称空间的顶级文件中设置自己的配置名称空间。

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

这对于s​​ysadmin编辑很友好。然后,当我需要诸如数据库连接信息之类的信息时,

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

路线/控制器

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

在我的app/server.coffeecoffeescript文件中,我做了:

[
  '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 markdown文件放在github的git repo根目录下。

将具有语义版本号的package.json文件放入NPM的git repo根目录中。


1
嘿,彼得!我真的很喜欢您要使用的这种方法。我正在开发一个快速项目,我真的想以正确的方式来做事情,而不只是去破解它并摆放它。如果您在github上有示例存储库和/或在其上有博客文章,那就太好了。
suVasH ..... 2012年

4
这个仓库有很多模式可以作为参考:github.com/focusaurus/peterlyons.com
Peter Lyons

75
Coffee脚本很难阅读://是否有机会进行香草JS编辑?谢谢
toasted_flakes

1
感谢您的回答。我只是想把我的想法包起来。您如何访问另一个内部的其他控制器(例如,在上述设置功能中app.put route, api.needId
chmanie

@PeterLyons:嘿,我确实看到了您的源代码,但不知道如何执行构建模式,我已经安装Go并将bin文件包含到结构中。您如何在其中运行该go文件bin
user2002495 2014年

51

以下是Peter Lyons的逐字回答,应其他一些人的要求,从Coffeescript移植到Vanilla JS。彼得的答案非常有能力,任何对我的答案进行投票的人也应该对他的投票。


设定档

你在做什么很好。我喜欢在具有config.js嵌套名称空间的顶级文件中设置自己的配置名称空间。

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

这对于s​​ysadmin编辑很友好。然后,当我需要诸如数据库连接信息之类的信息时,

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

路线/控制器

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

在我的app/server.jsJavaScript文件中,我这样做:

[
  '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 markdown文件放在github的git repo根目录下。

将具有语义版本号的package.json文件放入NPM的git repo根目录中。


43

我的问题是在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();
});

路线/

路由目录中有一个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);
};

每个路由模块都是独立的


您是否使用生成器来创建此结构?
Ashish


17

我认为这是一种很棒的方法。不限于表达,但我已经在github上看到了很多node.js项目在做同样的事情。他们取出配置参数+较小的模块(在某些情况下,每个URI)都放在单独的文件中。

我建议在github上进行特定于快递的项目,以获得一个想法。海事组织的做法是正确的。


16

现在是2015年底,在发展了3年的结构后,无论是大型项目还是大型项目,我的想法都得到了体现。结论?

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

所以...

为什么?

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

  • 您可以重用模块

  • 您可以单独进行测试

  • 您可以分开更换

  • 它们具有清晰(稳定)的界面

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

nodebootstrap项目也有类似的做法,以我的最终结构。(github

这种结构看起来如何?

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

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

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

  4. 全局配置,库和服务

  5. 永久集成的Docker,集群

Folderoverview(有关模块,请参见lib文件夹):

nodebootstrap结构


3
如果您还可以使用扩展的各个模块来更新文件夹概述图片,这将对您有所帮助,例如,如何构造它们的示例。
youngrrrr

8

我正在提供MVC样式的文件夹结构,请在下面找到。

我们将波纹管文件夹结构用于大中型Web应用程序。

 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

我已经创建了一个用于生成express mvc文件夹结构器的npm模块。

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

只需简单的步骤即可生成和使用此模块。

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

ii)检查选项 express -h

iii)生成Express MVC结构 express myapp

iv)安装依赖项npm install

v)打开您的config / database.js,请配置您的mongo数据库。

vi)运行应用程序node appnodemon app

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


7

自从对这个问题的最后一个答案以来已经过去了很长时间,Express最近还发布了版本4,该版本添加了一些用于组织应用程序结构的有用信息。

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

还有一个GitHub存储库,其中应用了本文中的建议。最新的Express版本始终是最新的。
https://github.com/terlici/base-express


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将包含您的所有路由,并且其中包含所有逻辑。


6

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


6

我已经写了一篇关于这个问题的帖子。基本上,它使用a routeRegistrar遍历/controllers调用其函数的文件夹中的文件init。函数init将express 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);


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上说出/展示了一个有趣的想法,即如何模块化快递应用程序- 使用Node.js和Express的模块化Web应用程序。强大而简单。


4

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

从网站:

“ Locomotive是一个用于Node.js的Web框架。机车支持MVC模式,RESTful路由和配置约定,同时与任何数据库和模板引擎无缝集成。机车基于Express构建,保留了您所期望的功能和简单性来自Node。”


3

我最近将模块作为独立的微型应用程序使用。

|-- 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和资产彼此相邻。子模块路由在父#.js中设置,另外两行

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

这样,甚至子子模块也是可能的。

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

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

任何有兴趣查看路线如何加载的github链接的结构,视图和模型的加载方式
Muhammad Umer,2018年

我认为一切都可以解释。路线只是经典的快车路线。视图需要以模块名称为前缀进行加载,模型需要通过引用相对路径来进行加载。
zevero

在最后一行,我将视图设置为src目录。因此,从这里开始,所有视图都可以相对于src目录访问。没有什么花哨。
zevero

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.js或中弹出这两个语句www

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层次结构的情况下进行表达的人。


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

0

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

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

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

    所有app.use应该是第二位。

    其后是其他api及其功能或其他文件中的route-continue

    实例

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

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

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

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


0

带有把手和Passportjs的ExpressJs项目的MVC结构的最佳方法

- app
      -config 
        -passport-setup.js
      -controllers
      -middleware
      -models
      -routes
      -service
    -bin
      -www
      -configuration.js
      -passport.js
    -node_modules
    -views
     -handlebars page
    -env
    -.gitignore
    -package.json
    -package-lock.json

@ sandro-munda,请检查
Manishkumar Bhavnani
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.