จะจัดโครงสร้างแอปพลิเคชัน express.js ได้อย่างไร?


102

มีหลักการทั่วไปสำหรับการแบ่งและแยกapp.jsไฟล์ในแอปพลิเคชันExpress.jsหรือไม่ หรือเป็นเรื่องปกติที่จะเก็บทุกอย่างไว้ในไฟล์เดียว?


3
มีคนทำลายพวกเขาเป็นเส้นทาง นอกจากนี้คุณสามารถดูแหล่งข้อมูลด่วน
BRampersad

@Brandon_R ลองทรัพยากรแล้วหรือยัง? ฉันเหลือบมองมันและคิดว่ามันดูเรียบร้อยแค่ยังไม่ได้เตะยาง
โอกาส

1
ช้าไปหน่อย แต่ฉันเพิ่งเปิดเราเตอร์สำหรับ Express ซึ่งช่วยให้คุณแยก app.js ตัวควบคุมอินโทรอย่างสวยงาม + มุมมองอื่น ๆ ดู: github.com/kishorenc/road
jeffreyveon

คำตอบ:


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

ฉันใช้การส่งออกเพื่อส่งคืนสิ่งที่เกี่ยวข้อง ตัวอย่างเช่นในโมเดลที่ฉันทำ:

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

จากนั้นถ้าฉันต้องการสร้างหมายเลขโทรศัพท์ก็ทำได้ง่ายๆดังนี้:

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

ถ้าฉันจำเป็นต้องใช้สคีมา PhoneNumber.schema

(ซึ่งสมมติว่าเรากำลังทำงานจากโฟลเดอร์เส้นทางและต้องขึ้น 1 ระดับแล้วลงไปที่โมเดล)


แก้ไข 4

วิกิพีเดียด่วนมีรายชื่อของกรอบขึ้นด้านบนของมัน

ในจำนวนนั้นฉันคิดว่ามาธาดอร์ของ Twitter มีโครงสร้างที่ค่อนข้างดี เราใช้วิธีการที่คล้ายกันมากในการโหลดบางส่วนของแอป

derby.jsก็ดูน่าสนใจมากเช่นกัน มันคล้ายกับดาวตกที่ไม่มีโฆษณาทั้งหมดและให้เครดิตจริง ๆ เมื่อถึงกำหนดเครดิต (โดยเฉพาะโหนดและด่วน)


แก้ไข 3

หากคุณเป็นแฟนของ CoffeeScript (ฉันไม่ใช่) และต้องการ L&F ของ Rails จริงๆก็มีTower.jsเช่นกัน


แก้ไข 2

หากคุณมีความคุ้นเคยกับทางรถไฟและไม่ทราบเลือดออกมากกว่าแนวคิดบางอย่างมีหัวรถจักร เป็นเฟรมเวิร์กน้ำหนักเบาที่สร้างขึ้นบน Express มีโครงสร้างที่คล้ายกันมากกับ RoR และมีแนวคิดพื้นฐานบางอย่าง (เช่นการกำหนดเส้นทาง)

ควรตรวจสอบแม้ว่าคุณจะไม่ได้วางแผนที่จะใช้ก็ตาม


แก้ไข 1

nodejs-express-mongoose-demoนั้นคล้ายกับโครงสร้างของฉันมาก ลองดูสิ


2
ตรรกะทางธุรกิจไปไหน? คุณเคยใช้ตัวช่วยสำหรับสิ่งต่างๆเช่นการพิสูจน์ตัวตนหรือไม่?
Eric the Red

@ErictheRed ถ้าคุณคุ้นเคยกับรูปแบบ MVC (ราง Asp.Net mvc ฯลฯ ) แล้วฉันจะถือว่า Routes เป็นตัวควบคุมของฉันและทุกอย่างก็เข้าที่หลังจากนั้น ตรรกะทางธุรกิจมีอยู่ในแบบจำลอง (แม้ว่าฉันจะมีปัญหาในการตรวจสอบความถูกต้องและพังพอน) สำหรับผู้ช่วยเหลือฉันใช้การส่งออกในไลบรารี util ภายในที่เรียบง่ายซึ่งฉันรวบรวมไว้ด้วยตัวเองสำหรับสิ่งที่ฉันนำมาใช้ใหม่
โอกาส

จะเป็นการดีที่จะอัปโหลดตัวอย่างการตั้งค่าไปยัง github เพื่อให้เราดู เกิดอะไรขึ้นในโฟลเดอร์ / ไฟล์เส้นทาง
chovy

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

โดยทั่วไปหมายความว่าฉันวาง bootstrapping ทั้งหมดไว้ในไฟล์แยกจากนั้นฉันบูตเซิร์ฟเวอร์

ดังนั้นสิ่งที่จะบูตทำอย่างไร

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

มันแยกการตั้งค่าเริ่มต้นเซิร์ฟเวอร์ทั้งหมดออกเป็นชิ้น ๆ โดยเฉพาะ

  • ฉันมีส่วนที่ตั้งค่าการตรวจสอบสิทธิ์ OAuth ระยะไกลทั้งหมดโดยใช้ everyauth
  • ฉันมีชิ้นส่วนที่กำหนดค่าแอปพลิเคชันของฉัน (เรียกโดยทั่วไป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) การโทรบล็อกการโทรแบบซิงโครนัสในเวลาเริ่มต้นของเซิร์ฟเวอร์ทำให้โค้ดอ่านง่ายขึ้น (โดยพื้นฐานแล้วเป็นการแฮ็ก)

    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 เพื่อใช้การอนุญาตจริง ๆ แล้วปล่อยให้ทอมและแจ็คคุยกับเซิร์ฟเวอร์ socket.io ของฉัน

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

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

ที่นี่ฉันเริ่มเส้นทางของฉันโดยส่งแบบจำลองที่เกี่ยวข้องไปยังวัตถุแต่ละเส้นทางที่ส่งคืนจากไฟล์เส้นทาง

โดยพื้นฐานแล้ว jist คือคุณจัดระเบียบทุกอย่างเป็นโมดูลเล็ก ๆ ที่สวยงามจากนั้นมีกลไกการบูตบางอย่าง

โครงการอื่น ๆ ของฉัน (บล็อกของฉัน) มีไฟล์ init มีโครงสร้างที่คล้ายกัน

ข้อจำกัดความรับผิดชอบ:บล็อกเสียและไม่ได้สร้างฉันกำลังดำเนินการแก้ไข



0

ฉันมีแอปของฉันที่สร้างขึ้นจากเครื่องมือสร้างด่วน คุณสามารถติดตั้งได้โดยเรียกใช้ 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;

หวังว่านี่จะช่วยตอบคำถามของคุณได้! ขอให้โชคดี!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.