Làm thế nào để cấu trúc một ứng dụng express.js?


102

Có quy ước chung nào để chia nhỏ và sửa đổi app.jstệp trong ứng dụng Express.js không? Hay là thông thường để giữ mọi thứ trong một tệp duy nhất?


3
Đã có người chia chúng thành các tuyến. Ngoài ra, bạn có thể xem các nguồn thông tin nhanh.
BRampersad

@Brandon_R bạn đã thử tài nguyên chưa? Tôi nhìn lướt qua và nghĩ nó trông gọn gàng, chỉ là chưa đạp lốp thôi.
Chance

1
Một chút trễ, nhưng tôi vừa mở nguồn một router cho nhanh mà cho phép bạn phá vỡ các app.js độc đáo giới thiệu quan điểm điều khiển +, vv Xem: github.com/kishorenc/road
jeffreyveon

Câu trả lời:


82

Tôi đã chia tay như sau:

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

Tôi sử dụng Exports để trả lại những gì có liên quan. Ví dụ, trong các mô hình tôi làm:

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

và sau đó nếu tôi cần tạo một số điện thoại, nó đơn giản như sau:

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

nếu tôi cần sử dụng lược đồ, thì PhoneNumber.schema

(giả định rằng chúng tôi đang làm việc từ thư mục tuyến đường và cần tăng 1 cấp độ rồi xuống mô hình)


CHỈNH SỬA 4

Các wiki nhanh có một danh sách của các khuôn khổ xây dựng trên đầu trang của nó.

Trong số đó, tôi nghĩ rằng matador của Twitter được cấu trúc khá tốt. Chúng tôi thực sự đã sử dụng một cách tiếp cận rất giống với cách họ tải các phần của ứng dụng.

derby.js cũng trông cực kỳ thú vị. Nó giống như một thiên thạch mà không có tất cả sự cường điệu và thực sự mang lại tín dụng khi tín dụng đến hạn (đặc biệt là nút và nhanh).


CHỈNH SỬA 3

Nếu bạn là một fan hâm mộ của CoffeeScript (tôi thì không) và thực sự muốn có L&F of Rails, thì cũng có Tower.js .


CHỈNH SỬA 2

Nếu bạn đã quen thuộc với Rails và không bận tâm đến việc thừa một số khái niệm thì đó là Locomotive . Nó là một khung công tác nhẹ được xây dựng trên Express. Nó có cấu trúc rất giống với RoR và mang một số khái niệm thô sơ hơn (chẳng hạn như định tuyến).

Nó đáng để kiểm tra ngay cả khi bạn không định sử dụng nó.


CHỈNH SỬA 1

nodejs-express-mongoose-demo rất giống với cách tôi đã cấu trúc. Kiểm tra nó ra.


2
Logic kinh doanh đi đến đâu? Bạn có bao giờ sử dụng trợ giúp cho những việc như xác thực không?
Eric the Red

@ErictheRed nếu bạn đã quen với MVC Pattern (rails, Asp.Net mvc, v.v.) thì tôi coi Routes là bộ điều khiển của mình và mọi thứ sẽ ổn thỏa sau đó. Logic kinh doanh đi trong các mô hình (mặc dù tôi đang gặp khó khăn với xác nhận và mongoose). Đối với người trợ giúp, tôi sử dụng Xuất trên một thư viện sử dụng nội bộ đơn giản mà tôi đang tập hợp lại cho chính mình cho những thứ tôi sử dụng lại.
Chance

Sẽ rất tuyệt nếu tải một thiết lập mẫu lên github để chúng tôi xem xét. Điều gì xảy ra trong thư mục / tệp Routes?
chovy

1
@chovy Tôi đã thêm một liên kết đến github.com/qed42/nodejs-express-mongoose-demo có cấu trúc rất giống
Chance

Tôi khuyên bạn nên tránh bất kỳ khuôn khổ cồng kềnh xây dựng trên đầu trang của nhanh
Raynos

9

Cảnh báo: mã tham chiếu mà tôi đã hack cùng nhau để loại bỏ nút, nó có vẻ hiệu quả nhưng không phải là thanh lịch hoặc bóng bẩy.

