Derby是一个新的,成熟的MVC框架,作为Express的中间件使用。 Express.js是使用中间件概念增强应用程序功能的一个流行的node框架。 Racer也支持Derby,他是一个数据同步引擎,类似Handlebars的模板引擎,拥有很多其他特性。 Meteor和Sails.js是另一个实时全栈Node.js的MVC框架,可与DerbyJS相媲美。 不过Meteor更保守些,他往往需要依赖于其他专有的解决方案和软件包。
本示例将使用Express.js、DerbyJS、MongoDB和Redis构建一个实时的应用程序。 项目结构: 1.项目依赖和package.json 2.服务器端代码 3.DerbyJS应用程序 4.DerbyJS视图 5.编辑器Tryout
创建项目文件夹editor和文件package.json
{ "name": "editor", "version": "0.0.1", "private": true, "description": "在线实时编辑器", "main": "index.js", "scripts": { "test": "mocha test" }, "git repository": "https://github.com/client-zy/aml", "keywords": "editor node derby real-time", "author": "lijian", "license": "BSD", "dependencies": { "derby": "~0.5.12", "express": "~3.4.8", "livedb-mongo": "~0.3.0", "racer-browserchannel": "~0.1.1", "redis": "~0.10.0" } }模块说明: derby(DerbyJS)和Express.js是为了路由 redis,racer-browserchannel和livedb-mongo是为了使DerbyJS用Redis和MongoDB数据库
这行代码用来启动Derby服务器
创建editor/server.js作为应用的入口文件 //1.引入依赖
var path = require('path'), express = require('express'), derby = require('derby'), racerBrowserChannel = require('racer-browserChannel'), liveDbMongo = require('livedb-mongo'),//2.定义Derby应用程序的文件
app = require(path.join(__dirname, 'app.js')),//3.实例化Express.js应用程序
expressApp = module.exports = express(),//4.Redis客户端
redis = require('redis').createClient(),//5.本地MongoDB连接URI
mongoUrl = 'mongodb://localhost:27017/editor';//6.使用连接URI和redis客户端对象创建一个liveDbMongo对象
var store = derby.createStore({ db: liveDbMongo(mongoUrl + '?auto_reconnect', { safe: true }), redis: redis });//7.定义一个公共文件夹
var publicDir = path.join(__dirname, 'public');//8.用链式调用声明使用Express.js中间件
expressApp .use(express.favicon()) .use(express.compress())//9.中间件DerbyJS-specific提供了Derby路由和模型对象
.use(app.scripts(store)) .use(racerBrowserChannel(store)) .use(store.modelMiddleware()) .use(app.router())//10.常规的Express.js路由中间件
.use(expressApp.router);//11.在一个服务器端混合使用Express.js和DerbyJS是可以的 //用404涵盖所有路由
expressApp.all('*', function(req, res, next){ return next('404: ' + req.url); });DerbyJS应用程序(app.js)巧妙地在浏览器和服务器间共享代码, 所以可以在一个地方(Node.js文件)写函数和方法。 然而,依赖DerbyJS规则可以把app.js中的部分代码变成浏览器JavaScript代码 这种行为可以更好地复用和组织代码,因为不需要复制路由、helper函数和实体方法。 把DerbyJS应用程序文件中的代码变成浏览器代码的一种方法是用app.ready(),
editor/app.js文件
//1.声明变量,创建一个应用程序 var app; app = require('derby').createApp(module); //2.声明根路由,当用户访问他时会创建一个新snippet并重定向到路径/:snippetId: app.get('/', function(page, model, _arg, next){ snippetId = model.add('snippets', { snippetName: _arg.snippetName, code: 'var' }); return page.redirect('/', + snippetId); }); //3.DerbyJS使用和Express.js相似的路由模型,DerbyJS响应页面,Express.js响应报文(res) //路由/:snippetId是编辑器显示的地方,调用subscribe以支持DOM的实时更新 app.get('/:snippetId', function(page, model, param, next){ //4.model.at方法在collection_name.ID模式中的参数类似于调用findById(),即我们从存储/数据库中得到对象 var snippet = model.at('snippets. '+param.snippetId); snippet.subscribe(function(err){ console.log(snippet.get()); //5.model.ref()允许把对象绑定到视图展现层。通常在视图层可以写{{_page.snippet}},他会实时地自我更新。 //我们可以使用Ace编辑器让代码看起来漂亮点,Ace被绑到全局的编辑器对象上。 model.ref('_page.snippet', snippet); page.render(); }); }); //6.DerbyJS的前端JavaScript代码是写在app.ready的回调里的,我们需要在应用程序启动时从Derby模型设置Ace的内容 app.ready(function(model){ editor.setValue(model.get('_page.snippet.code')); //7.监听模型的改变(来自其他用户)并用新文本更新Ace编辑器 model.on('change', '_page.snippet.code', function(){ if (editor.getValue() !== model.get('_page.snippet.code')){ //8.process.nextTick是一个函数,该函数声明了在下一个事件循环迭代的回调(作为参数传递给他) //这可以避免无限循环,即当用户的更新模型在Ace编辑器里触发改变事件时,会触发远程模型的不必要的更新 process.nextTick(function(){ editor.setValue(model.get('_page.snippet.code'), 1); }); } }); //9.监听Ace改变,并更新DerbyJS模型 editor.getSession().on('change', function(e){ if (editor.getValue() !== model.get('_page.snippet.code')){ process.nextTick(function(){ //10._page是DerbyJS专有的名字,用来渲染/绑定视图 model.set('_page.snippet.code', editor.getValue()); }); } }); });DerbyJS视图包含内置标签,如,大部分内容都是在页面加载完之后由Ace编辑器动态生成的。 views/app.html
<Title:> 在线实时编辑器 <Head:> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content="IE=edge, chrome=1"> <title>Editor</title> <style type="text/css" media="screen"> body{ overflow: hidden; } #editor{ margin:0; position: absolute; top: 0; bottom:0; left:0; right:0; } </style> //1.从内容分发网络(CDN)加载jQuery和Ace <script src="//cdnjs.cloudflare.com/ajax/libs/ace/1.1.01/ace.js"></script> <script src="//code.jquery.com/jquery-2.1.0.min.js"></script> //2.在body标签里用一个隐藏的input标签和editor元素 <Body:> <input type="hidden" value="{_page.snippet.code}" class="code" /> <pre id="editor" value="{_page.snippet.code}"></pre> //3.初始化Ace编辑器对象,作为一个全局变量(编辑器的变量) <script> var editor = ace.edit("editor"); editor.setTheme("ace/theme/twilight");//设置主题 editor.getSession().setMode("ace/mode/javascript");//设置语言 </script>注意:视图名称(app.html)要和DerbyJS应用程序文件的名称(app.js)保持一致,不然框架就关联不上
项目所有文件app.js,index.js,server.js,views/app.html和package.json
用$npm install安装模块, 用$mongod和$redis-server启动数据库 用$node .或者$node index启动应用程序
在浏览器中打开http://localhost:3000/, 他会重定向到一个新的snippet(用URL中的ID) 在第二个浏览器窗口中打开同样的url,并开始打字, 这时第一个窗口中的代码同步更新了。