原文: http://blog.ragingflame.co.za/2015/4/1/how-i-build-nodejs-applications

"保持简单, 保持模块化."

开发步骤

通常是从画一个项目的草图开始. :

  1. 分析项目的草图, 理解需要的Domain
  2. 创建项目的README文件
  3. 基于草图, 在文档中写出路由和 API
  4. 创建领域模型
  5. 选择软件堆栈和要依赖的Module
  6. 设置项目的仓储
  7. 写出数据库scheme, 创建数据库
  8. 开始编码,写Models 和 Collections
  9. 写单元测试
  10. 写Controllers 和类库
  11. 创建路由
  12. 写集成测试
  13. 创建API
  14. Review代码, 有必要的话进行调整

架构

我的应用受MVC的影响比较大. MVC 架构非常适合Node.js 开发.

下面是我的典型的目录结构.

  1. /
  2. api/
  3. bin/
  4. collections/
  5. config/
  6. controllers/
  7. env/
  8. lib/
  9. models/
  10. public/
  11. routes/
  12. test/
  13. views/
  14. .gitignore
  15. .jshintrc
  16. app.js
  17. package.json
  18. README.md

下面我们描述下每个文件夹和文件在我们项目目录里的用处.

Documentation (./README.md)

README.md是我项目里非常重要的一个文件.

我的 README.md 文件包含下面的信息:

  1. 项目名和描述
  2. 软件要求
  3. 依赖
  4. Getting started instructions
  5. 需求配置
  6. 任务命令
  7. 风格指南
  8. 应用架构
  9. 路由/API
  10. License信息

下面的例子是我怎么描述我的路由的:

  1. /**
  2. * Routes
  3. **/
  4. GET /items - get a collection of items
  5. GET /items/:id - get one item
  6. POST /items - save an item

./models

在软件应用中, model通常代表一个数据库表的记录.

./models/mymodel.js

  1. // get config
  2. var config = require('../config');
  3. // connect to the database
  4. var Bookshelf = require('../lib/dbconnect')(config);
  5. // define model
  6. var myModel = Bookshelf.Model.extend({
  7. tableName: 'items'
  8. });
  9. // export collection module
  10. module.exports = myModel;

./collections

Collections 像表一样的一组model. 一个collection 通常代表一个完整的数据库表.

./collections/mycollection.js

  1. //require the model for this collection
  2. var myModel = require('../models/mymodel');
  3. // define collection
  4. var myCollection = Bookshelf.Collection.extend({
  5. model: myModel
  6. });
  7. // export collection module
  8. module.exports = myCollection;

./controllers

Controllers, 和其他的典型的 MVC 一样, 负责应用的业务逻辑. 我们的controllers根据路由处理数据、查询数据库.

./controllers/items.js

  1. var myModel = require('../models/mymodel');
  2. var myCollection = require('../collections/mycollection');
  3. module.exports = {
  4. // GET /items/:id
  5. getItem: function(req, res, next) {
  6. var id = req.params.id;
  7. myModel.forge({id: id})
  8. .fetch()
  9. .then(function (model) {
  10. res.json(model.toJSON());
  11. })
  12. .otherwise(function (error) {
  13. res.status(500).json({msg: error.message});
  14. });
  15. },
  16. // GET /items
  17. getItems: function(req, res, next) {
  18. var id = req.params.id;
  19. myCollection.forge()
  20. .fetch()
  21. .then(function (collection) {
  22. res.json(collection.toJSON());
  23. })
  24. .otherwise(function (error) {
  25. res.status(500).json({msg: error.message});
  26. });
  27. },
  28. // POST /items
  29. // (Don't forget to validate and sanitize all user input)
  30. saveItem: function(req, res, next) {
  31. myModel.forge(req.body)
  32. .save()
  33. .then(function (model) {
  34. res.json(model.toJSON());
  35. })
  36. .otherwise(function (error) {
  37. res.status(500).json({msg: error.message});
  38. });
  39. }
  40. };

./routes

存放路由.

./routes/items.js

  1. var express = require('express');
  2. var itemsController = require('../controllers/items');
  3. module.exports = function () {
  4. var router = express.Router();
  5. router.get('/items', itemsController.getItems);
  6. router.get('/items/:id', itemsController.getItem);
  7. router.post('/items', itemsController.saveItem);
  8. return router;
  9. };

./config

