如何构建一个express.js应用程序?


102

是否有app.jsExpress.js应用程序中分解和模块化文件的通用约定?还是将所有内容保存在一个文件中很常见?


3
有人将它们分解成路线。您也可以看看快递资源。
BRampersad 2011年

@Brandon_R您尝试过资源吗?我瞥了一眼,以为它看上去很整洁,只是还没有踢过轮胎。
机会

1
有点晚了,但是我最近开放了一个用于express的路由器,它允许您很好地分解app.js的介绍性控制器和视图等。请参见:github.com/kishorenc/road
jeffreyveon 2011年

Answers:


82

我的分解如下:

~/app
|~controllers
| |-monkey.js
| |-zoo.js
|~models
| |-monkey.js
| |-zoo.js
|~views
| |~zoos
|   |-new.jade
|   |-_form.jade
|~test
|  |~controllers
|    |-zoo.js
|  |~models
|    |-zoo.js
|-index.js

我使用Exports返回相关内容。例如,在模型中,我这样做:

module.exports = mongoose.model('PhoneNumber', PhoneNumberSchema);

然后,如果我需要创建一个电话号码,它非常简单:

var PhoneNumber = require('../models/phoneNumber');
var phoneNumber = new PhoneNumber();

如果我需要使用架构,那么 PhoneNumber.schema

(假设我们正在routes文件夹中工作,需要先上一层然后再下一层模型)


编辑4

快递维基具有建立在它之上的框架的列表。

其中,我认为Twitter的斗牛士的结构非常好。实际上,我们使用了非常类似的方法来加载应用程序的各个部分。

derby.js看起来也非常有趣。它类似于流星,没有所有的炒作,实际上在应归功于信用的地方给予了荣誉(特别是节点和特快)。


编辑3

如果您是CoffeeScript的粉丝(我不是),并且又希望使用Rails的L&F,那么还有Tower.js


编辑2

如果您熟悉Rails,并且不介意某些概念的泛滥,那么您可以使用Locomotive。它是基于Express构建的轻量级框架。它具有与RoR非常相似的结构,并且继承了一些更基本的概念(例如路由)。

即使您不打算使用它,也值得一试。


编辑1

nodejs-express-mongoose-demo与我的结构非常相似。看看这个。


2
业务逻辑何去何从?您是否曾经使用助手来进行身份验证?
红色埃里克(Eric the Red)

@ErictheRed,如果您熟悉MVC模式(rails,Asp.Net mvc等),那么我认为我的Routes是我的控制器,此后一切都会付诸实践。模型中包含业务逻辑(尽管我在验证和猫鼬方面遇到困难)。对于助手,我在一个简单的内部util库上使用Exports,我为自己准备了重复使用的东西。
机会

将示例设置上传到github上供我们查看是很酷的。Routes文件夹/文件中包含什么?
chovy 2011年

1
@chovy我添加了一个链接到github.com/qed42/nodejs-express-mongoose-demo,该链接具有非常相似的结构
机会

我建议使用快递的顶部避免任何臃肿的框架构建
Raynos

9

警告:引用我一起砍掉的代码以进行节点敲除,虽然可以正常工作,但还远远不够优雅。

更具体地讲,app.js我有以下app.js文件

var express = require('express'),
    bootstrap = require('./init/bootstrap.js'),
    app = module.exports = express.createServer();

bootstrap(app);

这基本上意味着我将所有引导程序都放在单独的文件中,然后引导服务器。

那么引导程序会做什么?

var configure = require("./app-configure.js"),
    less = require("./watch-less.js"),
    everyauth = require("./config-everyauth.js"),
    routes = require("./start-routes.js"),
    tools = require("buffertools"),
    nko = require("nko"),
    sessionStore = new (require("express").session.MemoryStore)()

module.exports = function(app) {
    everyauth(app);
    configure(app, sessionStore);
    less();
    routes(app, sessionStore);
    nko('/9Ehs3Dwu0bSByCS');


    app.listen(process.env.PORT);
    console.log("server listening on port xxxx");
};

