经常活跃在各种论坛、博客、github上的朋友们不难发现,很多大咖都有自己的网站,而且以博客居多。作为一个立志做前端大白的博主,难道不应该向大牛学习吗?就这么干吧,前端部分和web开发博主做了很多学习和总结,也有很多写进了博客。对于后端,博主不敢说一点经验都没有,只是接触比较简单。于是,博主在去年6月底开始关注Node和Express,并利用业余时间创建了自己的博客。现阶段还存在很多不足,需要在今后不断完善。但这并不妨碍博主先总结一下自己的感受。UI设计和架构设计博主深感自己没有任何艺术功底,只能看各种设计稿来刺激神经,比如Dribbble、水陈UI、千库、DotSpin、LogoSpire、腾讯ISUX等..事实上,不仅如此。对比我看到的链接,我点进去了,不知道点了多少,然后硬是挤出了一个连入门级都算不上的UI设计(别笑,指点一下)。是的,就是这么简单粗暴,连ps都没用!架构设计部分没有太深入的了解。简单的MVC结构非常适合架构入门。就连现在的前端都有MV结构的React,MVVM的Angular和Vue。结构如下图所示。这次终于用上PS了。其实一句话就能画出来。(还是那句话:别笑,指点)框架选择由于没见过Angular、vue、React等流行的框架,前端的实现还是选择使用Bootstrap和Sass风格。并且结构选择了jade模板引擎。这里有几个问题:为什么要用Bootstrap?这并不复杂。毕竟希望能实现兼容移动端和PC端的响应式页面,所以只能说媒体查询是个利器,Bootstrap也没得选。我为什么使用Sass?写习惯了css,但是不习惯Scss的缩进。毕竟少了和Sass。选择Sass的原因如下:Sass有一些成熟稳定的框架,比如Compass、Foundation。侧面说明Sass比Less好。还有一个原因是国外同行讨论Sass的比Less多,用Sass的多。Sass具有更简洁的语法,就像一种编程语言,不像Less的混合方法使用起来不舒服。如果说Sass有什么不好的话,那就是它仍然构建在ruby??之上,这有点间接和笨重。为什么要用玉?这不需要太多的理由,比html更简洁,比html更强大!与其他模板引擎相比,它专用于html。与EJS相比,jade支持模板继承,而EJS不支持。事实上,我正在亲自开发它。如果是团队开发,我还是觉得EJS会好一些。可能是博主已经适应了挖坑的写法。使用html会使得前后端开发方便很多。而且jade的缩进风格在不同的IDE之间会很不方便。当然还有其他的模板引擎,比如swig,对于博主来说完全看不惯Django的风格。当然这里还有一个原因:快递默认玉石!!!后端开发采用Nodejs+Express+MongoDB。不得不说这个组合信息量很大,学习起来也比较方便。这里没有理由,我就是想学Node,不是世界上最美的语言,毕竟有js基础。为什么要使用MongoDB?说实话,这是博主第一次接触和使用非关系型数据库,突然发现自己喜欢上了。之前用的比较多MySQL。毕竟博客系统中存储的数据是文章,所以在关系型数据库中定义数据类型确实是一个坑。分配太大了,太浪费了,分配太小了,怎么写啊!当然,还有其他问题。由于找到了很多使用MongoDB的文章,我也就不再犹豫了。这里想说的是使用感受。一句话:JSON的存储方式,真是直接爽快!为什么要使用快递?我们都知道Express不能说是对Node的二次开发,而是一种扩展。博主开始学习前端,从基础做起没什么错。如果你想快速开发,只是把它当成一个工具,那么用sail会省去很多麻烦,用scaffolding会事半功倍。当然,Sail除了官方文档,好像也没有什么可以学的了。这个……其实Sail开发不了是有原因的:当然,如果有时间,博主还是想学习一下,koa和hapi是最后一个选择,项目构建工具。这里我可以直接说明我为什么用Gulp,为什么选择Gulp?事实上,这里有webpack和grunt可用。Gulp和webpack其实各有优势,比如gulp的任务定义和管理是Webpack做不到的,而且Webpack是基于模块依赖构建的。gulp也做不好。而且grunt确实比较繁琐复杂,很明显现在用的少了。其实gulp和webpack的使用感受是不一样的。Gulp是一个一个写任务,而webpack是写一个配置文件。请注意,我说的是感觉。Gulps从其核心功能出发,根据文件流的构造定义任务和块。并且webpack根据模块依赖构建目标文件,并且拥有支持不同模块的loader系统。如果要使用Webpack,请确保项目是模块化的,并且模块之间完全依赖。其他的建设工作应该交给gulp继续完成。博主目前的项目不是很大,模块依赖也比较简单,但是期望完成版本号替换、压缩代码、合并文件、发布到服务器等与模块化关系不大的任务,所以gulp是用过的。博主使用Gulp也是一个学习过程。正是因为Gulp和Webpack各有优缺点。下一步,博主还是打算用Webpack来重建这个项目,亲身体验一下它的魅力。项目总体流程确定功能,根据需求选择合适的框架和工具,设计界面、架构、数据库模式,构建express的服务器框架和目录结构,设计gulptask和livereload,编写页面测试功能模块,并进行必要的性能优化。遇到困难何铿总结了这个问题,博主真的觉得不好意思。以博主的性格,做之前会觉得:“我以前没做过,好难,不过今天早上查了资料肯定能做”,做完之后,总觉得:“没想到这么简单!!!”所以话说回来,既然搞定了,倒也不觉得太难。其实,最难的应该是快速学习和使用这些工具,快速发现和解决问题。博主花了一个月的时间每天晚上和周末学习Nodejs+Express+MongoDB+Gulp,做出了这篇博客。可以说对它们的开发逻辑、结构、基本用法都有了大概的了解。很多难解决的问题无非就是google、知乎、github。login函数实现登录功能,使用passport和validator组件。首先,验证登录。方法verifyPassword在用户模型中实现:UserSchema.methods.verifyPassword=function(password){returnpassword===this.password;}而对于需要认证的页面在用户控制器中实现中间件:varneedLogin=函数(req,res,next){if(req.user){next();}else{req.flash('错误','请先登录');res.redirect('/admin/users/login');}}module.exports.requireLogin=needLogin;对于验证器,根据需要在express.js中添加使用。app.use(validator({errorFormatter:function(param,msg,value){varnamespace=param.split('.'),root=namespace.shift(),formParam=root;while(namespace.length){formParam+='['+namespace.shift()+']';}return{param:formParam,msg:msg,value:value};}}));加密用的是md5,就不多说了。还有一点就是登录状态校验:在服务器端,登录状态保存在数据库的session集合中,通过passport和express-session实现:app.use(session({secret:'nodeblog',resave:false,saveUnitialized:true,cookie:{secure:false},store:newMongoStore({mongooseConnection:connection})}));app.use(passport.initialize());app.use(passport.session());app.use(function(req,res,next){req.user=null;if(req.session.passport&&req.session.passport.user){User.findById(req.session.passport.user,function(err,user){if(err)returnnext(err);user.password=null;req.user=user;next();})}else{next();}})已找到Markdown和内容验证before实施标记插件,github中'markdown'的第一节点插件。插件这里就不多说了。这里重点介绍内容验证,因为内容验证是安全保障的重要一环。这里,既要保证不会提交和运行恶意脚本,又要保证markdown能很好的转换数据。对于输入字符串处理,博主实现了几个实用函数:varclearUtil=function(app){};//清除XML标签clearUtil.clearXMLTags=function(str,deeply){vardeeply=deeply||错误的;vartemp=str.replace(/<[^>]+>/g,'');如果(深深地){temp=temp.replace(/[\r\n][\r\n]+/g,'');}returntemp;};//清除脚本标签和内容clearUtil.clearScripts=function(str){returnstr.replace(//ig,'');};//清除替换符号CR/LFclearUtil.clearReturns=function(str){returnstr.replace(/[\r\n]/g,'');};//转义xml尖括号clearUtil.TransferTags=function(str){vartemp=str.concat();temp=temp.replace(//g,'>');returntemp;};module.exports=clearUtil;性能优化部分主要是代码压缩和缓存利用。压缩方法是非常主流的方法。使用imagemin、clean-css、uglify对图片、css和js进行压缩,同时将网页以gzip格式传输,减少体积。同时对css和js添加缓存,实现服务器更新E-Tag和版本号。这部分其实已经由Express帮我们实现了。所以在这部分,有十几个gulp配置gulp.task('sass',function(){gulp.src('./source/css/**/*.scss').pipe(autoprefix()).pipe(sass()).pipe(clearCss()).pipe(gulp.dest('./dist/css')).pipe(browserSync.reload({stream:true}));});gulp.task('imagemin',function(){gulp.src('./source/img/*.{png,jpg,gif,ico}').pipe(imagemin()).pipe(gulp.dest('./dist/img'));});gulp.task('minifyjs',function(){returngulp.src('./source/js/**/*.js').pipe(rename({后缀:'.min'})).pipe(uglify()).pipe(gulp.dest('./dist/js'));});偷懒配置博主使用的是CentOS服务器,其实通过scp和ssh就可以实现上传和配置,但是根据“进步源于偷懒”的coder改进原则,博主还是自己做了一个上传部署的功能:/*gulpfile.js的一部分*/varshell=require('gulp-shell');varssh=require('gulp-ssh');vardeployConfig=require("./deploy-config");vargulpSequence=require('gulp-sequence');varzip=require('gulp-zip');varthrough=require('through2');varasync=require('async');varscpClient=require('scp2');vargulpUtil=require('gulp-util');vardeploySSH=require('./deploy-ssh');//上传功能实现主机gulp.task('up',function(){shell.task(['rm-rfpublish']);gulpSequence('copyFile','zipFile','deploy',function(){gulpUtil.log(PLUGIN_NAME,"*****DeployFinished!!!!!!");process.exit(0);});});gulp.task('copyFile',function(){returngulp.src(['node_modules/**','*.json','*.js','app/**','config/**','dist/**','!config.js'],{base:'./'}).pipe(gulp.dest('./publish'));});gulp.task('zipFile',function(){returngulp.src(['publish/**'],{base:'./'}).pipe(zip('publish.zip')).pipe(gulp.dest('./publish'));});gulp.task('deploy',function(){varconfig=deployConfig.production;config.deployPath='/home/faremax/website/publish/';returngulp.src("publish/publish.zip",{base:'./'}).pipe(deploySSH({servers:config.servers,dest:config.deployPath+'publish.zip',logPath:'deploy',shell:['cd'+config.deployPath,'shopt-sextglob','rm-rf!(logs|node_modules|config.js|publish.zip)','unzip-opublish.zip','cp-rfpublish/**.','rm-rfpublish',"rmpublish.zip",'npminstall--production','pm2startOrRestartpm2-start.json'],}));});/*deploy-ssh.js*/vargulp=require('gulp');vargutil=require('gulp-util');varthrough=require('through2');varScpClient=require('scp2').Client;varssh=require('gulp-ssh');varasync=require('async');varProgressBar=require('progress');constPLUGIN_NAME='deploy-ssh'module.exports=function(options){varservers=options.servers;vardest=options.dest;varshell=options.shell;varlogPath=options.logPath;returnthrough.obj(function(file,enc,callback){if(file.isNull()){callback(null,file);return;}if(file.isStream()){returncallback(newgutil.PluginError(PLUGIN_NAME,'不支持流'));}vari=0;async.eachSeries(servers,function(server,done){varhostName=server.sshConfig.host;gutil.log(PLUGIN_NAME,"startdeploy:"+hostName)varclient=newScpClient(server.sshConfig);varbar=null;client.on("transfer",function(buffer,uploaded,total){if(bar==null){bar=newProgressBar(hostName+'uploading[:bar]:percent:elapseds',{complete:'=',不完整:'',宽度:50,总计:total});}bar.tick(1);});client.write({destination:dest,content:file.contents},function(){ssh(server).shell(shell,{filePath:logPath+"-"+hostName+".log",autoExit:true}).on('error',function(err){done(err);gutil.PluginError(PLUGIN_NAME,err)}).on('finish',function(){gutil.log(PLUGIN_NAME,"finishdeploy:"+hostName);done();if(++i===servers.length){回调(null,文件);}}).pipe(gulp.dest('logs'));});});});};/*deploy-config.js*/varconfig={production:{servers:[{sshConfig:{host:'114,214,132,211',port:80,username:'******',password:'******',readyTimeout:600000}}]}};module.exports=config;从功能上看,网站只实现了博客展示、博客管理、分类管理三个基本部分。前台是给用户看的。这需要很多时间,而且有安全保障。这不能不注意前景的效果。每个人都可以看到这一点。不说了:当然,前台也有移动端:后台效果,东西不多,界面很简单,很多东西还是有的。需要逐步补充:
