如何构建 ExpressJS 应用程序?

发布于 2024-11-03 08:43:30 字数 1700 浏览 1 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(21

浊酒尽余欢 2024-11-10 08:43:30

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

focusaurus/express_code_struct 是包含最新代码的存储库。欢迎拉请求。

这是自述文件的快照,因为 stackoverflow 不喜欢只是一个链接的答案。我将进行一些更新,因为这是一个我将继续更新的新项目,但最终 github 存储库将成为此信息的最新位置。


#Express 代码结构

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

当前至少为 Express v4.14 2016 年 12 月

构建状态

js-standard-style

有多大你的应用程序是?

Web 应用程序并不完全相同,而且在我看来,不存在应该应用于所有express.js 应用程序的单一代码结构。

如果您的应用程序很小,则不需要如此深的目录结构,如此处所示。只需保持简单并将一些 .js 文件粘贴到存储库的根目录中即可。瞧。

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

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

您的整体架构是什么

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

  • 服务器端 MVC、Ruby on Rails
  • 单页应用程序风格、MongoDB/Express/Angular/Node (MEAN)
  • 具有某些形式的基本网站
  • 模型/操作/Views/Events 风格为 MVC 已死,是时候继续前进了
  • 以及许多其他当前和历史的内容

中的每一个都很好地适合不同的目录结构。就本示例而言,它只是脚手架,而不是一个完全工作的应用程序,但我假设以下关键架构点:

  • 该网站有一些传统的静态页面/模板
  • 网站的“应用程序”部分是作为单个应用程序开发的页面应用程序样式
  • 应用程序向浏览器公开 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中获取约定通常没有任何帮助。我什至会说原则优于约定优于配置

基本原则和动机

  • 精神上可控
    • 大脑一次只能处理和思考少量相关的事物。这就是我们使用目录的原因。它通过专注于小部分来帮助我们处理复杂性。
  • 尺寸合适
    • 不要创建只有 1 个文件且 3 个目录下的“Mansion 目录”。您可以在 Ansible 最佳实践 中看到这种情况的发生,它让小项目羞愧地创建了 10 多个目录当 1 个目录包含 3 个文件时,容纳 10 个以上文件会更合适。您不会驾驶公共汽车去上班(除非您是公共汽车司机,但即使如此,您在工作时驾驶公共汽车也不是工作),因此不要创建不符合其中实际文件合理性的文件系统结构.
  • 模块化但务实
    • 节点社区总体上偏爱小模块。任何可以完全从应用程序中分离出来的内容都应该提取到模块中以供内部使用或在 npm 上公开发布。但是,对于此处讨论的中型应用程序来说,这种开销可能会增加您的工作流程的乏味,而没有相应的价值。因此,当您有一些代码被分解但不足以证明完全独立的 npm 模块合理时,只需将其视为“原型模块”,并期望当它超过某个大小阈值时,它将被提取出来。
    • 一些人,例如 @hij1nx 甚至包含 app/node_modules 目录并具有proto-module 目录中的 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 文件分散到同级目录中只是令人烦恼。
    • 因此,我的每个路线文件都有其拥有的部分路线。如果您想要概述应用程序中的所有路线,则 Rails 风格的 routes.rb 文件会很方便,但在实际构建功能和修复错误时,您只关心与您所在的部分相关的路线改变。
  • 将测试存储在代码旁边
    • 这只是“通过耦合分组”的一个实例,但我想特别指出它。我编写了许多项目,其中测试位于名为“tests”的并行文件系统下,现在我已经开始将测试与其相应的代码放在同一目录中,我再也不会回去了。这更加模块化,更容易在文本编辑器中使用,并减少了许多“../../..”路径的废话。如果您有疑问,请在几个项目上尝试一下,然后自己决定。除此之外,我不会做任何事情来让您相信它更好。
  • 减少与事件的交叉耦合
    • 很容易想到“好吧,每当创建新交易时,我想向所有销售人员发送一封电子邮件”,然后只需将用于发送这些电子邮件的代码放在创建交易的路径中即可。
    • 但是,这种耦合最终会将您的应用变成一个巨大的泥球。
    • 相反,DealModel 应该只触发“创建”事件,而完全不知道系统可能会执行哪些其他操作来响应该事件。
    • 当您以这种方式编码时,将所有与用户相关的代码放入 app/users 中变得更加可能,因为不存在到处都是耦合业务逻辑的老鼠巢,污染了代码的纯度。用户代码库。
  • 代码流程可遵循
    • 不要做神奇的事情。不要从文件系统中的魔术目录自动加载文件。不要成为Rails。该应用从 app/server.js:1 启动,您可以按照代码查看它加载和执行的所有内容。
    • 不要为您的路线制作 DSL。不需要时不要进行愚蠢的元编程。
    • 如果您的应用太大,那么执行 magicRESRouter.route(somecontroller, { except: 'POST'}) 对您来说比 3 个基本的 app.get 是一个巨大的胜利>、app.putapp.del 等调用,您可能正在构建一个太大而无法有效运行的整体应用程序。着眼于大胜利,而不是将 3 个简单行转换为 1 个复杂行。
  • 使用小写的文件名
    • 此格式可避免跨平台的文件系统区分大小写问题
    • npm 禁止在新包名称中使用大写字母,这可以很好地配合

express.js 的具体细节

  • 配合得很好。 不要使用 app.configure。它几乎完全没用,你只是不需要它。由于无意识的复制,它出现在很多样板文件中。
  • Express 中的中间件和路由的顺序很重要!!!
    • 我在 stackoverflow 上看到的几乎每个路由问题都是无序的 Express 中间件
    • 一般来说,您希望路线解耦,而不是过分依赖顺序
    • 如果您确实只需要 2 个路由的中间件,请不要在整个应用程序中使用 app.use(我正在看着您,body-parser
    • 确保当一切都说完并完成后,您确实收到了以下命令:
      1. 任何超级重要的应用程序范围中间件
      2. 您的所有路线和各种路线中间件
      3. THEN 错误处理程序
  • 遗憾的是,受 sinatra 启发,express.js 大多数情况下假设所有路由都在 server.js 中,并且它将是清楚它们是如何排序的。对于中型应用程序,将事物分解为单独的路由模块很好,但它确实引入了无序中间件的危险

应用程序符号链接技巧

社区在要点中详细概述和讨论了许多方法< a href="https://gist.github.com/branneman/8048520" rel="noreferrer">更好的 Node.js 本地 require() 路径。我可能很快就会决定选择“只处理大量 ../../../..”或使用 requireFrom 模块。然而,目前,我一直在使用下面详细介绍的符号链接技巧。

因此,避免项目内需要像 require("../../../config") 这样烦人的相对路径的一种方法是使用以下技巧:

  • 在 node_modules 下为您的应用程序
    • cd node_modules && ln -nsf ../app
  • 仅添加node_modules/app符号链接本身,而不是整个node_modules文件夹到git
    • 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 用户,您需要坚持使用父目录相对路径。

配置

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

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

NODE_ENV

这是另一个从 Rails 继承下来的诱人但糟糕的想法。您的应用中应该有 1 个位置 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 污染。不要引用导出、模块或要求。
  3. CommonJS 的关闭块用于设置导出

OK, it's been a while and this is a popular question, so I've gone ahead and created a scaffolding github repository with JavaScript code and a long README about how I like to structure a medium-sized express.js application.

focusaurus/express_code_structure is the repo with the latest code for this. Pull requests welcome.

Here's a snapshot of the README since stackoverflow doesn't like just-a-link answers. I'll make some updates as this is a new project that I'll continue updating, but ultimately the github repo will be the up-to-date place for this information.


#Express Code Structure

This project is an example of how to organize a medium-sized express.js web application.

Current to at least express v4.14 December 2016

Build Status

js-standard-style

How big is your application?

Web applications are not all the same, and there's not, in my opinion, a single code structure that should be applied to all express.js applications.

If your application is small, you don't need such a deep directory structure as exemplified here. Just keep it simple and stick a handful of .js files in the root of your repository and you're done. Voilà.

If your application is huge, at some point you need to break it up into distinct npm packages. In general the node.js approach seems to favor many small packages, at least for libraries, and you should build your application up by using several npm packages as that starts to make sense and justify the overhead. So as your application grows and some portion of the code becomes clearly reusable outside of your application or is a clear subsystem, move it to its own git repository and make it into a standalone npm package.

So the focus of this project is to illustrate a workable structure for a medium-sized application.

What is your overall architecture

There are many approaches to building a web application, such as

  • Server Side MVC a la Ruby on Rails
  • Single Page Application style a la MongoDB/Express/Angular/Node (MEAN)
  • Basic web site with some forms
  • Models/Operations/Views/Events style a la MVC is dead, it's time to MOVE on
  • and many others both current and historical

Each of these fits nicely into a different directory structure. For the purposes of this example, it's just scaffolding and not a fully working app, but I'm assuming the following key architecture points:

  • The site has some traditional static pages/templates
  • The "application" portion of the site is developed as a Single Page Application style
  • The application exposes a REST/JSON style API to the browser
  • The app models a simple business domain, in this case, it's a car dealership application

And what about Ruby on Rails?

It will be a theme throughout this project that many of the ideas embodied in Ruby on Rails and the "Convention over Configuration" decisions they have adopted, though widely accepted and used, are not actually very helpful and sometimes are the opposite of what this repository recommends.

My main point here is that there are underlying principles to organizing code, and based on those principles, the Ruby on Rails conventions make sense (mostly) for the Ruby on Rails community. However, just thoughtlessly aping those conventions misses the point. Once you grok the basic principles, ALL of your projects will be well-organized and clear: shell scripts, games, mobile apps, enterprise projects, even your home directory.

For the Rails community, they want to be able to have a single Rails developer switch from app to app to app and be familiar and comfortable with it each time. This makes great sense if you are 37 signals or Pivotal Labs, and has benefits. In the server-side JavaScript world, the overall ethos is just way more wild west anything goes and we don't really have a problem with that. That's how we roll. We're used to it. Even within express.js, it's a close kin of Sinatra, not Rails, and taking conventions from Rails is usually not helping anything. I'd even say Principles over Convention over Configuration.

Underlying Principles and Motivations

  • Be mentally manageable
    • The brain can only deal with and think about a small number of related things at once. That's why we use directories. It helps us deal with complexity by focusing on small portions.
  • Be size-appropriate
    • Don't create "Mansion Directories" where there's just 1 file all alone 3 directories down. You can see this happening in the Ansible Best Practices that shames small projects into creating 10+ directories to hold 10+ files when 1 directory with 3 files would be much more appropriate. You don't drive a bus to work (unless you're a bus driver, but even then your driving a bus AT work not TO work), so don't create filesystem structures that aren't justified by the actual files inside them.
  • Be modular but pragmatic
    • The node community overall favors small modules. Anything that can cleanly be separated out from your app entirely should be extracted into a module either for internal use or publicly published on npm. However, for the medium-sized applications that are the scope here, the overhead of this can add tedium to your workflow without commensurate value. So for the time when you have some code that is factored out but not enough to justify a completely separate npm module, just consider it a "proto-module" with the expectation that when it crosses some size threshold, it would be extracted out.
    • Some folks such as @hij1nx even include an app/node_modules directory and have package.json files in the proto-module directories to facilitate that transition and act as a reminder.
  • Be easy to locate code
    • Given a feature to build or a bug to fix, our goal is that a developer has no struggle locating the source files involved.
      • Names are meaningful and accurate
      • crufty code is fully removed, not left around in an orphan file or just commented out
  • Be search-friendly
    • all first-party source code is in the app directory so you can cd there are run find/grep/xargs/ag/ack/etc and not be distracted by third party matches
  • Use simple and obvious naming
    • npm now seems to require all-lowercase package names. I find this mostly terrible but I must follow the herd, thus filenames should use kebab-case even though the variable name for that in JavaScript must be camelCase because - is a minus sign in JavaScript.
    • variable name matches the basename of the module path, but with kebab-case transformed to camelCase
  • Group by Coupling, Not by Function
    • This is a major departure from the Ruby on Rails convention of app/views, app/controllers, app/models, etc
    • Features get added to a full stack, so I want to focus on a full stack of files that are relevant to my feature. When I'm adding a telephone number field to the user model, I don't care about any controller other than the user controller, and I don't care about any model other than the user model.
    • So instead of editing 6 files that are each in their own directory and ignoring tons of other files in those directories, this repository is organized such that all the files I need to build a feature are colocated
    • By the nature of MVC, the user view is coupled to the user controller which is coupled to the user model. So when I change the user model, those 3 files will often change together, but the deals controller or customer controller are decoupled and thus not involved. Same applies to non-MVC designs usually as well.
    • MVC or MOVE style decoupling in terms of which code goes in which module is still encouraged, but spreading the MVC files out into sibling directories is just annoying.
    • Thus each of my routes files has the portion of the routes it owns. A rails-style routes.rb file is handy if you want an overview of all routes in the app, but when actually building features and fixing bugs, you only care about the routes relevant to the piece you are changing.
  • Store tests next to the code
    • This is just an instance of "group by coupling", but I wanted to call it out specifically. I've written many projects where the tests live under a parallel filesystem called "tests" and now that I've started putting my tests in the same directory as their corresponding code, I'm never going back. This is more modular and much easier to work with in text editors and alleviates a lot of the "../../.." path nonsense. If you are in doubt, try it on a few projects and decide for yourself. I'm not going to do anything beyond this to convince you that it's better.
  • Reduce cross-cutting coupling with Events
    • It's easy to think "OK, whenever a new Deal is created, I want to send an email to all the Salespeople", and then just put the code to send those emails in the route that creates deals.
    • However, this coupling will eventually turn your app into a giant ball of mud.
    • Instead, the DealModel should just fire a "create" event and be entirely unaware of what else the system might do in response to that.
    • When you code this way, it becomes much more possible to put all the user related code into app/users because there's not a rat's nest of coupled business logic all over the place polluting the purity of the user code base.
  • Code flow is followable
    • Don't do magic things. Don't autoload files from magic directories in the filesystem. Don't be Rails. The app starts at app/server.js:1 and you can see everything it loads and executes by following the code.
    • Don't make DSLs for your routes. Don't do silly metaprogramming when it is not called for.
    • If your app is so big that doing magicRESTRouter.route(somecontroller, {except: 'POST'}) is a big win for you over 3 basic app.get, app.put, app.del, calls, you're probably building a monolithic app that is too big to effectively work on. Get fancy for BIG wins, not for converting 3 simple lines to 1 complex line.
  • Use lower-kebab-case filenames
    • This format avoids filesystem case sensitivity issues across platforms
    • npm forbids uppercase in new package names, and this works well with that

express.js specifics

  • Don't use app.configure. It's almost entirely useless and you just don't need it. It is in lots of boilerplate due to mindless copypasta.
  • THE ORDER OF MIDDLEWARE AND ROUTES IN EXPRESS MATTERS!!!
    • Almost every routing problem I see on stackoverflow is out-of-order express middleware
    • In general, you want your routes decoupled and not relying on order that much
    • Don't use app.use for your entire application if you really only need that middleware for 2 routes (I'm looking at you, body-parser)
    • Make sure when all is said and done you have EXACTLY this order:
      1. Any super-important application-wide middleware
      2. All your routes and assorted route middlewares
      3. THEN error handlers
  • Sadly, being sinatra-inspired, express.js mostly assumes all your routes will be in server.js and it will be clear how they are ordered. For a medium-sized application, breaking things out into separate routes modules is nice, but it does introduce peril of out-of-order middleware

