[译]我是怎么构建Node.js程序的
原文: http://blog.ragingflame.co.za/2015/4/1/how-i-build-nodejs-applications
"保持简单, 保持模块化."
开发步骤
通常是从画一个项目的草图开始. :
- 分析项目的草图, 理解需要的Domain
- 创建项目的README文件
- 基于草图, 在文档中写出路由和 API
- 创建领域模型
- 选择软件堆栈和要依赖的Module
- 设置项目的仓储
- 写出数据库scheme, 创建数据库
- 开始编码,写Models 和 Collections
- 写单元测试
- 写Controllers 和类库
- 创建路由
- 写集成测试
- 创建API
- Review代码, 有必要的话进行调整
架构
我的应用受MVC的影响比较大. MVC 架构非常适合Node.js 开发.
下面是我的典型的目录结构.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | / api/ bin/ collections/ config/ controllers/ env/ lib/ models/ public/ routes/ test/ views/ .gitignore .jshintrc app.js package .json README.md |
下面我们描述下每个文件夹和文件在我们项目目录里的用处.
Documentation (./README.md)
README.md是我项目里非常重要的一个文件
.
我的 README.md
文件包含下面的信息:
- 项目名和描述
- 软件要求
- 依赖
- Getting started instructions
- 需求配置
- 任务命令
- 风格指南
- 应用架构
- 路由/API
- License信息
下面的例子是我怎么描述我的路由的:
1 2 3 4 5 6 | /** * Routes **/ GET /items - get a collection of items GET /items/:id - get one item POST /items - save an item |
./models
在软件应用中, model通常代表一个数据库表的记录.
./models/mymodel.js
1 2 3 4 5 6 7 8 9 10 | // get config var config = require( '../config' ); // connect to the database var Bookshelf = require( '../lib/dbconnect' )(config); // define model var myModel = Bookshelf.Model.extend({ tableName: 'items' }); // export collection module module.exports = myModel; |
./collections
Collections 像表一样的一组model. 一个collection
通常代表一个完整的数据库表.
./collections/mycollection.js
1 2 3 4 5 6 7 8 | //require the model for this collection var myModel = require( '../models/mymodel' ); // define collection var myCollection = Bookshelf.Collection.extend({ model: myModel }); // export collection module module.exports = myCollection; |
./controllers
Controllers, 和其他的典型的 MVC 一样, 负责应用的业务逻辑. 我们的controllers根据路由处理数据、查询数据库.
./controllers/items.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | var myModel = require( '../models/mymodel' ); var myCollection = require( '../collections/mycollection' ); module.exports = { // GET /items/:id getItem: function (req, res, next) { var id = req.params.id; myModel.forge({id: id}) .fetch() .then( function (model) { res.json(model.toJSON()); }) .otherwise( function (error) { res.status(500).json({msg: error.message}); }); }, // GET /items getItems: function (req, res, next) { var id = req.params.id; myCollection.forge() .fetch() .then( function (collection) { res.json(collection.toJSON()); }) .otherwise( function (error) { res.status(500).json({msg: error.message}); }); }, // POST /items // (Don't forget to validate and sanitize all user input) saveItem: function (req, res, next) { myModel.forge(req.body) .save() .then( function (model) { res.json(model.toJSON()); }) .otherwise( function (error) { res.status(500).json({msg: error.message}); }); } }; |
./routes
存放路由.
./routes/items.js
1 2 3 4 5 6 7 8 9 | var express = require( 'express' ); var itemsController = require( '../controllers/items' ); module.exports = function () { var router = express.Router(); router.get( '/items' , itemsController.getItems); router.get( '/items/:id' , itemsController.getItem); router.post( '/items' , itemsController.saveItem); return router; }; |
./config
当我们创建model的时候我们需要config module. config的唯一目的是检查环境类型从env文件夹加载适当的config文件. config目录只有一个文件
index.js
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | module.exports = ( function (env) { var config = {}; switch (env) { case 'production' : config = require( '../env/production' ); break ; case 'development' : config = require( '../env/development' ); break ; case 'testing' : config = require( '../env/testing' ); break ; case 'staging' : config = require( '../env/staging' ); break ; default : console.error( 'NODE_ENV environment variable not set' ); process.exit(1); } return config; })(process.env.NODE_ENV); |
./env
env
目录包含了对应不同环境模式的config文件: development.js
, production.js
, test.js
, and staging.js
.
Here is an example of one file:
1 2 3 4 5 6 7 8 9 10 11 12 13 | module.exports = { pg: { host: '127.0.0.1' , database: 'test' , user: 'test' , password: 'test' , charset: 'utf8' }, mongodb: { url: 'mongodb://localhost:27017/test' }, sessionSecret: 'ninja_cat' }; |
注意了: 别在config文件中包含敏感数据, 敏感数据放到环境变量中去
./api
api
文件夹包含应用的api文件. 我用创建controller一样的方法创建api文件, 唯一不同的是controller会加载一个视图文件.
./lib
lib
文件夹在Node modules中非常普遍. 如果你的应用使用了特别的算法或helpers lib目录适合放他们. 在大多数情况下controller需要一个lib 文件来执行一些特定的任务
.
./bin
bin包含我自己的
command-line scripts. 例如:
1 2 | #!/usr/bin/env node console.log( 'I am an executable file' ); |
./public
public
文件夹包含一些客户端的静态文件, 例如images, css, 前端JavaScript, fonts 等
./views
我所有的视图模板都放在这.
./test
test
目录包含了所有的测试用例.
./.gitignore
.gitignore
文件用来告诉GIT那些文件或者目录不要版本控制.
1 2 3 4 5 6 7 | *.zip *.psd *~ node_modules/ bower_components/ build/ temp/ |
./.jshintrc
.jshintrc
是 jshint 的配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | { "curly" : false , "eqeqeq" : true , "immed" : true , "latedef" : false , "newcap" : true , "noarg" : true , "sub" : true , "undef" : true , "boss" : true , "eqnull" : true , "node" : true , "browser" : true , "globals" : { "jQuery" : true , "define" : true , "requirejs" : true , "require" : true , "describe" : true , "it" : true , "beforeEach" : true , "before" : true } } |
./package.json
package.json
是一个标准的npm文件, 列出了所有应用的 dependencies 和 metadata.
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 | { ... "scripts" : { "start" : "node app.js" , "dev" : "nodemon app" , "jshint" : "jshint api collections config controllers env lib models public/javascripts routes test app.js" , "test" : "npm run jshint && mocha test" , "precommit" : "npm test" , "prepush" : "npm shrinkwrap && npm test" , "postmerge" : "npm install" } ... } |
一些我经常用的 modules
- Express - App frameworks
- Bookshelf - Postgres 和 MySQL 的 ORM
- lodash - 工具类库
- passport - 验证
- mongoose - MongoDB ODM
- when.js - promises library
- moment - 分析, 验证, manipulating, 格式化日期
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· 《HelloGitHub》第 108 期
· Windows桌面应用自动更新解决方案SharpUpdater5发布
· 我的家庭实验室服务器集群硬件清单
· Supergateway:MCP服务器的远程调试与集成工具
· C# 13 中的新增功能实操