如何构造一个应用程序?

我正在使用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)?

谢谢你的建议!

208431 次浏览

我认为这是一个很好的方法。不限于表达,但我在github上看到了相当多的node.js项目做同样的事情。它们将配置参数+较小的模块(在某些情况下是每个URI)分解到单独的文件中。

我建议你浏览一下github上的express-specific项目。在我看来,你的做法是正确的。

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

我喜欢使用全局“应用程序”,而不是导出一个函数等

更新(2013-10-29):请看看我的另一个答案,它有JavaScript而不是CoffeeScript的流行需求,以及一个样板文件github回购和一个广泛的自述me详细介绍了我对这个主题的最新建议。

配置

你做的很好。我喜欢在顶级的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}"

这对于系统管理员编辑是友好的。然后当我需要一些东西时,比如DB连接信息,它

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

放一个自述文件。Md markdown文件在你的git回购根github。

放一个包裹。json文件,在你的NPM的git repo根中有语义版本号。

我不认为在配置中添加路由是一个好方法。一个更好的结构可以是这样的:

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会包含所有的路由和逻辑。

你可能会感兴趣:

https://github.com/flatiron/nconf

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

我已经写了一篇关于这件事的文章。它基本上使用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);

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)在main 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上显示有趣的想法如何模块化表达应用程序- # EYZ0。强大而简单。

以下是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}"
};

这对于系统管理员编辑是友好的。然后当我需要一些东西时,比如DB连接信息,它

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

放一个自述文件。Md markdown文件在你的git回购根github。

放一个包裹。json文件,在你的NPM的git repo根中有语义版本号。

好吧,已经有一段时间了,这是一个很受欢迎的问题,所以我已经向前走了,用JavaScript代码创建了一个脚手架github存储库和一个关于我如何构造一个中型express.js应用程序的长README。

focusaurus / express_code_structure是带有最新代码的repo。欢迎拉请求。

下面是README的快照,因为stackoverflow不喜欢只有链接的答案。我会做一些更新,因为这是一个新的项目,我将继续更新,但最终github回购将是这个信息的最新地方。


快速代码结构

这个项目是一个如何组织一个中型express.js web应用程序的例子。

目前至少到2016年12月14日express v4.14

Build Status

js-standard-style

你的应用程序有多大?

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

如果您的应用程序很小,就不需要像这里所示的这样深的目录结构。只要保持简单,在存储库的根目录中插入少量.js文件就可以了。瞧。

如果你的应用程序很大,在某些时候你需要把它分解成不同的npm包。一般来说,node.js方法似乎更青睐于许多小的包,至少对于库来说是这样,你应该通过使用几个npm包来构建你的应用程序,因为这开始有意义并证明开销是合理的。因此,随着应用程序的增长,某些代码在应用程序之外可以明显重用,或者是一个明显的子系统,将其移到它自己的git存储库中,并使其成为一个独立的npm包。

所以这个项目的重点是为一个中型应用程序演示一个可行的结构。

你的整体架构是什么

构建web应用程序有许多方法,例如

  • 服务器端MVC,一种Ruby on Rails
  • 单页应用样式MongoDB/Express/Angular/Node (MEAN)
  • 基本的网站与一些形式
  • 模型/操作/视图/事件风格MVC已经死了,是时候继续前进了
  • 还有很多现在和历史上的

每一个都适合不同的目录结构。对于这个例子来说,它只是一个脚手架,而不是一个完全工作的应用程序,但我假设以下关键架构点:

  • 该网站有一些传统的静态页面/模板
  • 网站的“应用程序”部分是按单页应用程序样式开发的
  • 应用程序向浏览器公开REST/JSON样式的API
  • 该应用程序模拟了一个简单的业务领域,在本例中,它是一个汽车经销商应用程序

那么Ruby on Rails呢?

这个项目贯穿始终的一个主题是,Ruby on Rails中所体现的许多思想以及它们所采用的“约定优于配置”的决策,虽然被广泛接受和使用,但实际上并没有多大帮助,有时还与这个存储库所推荐的相反。

