hexo博客框架從入門到棄坑

引言

有些日子沒寫項目了,正好學了點Nodejs,就說拿koa2+react搭一個博客練練手。

在找博文存儲方案的時候瞭解到目前大多數博文都已markdown或類似的標記化語言文檔存儲,所以就找了較爲新穎的hexo博客框架試用一下,順帶研究下源碼。

起初覺得挺舒服,因爲配置和主題切換起來足夠簡單,官網的文檔也是希望用戶不需要了解太多,只有最簡單的教程,所以沒幾個小時就覺得不夠用了。

我的需求是通過Node實現博文的數據維護和接口,所以接下來我通過 hexo-adminhexo-generator-restful 兩個hexo插件來實驗,前者構建了一個管理界面,有賬號管理、博文編寫和管理等功能,後者提供了hexo中所有內容的輸出接口,巧的是通過查看源碼發現hexo-admin還提供了很多可用來維護博文的輸入接口。

後來我把hexo項目部署到了服務器上,前臺後臺預期功能也實現了,卻索然無味了……

hexo博客搭建

hexo博客在本地搭建起來很簡單,全命令行操作即可,官網也有不怎麼清楚的教程->點此進入

  1. node環境搭建

  2. 安裝hexo-cli
    npm install -g hexo-cli
  3. 通過hexo-cli初始化博客項目,將blog-site-name替換成你的項目名
    hexo init <blog-site-name>
  4. 搭建結束,開箱即用,目錄結構如圖
    圖片描述
  5. 命令行進入項目目錄,輸入命令運行。
    hexo server 或者 hexo s

    INFO  Start processing
    INFO  Hexo is running at http://localhost:4000 . Press Ctrl+C to stop.

這裏沒什麼說的,之後即可通過訪問 http://localhost:4000 進入博客。

構建接口服務

  1. 首先安裝 hexo-adminhexo-generator-restful 兩個插件

    npm install --save hexo-admin hexo-generator-restful

  2. 如果你願意的話可以看它們的文檔查看詳細使用方法:

    https://github.com/jaredly/he...
    https://github.com/yscoder/he...
  3. 我們來看hexo-admin插件的源碼,目錄結構如下:

    圖片描述

  4. 入口文件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);
    });
    
  5. 剖析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)
    })
     }

    類型太多,這裏以博文接口爲例,可以看到通過下級路由publishunpublishremoverename實現了對博文的發佈,撤回草稿,移除,改名操作,並且根據GETPOST請求類型對/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));
          });
        });
      });
  6. hexo-generator-restful

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章