我正在使用NodeJS的ExpressJS Web框架.
使用ExpressJS的人将他们的环境(开发,生产,测试......),他们的路线等放在了app.js.我认为这不是一个很好的方式,因为当你有一个很大的应用程序时,app.js太大了!
我想有这个目录结构:
| my-application
| -- app.js
| -- config/
| -- environment.js
| -- routes.js
Run Code Online (Sandbox Code Playgroud)
这是我的代码:
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);
Run Code Online (Sandbox Code Playgroud)
配置/ 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());
});
};
Run Code Online (Sandbox Code Playgroud)
配置/ routes.js
module.exports = function(app) {
app.get('/', function(req, res) {
res.send('Hello world !');
});
};
Run Code Online (Sandbox Code Playgroud)
我的代码运行良好,我认为目录的结构很漂亮.但是,代码必须进行调整,我不确定它是好还是漂亮.
使用我的目录结构并调整代码或只使用一个文件(app.js)更好吗?
谢谢你的建议!
Pet*_*ons 294
好吧,它已经有一段时间了,这是一个很受欢迎的问题,所以我继续创建了一个带有JavaScript代码的脚手架github存储库和一个关于我如何构建一个中型express.js应用程序的漫长自述文件.
focusaurus/express_code_structure是具有最新代码的repo.拉请求欢迎.
这是README的快照,因为stackoverflow不喜欢只是一个链接的答案.我将进行一些更新,因为这是一个我将继续更新的新项目,但最终github repo将成为此信息的最新位置.
该项目是如何组织中型express.js Web应用程序的示例.
目前至少表达2016年12月第4季度
Web应用程序并不完全相同,在我看来,并不是应该应用于所有express.js应用程序的单一代码结构.
如果您的应用程序很小,则不需要这样的深层目录结构.只需保持简单,并将少量.js文件粘贴到存储库的根目录中即可.瞧.
如果您的应用程序非常庞大,那么在某些时候您需要将其分解为不同的npm包.一般来说,node.js方法似乎支持许多小包,至少对于库而言,你应该通过使用几个npm包来构建你的应用程序,因为它开始有意义并且证明了开销.因此,当您的应用程序增长并且某些部分代码在应用程序之外变得清晰可重用或者是一个清晰的子系统时,将其移动到它自己的git存储库并将其转换为独立的npm包.
因此,该项目的重点是为中型应用程序说明可行的结构.
有许多方法可用于构建Web应用程序,例如
每个都很适合不同的目录结构.出于这个例子的目的,它只是脚手架而不是一个完全正常工作的应用程序,但我假设以下关键架构点:
这将是整个项目的一个主题,Ruby on Rails中体现的许多想法和他们采用的"约定优于配置"决策虽然被广泛接受和使用,但实际上并不是非常有用,有时与此存储库的相反建议.
我的主要观点是组织代码有基本原则,并且基于这些原则,Ruby on Rails约定(主要)对Ruby on Rails社区有意义.然而,只是不加思索地对这些公约进行抨击,忽略了这一点.一旦了解了基本原则,您的所有项目都将得到良好的组织和清晰:shell脚本,游戏,移动应用程序,企业项目,甚至是您的主目录.
对于Rails社区,他们希望能够有一个Rails开发人员从应用程序到应用程序切换到应用程序,并且每次都熟悉并熟悉它.如果您是37个信号或Pivotal Labs,这很有意义,并且有好处.在服务器端的JavaScript世界中,整体的风格是西方任何事情都变得越来越狂野,我们并没有真正的问题.这就是我们如何滚动.我们已经习惯了.即使在express.js中,它也是Sinatra的亲密关系,而不是Rails,从Rails获取约定通常无济于事.我甚至会说"关于配置的约定原则".
app/node_modules目录,并且package.json在proto-module目录中有文件以便于转换并充当提醒.app目录中,因此您可以cd运行find/grep/xargs/ag/ack/etc而不会被第三方匹配分心kebab-case即使JavaScript中的变量名必须是camelCase因为JavaScript -中的减号,文件名也应该使用.kebab-case转换为camelCaseapp/views,app/controllers,app/models,等routes.rb如果您想要了解应用程序中所有路径的概述,那么使用rails样式文件很方便,但是在实际构建功能和修复错误时,您只关心与要更改的部分相关的路径.app/users其中的可能性要大得多,因为在整个地方都没有老鼠的耦合业务逻辑嵌套来污染用户代码库的纯度.app/server.js:1,您可以按照代码查看加载和执行的所有内容.magicRESTRouter.route(somecontroller, {except: 'POST'})是为你在3个基本一大胜利app.get,app.put,app.del,电话,你可能会建立一个整体的应用程序,是太大了有效工作的.喜欢BIG胜利,而不是将3条简单的线转换为1条复杂的线.使用lower-kebab-case文件名
不要用app.configure.它几乎完全没用,你只是不需要它.由于无意识的copypasta,它有很多样板.
app.use如果您真的只需要2条路线的中间件(我正在看着你body-parser),请不要用于整个应用程序server.js并且很清楚它们是如何订购的.对于中型应用程序,将事物分解为单独的路径模块是很好的,但它确实引入了无序中间件的危险社区在Node.js的伟大要点Better local require()路径中详细介绍和讨论了许多方法.我可能很快就会选择"只处理大量的../../../ .."或使用requireFrom modlue.但是,目前,我一直在使用下面详述的符号链接技巧.
因此,避免项目内部的一种方法需要使用恼人的相对路径,例如require("../../../config")使用以下技巧:
.gitignore文件中仍然应该有"node_modules"var config = require("app/config");var DealModel = require("app/deals/deal-model");通常代码模块和类只需要options传入基本的JavaScript 对象.只app/server.js应该加载app/config.js模块.从那里它可以合成小options对象以根据需要配置子系统,但是将每个子系统耦合到充满额外信息的大型全局配置模块是不良耦合.
尝试集中创建数据库连接并将其传递到子系统,而不是传递连接参数,并让子系统自己进行传出连接.
这是从Rails继承的另一个诱人但可怕的想法.您的应用中应该只有一个位置,app/config.js它会查看NODE_ENV环境变量.其他所有内容都应该作为类构造函数参数或模块配置参数使用显式选项.
如果电子邮件模块有关于如何传递电子邮件(SMTP,登录到stdout,放入队列等)的选项,它应该采取类似的选项,{deliver: 'stdout'}但它绝对不应该检查NODE_ENV.
我现在将我的测试文件保存在与其相应代码相同的目录中,并使用文件扩展名命名约定来区分测试和生产代码.
foo.js 有模块"foo"的代码foo.tape.js 有foo的基于节点的测试,并且生活在同一个目录中foo.btape.js 可用于需要在浏览器环境中执行的测试我使用filesystem globs和find . -name '*.tape.js'命令来访问我所有的测试.
.js模块文件中组织代码这个项目的范围主要是关于文件和目录的位置,我不想添加很多其他范围,但我只想提一下,我将我的代码组织成3个不同的部分.
Pet*_*ons 156
更新(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}"
Run Code Online (Sandbox Code Playgroud)
这对系统管理员编辑很友好.然后当我需要某些东西时,比如数据库连接信息,它就是
require('./config').db.URL
Run Code Online (Sandbox Code Playgroud)
路线/控制器
我喜欢将我的路由留给我的控制器并将它们组织在一个app/controllers子目录中.然后我可以加载它们并让它们添加它们需要的任何路径.
在我的app/server.coffeecoffeescript文件中,我做:
[
'api'
'authorization'
'authentication'
'domains'
'users'
'stylesheets'
'javascripts'
'tests'
'sales'
].map (controllerName) ->
controller = require './controllers/' + controllerName
controller.setup app
Run Code Online (Sandbox Code Playgroud)
所以我有这样的文件:
app/controllers/api.coffee
app/controllers/authorization.coffee
app/controllers/authentication.coffee
app/controllers/domains.coffee
Run Code Online (Sandbox Code Playgroud)
例如在我的域控制器中,我有这样的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
Run Code Online (Sandbox Code Playgroud)
查看
提出意见app/views正在成为习惯的地方.我把它像这样摆好.
app/views/layout.jade
app/views/about.jade
app/views/user/EditUser.jade
app/views/domain/EditDomain.jade
Run Code Online (Sandbox Code Playgroud)
静态文件
进入一个public子目录.
Github上/ Semver/NPM
在您的git repo root上放置一个README.md markdown文件,用于github.
将一个带有语义版本号的package.json文件放在你的git repo root中,用于NPM.
dth*_*ree 52
以下是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}"
};
Run Code Online (Sandbox Code Playgroud)
这对系统管理员编辑很友好.然后当我需要某些东西时,比如数据库连接信息,它就是
require('./config').db.URL
Run Code Online (Sandbox Code Playgroud)
路线/控制器
我喜欢将我的路由留给我的控制器并将它们组织在一个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);
});
Run Code Online (Sandbox Code Playgroud)
所以我有这样的文件:
app/controllers/api.js
app/controllers/authorization.js
app/controllers/authentication.js
app/controllers/domains.js
Run Code Online (Sandbox Code Playgroud)
例如在我的域控制器中,我有这样的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);
});
}
Run Code Online (Sandbox Code Playgroud)
查看
提出意见app/views正在成为习惯的地方.我把它像这样摆好.
app/views/layout.jade
app/views/about.jade
app/views/user/EditUser.jade
app/views/domain/EditDomain.jade
Run Code Online (Sandbox Code Playgroud)
静态文件
进入一个public子目录.
Github上/ Semver/NPM
在您的git repo root上放置一个README.md markdown文件,用于github.
将一个带有语义版本号的package.json文件放在你的git repo root中,用于NPM.
San*_*nda 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, ...)
Run Code Online (Sandbox Code Playgroud)
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();
});
Run Code Online (Sandbox Code Playgroud)
路线/
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);
});
};
Run Code Online (Sandbox Code Playgroud)
使用该模块,创建新的路由定义和实现非常简单.例如,hello.js:
function hello(req, res) {
res.send('Hello world');
}
module.exports = function (app) {
app.get('/api/hello_world', hello);
};
Run Code Online (Sandbox Code Playgroud)
每个路由模块都是独立的.
nee*_*ebz 17
我认为这是一个很好的方式.不仅限于表达,但我在github上看到了很多相同的node.js项目.它们取出配置参数+较小的模块(在某些情况下,每个URI)都被分解在单独的文件中.
我建议在github上通过特定于快递的项目来获得一个想法.IMO你的方式是正确的.
Sim*_*kir 15
它现在是2015年底,经过3年的开发和小型和大型项目.结论?
不要做一个大的MVC,而是将它分成模块
所以...
为什么?
通常可以在一个模块(例如产品)上工作,您可以单独更改.
您可以重用模块
你可以分别测试它
你可以分开更换它
它们具有清晰(稳定)的接口
- 最新的,如果有多个开发人员在工作,模块分离会有所帮助
该nodebootstrap项目也有类似的做法,以我的最终结构.(github)
这个结构怎么样?
小型封装模块,每个模块都有独立的MVC
每个模块都有一个package.json
作为结构的一部分进行测试(在每个模块中)
全局配置,库和服务
集成Docker,集群,永远
Folderoverview(参见模块的lib文件夹):
我不认为将路由添加到配置是一个好方法.更好的结构可能是这样的:
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...
Run Code Online (Sandbox Code Playgroud)
所以products.js和users.js将包含你所有逻辑内的所有路由.
自问题的最后一个答案以来已经有一段时间了,Express最近还发布了第4版,它为组织应用程序结构添加了一些有用的东西.
以下是关于如何构建Express应用程序的最佳实践的最新博客文章. http://www.terlici.com/2014/08/25/best-practices-express-structure.html
还有一个GitHub存储库应用了本文中的建议.它始终与最新的Express版本保持同步.
https://github.com/terlici/base-express
我给MVC风格的文件夹结构请找下面.
我们在大中型Web应用程序中使用了bellow文件夹结构.
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
Run Code Online (Sandbox Code Playgroud)
我为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 app或nodemon app
vii)检查URL http:// localhost:8042/signup或http:// yourip:8042/signup
好吧,我将我的路由作为json文件,我在开头读取,并在app.js中的for循环中设置路由.route.json包括应该调用的视图,以及将发送到路由的值的键.
这适用于许多简单的情况,但我必须为特殊情况手动创建一些路由.
我已经写了一篇关于此事的文章.它基本上使用了一个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);
Run Code Online (Sandbox Code Playgroud)
http://locomotivejs.org/提供了一种构建使用 Node.js 和 Express 构建的应用程序的方法。
来自网站:
“Locomotive 是 Node.js 的 Web 框架。Locomotive 支持 MVC 模式、RESTful 路由和约定优于配置,同时与任何数据库和模板引擎无缝集成。Locomotive 基于 Express 构建,保留了您所期望的强大功能和简单性来自节点。”
| 归档时间: |
|
| 查看次数: |
159717 次 |
| 最近记录: |