好吧,它将所有服务器初始化设置拆分为漂亮的块。特别

  • 我有一个块可以使用everyauth设置所有远程OAuth身份验证。
  • 我有一个配置我的应用程序的块(基本上调用app.configure
  • 我有一点点代码可以减少打孔,因此它可以在运行时将少部分代码重新编译为css。
  • 我有设置所有路线的代码
  • 我称这个小NKO模块
  • 最后,我通过侦听端口来启动服务器。

例如,让我们看一下路由文件

var fs = require("fs"),
    parseCookie = require('connect').utils.parseCookie;

module.exports = function(app, sessionStore) {
    var modelUrl = __dirname + "/../model/",
        models = fs.readdirSync(modelUrl),
        routeUrl = __dirname + "/../route/"
        routes = fs.readdirSync(routeUrl);

在这里,我将所有模型和路线作为文件数组加载。

免责声明: readdirSync在启动http服务器之前(在之前.listen)被调用时可以。在服务器启动时调用同步阻塞调用只会使代码更具可读性(基本上是hack)

    var io = require("socket.io").listen(app);

    io.set("authorization", function(data, accept) {
        if (data.headers.cookie) {
            data.cookie = parseCookie(data.headers.cookie);

            data.sessionId = data.cookie['express.sid'];

            sessionStore.get(data.sessionId, function(err, session) {

                if (err) {
                    return accept(err.message, false);
                } else if (!(session && session.auth)) {
                    return accept("not authorized", false)
                }
                data.session = session;
                accept(null, true);
            });
        } else {
            return accept('No cookie', false);
        }
    });

在这里,我将socket.io打孔以实际使用授权,而不是让任何tom和jack与我的socket.io服务器进行通信

    routes.forEach(function(file) {
        var route = require(routeUrl + file),
            model = require(modelUrl + file);

        route(app, model, io);
    });
};

在这里,我通过将相关模型传递到从路由文件返回的每个路由对象中来开始路由。

基本上,基本原则是将所有内容组织到漂亮的小模块中,然后具有一些自举机制。

我的另一个项目(我的博客)有一个具有类似结构的init文件

免责声明:博客已损坏且无法构建,我正在努力。



0

我的应用程序基于express-generator工具构建。您可以通过运行安装它, npm install express-generator -g并使用运行它express <APP_NAME>

为了给您一个视角,我的一个较小的应用程序结构如下所示:

~/
|~bin
| |-www
|
|~config
| |-config.json
|
|~database
| |-database.js
|
|~middlewares
| |-authentication.js
| |-logger.js
|
|~models
| |-Bank.js
| |-User.js
|
|~routes
| |-index.js
| |-banks.js
| |-users.js
|
|~utilities
| |-fiat-converersion.js
|
|-app.js
|-package.json
|-package-lock.json

我喜欢我最终开发的任何快速应用程序采用的这种结构的一个很酷的事情是路由的组织方式。我不希望必须将每个路由文件都输入到app.js和app.use()每个路由中,尤其是当文件变大时。因此,我发现将所有我app.use()的文件集中和集中在./routes/index.js文件中很有帮助。

最后,我的app.js将如下所示:

...
const express = require('express');
const app = express();

...
require('./routes/index')(app);

我的./routes/index.js看起来像这样:

module.exports = (app) => {
  app.use('/users', require('./users'));
  app.use('/banks', require('./banks'));
};

我之所以能够这样做是require(./users)因为我使用express.Router()编写了用户路由,这使我可以“组合”多个路由,然后一次导出它们,以使应用程序更具模块化。

这是您可以在./routers/users.js路由上执行的操作的一个示例:


const router = require('express').Router();

router.post('/signup', async (req, res) => {
    // Signup code here
});

module.exports = router;

希望这有助于回答您的问题!祝你好运!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.