我在这里的主要观点是,有组织代码的基本原则,并且基于这些原则,Ruby on Rails约定对Ruby on Rails社区(主要)是有意义的。然而,只是不加思索地模仿这些惯例并没有抓住重点。一旦你掌握了基本的原则,你所有的项目都将被很好地组织和清晰:shell脚本,游戏,移动应用程序,企业项目,甚至你的主目录。

对于Rails社区来说,他们希望单个Rails开发人员能够从一个应用程序切换到另一个应用程序,并且每次都熟悉并适应它。如果你是37信号或Pivotal实验室,这很有意义,而且有好处。在服务器端JavaScript的世界里,整个风气就是蛮荒的西部,我们对此并没有什么问题。这就是我们的行事风格。我们已经习惯了。即使在express.js中,它也是Sinatra的近亲,而不是Rails,从Rails中获取约定通常没有任何帮助。我甚至会说原则优于约定优于配置

基本原则和动机

    精神上要可控
    • 大脑一次只能处理和思考少量相关的事情。这就是我们使用目录的原因。它通过关注小的部分来帮助我们处理复杂的问题。
    • 李< / ul > < / > <李>大小合适
      • 不要创建“豪宅目录”,其中只有一个文件单独3个目录。您可以在Ansible最佳实践中看到这种情况,它让小项目羞于创建10+个目录来保存10+个文件,而一个目录存放3个文件会更合适。你不会开着公交车去上班(除非你是公交车司机,但即使你开着公交车去上班也不是去上班),所以不要创建那些内部文件不合理的文件系统结构。
      • 李< / ul > < / > 要模块化,但要务实
        • 节点社区总体上倾向于小模块。任何可以从你的应用中完全分离出来的东西都应该被提取到一个模块中,供内部使用或在npm上公开发布。然而,对于这里所涉及的中型应用程序,这种开销可能会给您的工作流增加单调乏味的内容,但却没有相应的价值。因此,当你有一些代码被分解出来,但不足以证明一个完全独立的npm模块时,就把它看作“proto-module”,并期望当它超过某个大小阈值时,它就会被提取出来。
        • 一些人,如@hij1nx甚至包括app/node_modules目录和package.json文件在proto-module目录中,以促进过渡并作为提醒。
        • 李< / ul > < / >
        • 易于定位代码
          • 给定一个要构建的特性或一个要修复的错误,我们的目标是开发人员可以毫不费力地找到相关的源文件。
          • 名字是有意义和准确的
          • 杂乱的代码被完全删除,而不是留在孤立的文件中或被注释掉
          • 李< / ul > < / > <李>更易被搜索到
            • 所有第一方源代码都在app目录中,所以你可以在cd中运行find/grep/xargs/ag/ack/等,不会被第三方匹配分心
            • 李< / ul > < / >
            • 使用简单明显的命名
              • NPM现在似乎要求全小写的包名。我发现这很可怕,但我必须遵循群体,因此文件名应该使用kebab-case,即使JavaScript中的变量名必须是camelCase,因为-在JavaScript中是一个减号。
              • 变量name匹配模块路径的基名,但是将kebab-case转换为camelCase
              • 李< / ul > < / >
              • 通过耦合分组,而不是通过函数分组
                • 这与Ruby on Rails的app/viewsapp/controllersapp/models等惯例有很大的不同
                • 特性被添加到一个完整的堆栈中,所以我想关注与我的特性相关的完整文件堆栈。当我向用户模型添加电话号码字段时,我不关心用户控制器以外的任何控制器,也不关心用户模型以外的任何模型。
                • 因此,这个存储库不是编辑位于各自目录中的6个文件并忽略这些目录中的大量其他文件,而是将构建一个特性所需的所有文件组织在一起
                • 根据MVC的特性,用户视图耦合到用户控制器,而用户控制器又耦合到用户模型。所以当我改变用户模型时,这3个文件通常会一起改变,但交易控制器或客户控制器是解耦的,因此不涉及。这通常也适用于非mvc设计。
                • MVC或MOVE风格的解耦在哪些代码放入哪个模块方面仍然受到鼓励,但将MVC文件分散到兄弟目录中只是令人讨厌。
                • 因此,我的每个路由文件都有它所拥有的部分路由。如果你想要应用中所有路由的概述,rails风格的routes.rb文件是很方便的,但在实际构建功能和修复错误时,你只关心与你正在更改的部分相关的路由。
                • 李< / ul > < / >
                • 将测试存储在代码旁边
                  • 这只是“通过耦合分组”的一个实例,但我想特别指出它。我写过很多项目,其中的测试都在一个名为“tests”的并行文件系统下,现在我已经开始将我的测试和它们对应的代码放在同一个目录下,我再也不会回去了。这更加模块化,更容易在文本编辑器中使用,并减轻了许多“../../..”路径的无意义内容。如果你有疑问,可以尝试一些项目,然后自己决定。除了这个,我不会做任何事来说服你,它更好。
                  • 李< / ul > < / >
                  • 减少与事件的横切耦合
                    • 很容易想到“好的,每当创建一个新交易时,我想向所有销售人员发送电子邮件”,然后只需将发送这些电子邮件的代码放在创建交易的路由中。
                    • 然而,这种耦合最终会把你的应用变成一个巨大的泥球。
                    • 相反,DealModel应该只是触发一个“create”事件,完全不知道系统可能会做什么来响应该事件。
                    • 当您以这种方式编码时,更有可能将所有与用户相关的代码放到app/users中,因为不会到处都是耦合业务逻辑的老鼠洞,这会污染用户代码库的纯度。
                    • 李< / ul > < / >
                    • 代码流是可遵循的
                      • 不要做魔法的事情。不要从文件系统中的魔法目录自动加载文件。不要成为Rails。应用程序从app/server.js:1开始,您可以通过遵循代码看到它加载和执行的所有内容。
                      • 不要为你的路线制作dsl。不要在不需要的时候做愚蠢的元编程。
                      • 如果你的应用太大了,做magicRESTRouter.route(somecontroller, {except: 'POST'})对你来说比3个基本的app.getapp.putapp.del调用更重要,那么你可能正在构建一个大到无法有效工作的整体应用。想要赢得大的胜利,而不是把3条简单的线转换成1条复杂的线。
                      • 李< / ul > < / >
                      • 使用小写的文件名

                        • 这种格式避免了跨平台文件系统大小写敏感问题
                        • npm禁止在新包名中使用大写,这样可以很好地工作

                          express.js细节< / h2 >

                        • 李< / ul > < / >
                        • 不要使用app.configure。它几乎完全没用,你根本不需要它。由于盲目的抄写,它出现在很多样板文件中。

                        • 在快递中中间件和路由的顺序很重要!!
                          • 我在stackoverflow上看到的几乎每个路由问题都是无序的快速中间件
                          • 一般来说,你希望你的路由是解耦的,不那么依赖顺序
                          • 如果你真的只需要在2条路由上使用这个中间件,那么就不要在整个应用程序中使用app.use(我在看你,body-parser)
                          • 确保当所有的都说了,做了,你有准确的顺序:
                            1. 任何超级重要的应用程序级中间件
                            2. 所有的路由和各种路由中间件
                            3. THEN错误处理程序
                            4. 李< / ol > < / > 李< / ul > < / >
                            5. 不幸的是,由于受到sinatra的启发,express.js大多假设你的所有路线都在server.js中,并且它们的顺序很清楚。对于中等规模的应用程序,将内容分解为单独的路由模块是很好的,但这确实会带来中间件无序的危险

                          应用程序符号链接技巧

                          社区在伟大的主旨为Node.js提供更好的本地require()路径中概述并详细讨论了许多方法。我可能很快就会决定要么“处理大量的../../../..”,要么使用requireFrom模块。然而,目前,我一直在使用下面详细介绍的符号链接技巧。

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

                            为你的应用程序在node_modules下创建一个符号链接
                            • CD node_modules &&Ln -nsf ../app
                            • 李< / ul > < / > 在git中添加只有node_modules/app符号链接本身,而不是整个node_modules文件夹
                              • Git添加-f node_modules/app
                              • 是的,在.gitignore文件中仍然应该有“node_modules”
                              • 不,你不应该把“node_modules”放到你的git仓库中。有些人会建议你这样做。他们是错误的。
                              • 李< / ul > < / >
                              • 现在您可以使用该前缀要求项目内模块
                                • # EYZ0
                                • # EYZ0;
                                • 李< / ul > < / >
                                • 基本上,这使得项目内部需求与外部npm模块的需求非常相似。
                                • 对不起,Windows用户,您需要坚持使用父目录相对路径。

                                配置

                                通常,代码模块和类只需要传入一个基本的JavaScript options对象。只有app/server.js应该加载app/config.js模块。从那里,它可以合成小的options对象来根据需要配置子系统,但是将每个子系统耦合到一个充满额外信息的大全局配置模块是糟糕的耦合。

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

                                NODE_ENV

                                这是另一个从Rails继承而来的诱人但糟糕的想法。在你的应用中应该有一个位置,app/config.js,它查看NODE_ENV环境变量。其他所有内容都应采用显式选项作为类构造函数参数或模块配置参数。

                                如果电子邮件模块有一个关于如何发送电子邮件的选项(SMTP,登录到标准输出,放入队列等),它应该采取像{deliver: 'stdout'}这样的选项,但它绝对不应该检查NODE_ENV

                                测试

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

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

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

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

                                这个项目的作用域主要是关于文件和目录的位置,我不想添加太多其他作用域,但我只想提到,我将代码组织成3个不同的部分。

                                1. CommonJS的打开块需要调用状态依赖项
                                2. 纯javascript的主要代码块。这里没有CommonJS污染。不要引用导出、模块或require。
                                3. CommonJS设置导出的关闭块

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

