<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet href='http://feed.feedsky.com/styles/feedsky6.xsl' type='text/xsl' ?><!--这是一个由Feedsy提供技术支持的Feed，为了提高读者阅读的体验，以及满足用户美化自己Feed的需要，我们设计了多种精美的Feed模板，提供给大家选择，所有最终呈现出来的样式，皆由用户自愿选择使用，未经许可，任何团体和个人，请不要擅自修改样式或者盗用，这是对于用户选择权的尊重。--><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:fs="http://www.feedsky.com/namespace/feed" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0"><channel><atom:link href="http://feed.feedsky.com/mockee" type="application/rss+xml" rel="self"></atom:link><fs:self_link href="http://feed.feedsky.com/mockee" type="application/rss+xml"></fs:self_link><lastBuildDate>Thu, 15 Sep 2011 09:23:18 GMT</lastBuildDate><title>Mockee Nodes</title><description>Happiness only real when shared.</description><image><url>http://www.feedsky.com/feed/mockee/sc/gif</url><title>Mockee Nodes</title><link>http://mockee.com</link></image><link>http://mockee.com</link><link xmlns="http://www.w3.org/2005/Atom" href="http://mockee.com"></link><author xmlns="http://www.w3.org/2005/Atom"><name>mockee</name></author><id xmlns="http://www.w3.org/2005/Atom">urn:uuid:4124a23f-32c1-4dc0-9056-f2083c4d295e</id><pubDate>Thu, 15 Sep 2011 09:23:18 GMT</pubDate><managingEditor>mockee</managingEditor><item><title>NodeCat 开发笔记</title><link>http://item.feedsky.com/~feedsky/mockee/~8785823/598755267/5275636/1/item.html</link><id xmlns="http://www.w3.org/2005/Atom">urn:uuid:b99c8b3c-60da-4a53-928a-0120b58baddf</id><content xmlns="http://www.w3.org/2005/Atom" type="html" xml:base="http://www.mockee.com/" xml:lang="en">&lt;a href=&quot;http://storify.com/_nw_/nodejs-logo&quot; title=&quot;node turtle&quot;&gt;&lt;img width=&quot;640&quot; height=&quot;506&quot; src=&quot;http://static.mockee.com/uploads/2011/09/5d3476944ceff9b64cc0f49a1e894305.png&quot; /&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;简单记录下开发中遇到的一些问题与解决办法，方便日后查阅：&lt;br&gt;&lt;br&gt;&lt;strong&gt;中间件与框架&lt;/strong&gt;&lt;br&gt;&lt;br&gt;NodeCat 使用 &lt;a href=&quot;https://github.com/visionmedia/express&quot; title=&quot;express&quot;&gt;Express&lt;/a&gt; 框架搭建完成，当然也可以说是 &lt;a href=&quot;https://github.com/senchalabs/connect&quot; title=&quot;Connect&quot;&gt;Connect&lt;/a&gt; 这个中间件系统协助完成了大部分工作并让整个开发过程变得简单轻松——&lt;a href=&quot;https://github.com/visionmedia/express&quot; title=&quot;express&quot;&gt;Express&lt;/a&gt; 基于 &lt;a href=&quot;https://github.com/senchalabs/connect&quot; title=&quot;Connect&quot;&gt;Connect&lt;/a&gt; 构建，中间件的设置方法与其基本一致，比如协助将客户端 post 的内容放入 req.body 的 bodyParser()、处理用 POST 伪装的 HTTP 方法（PUT 和 DELETE 等）的 methodOverride() 以及用于错误处理的 errorHandler()、请求日志的 logger() 等等。此外，&lt;a href=&quot;https://github.com/senchalabs/connect&quot; title=&quot;Connect&quot;&gt;Connect&lt;/a&gt; 在借鉴 Rack（介于 Ruby web 框架与 Ruby 运行时之间的中间层，类似于 &lt;a href=&quot;https://github.com/visionmedia/express&quot; title=&quot;express&quot;&gt;Express&lt;/a&gt; 与 node.js 之间的 &lt;a href=&quot;https://github.com/senchalabs/connect&quot; title=&quot;Connect&quot;&gt;Connect&lt;/a&gt;） 和 ejsgi 后所提出的分层处理 HTTP 请求和响应的想法更是令开发灵活多变。&lt;br&gt;&lt;br&gt;&lt;a href=&quot;https://github.com/senchalabs/connect&quot; title=&quot;Connect&quot;&gt;Connect&lt;/a&gt; 1.7.0 提供了一个位于 static() 之上名为 staticCache() 的新的中间件作为 memory cache 服务，ApacheBench 结果显示它比单独使用 static() 中间件或 &lt;a href=&quot;https://github.com/cloudhead/node-static&quot; title=&quot;node-static&quot;&gt;node-static&lt;/a&gt; 的性能都出色：&lt;br&gt;&lt;br&gt;&lt;blockquote cite=&quot;http://tjholowaychuk.com/post/9682643240/connect-1-7-0-fast-static-file-memory-cache-and-more&quot;&gt;Then we have the new staticCache() middleware paired with static() serving ~5000rps, a 24% increase over node-static (which also performs memory caching), and ~52% over static() alone.&lt;/blockquote&gt;&lt;br&gt;同样可以为 &lt;a href=&quot;https://github.com/visionmedia/express&quot; title=&quot;express&quot;&gt;Express&lt;/a&gt; 加入 staticCache：&lt;br&gt;&lt;br&gt;&lt;pre class=&quot;sh_javascript&quot;&gt;app.use(express.staticCache());&lt;/pre&gt;&lt;br&gt;&lt;br&gt;在 &lt;a href=&quot;https://github.com/visionmedia/express&quot; title=&quot;express&quot;&gt;Express&lt;/a&gt; 中实现图片上传功能很简单，利用表单数据解析模块 &lt;a href=&quot;https://github.com/felixge/node-formidable&quot; title=&quot;formidable&quot;&gt;node-formidable&lt;/a&gt; 以及中间件 &lt;a href=&quot;https://github.com/visionmedia/connect-form&quot; title=&quot;connect-form&quot;&gt;connect-form&lt;/a&gt; 就可以轻松完成。存放图片的路径通常是根据当前日期来设定，所以就会有个多级目录的创建问题，当然这并不困难，引入 path 与 fs 模块写个递归就可以解决（或者直接用 &lt;a href=&quot;https://github.com/substack/node-mkdirp&quot; title=&quot;connect-form&quot;&gt;node-mkdirp&lt;/a&gt;），需要注意的是创建目录时的权限问题。&lt;br&gt;&lt;br&gt;&lt;strong&gt;模板引擎与 CSS 语言&lt;/strong&gt;&lt;br&gt;&lt;br&gt;&lt;a href=&quot;https://github.com/visionmedia/jade&quot;&gt;jade&lt;/a&gt; 可以选择将 HTML 压成一行，但并不包括行内脚本；&lt;a href=&quot;http://stackoverflow.com&quot; title=&quot;stackoverflow&quot;&gt;stackoverflow&lt;/a&gt; 上有人提出使用 &lt;a href=&quot;https://github.com/mishoo/UglifyJS&quot; title=&quot;UglifyJS&quot;&gt;UglifyJS&lt;/a&gt; 并为 &lt;a href=&quot;https://github.com/visionmedia/jade&quot;&gt;jade&lt;/a&gt; 增加一个 filter 的方法来处理，可行，但却修改了 jade lib 中的文件，所以我并没有在实际项目中使用这个方法。好在 nodecat 的行内脚本大多只进行模块的组织工作并不涉及业务逻辑，代码量小，手动压缩即可。如果你不喜欢 jade，可以随时将 &lt;a href=&quot;https://github.com/visionmedia/express&quot; title=&quot;express&quot;&gt;Express&lt;/a&gt; 的 view engine 换掉，比如使用熟悉的 &lt;a href=&quot;http://mustache.github.com/&quot; title=&quot;Mustache&quot;&gt;Mustache&lt;/a&gt;，有个名叫 &lt;a href=&quot;https://github.com/fat/stache&quot; title=&quot;Stache&quot;&gt;Stache&lt;/a&gt; 的项目可以帮你在 &lt;a href=&quot;https://github.com/visionmedia/express&quot; title=&quot;express&quot;&gt;Express&lt;/a&gt; 中实现：&lt;br&gt;&lt;br&gt;&lt;pre class=&quot;sh_javascript&quot;&gt;app.set('view engine', 'mustache')&lt;br&gt;app.register(&quot;.mustache&quot;, require('stache'));&lt;/pre&gt;&lt;br&gt;&lt;br&gt;从功能上来说，&lt;a href=&quot;https://github.com/LearnBoost/stylus&quot; title=&quot;stylus&quot;&gt;Stylus&lt;/a&gt;、&lt;a href=&quot;https://github.com/nex3/sass&quot; title=&quot;Sass&quot;&gt;Saas&lt;/a&gt;、&lt;a href=&quot;https://github.com/cloudhead/less&quot; title=&quot;LESS&quot;&gt;LESS&lt;/a&gt; 都很强大，但更偏爱语法简洁的 &lt;a href=&quot;https://github.com/LearnBoost/stylus&quot; title=&quot;stylus&quot;&gt;Stylus&lt;/a&gt;，搭配 &lt;a href=&quot;https://github.com/visionmedia/nib&quot; title=&quot;nib&quot;&gt;nib&lt;/a&gt;（如果你使用 &lt;a href=&quot;https://github.com/cloudhead/less&quot; title=&quot;LESS&quot;&gt;LESS&lt;/a&gt;，&lt;a href=&quot;http://lesselements.com&quot;&gt;LESS Elements&lt;/a&gt; 也是很好的选择）可以有条理地规划并高效地书写 CSS（在过去的很长一段时间内，前端工程师都在为处理浏览器兼容性以及不可避免地堆砌冗余样式耗费着大量时间）。有关 &lt;a href=&quot;https://github.com/LearnBoost/stylus&quot; title=&quot;stylus&quot;&gt;Stylus&lt;/a&gt; 的配置（compress, debug）和常用方法（function, arithmetic, mixin）都可以在 &lt;a href=&quot;https://github.com/LearnBoost/stylus/tree/master/examples&quot;&gt;example&lt;/a&gt; 中找到。&lt;br&gt;&lt;br&gt;&lt;strong&gt;数据存储&lt;/strong&gt;&lt;br&gt;&lt;br&gt;在 &lt;a href=&quot;https://github.com/visionmedia/express&quot; title=&quot;express&quot;&gt;Express&lt;/a&gt; 中，session 中间件默认使用 &lt;a href=&quot;https://github.com/senchalabs/connect&quot; title=&quot;Connect&quot;&gt;Connect&lt;/a&gt; 内置的内存存储方式，但除此之外还有很多其他的选择，比如使用 &lt;a href=&quot;https://github.com/masylum/connect-mongodb&quot; title=&quot;connect-mongodb&quot;&gt;connect-mongodb&lt;/a&gt; 将 MongoDB 作为 session 的存储介质等。由于我在 NodeCat 中同时使用了 &lt;a href=&quot;https://github.com/LearnBoost/mongoose&quot; title=&quot;Mongoose&quot;&gt;Mongoose&lt;/a&gt;，所以换用 &lt;a href=&quot;https://github.com/kcbanner/connect-mongo&quot; title=&quot;connect-mongo&quot;&gt;connect-mongo&lt;/a&gt; 更方便（Stack 上也有人提到 &lt;a href=&quot;http://stackoverflow.com/questions/6819911/nodejs-expressjs-session-handling-with-mongodb-mongoose&quot;&gt;同样的问题&lt;/a&gt;）：&lt;br&gt;&lt;br&gt;&lt;pre class=&quot;sh_javascript&quot;&gt;var mongoose = require('mongoose'),&lt;br&gt;    mongoStore = require('connect-mongo');&lt;br&gt;// configure&lt;br&gt;app.use(express.session({&lt;br&gt;    secret: 'nodecat',&lt;br&gt;    store: new mongoStore({ url: app.set('connection') })&lt;br&gt;}));&lt;br&gt;// connect to mongodb a second time using mongoose&lt;br&gt;mongoose.connect(app.set('connection'));&lt;/pre&gt;&lt;br&gt;&lt;br&gt;NodeCat 中没有文章分类功能，相较分类我更喜欢标签（tag）这种细粒度的泛描述。每篇笔记（每个 Note Schema 的实例）都有自己对应的 tags 数组，这样，根据具体 tag 的名字就可以方便地找出包含此 tag 的所有文章，如果数据量大，可以为 Note Schema 建立 tags 的索引。&lt;br&gt;&lt;br&gt;网站首页右侧有个最近回复列表，需要显示最近回复者的名字以及被回复文章的标题和链接。之前对 MongoDB 了解不多，在设计 Note Schema 的时候把 Comments 对象也塞了进去，导致取数据时绕了弯子，后经同事点拨，为 Comment 单独建立了 Schema，将笔记与回复分离，用 id 做关联，这样按创建时间获取回复数据自然就是“最近回复”了。&lt;br&gt;&lt;br&gt;曾考虑用 &lt;a href=&quot;http://disqus.com/&quot; title=&quot;disqus&quot;&gt;disqus&lt;/a&gt; 作评论系统，省事省心，速度也不错，但最终还是放弃了，毕竟不是本土服务，链接被重置的情况随时可能发生，伤不起。正如你看到的，目前 nodecat 没有在评论部分多费精力，对于自用的东西多少有些放纵——我假设来到这里的朋友都可以正确地使用自己的名字与 email 并对言论负责。&lt;br&gt; &lt;br&gt;评论中的用户头像都是通过被 &lt;a href=&quot;https://github.com/brainfucker/hashlib&quot; title=&quot;lib for node which makes hashes&quot;&gt;hashlib&lt;/a&gt; 模块 md5 加密过的 email 到 &lt;a href=&quot;http://gravatar.com&quot; title=&quot;Gravatar&quot;&gt;Gravatar&lt;/a&gt; 换取的，&lt;a href=&quot;http://mongoosejs.com&quot; title=&quot;Mongoose&quot;&gt;Mongoose&lt;/a&gt; 的 &lt;a href=&quot;http://mongoosejs.com/docs/virtuals.html&quot;&gt;virtual attributes&lt;/a&gt; 可以方便地将这个过程封装起来供 comment 实例调用而不必单独存储 avatar 到 mongodb：&lt;br&gt;&lt;br&gt;&lt;pre class=&quot;sh_javascript&quot;&gt;Comment.virtual('gravatar').get(function () {&lt;br&gt;    var gravatarHost = 'http://www.gravatar.com/avatar/';&lt;br&gt;    return gravatarHost + hashlib.md5(this.email) + '.jpg?s=' + 32;&lt;br&gt;});&lt;/pre&gt;&lt;br&gt;&lt;br&gt;除此之外还有很多地方都用到了 virtual，比如输出被 &lt;a href=&quot;https://github.com/andris9/node-markdown&quot; title=&quot;node-markdown&quot;&gt;node-markdown&lt;/a&gt; 解析过的正文与评论、格式化日期和 url 等。同时不免还要用到  &lt;a href=&quot;http://mongoosejs.com/docs/methods-statics.html&quot; title=&quot;methods statics&quot;&gt;Methods&lt;/a&gt;，比如 password virtual 的 set function 中将密码掺入 salt 后加密的 encryptPassword method：&lt;br&gt;&lt;br&gt;&lt;pre class=&quot;sh_javascript&quot;&gt;User.method('encryptPassword', function (str) {&lt;br&gt;    return crypto.createHmac('sha1', this.salt).update(str).digest('hex');&lt;br&gt;});&lt;/pre&gt;&lt;br&gt;&lt;br&gt;&lt;strong&gt;服务器&lt;/strong&gt;&lt;br&gt;&lt;br&gt;&lt;a href=&quot;https://github.com/LearnBoost/cluster&quot; title=&quot;Cluster&quot;&gt;Cluster&lt;/a&gt; 是目前正在使用的服务器管理模块，它可以利用服务器的多核心来动态实现简单的负载均衡以确保网站可以无间断地提供服务。修改 node 程序后无须重启服务就可生效是 &lt;a href=&quot;https://github.com/LearnBoost/cluster&quot; title=&quot;Cluster&quot;&gt;Cluster&lt;/a&gt; 的特性之一，其丰富的扩展还可以协助完成优雅停机、重启、杀进程、监控网站状况等操作。昨天我还尝试使用了另一个插件 &lt;a href=&quot;https://github.com/visionmedia/cluster-live&quot;&gt;cluster-live&lt;/a&gt;，它可以进行实时管理与统计并通过 canvas 绘制动态图表。下面这张是在我本地测试时的截图，小清新风格：&lt;br&gt;&lt;br&gt;&lt;img src=&quot;http://static.mockee.com/uploads/2011/09/4f8a5635a24d6f835776ac77c1154508.png&quot; alt=&quot;nodecat with cluster live&quot; width=&quot;747&quot; height=&quot;347 &quot;/&gt;&lt;br&gt;&lt;br&gt;&lt;strong&gt;代码部署&lt;/strong&gt;&lt;br&gt;&lt;br&gt;平时工作中规定使用 SVN 和 Mercurial 来对代码进行版本控制，但我更喜欢 Git，个人的小项目也都放在自己的 Git 仓库中，NodeCat 也不例外。除了代码管理，还可以使用 Git 的 hook 协助完成远程 checkout 实现网站的自动部署。如果部署后网站没有变化，可以检查下是否使用了 &lt;a href=&quot;https://github.com/senchalabs/connect&quot; title=&quot;Connect&quot;&gt;Connect&lt;/a&gt; 的 staticCache 或 nginx（如果用到了的话）的某些配置导致静态文件被缓存住了需要清理，还有可能是自定义了 &lt;a href=&quot;https://github.com/LearnBoost/cluster&quot; title=&quot;Cluster&quot;&gt;Cluster&lt;/a&gt; 的 reload 方法，但修改的 node.js 文件或目录没有加到其配置中。&lt;br&gt;&lt;br&gt;暂时想到这么多，随着后续开发的进行肯定会有更多东西需要记录，嗯。</content><content:encoded>&lt;a href=&quot;http://storify.com/_nw_/nodejs-logo&quot; title=&quot;node turtle&quot;&gt;&lt;img width=&quot;640&quot; height=&quot;506&quot; src=&quot;http://static.mockee.com/uploads/2011/09/5d3476944ceff9b64cc0f49a1e894305.png&quot; /&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;简单记录下开发中遇到的一些问题与解决办法，方便日后查阅：&lt;br&gt;&lt;br&gt;&lt;strong&gt;中间件与框架&lt;/strong&gt;&lt;br&gt;&lt;br&gt;NodeCat 使用 &lt;a href=&quot;https://github.com/visionmedia/express&quot; title=&quot;express&quot;&gt;Express&lt;/a&gt; 框架搭建完成，当然也可以说是 &lt;a href=&quot;https://github.com/senchalabs/connect&quot; title=&quot;Connect&quot;&gt;Connect&lt;/a&gt; 这个中间件系统协助完成了大部分工作并让整个开发过程变得简单轻松——&lt;a href=&quot;https://github.com/visionmedia/express&quot; title=&quot;express&quot;&gt;Express&lt;/a&gt; 基于 &lt;a href=&quot;https://github.com/senchalabs/connect&quot; title=&quot;Connect&quot;&gt;Connect&lt;/a&gt; 构建，中间件的设置方法与其基本一致，比如协助将客户端 post 的内容放入 req.body 的 bodyParser()、处理用 POST 伪装的 HTTP 方法（PUT 和 DELETE 等）的 methodOverride() 以及用于错误处理的 errorHandler()、请求日志的 logger() 等等。此外，&lt;a href=&quot;https://github.com/senchalabs/connect&quot; title=&quot;Connect&quot;&gt;Connect&lt;/a&gt; 在借鉴 Rack（介于 Ruby web 框架与 Ruby 运行时之间的中间层，类似于 &lt;a href=&quot;https://github.com/visionmedia/express&quot; title=&quot;express&quot;&gt;Express&lt;/a&gt; 与 node.js 之间的 &lt;a href=&quot;https://github.com/senchalabs/connect&quot; title=&quot;Connect&quot;&gt;Connect&lt;/a&gt;） 和 ejsgi 后所提出的分层处理 HTTP 请求和响应的想法更是令开发灵活多变。&lt;br&gt;&lt;br&gt;&lt;a href=&quot;https://github.com/senchalabs/connect&quot; title=&quot;Connect&quot;&gt;Connect&lt;/a&gt; 1.7.0 提供了一个位于 static() 之上名为 staticCache() 的新的中间件作为 memory cache 服务，ApacheBench 结果显示它比单独使用 static() 中间件或 &lt;a href=&quot;https://github.com/cloudhead/node-static&quot; title=&quot;node-static&quot;&gt;node-static&lt;/a&gt; 的性能都出色：&lt;br&gt;&lt;br&gt;&lt;blockquote cite=&quot;http://tjholowaychuk.com/post/9682643240/connect-1-7-0-fast-static-file-memory-cache-and-more&quot;&gt;Then we have the new staticCache() middleware paired with static() serving ~5000rps, a 24% increase over node-static (which also performs memory caching), and ~52% over static() alone.&lt;/blockquote&gt;&lt;br&gt;同样可以为 &lt;a href=&quot;https://github.com/visionmedia/express&quot; title=&quot;express&quot;&gt;Express&lt;/a&gt; 加入 staticCache：&lt;br&gt;&lt;br&gt;&lt;pre class=&quot;sh_javascript&quot;&gt;app.use(express.staticCache());&lt;/pre&gt;&lt;br&gt;&lt;br&gt;在 &lt;a href=&quot;https://github.com/visionmedia/express&quot; title=&quot;express&quot;&gt;Express&lt;/a&gt; 中实现图片上传功能很简单，利用表单数据解析模块 &lt;a href=&quot;https://github.com/felixge/node-formidable&quot; title=&quot;formidable&quot;&gt;node-formidable&lt;/a&gt; 以及中间件 &lt;a href=&quot;https://github.com/visionmedia/connect-form&quot; title=&quot;connect-form&quot;&gt;connect-form&lt;/a&gt; 就可以轻松完成。存放图片的路径通常是根据当前日期来设定，所以就会有个多级目录的创建问题，当然这并不困难，引入 path 与 fs 模块写个递归就可以解决（或者直接用 &lt;a href=&quot;https://github.com/substack/node-mkdirp&quot; title=&quot;connect-form&quot;&gt;node-mkdirp&lt;/a&gt;），需要注意的是创建目录时的权限问题。&lt;br&gt;&lt;br&gt;&lt;strong&gt;模板引擎与 CSS 语言&lt;/strong&gt;&lt;br&gt;&lt;br&gt;&lt;a href=&quot;https://github.com/visionmedia/jade&quot;&gt;jade&lt;/a&gt; 可以选择将 HTML 压成一行，但并不包括行内脚本；&lt;a href=&quot;http://stackoverflow.com&quot; title=&quot;stackoverflow&quot;&gt;stackoverflow&lt;/a&gt; 上有人提出使用 &lt;a href=&quot;https://github.com/mishoo/UglifyJS&quot; title=&quot;UglifyJS&quot;&gt;UglifyJS&lt;/a&gt; 并为 &lt;a href=&quot;https://github.com/visionmedia/jade&quot;&gt;jade&lt;/a&gt; 增加一个 filter 的方法来处理，可行，但却修改了 jade lib 中的文件，所以我并没有在实际项目中使用这个方法。好在 nodecat 的行内脚本大多只进行模块的组织工作并不涉及业务逻辑，代码量小，手动压缩即可。如果你不喜欢 jade，可以随时将 &lt;a href=&quot;https://github.com/visionmedia/express&quot; title=&quot;express&quot;&gt;Express&lt;/a&gt; 的 view engine 换掉，比如使用熟悉的 &lt;a href=&quot;http://mustache.github.com/&quot; title=&quot;Mustache&quot;&gt;Mustache&lt;/a&gt;，有个名叫 &lt;a href=&quot;https://github.com/fat/stache&quot; title=&quot;Stache&quot;&gt;Stache&lt;/a&gt; 的项目可以帮你在 &lt;a href=&quot;https://github.com/visionmedia/express&quot; title=&quot;express&quot;&gt;Express&lt;/a&gt; 中实现：&lt;br&gt;&lt;br&gt;&lt;pre class=&quot;sh_javascript&quot;&gt;app.set('view engine', 'mustache')&lt;br&gt;app.register(&quot;.mustache&quot;, require('stache'));&lt;/pre&gt;&lt;br&gt;&lt;br&gt;从功能上来说，&lt;a href=&quot;https://github.com/LearnBoost/stylus&quot; title=&quot;stylus&quot;&gt;Stylus&lt;/a&gt;、&lt;a href=&quot;https://github.com/nex3/sass&quot; title=&quot;Sass&quot;&gt;Saas&lt;/a&gt;、&lt;a href=&quot;https://github.com/cloudhead/less&quot; title=&quot;LESS&quot;&gt;LESS&lt;/a&gt; 都很强大，但更偏爱语法简洁的 &lt;a href=&quot;https://github.com/LearnBoost/stylus&quot; title=&quot;stylus&quot;&gt;Stylus&lt;/a&gt;，搭配 &lt;a href=&quot;https://github.com/visionmedia/nib&quot; title=&quot;nib&quot;&gt;nib&lt;/a&gt;（如果你使用 &lt;a href=&quot;https://github.com/cloudhead/less&quot; title=&quot;LESS&quot;&gt;LESS&lt;/a&gt;，&lt;a href=&quot;http://lesselements.com&quot;&gt;LESS Elements&lt;/a&gt; 也是很好的选择）可以有条理地规划并高效地书写 CSS（在过去的很长一段时间内，前端工程师都在为处理浏览器兼容性以及不可避免地堆砌冗余样式耗费着大量时间）。有关 &lt;a href=&quot;https://github.com/LearnBoost/stylus&quot; title=&quot;stylus&quot;&gt;Stylus&lt;/a&gt; 的配置（compress, debug）和常用方法（function, arithmetic, mixin）都可以在 &lt;a href=&quot;https://github.com/LearnBoost/stylus/tree/master/examples&quot;&gt;example&lt;/a&gt; 中找到。&lt;br&gt;&lt;br&gt;&lt;strong&gt;数据存储&lt;/strong&gt;&lt;br&gt;&lt;br&gt;在 &lt;a href=&quot;https://github.com/visionmedia/express&quot; title=&quot;express&quot;&gt;Express&lt;/a&gt; 中，session 中间件默认使用 &lt;a href=&quot;https://github.com/senchalabs/connect&quot; title=&quot;Connect&quot;&gt;Connect&lt;/a&gt; 内置的内存存储方式，但除此之外还有很多其他的选择，比如使用 &lt;a href=&quot;https://github.com/masylum/connect-mongodb&quot; title=&quot;connect-mongodb&quot;&gt;connect-mongodb&lt;/a&gt; 将 MongoDB 作为 session 的存储介质等。由于我在 NodeCat 中同时使用了 &lt;a href=&quot;https://github.com/LearnBoost/mongoose&quot; title=&quot;Mongoose&quot;&gt;Mongoose&lt;/a&gt;，所以换用 &lt;a href=&quot;https://github.com/kcbanner/connect-mongo&quot; title=&quot;connect-mongo&quot;&gt;connect-mongo&lt;/a&gt; 更方便（Stack 上也有人提到 &lt;a href=&quot;http://stackoverflow.com/questions/6819911/nodejs-expressjs-session-handling-with-mongodb-mongoose&quot;&gt;同样的问题&lt;/a&gt;）：&lt;br&gt;&lt;br&gt;&lt;pre class=&quot;sh_javascript&quot;&gt;var mongoose = require('mongoose'),&lt;br&gt;    mongoStore = require('connect-mongo');&lt;br&gt;// configure&lt;br&gt;app.use(express.session({&lt;br&gt;    secret: 'nodecat',&lt;br&gt;    store: new mongoStore({ url: app.set('connection') })&lt;br&gt;}));&lt;br&gt;// connect to mongodb a second time using mongoose&lt;br&gt;mongoose.connect(app.set('connection'));&lt;/pre&gt;&lt;br&gt;&lt;br&gt;NodeCat 中没有文章分类功能，相较分类我更喜欢标签（tag）这种细粒度的泛描述。每篇笔记（每个 Note Schema 的实例）都有自己对应的 tags 数组，这样，根据具体 tag 的名字就可以方便地找出包含此 tag 的所有文章，如果数据量大，可以为 Note Schema 建立 tags 的索引。&lt;br&gt;&lt;br&gt;网站首页右侧有个最近回复列表，需要显示最近回复者的名字以及被回复文章的标题和链接。之前对 MongoDB 了解不多，在设计 Note Schema 的时候把 Comments 对象也塞了进去，导致取数据时绕了弯子，后经同事点拨，为 Comment 单独建立了 Schema，将笔记与回复分离，用 id 做关联，这样按创建时间获取回复数据自然就是“最近回复”了。&lt;br&gt;&lt;br&gt;曾考虑用 &lt;a href=&quot;http://disqus.com/&quot; title=&quot;disqus&quot;&gt;disqus&lt;/a&gt; 作评论系统，省事省心，速度也不错，但最终还是放弃了，毕竟不是本土服务，链接被重置的情况随时可能发生，伤不起。正如你看到的，目前 nodecat 没有在评论部分多费精力，对于自用的东西多少有些放纵——我假设来到这里的朋友都可以正确地使用自己的名字与 email 并对言论负责。&lt;br&gt; &lt;br&gt;评论中的用户头像都是通过被 &lt;a href=&quot;https://github.com/brainfucker/hashlib&quot; title=&quot;lib for node which makes hashes&quot;&gt;hashlib&lt;/a&gt; 模块 md5 加密过的 email 到 &lt;a href=&quot;http://gravatar.com&quot; title=&quot;Gravatar&quot;&gt;Gravatar&lt;/a&gt; 换取的，&lt;a href=&quot;http://mongoosejs.com&quot; title=&quot;Mongoose&quot;&gt;Mongoose&lt;/a&gt; 的 &lt;a href=&quot;http://mongoosejs.com/docs/virtuals.html&quot;&gt;virtual attributes&lt;/a&gt; 可以方便地将这个过程封装起来供 comment 实例调用而不必单独存储 avatar 到 mongodb：&lt;br&gt;&lt;br&gt;&lt;pre class=&quot;sh_javascript&quot;&gt;Comment.virtual('gravatar').get(function () {&lt;br&gt;    var gravatarHost = 'http://www.gravatar.com/avatar/';&lt;br&gt;    return gravatarHost + hashlib.md5(this.email) + '.jpg?s=' + 32;&lt;br&gt;});&lt;/pre&gt;&lt;br&gt;&lt;br&gt;除此之外还有很多地方都用到了 virtual，比如输出被 &lt;a href=&quot;https://github.com/andris9/node-markdown&quot; title=&quot;node-markdown&quot;&gt;node-markdown&lt;/a&gt; 解析过的正文与评论、格式化日期和 url 等。同时不免还要用到  &lt;a href=&quot;http://mongoosejs.com/docs/methods-statics.html&quot; title=&quot;methods statics&quot;&gt;Methods&lt;/a&gt;，比如 password virtual 的 set function 中将密码掺入 salt 后加密的 encryptPassword method：&lt;br&gt;&lt;br&gt;&lt;pre class=&quot;sh_javascript&quot;&gt;User.method('encryptPassword', function (str) {&lt;br&gt;    return crypto.createHmac('sha1', this.salt).update(str).digest('hex');&lt;br&gt;});&lt;/pre&gt;&lt;br&gt;&lt;br&gt;&lt;strong&gt;服务器&lt;/strong&gt;&lt;br&gt;&lt;br&gt;&lt;a href=&quot;https://github.com/LearnBoost/cluster&quot; title=&quot;Cluster&quot;&gt;Cluster&lt;/a&gt; 是目前正在使用的服务器管理模块，它可以利用服务器的多核心来动态实现简单的负载均衡以确保网站可以无间断地提供服务。修改 node 程序后无须重启服务就可生效是 &lt;a href=&quot;https://github.com/LearnBoost/cluster&quot; title=&quot;Cluster&quot;&gt;Cluster&lt;/a&gt; 的特性之一，其丰富的扩展还可以协助完成优雅停机、重启、杀进程、监控网站状况等操作。昨天我还尝试使用了另一个插件 &lt;a href=&quot;https://github.com/visionmedia/cluster-live&quot;&gt;cluster-live&lt;/a&gt;，它可以进行实时管理与统计并通过 canvas 绘制动态图表。下面这张是在我本地测试时的截图，小清新风格：&lt;br&gt;&lt;br&gt;&lt;img src=&quot;http://static.mockee.com/uploads/2011/09/4f8a5635a24d6f835776ac77c1154508.png&quot; alt=&quot;nodecat with cluster live&quot; width=&quot;747&quot; height=&quot;347 &quot;/&gt;&lt;br&gt;&lt;br&gt;&lt;strong&gt;代码部署&lt;/strong&gt;&lt;br&gt;&lt;br&gt;平时工作中规定使用 SVN 和 Mercurial 来对代码进行版本控制，但我更喜欢 Git，个人的小项目也都放在自己的 Git 仓库中，NodeCat 也不例外。除了代码管理，还可以使用 Git 的 hook 协助完成远程 checkout 实现网站的自动部署。如果部署后网站没有变化，可以检查下是否使用了 &lt;a href=&quot;https://github.com/senchalabs/connect&quot; title=&quot;Connect&quot;&gt;Connect&lt;/a&gt; 的 staticCache 或 nginx（如果用到了的话）的某些配置导致静态文件被缓存住了需要清理，还有可能是自定义了 &lt;a href=&quot;https://github.com/LearnBoost/cluster&quot; title=&quot;Cluster&quot;&gt;Cluster&lt;/a&gt; 的 reload 方法，但修改的 node.js 文件或目录没有加到其配置中。&lt;br&gt;&lt;br&gt;暂时想到这么多，随着后续开发的进行肯定会有更多东西需要记录，嗯。&lt;img src=&quot;http://www1.feedsky.com/t1/598755267/mockee/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/mockee/~8785823/598755267/5275636/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><pubDate>Thu, 15 Sep 2011 17:23:18 +0800</pubDate><guid isPermaLink="false">urn:uuid:b99c8b3c-60da-4a53-928a-0120b58baddf</guid><fs:srclink>http://www.mockee.com/2011/09/15/nodecat-dev-notes/</fs:srclink><fs:srcfeed>http://mockee.com/atom.xml</fs:srcfeed><fs:itemid>feedsky/mockee/~8785823/598755267/5275636</fs:itemid></item><item><title>Fresh start with NodeCat</title><link>http://item.feedsky.com/~feedsky/mockee/~8785823/598755268/5275636/1/item.html</link><id xmlns="http://www.w3.org/2005/Atom">urn:uuid:d1377d5b-0252-492f-92b0-1dafefa39a3d</id><content xmlns="http://www.w3.org/2005/Atom" type="html" xml:base="http://www.mockee.com/" xml:lang="en">这是我的新 blog，Codename: NodeCat —— 基于 &lt;a href=&quot;http://nodejs.org&quot; title=&quot;node.js&quot;&gt;node.js&lt;/a&gt;，对猫偏爱有加，作为开发代号，仅此而已。同时这也是我第一次尝试使用 node 编写 web 应用，其中用到的开源产品多半出自高质高产的 &lt;a href=&quot;https://github.com/visionmedia&quot; title=&quot;TJ Holowaychuk&quot;&gt;TJ&lt;/a&gt; 之手：&lt;a href=&quot;https://github.com/visionmedia/express&quot; title=&quot;expess-*&quot;&gt;express-*&lt;/a&gt;, &lt;a href=&quot;https://github.com/LearnBoost/cluster&quot; title=&quot;cluster-*&quot;&gt;cluster-*&lt;/a&gt;, &lt;a href=&quot;https://github.com/visionmedia/jade&quot; title=&quot;jade&quot;&gt;jade&lt;/a&gt;，后来干脆用 &lt;a href=&quot;https://github.com/LearnBoost/stylus&quot; title=&quot;stylus&quot;&gt;stylus&lt;/a&gt; + &lt;a href=&quot;https://github.com/visionmedia/nib&quot; title=&quot;nib&quot;&gt;nib&lt;/a&gt; 换掉了 &lt;a href=&quot;https://github.com/cloudhead/less&quot; title=&quot;less&quot;&gt;less&lt;/a&gt;。除了探索技术可行性外，创建 NodeCat 更多是为了满足个人需求，所以从技术角度而言，目前这个版本并没有太多值得分享的内容。&lt;br&gt;&lt;br&gt;mockee.com 已有近两年的时间不曾指向过任何有意义的页面了，今天将它重新解析到我那台已连续工作了四年代号为 Kaavie 的服务器上，其实并无特别的打算，只是觉得，应该像从前那样，在一个有归属感的小地方，安静地写下点什么。习惯了用 &lt;a href=&quot;http://ohlife.com&quot; title=&quot;Ohlife&quot;&gt;Ohlife&lt;/a&gt; 给自己发私信，第 289 天。希望在这里也可以坚持下去。&lt;br&gt;&lt;br&gt;&lt;a href=&quot;http://www.flickr.com/photos/kaavie/6000632454/&quot;&gt;&lt;img src=&quot;http://static.mockee.com/uploads/2011/09/9112ef75a8ae00e8f8d05a7c593108a3.jpg&quot; alt=&quot;清晨&quot; /&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;ps, NodeCat 的大部分代码是在这个简单舒服的角落完成的。&lt;br&gt;现在我同样坐在这里，写下第一篇笔记。</content><content:encoded>这是我的新 blog，Codename: NodeCat —— 基于 &lt;a href=&quot;http://nodejs.org&quot; title=&quot;node.js&quot;&gt;node.js&lt;/a&gt;，对猫偏爱有加，作为开发代号，仅此而已。同时这也是我第一次尝试使用 node 编写 web 应用，其中用到的开源产品多半出自高质高产的 &lt;a href=&quot;https://github.com/visionmedia&quot; title=&quot;TJ Holowaychuk&quot;&gt;TJ&lt;/a&gt; 之手：&lt;a href=&quot;https://github.com/visionmedia/express&quot; title=&quot;expess-*&quot;&gt;express-*&lt;/a&gt;, &lt;a href=&quot;https://github.com/LearnBoost/cluster&quot; title=&quot;cluster-*&quot;&gt;cluster-*&lt;/a&gt;, &lt;a href=&quot;https://github.com/visionmedia/jade&quot; title=&quot;jade&quot;&gt;jade&lt;/a&gt;，后来干脆用 &lt;a href=&quot;https://github.com/LearnBoost/stylus&quot; title=&quot;stylus&quot;&gt;stylus&lt;/a&gt; + &lt;a href=&quot;https://github.com/visionmedia/nib&quot; title=&quot;nib&quot;&gt;nib&lt;/a&gt; 换掉了 &lt;a href=&quot;https://github.com/cloudhead/less&quot; title=&quot;less&quot;&gt;less&lt;/a&gt;。除了探索技术可行性外，创建 NodeCat 更多是为了满足个人需求，所以从技术角度而言，目前这个版本并没有太多值得分享的内容。&lt;br&gt;&lt;br&gt;mockee.com 已有近两年的时间不曾指向过任何有意义的页面了，今天将它重新解析到我那台已连续工作了四年代号为 Kaavie 的服务器上，其实并无特别的打算，只是觉得，应该像从前那样，在一个有归属感的小地方，安静地写下点什么。习惯了用 &lt;a href=&quot;http://ohlife.com&quot; title=&quot;Ohlife&quot;&gt;Ohlife&lt;/a&gt; 给自己发私信，第 289 天。希望在这里也可以坚持下去。&lt;br&gt;&lt;br&gt;&lt;a href=&quot;http://www.flickr.com/photos/kaavie/6000632454/&quot;&gt;&lt;img src=&quot;http://static.mockee.com/uploads/2011/09/9112ef75a8ae00e8f8d05a7c593108a3.jpg&quot; alt=&quot;清晨&quot; /&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;ps, NodeCat 的大部分代码是在这个简单舒服的角落完成的。&lt;br&gt;现在我同样坐在这里，写下第一篇笔记。&lt;img src=&quot;http://www1.feedsky.com/t1/598755268/mockee/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/mockee/~8785823/598755268/5275636/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><pubDate>Fri, 09 Sep 2011 09:04:21 +0800</pubDate><guid isPermaLink="false">urn:uuid:d1377d5b-0252-492f-92b0-1dafefa39a3d</guid><fs:srclink>http://www.mockee.com/2011/09/09/fresh-start-with-nodecat/</fs:srclink><fs:srcfeed>http://mockee.com/atom.xml</fs:srcfeed><fs:itemid>feedsky/mockee/~8785823/598755268/5275636</fs:itemid></item></channel></rss>