Để cụ thể hơn về việc chia nhỏ, app.jstôi có tệp app.js sau

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

bootstrap(app);

Về cơ bản, điều này có nghĩa là tôi đặt tất cả khởi động của mình trong một tệp riêng biệt, sau đó tôi khởi động máy chủ.

Vậy bootstrap để làm gì?

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

Nó chia nhỏ tất cả thiết lập khởi tạo máy chủ thành nhiều phần đẹp mắt. Đặc biệt

  • Tôi có một phần mềm thiết lập tất cả xác thực OAuth từ xa của mình bằng everyauth.
  • Tôi có một đoạn định cấu hình ứng dụng của mình (về cơ bản là gọi app.configure)
  • Tôi có một chút mã ít đục lỗ hơn để nó biên dịch lại bất kỳ mã nào ít hơn của tôi thành css tại thời điểm chạy.
  • Tôi có mã thiết lập tất cả các tuyến đường của mình
  • Tôi gọi đây là mô-đun nko nhỏ
  • Cuối cùng tôi khởi động máy chủ bằng cách lắng nghe một cổng.

Ví dụ, chúng ta hãy xem xét tệp định tuyến

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

Ở đây tôi tải tất cả các mô hình và tuyến đường của mình dưới dạng các mảng tệp.

Disclaimer: readdirSync chỉ ok khi được gọi trước khi bạn khởi động máy chủ http (trước đó .listen). Gọi các cuộc gọi chặn đồng bộ vào thời gian bắt đầu của máy chủ chỉ làm cho mã dễ đọc hơn (về cơ bản đó là một cuộc tấn công)

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

Ở đây tôi đục lỗ socket.io để thực sự sử dụng ủy quyền thay vì cho phép bất kỳ tom và jack nào nói chuyện với máy chủ socket.io của tôi

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

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

Ở đây tôi bắt đầu các tuyến đường của mình bằng cách chuyển mô hình có liên quan vào từng đối tượng tuyến đường được trả về từ tệp tuyến đường.

Về cơ bản, jist là bạn sắp xếp mọi thứ thành các mô-đun nhỏ xinh và sau đó có một số cơ chế khởi động.

Dự án khác của tôi (blog của tôi) có tệp init có cấu trúc tương tự .

Tuyên bố từ chối trách nhiệm: blog bị hỏng và không xây dựng được, tôi đang làm việc trên nó.



0

Tôi có các ứng dụng của mình được xây dựng dựa trên công cụ tạo nhanh. Bạn có thể cài đặt nó bằng cách chạy npm install express-generator -gvà chạy nó bằng cách sử dụng express <APP_NAME>.

Để cung cấp cho bạn một góc nhìn, một trong những cấu trúc ứng dụng nhỏ hơn của tôi trông như thế này:

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

Một điều thú vị mà tôi thích về cấu trúc này mà tôi cuối cùng đã áp dụng cho bất kỳ ứng dụng express nào mà tôi phát triển là cách các tuyến đường được tổ chức. Tôi không thích phải yêu cầu từng tệp định tuyến vào app.js và app.use()từng tuyến đường, đặc biệt là khi tệp lớn hơn. Do đó, tôi thấy hữu ích khi nhóm và tập trung tất cả app.use()vào tệp ./routes/index.js.

Cuối cùng, app.js của tôi sẽ trông giống như sau:

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

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

và ./routes/index.js của tôi sẽ trông giống như sau:

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

Tôi có thể đơn giản là require(./users)vì tôi đã viết tuyến người dùng bằng express.Router () cho phép tôi "nhóm" nhiều tuyến và sau đó xuất chúng cùng một lúc, với mục tiêu làm cho ứng dụng trở nên mô-đun hơn.

Đây là một ví dụ về những gì bạn sẽ ổn trên tuyến đường ./routers/users.js của tôi:


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

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

module.exports = router;

Hy vọng rằng điều này đã giúp trả lời câu hỏi của bạn! May mắn nhất!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.