ExpressJS如何构build应用程序?
我正在使用NodeJS的ExpressJS Web框架。
使用ExpressJS的人把他们的环境(开发,生产,testing…),他们的路线等放在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);
configuration/ 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()); }); };
configuration/ routes.js
module.exports = function(app) { app.get('/', function(req, res) { res.send('Hello world !'); }); };
我的代码运行良好,我认为目录的结构是美丽的。 但是,代码必须适应,我不确定它是好还是美。
使用我的目录结构并修改代码或仅使用一个文件(app.js)更好吗?
感谢您的build议!
好吧,这已经有一段时间了,这是一个很受欢迎的问题,所以我已经提前创build了一个带有JavaScript代码的脚手架github存储库和一个关于如何构build中型express.js应用程序的长篇README。
focusaurus / express_code_structure是具有最新代码的回购。 拉请求欢迎。
这里是README的快照,因为stackoverflow不喜欢只是一个链接的答案。 我会做一些更新,因为这是一个新的项目,我会继续更新,但最终github回购将是最新的这个信息的地方。
快速代码结构
这个项目是如何组织一个中等规模的express.js Web应用程序的例子。
目前至less要expression2016年12月的第4.14版
你的申请有多大?
Web应用程序并不完全相同,在我看来,并不是所有的express.js应用程序都应该使用单一的代码结构。
如果您的应用程序很小,则不需要如此处所示的深度目录结构。 只要保持简单,并将一些.js
文件粘贴到存储库的根目录下即可。 瞧。
如果你的应用程序非常庞大,在某些时候你需要把它分解成不同的npm包。 一般情况下,node.js方法似乎赞成许多小包,至less对于库来说,你应该使用几个npm包来构build你的应用程序,因为这开始有意义,并certificate了开销。 因此,随着应用程序的增长,代码的某些部分在您的应用程序之外明显可重用,或者是一个明确的子系统,请将其移至自己的git存储库,并将其转换为独立的npm包。
所以这个项目的重点是为中型应用程序说明一个可行的结构。
你的整体架构是什么?
构buildWeb应用程序有许多方法,比如
- 服务器端MVC a la Ruby on Rails
- 单页面应用程序样式la MongoDB / Express / Angular / Node(MEAN)
- 基本网站的一些forms
- 模型/操作/视图/事件风格一个MVC已经死了,现在是时候了
- 和许多其他的现在和历史
这些都适合不同的目录结构。 对于这个例子来说,这只是脚手架,而不是一个完整的应用程序,但我假设以下关键架构点:
- 该网站有一些传统的静态页面/模板
- 该网站的“应用程序”部分被开发为单页面应用程序样式
- 该应用程序向浏览器公开REST / JSON风格的API
- 该应用程序模拟一个简单的业务领域,在这种情况下,它是一个汽车经销商应用程序
那么Ruby on Rails呢?
这个项目的主题是Ruby on Rails中包含的许多思想以及他们采用的“约定优于configuration”的决定虽然被广泛接受和使用,但实际上并不是非常有用,有时与这个存储库相反build议。
我的主要观点是组织代码有基本的原则,并且基于这些原则,Ruby on Rails约定对于Ruby on Rails社区是有意义的(大部分)。 然而,只是毫不留情地这些惯例忽略了这一点。 一旦你了解了基本的原则,你所有的项目都将被组织和清晰:shell脚本,游戏,移动应用程序,企业项目,甚至你的主目录。
对于Rails社区,他们希望能够从应用程序到应用程序到应用程序的单一Rails开发人员切换,并且每次都能熟悉并且熟悉它。 这是非常有意义的,如果你是37信号或Pivotal实验室,并有好处。 在服务器端的JavaScript世界里,整体的风气只是西方的一切而已,而我们并没有真正的问题。 这就是我们如何滚动。 我们习惯了。 即使在express.js中,它也是Sinatra的亲戚,而不是Rails,而从Rails那里得到的约定通常不起任何作用。 我甚至会说原则而不是惯例 。
基本原则和动机
- 精神上可以pipe理
- 大脑只能同时处理和思考一小部分相关的事情。 这就是我们使用目录的原因。 它通过专注于小部分来帮助我们处理复杂性。
- 适合大小
- 不要创build“大厦目录”,只有一个文件只有3个目录。 您可以在Ansible最佳实践中看到这一点,这个实践让小项目感到羞耻 ,创build了10个以上的目录来存放10个以上的文件。 你不要开公共汽车去上class(除非你是公交车司机,但是即使你驾驶的公交车在工作也不行),所以不要创build文件系统结构,而这些文件系统结构并不是由内部的实际文件certificate的。
- 模块化但务实
- 节点社区整体青睐小模块。 任何可以完全从应用程序中分离出来的东西都应该被提取到一个模块中,供内部使用或在npm上公开发布。 但是,对于这里范围的中等规模的应用程序来说,这样的开销会使您的工作stream程没有相应的价值。 所以当你有一些代码被分解出来,但是不足以certificate一个完全独立的npm模块的时候,只要把它看作是一个“ 原模块 ”,期望当它超过一定的大小阈值时,它就会被提取出来。
- 一些人像@ hij1nx甚至包括一个
app/node_modules
目录,并在proto-module目录中有package.json
文件来促进这种转换并作为提醒。
- 很容易find代码
- 鉴于要构build的function或修复的错误,我们的目标是开发人员不必费力地查找涉及的源文件。
- 名字是有意义和准确的
- 严重代码完全删除,不留在孤儿文件或只是注释掉
- search友好
- 所有的第一方源代码是在
app
目录,所以你可以cd
有运行find / grep / xargs / ag / ack /等,不被第三方匹配分心
- 所有的第一方源代码是在
- 使用简单而明显的命名
- 现在npm似乎需要全小写的软件包名称。 我发现这个很糟糕,但是我必须遵循这个规则,因此文件名应该使用
kebab-case
即使JavaScript中的variables名必须是camelCase
因为-
在JavaScript中是负号。 - variables名称与模块path的基本名称相匹配,但将
kebab-case
转换为camelCase
- 现在npm似乎需要全小写的软件包名称。 我发现这个很糟糕,但是我必须遵循这个规则,因此文件名应该使用
- 按function分组,按function分组
- 这是一个从
app/views
,app/controllers
,app/models
等Ruby on Rails约定的重大背离 - function被添加到一个完整的堆栈,所以我想专注于与我的function相关的完整堆栈文件。 当我将电话号码字段添加到用户模型时,我不关心用户控制器以外的任何控制器,并且我不关心用户模型以外的任何模型。
- 所以不是编辑6个文件,每个文件都在他们自己的目录中,而忽略这些目录中的大量其他文件,这个存储库被组织起来,使得我需要build立一个特征的所有文件共同存在
- 根据MVC的性质,用户视图被耦合到耦合到用户模型的用户控制器。 所以当我改变用户模型时,这3个文件经常会一起改变,但是交易控制器或客户控制器是分离的,因此不涉及。 通常也适用于非MVCdevise。
- MVC或MOVE风格的解耦,在哪些代码去哪个模块仍然鼓励,但传播到同级目录的MVC文件只是令人讨厌。
- 因此,我的每个路由文件都拥有它所拥有的路由的一部分。 如果您想要了解应用程序中所有路线的概况,但是在实际构buildfunction和修复错误时,只需要关心与正在更改的部分相关的路线,则可以使用rails风格的
routes.rb
文件。
- 这是一个从
- 在代码旁边存储testing
- 这只是“偶合”的一个实例,但我想专门说出来。 我已经写了许多项目,其中testing生活在一个名为“testing”的并行文件系统下,现在我已经开始把我的testing与他们相应的代码放在同一个目录中,我永远不会回头。 这是更模块化,更容易在文本编辑器中使用,并减轻了很多“../../ ..”path的废话。 如果您有疑问,请尝试一些项目并自行决定。 除此之外,我不会做任何事情来说服你,这样做更好。
- 减less与事件的交叉耦合
- 很容易想到“好的,每当创build一个新的交易,我想发送一封电子邮件给所有的销售人员”,然后只是把这些电子邮件发送到创build交易的路线。
- 然而,这种耦合最终会把你的应用程序变成一个巨大的泥球。
- 相反,DealModel应该发起一个“创build”事件,并且完全不知道系统可以做什么来响应这个事件。
- 当你用这种方式进行编码时,将所有与用户相关的代码放入
app/users
变得更加可能,因为在整个地方没有鼠标耦合的业务逻辑来污染用户代码库的纯度。
- 代码stream是可以遵循的
- 不要做神奇的事情。 不要自动加载文件系统中魔术目录的文件。 不要成为铁轨。 该应用程序从
app/server.js:1
,您可以看到它加载的所有内容,并通过执行代码执行。 - 不要为你的路线制作DSL。 不要求傻的元编程。
- 如果你的应用程序如此之大,
magicRESTRouter.route(somecontroller, {except: 'POST'})
对于你来说超过了3个基本的app.get
,app.put
,app.del
,calls,你可能正在build设中一个单一的应用程序太大,不能有效地工作。 获得大胜的胜利,而不是转换3简单的线条到1复杂的线。
- 不要做神奇的事情。 不要自动加载文件系统中魔术目录的文件。 不要成为铁轨。 该应用程序从
-
使用低级烤肉串文件名
- 这种格式避免了跨平台的文件系统区分大小写问题
- npm禁止在新包名中使用大写字母,这个效果很好
express.js的细节
-
不要使用
app.configure
。 这几乎是无用的,你只是不需要它。 这是由于无意识的副本,在很多的样板。 - 中间件和程序在EXPRESS中的顺序!!!
- 我在stackoverflow上看到的几乎每一个路由问题都是无序的快递中间件
- 一般来说,你希望你的路线解耦,而不是依靠那么多的订单
- 如果你真的只需要2个路由的中间件,就不要在你的整个应用中使用
app.use
(我在看你,body-parser
) - 确保所有的说法和完成时,你有这个顺序:
- 任何超级重要的应用程序中间件
- 所有的路线和各种路线中间件
- 那么error handling程序
- 可悲的是,作为sinatra的启发,express.js大多假设你所有的路由将在
server.js
,并且将清楚如何订购。 对于一个中等规模的应用程序来说,把事情分解成单独的路由模块是很好的,但它确实会导致无序的中间件
应用符号链接技巧
有很多方法在社区中概述和讨论了很好的要点更好的本地require()pathNode.js。 我可能很快决定select“只处理很多../../../ ..”或使用requireFrom模型。 然而,目前,我一直在使用下面详述的符号链接技巧。
所以避免项目内部的一种方法需要像require("../../../config")
这样的相对path,这个方法就是使用下面的技巧:
- 在node_modules下为你的应用程序创build一个符号链接
- cd node_modules && ln -nsf ../app
- 添加node_modules / app符号链接本身 ,而不是整个node_modules文件夹,以混帐
- git add -f node_modules / app
- 是的,你的
.gitignore
文件中仍然应该有“node_modules” - 不,你不应该把“node_modules”放到你的git仓库中。 有些人会build议你这样做。 他们是不正确的。
- 现在,您可以使用此前缀来请求项目内模块
-
var config = require("app/config");
-
var DealModel = require("app/deals/deal-model")
;
-
- 基本上,这使得项目内部需要非常类似于需要外部npm模块的工作。
- 对不起,Windows用户,你需要坚持父目录的相对path。
组态
一般情况下,代码模块和类只需要传入一个基本的JavaScript options
对象。只有app/server.js
应该加载app/config.js
模块。 从那里它可以合成小的options
对象来根据需要configuration子系统,但是将每个子系统耦合到充满额外信息的大的全局configuration模块是不好的耦合。
尝试集中创build数据库连接并将其传递到子系统,而不是传递连接参数,并让子系统自己创build传出连接。
NODE_ENV
这是来自Rails的另一个诱人而又可怕的想法。 应用程序中应该只有一个地方, app/config.js
查看NODE_ENV
环境variables。 其他的东西都应该把一个显式的选项作为类的构造参数或模块configuration参数。
如果电子邮件模块有一个关于如何发送电子邮件(SMTP,login到标准输出,放入队列等)的选项,它应该采取像{deliver: 'stdout'}
的选项,但它绝对不应该检查NODE_ENV
。
testing
现在,我将testing文件保存在与其相应代码相同的目录中,并使用文件扩展名命名约定将testing与生产代码区分开来。
-
foo.js
有模块“foo”的代码 -
foo.tape.js
具有基于节点的footesting,并且位于相同的目录中 -
foo.btape.js
可用于需要在浏览器环境中执行的testing
我使用文件系统和find . -name '*.tape.js'
find . -name '*.tape.js'
命令根据需要访问我所有的testing。
如何在每个.js
模块文件中组织代码
这个项目的范围大部分是关于文件和目录的位置,我不想添加其他范围,但是我只提到我将代码组织到3个不同的部分。
- CommonJS的开放块需要调用状态依赖关系
- 纯JavaScript的主要代码块。 这里没有CommonJS污染。 不要引用出口,模块或要求。
- closuresCommonJS的块build立出口
更新(2013-10-29) :请参阅我的另一个答案以及JavaScript的,而不是CoffeeScript的stream行的需求,以及一个样板github回购和广泛的README详细介绍了我对这个主题的最新build议。
configuration
你在做什么是好的。 我喜欢在顶层的config.coffee
文件中设置自己的configuration名称空间,并使用这样的嵌套名称空间。
#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}"
这对于系统pipe理员编辑是很友好的。 然后当我需要的东西,如数据库连接信息,这是
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
function。
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文件放到git的git仓库中。
将一个包含语义版本号的package.json文件放在你的git仓库中,以供NPM使用。
以下是Peter Lyons的逐字回答,按照其他几个人的要求从Coffeescript转移到了香草JS。 彼得的答案是非常有能力的,任何投票答复的人都应该对他投票。
configuration
你在做什么是好的。 我喜欢把自己的configuration名称空间设置在顶层的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}" };
这对于系统pipe理员编辑是很友好的。 然后当我需要的东西,如数据库连接信息,这是
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
function。
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文件放到git的git仓库中。
将一个包含语义版本号的package.json文件放在你的git仓库中,以供NPM使用。
我的问题是在2011年4月推出的,它很安静。 在此期间,我可以通过Express.js提高自己的体验,以及如何构build使用此库编写的应用程序。 所以,我在这里分享我的经验。
这是我的目录结构:
├── app.js // main entry ├── config // The configuration of my applications (logger, global config, ...) ├── models // The model data (eg 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 (eg Jade, EJS, ...)
App.js
app.js
文件的目标是引导expressjs应用程序。 它加载configuration模块,logging器模块,等待数据库连接,…,并运行快速服务器。
'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); }); };
使用该模块,创build新的路由定义和实现非常简单。 例如, hello.js
:
function hello(req, res) { res.send('Hello world'); } module.exports = function (app) { app.get('/api/hello_world', hello); };
每个路由模块是独立的 。
我喜欢使用全球“应用程序”,而不是导出function等
我认为这是一个很好的方法来做到这一点。 不限于expression,但我看到相当多的Node.js项目在github上做同样的事情。 他们拿出configuration参数+更小的模块(在某些情况下,每个URI)被分解成单独的文件。
我build议在github上通过特定于expression式的项目来获得一个想法。 海事组织你做的方式是正确的。
现在是2015年底,经过三年的发展和大小项目的发展。 结论?
不要做一个大的MVC,但要把它分成几个模块
所以…
为什么?
-
通常在一个模块(例如产品)上工作,您可以独立更改。
-
您可以重复使用模块
-
你可以单独testing它
-
你可以分开replace它
-
他们有清晰(稳定)的接口
最近,如果有多个开发人员在工作,模块分离有帮助
nodebootstrap项目与我的最终结构有类似的方法。 ( github )
这个结构是怎样的?
-
小型封装模块 ,每个都有独立的MVC
-
每个模块都有一个package.json
-
作为结构的一部分进行testing (在每个模块中)
-
全局configuration ,库和服务
-
集成的Docker,集群,永远
Folderoverview(请参阅lib文件夹的模块):
我不认为这是添加路由到configuration的好方法。 更好的结构可以是这样的:
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将包含你所有的路由将所有的逻辑。
自上次回答这个问题已经有一段时间了,Express最近也发布了第4版,它为组织你的应用程序结构增加了一些有用的东西。
以下是有关如何构build快速应用程序的最佳实践的最新博客文章。 http://www.terlici.com/2014/08/25/best-practices-express-structure.html
还有一个GitHub仓库应用文章中的build议。 它始终与最新的Express版本保持一致。
https://github.com/terlici/base-express
那么我把我的路线作为json文件,我开始读,并在app.js for循环设置路线。 route.json包括应该调用哪个视图,以及将被发送到路由中的值的关键字。
这适用于很多简单的情况,但我不得不手动创build一些特殊情况下的路线。
这可能是有趣的:
https://github.com/flatiron/nconf
具有文件,环境variables,命令行参数和primefaces对象合并的分层node.jsconfiguration。
我已经写了一个关于这个问题的post。 它基本上使用一个routeRegistrar
来遍历文件夹/controllers
中的文件,调用它的函数init
。 函数init
将快速app
variables作为参数,以便您可以按照自己的方式注册路由。
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)在主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/ ...
- 最适合testing
- 最好的规模
- 分开取决于模块
- 按function(或模块)分组路线
tj说/展示在Vimeo有趣的想法如何模块化表示应用程序 – 与Node.js和Express的模块化Web应用程序 。 强大而简单。
http://locomotivejs.org/提供了一种构build使用Node.js和Express构build的应用程序的方法。;
从网站:
“机车是一个Node.js.的networking框架,机车支持MVC模式,RESTful路线,以及约定configuration,同时与任何数据库和模板引擎无缝集成。机车build立在Express上,保留了您期望的function和简单性来自节点“。
我给MVC风格的文件夹结构,请find下面的内容。
我们使用bellow文件夹结构为我们的大中型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
我创build了一个用于生成mvc文件夹结构的npm模块。
Please find the bellow https://www.npmjs.com/package/express-mvc-generator
Just simple steps to generate and use this modules .
i) install module npm install express-mvc-generator -g
ii) check options express -h
iii) Generate express mvc structure express myapp
iv) Install dependencies: npm install
:
v)Open your config/database.js , Please configure your mongo db.
vi)Run the application node app
or nodemon app
vii)Check URL http://localhost:8042/signup OR http://yourip:8042/signup
This is how most of my express project directory structure looks.
I usually do a express dirname
to initialise the project, forgive my laziness, but it's very flexible and extendable. PS – you need to get express-generator
for that (for those who're looking for it sudo npm install -g express-generator
, sudo because you're installing it globally)
|-- 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
You must be wondering why .env files? Because they work! I use dotenv
module in my projects (a lot recently) and it works! Pop in these 2 statements in app.js
or www
var dotenv = require('dotenv'); dotenv.config({path: path.join(__dirname + "/.env")});
And another line to quickly set /bower_components
to serve static content under the resource /ext
app.use('/ext', express.static(path.join(__dirname, 'bower_components')));
It probably can be a fit for people who're looking to use Express and Angular together, or just express without that javascripts
hierarchy of course.
I recently embraced modules as independent mini-apps.
|-- src |--module1 |--module2 |--www |--img |--js |--css |--#.js |--index.ejs |--module3 |--www |--bower_components |--img |--js |--css |--#.js |--header.ejs |--index.ejs |--footer.ejs
Now for any module routing (#.js), views (*.ejs), js, css and assets are next to each other. submodule routing is set up in the parent #.js with two additional lines
router.use('/module2', opt_middleware_check, require('./module2/#')); router.use(express.static(path.join(__dirname, 'www')));
This way even subsubmodules are possible.
Don't forget to set view to the src directory
app.set('views', path.join(__dirname, 'src'));