用node.js和express.js和jade搭建轻型cms系统
http://cnodejs.org/topic/4f16442ccae1f4aa270010bf
前言:
我们主要做的是iphone/ipad程序,但关注node.js很久,因为我们多少总是要做网站,做后台。node.js就像一个非常快的ruby。对于我们而言,其实学习node.js起来还是很简单,网上资料很多,但没有看到一些比较完整的例子。所以回报一下大家,在这里把我们基本上最核心的源码分享给大家了。
背景介绍:
我用node.js已经实现过一些小的应用利用websockets配合移动终端做网页同步显示,但是没有一个真正的项目。
最近把公司官网移植到node.js上,已经上线:qinyh.com。
我们官网内容大概很少会变化,于是我们考虑把内容放在一个js文件里(chinese.json),而所有的路径放在另一个js文件里(route.json)。总共最后用了包括layout和404页面在内的八个视图。虽然不能说是一个完整的cms,但是已经实现了版面与内容的分离。也可以非常轻松地修改内容和图片。
我们还用ajax配合node-mailer实现异步的发信功能,这个以后跟大家介绍。
核心技术介绍:
- node.js (nodejs.org)运行快开发快的服务器框架,使用v8跑javascript
- express.js(expressjs.com) node.js上目前最好的网站服务器框架,尤其特别合适做REST协议。
- jade (jade-lang.com)一个非常干净易用的html模板语言
框架结构
- 代码
- /server.js 80端口上的服务器(负责虚拟主机)
- /app.js 官网服务器
- /email.js 邮件模块(这次没有讲)
- 路由列表
- /router.json 关联路径,视图和内容
- 视图
- /views/layout.jade 基础模板
- /views/index.jade 首页
- /views/.... 还有6个模板
- /views/404.jade 错误页面
- 内容
- /chinese.json 存放内容和图片路径
- 其他静态资源
- /public/js/... 存放js文件
- /public/css/... 存放css文件
- /public/images/... 存放图片
联系我们
有什么疑问可以直接留言,或者也可以联系我:hts_某种符号_qinyh.com (也欢迎node.js工程师投简历)
接下来是代码
/server.js
我们使用forever(https://github.com/indexzero/forever)来跑node.js脚本,这样可以保证服务器不会down掉。
由于我们主机还想做别的项目所以我们要用到虚拟主机:
/*** Module dependencies.*/var express = require('express');var offical = require('./app.js');var site_vhosts=[],vhosts;// Virtual Hostssite_vhosts.push(express.vhost('qinyh.com',offical));site_vhosts.push(express.vhost('www.qinyh.com',offical));vhost=express.createServer.apply(this,site_vhosts);vhost.listen(80);console.log("Express router Listening on port 80");
/app.js
以下才是我们程序的主干部分,忽略掉了ajax邮件发送模块⋯⋯下次再讲
注意只有当在production mode时,才会开启缓存,才保证性能。
/*** Module dependencies.*/var express = require('express');var app = module.exports = express.createServer();var fs=require('fs');// Configurationvar oldconsole=console.log;log=function(obj,error){if(process.platform!="win32"){var color=(error)?"33[1;31m":"33[1;32m";process.stdout.write(color);oldconsole(obj);process.stdout.write("33[0m");}else{oldconsole(obj);}}console.log=function(obj){log(obj,true);}app.configure(function(){app.set('views', __dirname + '/views');app.set('view engine', 'jade');app.use(express.bodyParser());app.use(express.methodOverride());app.use(express.static(__dirname + '/public')); //注意顺序,为了能够用到404,要把这个提前。app.use(app.router);});app.configure('development', function(){app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));log("Warning: Server in Development Mode, add NODE_ENV=production",true);});app.configure('production', function(){app.use(express.errorHandler());log("Production Mode");});// Read JSON files//这里出现过一个非常恶心的bug,我们发现我们拿windows记事本产生的json文件node.js解析会有问题,于是去掉第一个字节。为了保证安全,文件也上来加了一个回车。//由于我们是一上来只解析一次,所以我们采用了同步方式
var info=JSON.parse(fs.readFileSync('chinese.json', 'utf8').substr(1));var routes=JSON.parse(fs.readFileSync('router.json','utf8').substr(1));// Start routervar startRouter=function(path){app.get(route, function(req,res){//console.log("Connect to "+path);var page=info[routes[path].data];res.render(routes[path].template,page);//最核心的一句});};for(route in routes){//如果直接for循环而不是调用函数,你就会发现route永远是最后一个startRouter(route);}//File not foundapp.get('/*', function(req, res){res.render('404',{status: 404,title:'404 - 文件未找到'});});try{app.listen(3000);log("Express server listening on port 3000");}catch(e){log("Error: "+e.message,1);}
/router.json
我们通过router.json实现了路由表,可以看到index是view,而data是chinese.json里对应的内容:
{"/": {"template": "index","data": "index"},"/products": {"template": "secondary","data": "products"},"/products/clothes": {"template": "products","data": "clothes"},"/products/wine": {"template": "products","data": "wine"},"/products/furniture": {"template": "products","data": "furniture"},"/solutions": {"template": "secondary","data": "solutions"},"/solutions/shop": {"template": "solutions","data": "shop"},"/solutions/e-shop": {"template": "solutions","data": "eshop"},"/solutions/next-gen": {"template": "solutions","data": "nextgen"},"/company": {"template": "secondary","data": "company"},"/company/team": {"template": "about","data": "team"},"/company/ideals": {"template": "company","data": "ideals"},"/company/contact": {"template": "contact","data": "contact"},"/company/jobs": {"template": "secondary","data": "jobs"},"/company/jobs/it": {"template": "jobs","data": "it"},"/company/jobs/design": {"template": "jobs","data": "design"},"/company/jobs/sales": {"template": "jobs","data": "sales"}}
/chinese.json
然后内容和图片是放在chinese.json里,我们由于一般改动很少,所以直接文本编辑器就很方便。如果经常更新,其实加一个后台也非常容易。
实际内容太多,只给两个例子
{"index": {"title": "首页 | 北京秦运恒信息技术有限公司","motto": "原来购物可以如此简单和生动","columns": [{"title": "最新产品","desc": "使用iPad展示商品为顾客提供更加丰富的渠道来探索和喜爱您的产品。","img": "/images/index/img1.png","href": "/products/"},{"title": "解决方案","desc": "我们会与您一起找到适合您的解决方案,让您的事业蒸蒸日上。","img": "/images/index/img2.png","href": "/solutions/"},{"title": "关于我们","desc": "年轻而专业。梦想加实干。敏捷和执着。这就是我们,您一定会喜欢跟我们合作。","img": "/images/index/img3.png","href": "/company/"}]},"products": {"title": "产品介绍 | 北京秦运恒信息技术有限公司","motto": "精益求精,宁缺毋滥","banner": "banner-2","columns": [{"title": "精品家具专家","desc": "苹果iPad上展现家具的全部风采,捕捉顾客的想象力和心,连样板间都可以展现上百种家具。","img": "/images/product/img1.png","href": "/products/furniture/"},{"title": "葡萄酒指南","desc": "中国即将成为世界红酒消费第一大国,然而多数消费者只认得电视广告。有了这样的指南,您的好酒再也不愁无人问津。","img": "/images/product/img2.png","href": "/products/wine/"},{"title": "服装时尚导购","desc": "顾客看到苹果iPad上的服装模特会动的那一刻,已经决定了您和其他店的区别。从今以后您的顾客可以和朋友一起坐着逛街了。","img": "/images/product/img3.png","href": "/products/clothes/"}]},....]
/views/layout.jade
然后就是通用的模板layout.jade,放在views目录下,用jade写的,非常简约。!=body 是插入别的页面的地方。
!!! transitionalhtml(xmlns='http://www.w3.org/1999/xhtml')headmeta(http-equiv='Content-Type', content='text/html; charset=utf-8')title= titlelink(rel='shortcut icon', href='/favicon.ico', type='image/x-icon')link(rel='stylesheet', type='text/css', href='/css/index.css')body#alldiv(style='clear:both')#logo.contenta(href='/')img(src='/images/logo.png', width='232', height='35', alt='北京秦运恒信息技术有限公司')ullia(href='/') 首页lia(href='/products/') 产品介绍lia(href='/solutions/') 解决方案lia(href='/company/') 关于我们lia(href='/company/jobs/') 加入我们!=body#footerp(align='center') @2010 北京秦运恒信息技术有限公司 京备ICP10028133号
/views/index.jade
有那么多视图就不上传了,我就把首页上传给大家看看
#p-1.contentp= motto#main.content- for (var i in columns)- var last=(i<columns.length-1)?'':'last' dl(class='#{last}')dta(href='#{columns[i].href}')img(src='#{columns[i].img}', width='276', height='164', alt='#{columns[i].title}')dda(href='#{columns[i].href}')span=columns[i].titlebr| #{columns[i].desc}.slider-wrapper.theme-custom.slider-wrapper2#slider.nivoSliderimg(src='../images/index/banner1.png', width='100%', height='366', alt='首页')img(src='../images/index/banner2.png', width='100%', height='366', alt='首页')img(src='../images/index/banner3.png', width='100%', height='366', alt='首页')script(type='text/javascript', src='/js/jquery-1.6.1.min.js')script(type='text/javascript', src='/js/jquery.nivo.slider.js')script(type='text/javascript')$(document).bind("ready",function() {$('#slider').nivoSlider();});
其他资源
其他资源一股脑扔倒/public目录下就可以了。
请关注第二讲,AJAX和邮件系统
标签: 原创文章 tianshuo 在 2011-8-10 13:04发布 tianshuo 在 1-19 11:50重新编辑 分享到 weibo
#1awen1983 在 2011-8-10 16:34回复
#2tianshuo 在 2011-8-10 18:09回复
我们会把邮件系统和我们的改进放到下一讲,敬请关注。
#3aujade 在 2011-8-11 12:00回复
#4snoopy 在 2011-8-12 13:38回复
不过我拿GOOGLE的PAGESPPED为:http://qinyh.com/ 打分,很悲剧的事情,
运行了4次,第1次是27/100分,后次是31/100分,最后一次还是27/100分,不知道是不是我这里的pagespeed出问题了,建议楼主查查原因。
pagespeed给出报告是图片,CSS,以及JS都没有压缩,
个人认为,丢分的最大原因是PNG图片没有压缩
其中CSS还包括了很多注释。
之后我用FIREBUG看了一下,发现一个严重性能问题,每次大图的切换都会发送一次图片的请求,奇怪的是每次请求的图片之前都已经请求过了,这样将严重影响服务端的性能,(按CTRL+F5刷新)请楼主去查查原因。
#5anonymous 在 2011-8-12 18:24回复
你是哪天运行的呢?
为什么我运行的结果是
Page Speed Online
网页 首页 | 北京秦运恒信息技术有限公司 的总体 Page Speed 得分为 98(满分 100 分)。
倒是有关你说的性能问题,我们想知道应该怎么改会比较好呢?
#6snoopy 在 2011-8-12 22:47回复
很高兴你能关注我的建议
问题1:
我的page speed是通过以下域名安装的
http://code.google.com/intl/zh-CN/speed/page-speed/docs/using_chrome.html#Installing
page speed是安装在 Chrome Developer Tools中的
回到家中,我又用Chrome Developer Tools的page speed测试还是27/100分。
不过我看了page speed在线确实是98分,我也很奇怪,不过CSS中有注释和未压缩的JS,应该很难得到98/100分。
不过这些问题不大
问题2:
单位里ff5.0,家里是ff3.6都存在在ctrl+f5刷新后每隔一定时间就会去请求banner1-3.png这3张图片,应该和你用的jQuery Nivo Slider v2.6插件有关系,可能和修改IMG SRC属性有关,可以考虑更换算法,比如利用display:none来代替更换src的方法。不过这个问题在chrome没有发现。
#7tianshuo 在 2011-8-18 14:49回复
#8anonymous 在 2011-8-27 20:02回复
我遇到了问题。。。
我用windows 的node.exe 来运行,
setup 如下,
mime ver 1.2.2
qs ver 0.3.0
express 1.0.7
connect 0.5.4
当我运行 node server.js 时, 我会遇到TypeError: Object # has no method 'bodyParser'
好像connect 0.5.4没有bodyParser。
当我用connect 1.0.0 时,我会遇到TypeError: Cannot read property 'prototype' of undefined
我想请问tianshuo是用什么setup的呢?
谢谢
#9anonymous 在 2011-9-5 12:46回复
你是用 utf-8 作為網站編碼嗎?如果是,那我猜你在用 notepad 存檔時,把 utf-8 的 BOM (byte order mark) 也存下去了。
請用其他編輯器,如Notepad++ 或是 UltraEdit 另存成沒有 BOM 的 utf-8 文件。
#10anonymous 在 2011-10-8 16:09回复
#11anonymous 在 2011-10-9 08:55回复
#12abbish 在 2011-10-19 10:36回复
#13freemem 在 6-1 16:20回复
非常好的实例!谢谢!
#14ruandao 在 7-28 19:46回复
好像当机了
#15tianshuo 在 7-30 15:03回复
嗯,php部分被黑客攻击后网站一直还没恢复呢
#16goooice 在 8-6 01:27回复
express.vhost 在3.0里没有了还是怎么的?网上搜了一些资料,是content。host的?请问这是怎么做的?
用node.js和express.js和jade搭建轻型cms系统相关推荐
- node.js安装express(零起点搭建本地测试服务器)- 教程篇
(含图文教程.代码对比,等)node.js安装express(零起点搭建本地测试服务器)- 教程篇 原教程 · 参考地址 执行step3之后,结果截图 · 如下图2 : 之后,执行step4,截图如下 ...
- node js 非阻塞io_Node Express JS:套接字IO模块示例
node js 非阻塞io Before reading post, please go through my previous posts: "Express JS WebApplicat ...
- [译] Node.js, Express.js 搭建 HTTP/2 服务器
原文:Easy HTTP/2 Server with Node.js and Express.js 作者:Azat Mardan 代码:http2-express 什么是 HTTP/2 现代互联网的 ...
- 如何在Node.js上的Express.js中获取GET(查询字符串)变量?
是否可以像在PHP的$_GET中那样在Node.js的查询字符串中获取变量? 我知道在Node.js中,我们可以在请求中获取URL. 有没有获取查询字符串参数的方法? #1楼 2014年5月4日更新 ...
- 什么是Express.js?
本文翻译自:What is Express.js? I am a learner in Node.js . 我是Node.js的学习者. What is Express.js ? 什么是Express ...
- pacf和acf_如何通过Wordpress API,ACF和Express.js使Wordpress更加令人兴奋
pacf和acf by Tyler Jackson 泰勒·杰克逊(Tyler Jackson) 如何通过Wordpress API,ACF和Express.js使Wordpress更加令人兴奋 (Ho ...
- 使用Enide Studio 2014 IDE进行Express JS路由
This post is a continuation post of my previous post "Express JS WebApplication with Enide Stud ...
- express-cli入门_使用Express.js入门
express-cli入门 by Victor Ofoegbu 由Victor Ofoegbu 使用Express.js入门 (Getting off the ground with Express. ...
- 安装node.js,CoffeeScript,Express.js,mysql,jade
node-v0.10.5-x86.msi 版本已经包含了节点包管理器 (NPM),安装了这个版本的node.js后,就可以在命令行利用npm命令安装CoffeeScript,Express.js,my ...
最新文章
- oracle视图能用etl工具_(转)使用kettle作为sqlserver2008和oracle10G之间的ETL工具
- 二进制八进制十六进制之间的快速转换------ 心算笔算方法总结
- 华尔街弃儿:雷曼兄弟158岁被清算
- ASP.NET Core 源码学习之 Logging[2]:Configure
- Mozilla 修复已遭利用的两个火狐浏览器 0day
- Windows8测试版使用感受
- windows下安装TensorFlow(Win8 + Anaconda4.4 python3.6)
- ONVIF流媒体播放流程
- 联想云计算机终端,联想智能云教室系统 V1.3.20.1109_C201105 最新官网版本
- 微信小程序开发页面跳转教程
- SSD网络及代码理解
- 用2008系统安装k3服务器,金蝶K3SQL-Server-2008-R2安装方法介绍
- XML外部实体(XXE)注入详解
- 【大话设计模式】第0章 面向对象基础
- Android在一个app中启动其他app中的service或者Activity
- uniapp 使用图表
- LaTeX之公式及编号
- 计算机的职业形象,计算机专业科开展学生干部职业形象塑造专题培训
- hadoop实战-06.ubuntu14.0安装hadoop 2.7.1( 3台主机) 小集群
- 技嘉主板大部分型号开启WOL(Wake up-On-LAN)网络唤醒与定时开机
热门文章
- 计算机二级考试字处理真题,计算机二级office字处理软件的重难点总结
- 潍坊学院java比赛_潍坊学院在山东省第六届“超星杯”高校教师教学比赛中再获佳绩...
- matlab牛顿解方程,牛顿迭代法解非线性方程matlab实现
- TS与JS区别、优势
- opencv: 图像缩放(cv2.resize)
- 又整理了一周爬虫的学习资料,内含入门、实战、视频,请收藏
- MongoDB基础教程
- vue组件引入scss变量_SCSS特色的Vue.js ui组件设计系统
- 机器学习/深度学习中的常用损失函数公式、原理与代码实践(持续更新ing...)
- 【论文笔记】Generative Adversarial Frontal View to Bird View Synthesis - 论文阅读笔记