爱凉拌菜真是太好了

使用Vue搭建博客(二)——后端进行Markdown解析

后台搭建代码忽略不计, 核心就是将markdown文本解析成HTML,然后保存进mongodb就行

blog的数据结构(使用Mongodb)

其中content字段是存储转换过后的HTML文档,contentMD字段是存储原生Markdown文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var { mongoose } = require('./connect');
var Schema = mongoose.Schema;
var articleSchema = new Schema({
author: String,
title: String,
time: Date,
updateTime: Date,
abstract: String,
tags: Array,
content: String, // 转换过后的html
contentMD: String // markdown
});
var tagSchema = new Schema ({
blogid: {type: mongoose.Schema.Types.ObjectId, ref: 'articles'},
tag: {type: String},
blogTime: Date,
blogTitle: String
});
var Blog = mongoose.model('articles',articleSchema);
var Tag = mongoose.model('tags', tagSchema)
exports.Tag = Tag;
exports.Blog = Blog;

使用marked进行Markdown渲染并将结果保存到Mongodb

marked使用方式https://github.com/chjj/marked

请忽略糟糕的回调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
var { Blog, Tag } = require('../mongo/blog');
var marked = require('marked');
var renderer = new marked.Renderer();
var ObjectId = require('mongoose').Types.ObjectId;
renderer.heading = function (text, level) {
var escapedText = text
return '<h' + level + '><a name="' +
escapedText +
'" class="anchor" href="#' +
escapedText +
'"><span class="header-link"></span></a>' +
text + '</h' + level + '>';
},
marked.setOptions({
renderer: renderer,
gfm: true,
tables: true,
breaks: false,
pedantic: false,
sanitize: false,
smartLists: true,
smartypants: false,
highlight: function (code) {
return require('highlight.js').highlightAuto(code).value;
}
});
exports.mdparser = function ({md, article}, callback) {
/*
* ---
title: 一份完整的express4后台配置
date: 2017-09-21 11:01:28
tags: [nodeJS, express]
---
*/
// 解析 如上的文章头部
let title,time,tags
// md表示hexo格式的原生md文档, article 表示直接传入的是一个article对象
// 如果只有md,没有article, 则表示通过上传的方式传入文章解析到的md文档(一般为hexo生成的markdown, 具有如上的文章头部信息)
// 如果只有article, 没有md ,则表示第一次创建该文章是通过博客的admin页面在线创建、或者修改
if (!article && md) {
let hrlen = '---'.length;
let contentIndex = md.indexOf('---',md.indexOf('---') + hrlen) + hrlen // 正文开始的index
let desc = md.slice(0, contentIndex); // 文件头部
title = desc.match(/title:(.*)/)[1];
time = desc.match(/date:(.*)/)[1];
tags = desc.match(/tags:(.*)/)[1].replace(/[\[\]]/g,'').trim();
if (tags === '') {
tags = []
} else {
tags = tags.split(',')
}
if (title.length <= 0 && time.length <= 0) {
callback && callback({status: 'err', err: 'cannot parse article'})
return
}
md = md.slice(contentIndex);
} else if (article){
md = article.contentMD;
title = article.title;
tags = article.tags;
time = article.time || new Date();
} else {
callback && callback({status: 'err', err: 'both Object article and markdown file are invalid'})
return
}
marked(md, function(err, html) {
if(err) {
callback && callback ({status: 'err', err: err});
return
}
// 提取解析后文档 <!--more--> 之前的部分,左右abstract
let more = html.match(/<!--\s*(more)\s*-->/);
let moreIndex = 0;
let abstract = '';
if(more!==null) {
moreIndex = more.index;
abstract = html.slice(0, moreIndex)
}
// 到这儿已经解析完毕, 剩下的操作就是将解析的HTML存放到Mongodb
if(!err) {
// 如果已经有该blog, 则更新,没有则创建
Blog.findOneAndUpdate({
title: title,
},{
title: title,
time: new Date(time),
content: html,
abstract: abstract,
tags: tags,
contentMD: md
},{
upsert: true // if not exist , create the object
}, function (err, doc) {
let promises = [];
if(err) {
callback && callback({status: 'err', err: err});
return
}
if(!doc) {
Blog.findOne({title: title}, (err, doc2) => {
let promises = []
if(tags.length <= 0) {
callback && callback({status: 'ok', warnning: 'no tag', msg: 'created'})
return
}
tags.forEach((item, index) => {
let data = {
tag: item,
blogid: new ObjectId(doc2._id),
blogTitle: doc2.title,
blogTime: doc2.time
}
// 如果tag数据没有变动,则数据维持原样
let promise = new Promise((resolve, reject) => {
Tag.findOneAndUpdate(data/*query*/,data/*update*/,{upsert: true},(err) => {
if(err) {
console.log('Tag save error: ' + err);
reject({status: 'err', err: err})
return
} else {
resolve({status: 'ok', msg: 'created'})
}
})
})
promises.push(promise)
})
Promise.all(promises).then((messages) => {
callback && callback({status: 'ok', msg: 'created'})
}).catch((err) => {
callback && callback({status: 'err', err: err})
})
})
return;
}
if(tags.length <= 0) {
callback && callback({status: 'ok', warnning: 'no tag', msg: 'updated'})
return
}
tags.forEach((item, index) => {
let data = {
tag: item,
blogid: new ObjectId(doc._id),
blogTitle: doc.title,
blogTime: doc.time
}
let promise = new Promise((resolve, reject) => {
// 如果tag数据没有变动,则数据维持原样
Tag.findOneAndUpdate(data/*query*/,data/*update*/,{upsert: true},(err) => {
if(err) {
console.log('Tag save error: ' + err);
reject({status: 'err', err: err})
return
} else {
resolve({status: 'ok', msg: 'updated'})
}
})
})
promises.push(promise)
})
Promise.all(promises).then((messages) => {
callback && callback({status: 'ok', msg: 'updated'})
}).catch(err => {
console.log(err)
callback && callback({status: 'err', err: err})
})
})
}
})
}