The app symlink trick

There are many approaches outlined and discussed at length by the community in the great gist Better local require() paths for Node.js. I may soon decide to prefer either "just deal with lots of ../../../.." or use the requireFrom modlue. However, at the moment, I've been using the symlink trick detailed below.

So one way to avoid intra-project requires with annoying relative paths like require("../../../config") is to use the following trick:

  • create a symlink under node_modules for your app
    • cd node_modules && ln -nsf ../app
  • add just the node_modules/app symlink itself, not the entire node_modules folder, to git
    • git add -f node_modules/app
    • Yes, you should still have "node_modules" in your .gitignore file
    • No, you should not put "node_modules" into your git repository. Some people will recommend you do this. They are incorrect.
  • Now you can require intra-project modules using this prefix
    • var config = require("app/config");
    • var DealModel = require("app/deals/deal-model");
  • Basically, this makes intra-project requires work very similarly to requires for external npm modules.
  • Sorry, Windows users, you need to stick with parent directory relative paths.

Configuration

Generally code modules and classes to expect only a basic JavaScript options object passed in. Only app/server.js should load the app/config.js module. From there it can synthesize small options objects to configure subsystems as needed, but coupling every subsystem to a big global config module full of extra information is bad coupling.

Try to centralize creation of DB connections and pass those into subsystems as opposed to passing connection parameters and having subsystems make outgoing connections themselves.

