hexo博客框架从入门到弃坑
引言
有些日子没写项目了,正好学了点Nodejs,就说拿koa2+react搭一个博客练练手。
在找博文存储方案的时候了解到目前大多数博文都已markdown或类似的标记化语言文档存储,所以就找了较为新颖的hexo博客框架试用一下,顺带研究下源码。
起初觉得挺舒服,因为配置和主题切换起来足够简单,官网的文档也是希望用户不需要了解太多,只有最简单的教程,所以没几个小时就觉得不够用了。
我的需求是通过Node实现博文的数据维护和接口,所以接下来我通过 hexo-admin 和 hexo-generator-restful 两个hexo插件来实验,前者构建了一个管理界面,有账号管理、博文编写和管理等功能,后者提供了hexo中所有内容的输出接口,巧的是通过查看源码发现hexo-admin还提供了很多可用来维护博文的输入接口。
后来我把hexo项目部署到了服务器上,前台后台预期功能也实现了,却索然无味了……
hexo博客搭建
hexo博客在本地搭建起来很简单,全命令行操作即可,官网也有不怎么清楚的教程->点此进入。
node环境搭建
- windows环境: https://www.cnblogs.com/zhouy...
- centos环境: https://www.cnblogs.com/codey... (没记错的话,装完需要重启)
- 安装hexo-cli
npm install -g hexo-cli
- 通过hexo-cli初始化博客项目,将blog-site-name替换成你的项目名
hexo init <blog-site-name>
- 搭建结束,开箱即用,目录结构如图
命令行进入项目目录,输入命令运行。
hexo server
或者hexo s
INFO Start processing INFO Hexo is running at http://localhost:4000 . Press Ctrl+C to stop.
这里没什么说的,之后即可通过访问 http://localhost:4000 进入博客。
构建接口服务
- 首先安装 hexo-admin 和 hexo-generator-restful 两个插件
npm install --save hexo-admin hexo-generator-restful
如果你愿意的话可以看它们的文档查看详细使用方法:
https://github.com/jaredly/he...
https://github.com/yscoder/he...- 我们来看hexo-admin插件的源码,目录结构如下:
入口文件index.js片段
这里通过hexo的api方法在服务请求中间件中加入了登陆模块和路由模块。
其中路由模块分后台管理页面admin/
和 后台管理接口admin/api/
hexo.extend.filter.register('server_middleware', function(app) { // 如果配置文件中要求用密码登陆 if (passwordProtected) { require('./auth')(app, hexo); // setup authentication, login page, etc. } // Main routes app.use(hexo.config.root + 'admin/', serveStatic(path.join(__dirname, 'www'))); app.use(hexo.config.root + 'admin/api/', bodyParser.json({limit: '50mb'})); // setup the json api endpoints api(app, hexo); });
剖析api.js
api.js
中就是所有接口代码。
这是接口封装函数:var use = function (path, fn) { app.use(hexo.config.root + 'admin/api/' + path, function (req, res) { var done = function (val) { if (!val) { res.statusCode = 204 return res.end(''); } res.setHeader('Content-type', 'application/json') res.end(JSON.stringify(val, function(k, v) { // tags and cats have posts reference resulting in circular json.. if ( k == 'tags' || k == 'categories' ) { // convert object to simple array return v.toArray ? v.toArray().map(function(obj) { return obj.name }) : v } return v; })) } res.done = done res.send = function (num, data) { res.statusCode = num res.end(data) } fn(req, res) }) }
类型太多,这里以博文接口为例,可以看到通过下级路由
publish
、unpublish
、remove
、rename
实现了对博文的发布,撤回草稿,移除,改名操作,并且根据GET
、POST
请求类型对/post
功能进行了区分。use('posts/', function (req, res, next) { var url = req.url if (url[url.length - 1] === '/') { url = url.slice(0, -1) } var parts = url.split('/') var last = parts[parts.length-1] if (last === 'publish') { return publish(parts[parts.length-2], req.body, res) } if (last === 'unpublish') { return unpublish(parts[parts.length-2], req.body, res) } if (last === 'remove') { return remove(parts[parts.length-2], req.body, res) } if (last === 'rename') { return rename(parts[parts.length-2], req.body, res) } var id = last if (id === 'posts' || !id) return next() if (req.method === 'GET') { var post = hexo.model('Post').get(id) if (!post) return next() return res.done(addIsDraft(post)) } if (!req.body) { return res.send(400, 'No post body given'); } update(id, req.body, function (err, post) { if (err) { return res.send(400, err); } res.done({ post: addIsDraft(post), tagsCategoriesAndMetadata: tagsCategoriesAndMetadata() }) }, hexo); });
其他细节就不赘述,可以直接看其源码,但有一点要说明一下,就是hexo创建博文的方式:通过
/new
我们可见一斑。hexo通过new创建实体markdown文件,再通过update方法更新其内容。use('pages/new', function (req, res, next) { if (req.method !== 'POST') return next() if (!req.body) { return res.send(400, 'No page body given'); } if (!req.body.title) { return res.send(400, 'No title given'); } hexo.post.create({title: req.body.title, layout: 'page', date: new Date()}) .error(function(err) { console.error(err, err.stack) return res.send(500, 'Failed to create page') }) .then(function (file) { var source = file.path.slice(hexo.source_dir.length) hexo.source.process([source]).then(function () { var page = hexo.model('Page').findOne({source: source}) res.done(addIsDraft(page)); }); }); });
- hexo-generator-restful
官方文档已经介绍的很详细了,他能提供站点配置site.json,博文post.json等等等等。
目前为止,接口搭建工作就基本完成了
hexo部署
静态部署
hexo官方推荐使用 hexo-deployer-git
做静态部署,也就是说,通过下面的配置,hexo会将工程文件转译成一个.deploy文件夹,并将该文件夹force push到所配置的git目录中,你可以通过github将该目录下文件进行渲染,也可以将该静态目录clone到自己服务器上进行渲染。
deploy: type: git repo: <repository url> #https://bitbucket.org/JohnSmith/johnsmith.bitbucket.io branch: [branch] #published message: [message]
这意味着每次同步服务器上的博客都需要先将博文push到gihub上,再从服务器端手动pull相应的更新,是不是很麻烦,虽然静态部署无论是从安全性还是稳定性上都比较可靠,而且也有了hexo插件能够自动实现这些操作,但是这不是我想要的。
静态资源文件目录:
动态部署
我心中最理想的架构是将博文、图片等静态资源存放在github中,服务端通过定时更新或监听更新的方式同步github上的资源文件,然后在github上编写markdown文件即可自动同步博客网站的内容。这样做内容管理优势有几点:
- github充当备份,万一哪天你忘了你服务器上还有这个博客服务,你还有github帮你记着。
- 免去了markdown编辑器的开发工作,github上可以新增和编辑markdown文件,当然你可以使用印象笔记等软件编写然后复制过来。自己写的编辑器还要做大量的优化工作,大概率没别人写的好,所以就不造轮子了。
- 免去繁杂的同步工作。
服务端也可以选择使用 hexo theme 模板 或前后端分离的方式进行开发,我这里选择只提供接口做数据服务。当然hexo theme模板来的简单,也好看。
以centos7为例,下面是部署方式:
- node环境、hexo环境、接口搭建
npm install -g forever
- cd <your-blog-site>
创建一个index.js文件,内容如下:
const Hexo = require('hexo'); const hexo = new Hexo(process.cwd(),{ debug: true }); hexo.init().then(function(){ hexo.call('server', {}).then(function(){ console.log('server started'); }) })
forever start index.js
netstat -ntpl
查看4000端口是不是被启用了。- 用nginx把这个端口代理了,然后就可以访问了。
到这里我们就完成了博客的内容管理,实现了IO接口,但这时候我放弃了。
我开始思考我为什么要做用这么一个需要长期维护的东西来练手,要写东西的话有简书、segementfault等网站支持,为什么不从那边写完再爬数据。而且接下来要做服务器与github同步的工作还挺复杂,功能简单,但很消耗我的服务器性能,实在是得不偿失……
Hexo博客框架适合人群
- 学生,用于找工作,搭建真的很傻瓜,但效果还蛮好的,上手操作也简单。
- 设计工作者,hexo是偏向内容管理的,我在theme库中看到了好多比较好看的博客模板,到目前为止还在使用的那些博主几乎都是做设计的。
这里分享一个我很喜欢的风格:
https://clovertuan.github.io/