当我们创建model的时候我们需要config module. config的唯一目的是检查环境类型从env文件夹加载适当的config文件. config目录只有一个文件 index.js.

  1. module.exports = (function (env) {
  2. var config = {};
  3. switch (env) {
  4. case 'production':
  5. config = require('../env/production');
  6. break;
  7. case 'development':
  8. config = require('../env/development');
  9. break;
  10. case 'testing':
  11. config = require('../env/testing');
  12. break;
  13. case 'staging':
  14. config = require('../env/staging');
  15. break;
  16. default:
  17. console.error('NODE_ENV environment variable not set');
  18. process.exit(1);
  19. }
  20. return config;
  21. })(process.env.NODE_ENV);

./env

env 目录包含了对应不同环境模式的config文件: development.jsproduction.jstest.js, and staging.js.

Here is an example of one file:

  1. module.exports = {
  2. pg: {
  3. host: '127.0.0.1',
  4. database: 'test',
  5. user: 'test',
  6. password: 'test',
  7. charset: 'utf8'
  8. },
  9. mongodb: {
  10. url: 'mongodb://localhost:27017/test'
  11. },
  12. sessionSecret: 'ninja_cat'
  13. };

注意了: 别在config文件中包含敏感数据, 敏感数据放到环境变量中去

./api

api 文件夹包含应用的api文件. 我用创建controller一样的方法创建api文件, 唯一不同的是controller会加载一个视图文件.

./lib

lib 文件夹在Node modules中非常普遍. 如果你的应用使用了特别的算法或helpers lib目录适合放他们. 在大多数情况下controller需要一个lib 文件来执行一些特定的任务.

./bin

bin包含我自己的command-line scripts. 例如:

  1. #!/usr/bin/env node
  2. console.log('I am an executable file');

./public

public 文件夹包含一些客户端的静态文件, 例如images, css, 前端JavaScript, fonts 等

./views

我所有的视图模板都放在这.

./test

test 目录包含了所有的测试用例.

./.gitignore

.gitignore 文件用来告诉GIT那些文件或者目录不要版本控制.

  1. *.zip
  2. *.psd
  3. *~
  4. node_modules/
  5. bower_components/
  6. build/
  7. temp/

./.jshintrc

.jshintrc 是 jshint 的配置文件

  1. {
  2. "curly": false,
  3. "eqeqeq": true,
  4. "immed": true,
  5. "latedef": false,
  6. "newcap": true,
  7. "noarg": true,
  8. "sub": true,
  9. "undef": true,
  10. "boss": true,
  11. "eqnull": true,
  12. "node": true,
  13. "browser": true,
  14. "globals": {
  15. "jQuery": true,
  16. "define": true,
  17. "requirejs":true,
  18. "require": true,
  19. "describe": true,
  20. "it": true,
  21. "beforeEach": true,
  22. "before": true
  23. }
  24. }

./package.json

package.json 是一个标准的npm文件, 列出了所有应用的 dependencies 和 metadata.

例子:

  1. {
  2. ...
  3. "scripts": {
  4. "start": "node app.js",
  5. "dev": "nodemon app",
  6. "jshint": "jshint api collections config controllers env lib models public/javascripts routes test app.js",
  7. "test": "npm run jshint && mocha test",
  8. "precommit": "npm test",
  9. "prepush": "npm shrinkwrap && npm test",
  10. "postmerge": "npm install"
  11. }
  12. ...
  13. }

一些我经常用的 modules

  • Express - App frameworks
  • Bookshelf - Postgres 和 MySQL 的 ORM
  • lodash - 工具类库
  • passport - 验证
  • mongoose - MongoDB ODM
  • when.js - promises library
  • moment - 分析, 验证, manipulating, 格式化日期