NODE_ENV

This is another enticing but terrible idea carried over from Rails. There should be exactly 1 place in your app, app/config.js that looks at the NODE_ENV environment variable. Everything else should take an explicit option as a class constructor argument or module configuration parameter.

If the email module has an option as to how to deliver emails (SMTP, log to stdout, put in queue etc), it should take an option like {deliver: 'stdout'} but it should absolutely not check NODE_ENV.

Tests

I now keep my test files in the same directory as their corresponding code and use filename extension naming conventions to distinguish tests from production code.

  • foo.js has the module "foo"'s code
  • foo.tape.js has the node-based tests for foo and lives in the same dir
  • foo.btape.js can be used for tests that need to execute in a browser environment

I use filesystem globs and the find . -name '*.tape.js' command to get access to all my tests as necessary.

How to organize code within each .js module file

This project's scope is mostly about where files and directories go, and I don't want to add much other scope, but I'll just mention that I organize my code into 3 distinct sections.

  1. Opening block of CommonJS require calls to state dependencies
  2. Main code block of pure-JavaScript. No CommonJS pollution in here. Don't reference exports, module, or require.
  3. Closing block of CommonJS to set up exports
木格 2024-11-10 08:43:30

更新(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}"

这对于系统管理员编辑来说是友好的。然后,当我需要某些东西(例如数据库连接信息)时,它是

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