每个路由模块都是独立的

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

来自网站:

机车是一个Node.js的web框架。机车支持MVC 模式、RESTful路由和约定优于配置,而 与任何数据库和模板引擎无缝集成。 机车建立在快车,保留权力和简单 您对Node的期望。" < / p >

距离上次回答这个问题已经有一段时间了,Express最近也发布了第4版,它增加了一些有用的东西来组织应用程序结构。

下面是一篇关于如何构建Express应用程序的最佳实践的最新博客文章。 # EYZ0 < / p > 还有一个GitHub存储库应用了文章中的建议。它总是最新的Express版本。
# EYZ0 < / p >

这是我的大多数express项目目录结构的外观。

我通常使用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层次结构的人。

现在是2015年底,在开发我的结构3年之后,在小型和大型项目中。结论?

不做一个大的MVC,而是在模块中分离

所以…

为什么?

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

  • 您可以重用模块

  • 你可以单独测试它

  • 你可以单独替换它

  • 他们有清晰(稳定)的接口

    至少,如果有多个开发人员工作,模块分离有助于

nodebootstrap项目与我的最终结构采用了类似的方法。(# EYZ1)

这个结构是什么样的?

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

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

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

  4. 全局配置,库和服务

  5. 集成Docker,集群,永远

文件夹概述(参见lib文件夹中的模块):

nodebootstrap structure

我最近把模块当成了独立的小应用。

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

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

不要忘记将view设置为src目录

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

我给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)生成快捷mvc结构express myapp

iv)安装依赖项:npm install:

v)打开config/database.js, Please configure your mongo db。

vi)运行node appnodemon app应用程序

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

我的结构表达4。 # EYZ0 < / p >

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

一个简单的方法来结构你的express应用程序:

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

    所有app.set应该放在第一位。

    所有app.use应该是第二。

    然后是其他api及其函数或其他文件中的route-continue

    简单的

    app.use(“/密码”,passwordApi);

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

    app.post(“/令牌”,passport.createToken);

    app.post(“/注销”,passport.logout)

    李< /引用> < / >

为ExpressJs项目提供MVC结构的最佳方法Passportjs

- 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

js结构看起来很好,干净给我,所以我使用MVC风格的结构为我的表达项目,类似于帆。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

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

样板项目可以在这里找到,
# EYZ0 < / p >