[译]我是怎么构建Node.js程序的的更多相关文章

  1. 在Visual Studio上开发Node.js程序(2)——远程调试及发布到Azure

    [题外话] 上次介绍了VS上开发Node.js的插件Node.js Tools for Visual Studio(NTVS),其提供了非常方便的开发和调试功能,当然很多情况下由于平台限制等原因需要在 ...

  2. [译]How to Install Node.js on Ubuntu 14.04 如何在ubuntu14.04上安装node.js

    原文链接为 http://www.hostingadvice.com/how-to/install-nodejs-ubuntu-14-04/ 由作者Jacob Nicholson 发表于October ...

  3. 玩儿转物联网IoT - 在Beagle Bone Black上运行node.js 程序

    物联网(IoT)技术方兴未艾,智能手环,智能血压计,智能眼镜甚至智能鞋垫都开始进入我们的生活,各种智能设备层出不穷,世界已经到了一个"人有多大胆,地有多大产"的时代,不玩儿点物联网 ...

  4. 在Visual Studio上开发Node.js程序

    [题外话] 最近准备用Node.js做些东西,于是找找看能否有Visual Studio上的插件以方便开发.结果还真找到了一个,来自微软的Node.js Tools for Visual Studio ...

  5. 使用events.EventEmitter 控制Node.js 程序执行流程

    使用events.EventEmitter 控制Node.js 程序执行流程 标题写的可能也不太对,大家领会精神: Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台. ...

  6. 一种简单的生产环境部署Node.js程序方法

    最近在部署Node.js程序时,写了段简单的脚本,发觉还挺简单的,忍不住想与大家分享. 配置文件 首先,本地测试环境和生产环境的数据库连接这些配置信息是不一样的,需要将其分开为两个文件存储 到conf ...

  7. Node.js程序在node-windows中不能运行

      Node.js程序部分功能在命令行中运行良好,但在node-windows中不能运行,怎么回事? 答:路径问题. 请看如下的描述: My script runs fine on it's own, ...

  8. 在Visual Studio 2013 上开发Node.js程序

    [题外话] 最近准备用Node.js做些东西,于是找找看能否有Visual Studio上的插件以方便开发.结果还真找到了一个,来自微软的Node.js Tools for Visual Studio ...

  9. 3.第一个Node.js程序:Hello World!

    转自:http://www.runoob.com/nodejs/nodejs-tutorial.html 以下是我们的第一个Node.js程序: console.log("Hello Wor ...

随机推荐

  1. JeeSite环境搭建及运行和打包(master20161117)

    涉及的软件: 1.phpStudy(主要用MySql) 2.maven3(用于依赖包,下面我将上传已经下载好所有依赖包的版本,保证运行正常) 具体操作: 0.前言 由于GitHub上的Release版 ...

  2. bzoj1124[POI2008]枪战maf

    这代码快写死我了.....死人最多随便推推结论.死人最少,每个环可以单独考虑,每个环上挂着的每棵树也可以分别考虑.tarjan找出所有环,对环上每个点,求出选它和不选它时以它为根的树的最大独立集(就是 ...

  3. Git: 一些基本命令

    1.快速获取远程项目 1) git clone xxx.git // 如:git clone git://git.kernel.org/pub/scm/git/git.git 2) git clone ...

  4. 【翻译自nikic大神】PHP中原生类型的方法

    引言 第一次,翻译别人的文章,用四级英语的水平来翻译~~囧,可能有很多不太恰当的地方,尽管拍砖(有些地方实在想不到恰当的翻译,我同时贴出了原文和自己很low的翻译). 翻译这篇文章用了我3个晚上一个中 ...

  5. pom中定义某jar包的依赖,但并不使用该jar包,那最后部署的应用中会有这个jar包么?

    关于这个问题,首先得明确这个jar包的依赖是怎么定义的,我们知道在maven的pom文件中,会有:dependencymanagement和dependency2个部分   一般我们说在depende ...

  6. codevs 3143 二叉树的序遍历

    传送门 Description 求一棵二叉树的前序遍历,中序遍历和后序遍历 Input 第一行一个整数n,表示这棵树的节点个数. 接下来n行每行2个整数L和R.第i行的两个整数Li和Ri代表编号为i的 ...

  7. django 提示ImportError: cannot import name json_response

    from json_response import JsonResponse, json_response as json_resp 使用的语句如上,其实并不是没有安装,只是需要升级一下 pip in ...

  8. JavaWeb学习总结-04 Servlet 学习和使用

    一 Servlet 1 Servlet概念 Servlet时运行在服务器端的Java程序. Servlet的框架核心是 javax.servlet.Servlet 接口. 所有自定义的Servlet都 ...

  9. JQuery 和JavaScript的区别

    Google提供的jquery包: http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js jQuery官方的jquery包: ...

  10. 百度云管家 5.3.6 VIP破解不限速版下载分享|百度云管家破解提速

    百度云管家PC客户端v5.3.6绿色版本,属于VIP破解不限速版.百度网盘为您提供文件的网络备份.同步和分享服务.空间大.速度快.安全稳固,支持教育网加速,支持手机端.它支持便捷地查看.上传.下载云端 ...