将带有语义版本号的 package.json 文件放入 NPM 的 git 存储库根目录中。

UPDATE (2013-10-29): Please see my other answer as well which has JavaScript instead of CoffeeScript by popular demand as well as a boilerplate github repo and an extensive README detailing my latest recommendations on this topic.

Config

What you are doing is fine. I like to have my own config namespace set up in a top-level config.coffee file with a nested namespace like this.

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

This is friendly for sysadmin editing. Then when I need something, like the DB connection info, it`s

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

Routes/Controllers

I like to leave my routes with my controllers and organize them in an app/controllers subdirectory. Then I can load them up and let them add whatever routes they need.

In my app/server.coffee coffeescript file I do:

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

So I have files like:

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

And for example in my domains controller, I have a setup function like this.

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

Views

Putting views in app/views is becoming the customary place. I lay it out like this.

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

Static Files

Go in a public subdirectory.

Github/Semver/NPM

Put a README.md markdown file at your git repo root for github.

Put a package.json file with a semantic version number in your git repo root for NPM.

荒人说梦 2024-11-10 08:43:30

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

这对于系统管理员编辑来说是友好的。然后,当我需要某些东西(例如数据库连接信息)时,它是

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

将带有 语义版本 编号的 package.json 文件放入 NPM 的 git 存储库根目录中。

The following is Peter Lyons' answer verbatim, ported over to vanilla JS from Coffeescript, as requested by several others. Peter's answer is very able, and anyone voting on my answer should vote on his as well.


Config

What you are doing is fine. I like to have my own config namespace set up in a top-level config.js file with a nested namespace like this.

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

This is friendly for sysadmin editing. Then when I need something, like the DB connection info, it`s

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

