OK, đã được một thời gian và đây là một câu hỏi phổ biến, vì vậy tôi đã đi trước và tạo ra một kho lưu trữ github giàn giáo với mã JavaScript và một README dài về cách tôi muốn cấu trúc một ứng dụng express.js cỡ trung bình.
Focusaurus / express_code_itectture là repo với mã mới nhất cho việc này. Kéo yêu cầu chào mừng.
Đây là ảnh chụp nhanh của README vì stackoverflow không giống như câu trả lời chỉ là một liên kết. Tôi sẽ thực hiện một số cập nhật vì đây là một dự án mới mà tôi sẽ tiếp tục cập nhật, nhưng cuối cùng thì repo github sẽ là nơi cập nhật cho thông tin này.
Cấu trúc mã nhanh
Dự án này là một ví dụ về cách tổ chức một ứng dụng web express.js cỡ trung bình.
Hiện tại ít nhất là v4,14 tháng 12 năm 2016
Ứng dụng của bạn lớn như thế nào?
Các ứng dụng web không giống nhau và theo tôi, không có một cấu trúc mã nào được áp dụng cho tất cả các ứng dụng express.js.
Nếu ứng dụng của bạn nhỏ, bạn không cần cấu trúc thư mục sâu như ví dụ ở đây. Chỉ cần đơn giản và dán một số .js
tệp trong thư mục gốc của kho lưu trữ của bạn và bạn đã hoàn tất. Võngà.
Nếu ứng dụng của bạn rất lớn, đến một lúc nào đó bạn cần chia nó thành các gói npm riêng biệt. Nói chung, cách tiếp cận node.js dường như ưu tiên nhiều gói nhỏ, ít nhất là cho các thư viện và bạn nên xây dựng ứng dụng của mình bằng cách sử dụng một số gói npm vì điều đó bắt đầu có ý nghĩa và biện minh cho chi phí. Vì vậy, khi ứng dụng của bạn phát triển và một phần mã trở nên rõ ràng có thể tái sử dụng bên ngoài ứng dụng của bạn hoặc là một hệ thống con rõ ràng, hãy chuyển nó sang kho git của chính nó và biến nó thành một gói npm độc lập.
Vì vậy, trọng tâm của dự án này là minh họa một cấu trúc hoàn toàn khả thi cho một ứng dụng cỡ trung bình.
Kiến trúc tổng thể của bạn là gì
Có nhiều cách tiếp cận để xây dựng một ứng dụng web, chẳng hạn như
- Server Side MVC là một Ruby trên Rails
- Ứng dụng một trang kiểu a la MongoDB / Express / Angular / Node (MEAN)
- Trang web cơ bản với một số hình thức
- Mô hình / Hoạt động / Lượt xem / Phong cách sự kiện theo kiểu MVC đã chết, đã đến lúc chuyển sang
- và nhiều người khác cả hiện tại và lịch sử
Mỗi trong số này phù hợp độc đáo vào một cấu trúc thư mục khác nhau. Đối với mục đích của ví dụ này, nó chỉ là giàn giáo và không phải là một ứng dụng hoạt động hoàn toàn, nhưng tôi giả sử các điểm kiến trúc chính sau:
- Trang web có một số trang / mẫu tĩnh truyền thống
- Phần "ứng dụng" của trang web được phát triển theo kiểu Ứng dụng một trang
- Ứng dụng hiển thị API kiểu REST / JSON cho trình duyệt
- Ứng dụng này mô hình một miền kinh doanh đơn giản, trong trường hợp này, đó là một ứng dụng đại lý xe hơi
Còn Ruby on Rails thì sao?
Đây sẽ là một chủ đề xuyên suốt dự án này, nhiều ý tưởng thể hiện trong Ruby on Rails và các quyết định "Công ước về cấu hình" mà họ đã thông qua, mặc dù được chấp nhận và sử dụng rộng rãi, nhưng thực sự không hữu ích và đôi khi trái ngược với những gì kho lưu trữ này đề nghị.
Quan điểm chính của tôi ở đây là có các nguyên tắc cơ bản để tổ chức mã và dựa trên các nguyên tắc đó, các quy ước của Ruby on Rails có ý nghĩa (chủ yếu) đối với cộng đồng Ruby on Rails. Tuy nhiên, chỉ cần vô tư kích hoạt những quy ước đó bỏ lỡ điểm. Khi bạn tìm hiểu các nguyên tắc cơ bản, TẤT CẢ các dự án của bạn sẽ được tổ chức tốt và rõ ràng: kịch bản shell, trò chơi, ứng dụng di động, dự án doanh nghiệp, thậm chí thư mục chính của bạn.
Đối với cộng đồng Rails, họ muốn có thể có một nhà phát triển Rails duy nhất chuyển từ ứng dụng này sang ứng dụng này sang ứng dụng khác và làm quen và thoải mái với nó mỗi lần. Điều này rất có ý nghĩa nếu bạn là 37 tín hiệu hoặc Pivotal Labs và có lợi ích. Trong thế giới JavaScript phía máy chủ, các đặc điểm chung chỉ là cách mọi thứ ở phía tây hoang dã hơn và chúng ta không thực sự có vấn đề với điều đó. Đó là cách chúng tôi lăn. Chúng ta đã quen với nó. Ngay cả trong express.js, đó là người thân của Sinatra, không phải Rails và việc thực hiện các quy ước từ Rails thường không giúp được gì. Tôi thậm chí sẽ nói Nguyên tắc về Công ước về Cấu hình .
Nguyên tắc và động lực cơ bản
Thủ thuật symlink ứng dụng
Có rất nhiều cách tiếp cận nêu và thảo luận tại chiều dài của cộng đồng trong các ý chính lớn Better địa phương yêu cầu () đường dẫn cho Node.js . Tôi có thể sớm quyết định thích "chỉ giao dịch với nhiều ../../../ .." hoặc sử dụng modlue requestFrom . Tuy nhiên, hiện tại, tôi đã sử dụng thủ thuật symlink chi tiết bên dưới.
Vì vậy, một cách để tránh yêu cầu nội bộ dự án với các đường dẫn tương đối khó chịu như require("../../../config")
là sử dụng thủ thuật sau:
- tạo một liên kết tượng trưng dưới node_modules cho ứng dụng của bạn
- cd node_modules && ln -nsf ../app
- chỉ thêm chính symlink node_modules / app , chứ không phải toàn bộ thư mục node_modules, vào git
- git add -f node_modules / ứng dụng
- Có, bạn vẫn nên có "node_modules" trong
.gitignore
tệp của mình
- Không, bạn không nên đặt "node_modules" vào kho git của mình. Một số người sẽ khuyên bạn nên làm điều này. Họ không chính xác.
- Bây giờ bạn có thể yêu cầu các mô-đun nội bộ dự án bằng cách sử dụng tiền tố này
var config = require("app/config");
var DealModel = require("app/deals/deal-model")
;
- Về cơ bản, điều này làm cho nội bộ dự án đòi hỏi công việc rất giống với yêu cầu cho các mô-đun npm bên ngoài.
- Xin lỗi, người dùng Windows, bạn cần phải gắn bó với các đường dẫn tương đối của thư mục cha.
Cấu hình
Nói chung, các mô-đun mã và các lớp chỉ mong đợi một options
đối tượng JavaScript cơ bản được truyền vào. Chỉ app/server.js
nên tải app/config.js
mô-đun. Từ đó, nó có thể tổng hợp các options
đối tượng nhỏ để cấu hình các hệ thống con khi cần, nhưng ghép mọi hệ thống con với một mô-đun cấu hình toàn cầu lớn chứa đầy thông tin bổ sung là khớp nối xấu.
Cố gắng tập trung vào việc tạo các kết nối DB và chuyển chúng vào các hệ thống con trái ngược với việc truyền các tham số kết nối và có các hệ thống con tự tạo các kết nối đi.
NODE_ENV
Đây là một ý tưởng hấp dẫn nhưng khủng khiếp khác được thực hiện từ Rails. Cần có chính xác 1 vị trí trong ứng dụng của bạn, app/config.js
đó là xem NODE_ENV
biến môi trường. Mọi thứ khác nên có một tùy chọn rõ ràng làm tham số cấu trúc mô đun hoặc tham số cấu hình mô đun.
Nếu mô-đun email có một tùy chọn về cách gửi email (SMTP, đăng nhập vào thiết bị xuất chuẩn, đặt hàng đợi, v.v.), thì nó sẽ có một tùy chọn như thế {deliver: 'stdout'}
nhưng tuyệt đối không nên kiểm tra NODE_ENV
.
Xét nghiệm
Bây giờ tôi giữ các tệp thử nghiệm của mình trong cùng thư mục với mã tương ứng của chúng và sử dụng các quy ước đặt tên mở rộng tên tệp để phân biệt các thử nghiệm với mã sản xuất.
foo.js
có mã của mô-đun "foo"
foo.tape.js
có các bài kiểm tra dựa trên nút cho foo và sống trong cùng một thư mục
foo.btape.js
có thể được sử dụng cho các bài kiểm tra cần thực hiện trong môi trường trình duyệt
Tôi sử dụng các hệ thống tập tin và find . -name '*.tape.js'
lệnh để có quyền truy cập vào tất cả các bài kiểm tra của tôi khi cần thiết.
Cách tổ chức mã trong mỗi .js
tệp mô-đun
Phạm vi của dự án này chủ yếu là về nơi các tệp và thư mục đi đến và tôi không muốn thêm nhiều phạm vi khác, nhưng tôi sẽ chỉ đề cập rằng tôi sắp xếp mã của mình thành 3 phần riêng biệt.
- Mở khối CommonJS yêu cầu các cuộc gọi đến các phụ thuộc trạng thái
- Khối mã chính của JavaScript thuần. Không có ô nhiễm CommonJS ở đây. Không tham chiếu xuất khẩu, mô-đun, hoặc yêu cầu.
- Đóng khối CommonJS để thiết lập xuất khẩu