Routes/Controllers

I like to leave my routes with my controllers and organize them in an app/controllers subdirectory. Then I can load them up and let them add whatever routes they need.

In my app/server.js javascript file I do:

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

So I have files like:

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

And for example in my domains controller, I have a setup function like this.

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

Views

Putting views in app/views is becoming the customary place. I lay it out like this.

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

Static Files

Go in a public subdirectory.

Github/Semver/NPM

Put a README.md markdown file at your git repo root for github.

Put a package.json file with a semantic version number in your git repo root for NPM.

Saygoodbye 2024-11-10 08:43:30

我的问题是 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 应用程序。它加载配置模块、记录器模块、等待数据库连接……并运行 Express 服务器。

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

每个路由模块都是独立的

My question was introduced in April 2011, it's quiet old. During this time, I could improve my experience with Express.js and how to architecture an application written using this library. So, I share here my experience.

Here's my directory structure:

├── 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

The goal of the app.js file is to bootstrap the expressjs application. It loads the configuration module, the logger module, wait for database connection, ..., and run the express server.

'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/

The routes directory has a index.js file. Its goal is to introduce a kind of magic to load all other files inside the routes/ directory. Here's the implementation:

/**
 * 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);
  });
};

With that module, creating a new route definition and implementation is really easy. For examples, hello.js:

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

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

Each route module is standalone.

星星的軌跡 2024-11-10 08:43:30

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

我建议您浏览 github 上的 Express 特定项目以获得一个想法。 IMO,你的做法是正确的。

I think it's a great way to do it. Not limited to express but I've seen quite a number of node.js projects on github doing the same thing. They take out the configuration parameters + smaller modules (in some cases every URI) are factored in separate files.

I would recommend going through express-specific projects on github to get an idea. IMO the way you are doing is correct.

傲鸠 2024-11-10 08:43:30

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

I like to use a global "app", rather than exporting a function etc

破晓 2024-11-10 08:43:30

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

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

所以...

为什么?

  • 通常一个模块适用于一个模块(例如产品),您可以更改该模块独立。

  • 您可以重用模块

  • 您可以单独测试它

  • 您可以单独替换它

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

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

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

这个结构是什么样的?

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

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

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

  4. 全局配置、库和服务

  5. 集成 Docker、集群,永远

    >

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

nodebootstrap 结构< /a>

it is now End of 2015 and after developing my structure for 3 years and in small and large projects. Conclusion?

Do not do one large MVC, but separate it in modules

So...

Why?

  • Usually one works on one module (e.g. Products), which you can change independently.

  • You are able to reuse modules

  • You are able to test it separatly

  • You are able to replace it separatly

  • They have clear (stable) interfaces

    -At latest, if there were multiple developers working, module separation helps

The nodebootstrap project has a similar approach to my final structure. (github)

How does this structure look like?

  1. Small, capsulated modules, each with separate MVC

  2. Each module has a package.json

  3. Testing as a part of the structure (in each module)

  4. Global configuration, libraries and Services

  5. Integrated Docker, Cluster, forever

Folderoverview (see lib folder for modules):

nodebootstrap structure

⒈起吃苦の倖褔 2024-11-10 08:43:30

我给出了 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

我创建了一个 npm 模块来生成 Express Mvc 文件夹结构。

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

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

i) 安装模块 npm installexpress-mvc-generator -g

ii) 检查选项 express -h

iii) 生成express mvc 结构 express myapp

iv ) 安装依赖项: npm install:

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

vi) 运行应用程序 node appnodemon app

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

I am giving MVC style folder structure please find bellow .

We used bellow folder structure for our big and medium web applications .

 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

I have created one npm module for generation express mvc folder structurer.

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

坏尐絯℡ 2024-11-10 08:43:30

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

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 将包含所有路由以及其中的所有逻辑。

I don't think it's a good approach to add routes to config. A better structure could be something like this:

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...

So products.js and users.js will contain all your routes will all logic within.

慈悲佛祖 2024-11-10 08:43:30

自从上次回答这个问题以来已经有一段时间了,Express 最近还发布了版本 4,它添加了一些用于组织应用程序结构的有用内容。

下面是一篇长篇最新博客文章,介绍如何构建 Express 应用程序的最佳实践。
http://www.terlici.com/2014/08 /25/best-practices-express-struct.html

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

It's been quite a while since the last answer to this question and Express has also recently released version 4, which added a few useful things for organising your app structure.

Below is a long up to date blog post about best practices on how to structure your Express app.
http://www.terlici.com/2014/08/25/best-practices-express-structure.html

There is also a GitHub repository applying the advice in the article. It is always up to date with the latest Express version.
https://github.com/terlici/base-express

此生挚爱伱 2024-11-10 08:43:30

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

Well I put my routes as a json file, that I read at the beginning, and in a for-loop in app.js set up the routes. The route.json includes which view that should be called, and the key for the values that will be sent into the route.
This works for many simple cases, but I had to manually create some routes for special cases.

醉南桥 2024-11-10 08:43:30

我专门写了一篇文章来讨论这个问题。它基本上利用了一个 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);

I have written a post exactly about this matter. It basically makes use of a routeRegistrar that iterates through files in the folder /controllers calling its function init. Function init takes the express app variable as a parameter so you can register your routes the way you want.

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);
厌倦 2024-11-10 08:43:30

这可能会引起兴趣:

https://github.com/flatiron/nconf

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

This may be of interest:

https://github.com/flatiron/nconf

Hierarchical node.js configuration with files, environment variables, command-line arguments, and atomic object merging.

月野兔 2024-11-10 08:43:30

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

来自网站:

“Locomotive是Node.js的Web框架。Locomotive支持MVC
模式、RESTful 路由和约定优于配置,同时
与任何数据库和模板引擎无缝集成。
Locomotive 以 Express 为基础,保留了强大功能和简单性
您已经对 Node 抱有期望了。”

http://locomotivejs.org/ provides a way to structure an app built with Node.js and Express.

From the website:

"Locomotive is a web framework for Node.js. Locomotive supports MVC
patterns, RESTful routes, and convention over configuration, while
integrating seamlessly with any database and template engine.
Locomotive builds on Express, preserving the power and simplicity
you've come to expect from Node."

幽蝶幻影 2024-11-10 08:43:30

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 应用程序。功能强大且简单。

1) Your Express project filesystem maybe like:

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

app.js - you global app container

2) Module main file (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) Connect module in main app.js

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

4) Sample logic

lib/login
lib/db
lib/config
lib/users
lib/verify
lib/
   /api/ 
   ...
lib/
   /admin/
      /users/
      /settings/
      /groups/
...
  • Best for testing
  • Best for scale
  • Separate depends by module
  • Grouping route by functionality (or modules)

tj says/show on Vimeo interesting idea how modularize express application -
Modular web applications with Node.js and Express. Powerful and simple.

叹梦 2024-11-10 08:43:30

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

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

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'));
痴骨ら 2024-11-10 08:43:30

Sails.js 结构对我来说看起来又漂亮又干净,所以我在我的 Express 项目中使用 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-样板文件

Sails.js structure looks nice and clean to me, so I use MVC style structure for my express projects, similar to 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  

App folder - contains overall login for application.
Config folder - contains app configurations, constants, routes.
Public folder - contains styles, images, scripts etc.
Views folder - contains views for each model (if any)

Boilerplate project could be found here,
https://github.com/abdulmoiz251/node-express-rest-api-boilerplate

吻风 2024-11-10 08:43:30

这就是我的大部分 Express 项目目录结构的样子。

我通常会使用 express dirname 来初始化项目,请原谅我的懒惰,但它非常灵活且可扩展。 PS - 您需要为此获取 express-generator (对于那些正在寻找它的人 sudo npm install -gexpress-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 中弹出这 2 条语句

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

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.

风流物 2024-11-10 08:43:30

我的结构表达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

My structure express 4.
https://github.com/odirleiborgert/borgert-express-boilerplate

Packages

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

Structure

|-- app
    |-- controllers
    |-- helpers
    |-- middlewares
    |-- models
    |-- routes
    |-- services
|-- bin
|-- logs
|-- node_modules
|-- public
    |-- components
    |-- images
    |-- javascripts
    |-- stylesheets
|-- views
|-- .env
|-- .env-example
|-- app.js
|-- README.md
稀香 2024-11-10 08:43:30

构建 Express 应用程序的简单方法:

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

    <块引用>

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

    所有app.use应该排在第二位。

    后跟其他 api 及其函数或在其他文件中继续路由

    示例

    app.use("/password",passwordApi);

    app.use("/user", userApi);

    app.post("/token", Passport.createToken);

    app.post("/logout", Passport.logout)

A simple way to structure ur express app:

  • In main index.js the following order should be maintained.

    all app.set should be first.

    all app.use should be second.

    followed by other apis with their functions or route-continue in other files

    Exapmle

    app.use("/password", passwordApi);

    app.use("/user", userApi);

    app.post("/token", passport.createToken);

    app.post("/logout", passport.logout)

萌面超妹 2024-11-10 08:43:30

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

Best Way To MVC Structure for ExpressJs Project with handlebar & 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文