在我转前端以来,一直想要实现一个愿望:javascript
“本身搭建一个能够自动解析Markdown文档的我的站”html
今天终于实现啦,先贴上个人blog地址前端
其实一个最简单的我的站,就是许多的HTML页面,你只要能够用HTML写出来就能够,而后挂到Github pages
上。但这并非我想要的。vue
也有许多的人会选择用Vuepress,Hexo,Wordpress,Jekyll等等这样的博客框架来搭建本身的博客,我也都尝试过,有不少的主题能够给你选择,你甚至能够本身写一个主题或者修改其余人的主题让你的博客变得独一无二,但这也不是我想要的。java
那,我想要的是什么呢?node
用Markdown语法书写博客,支持代码高亮。react
其实上面不少的博客系统,或者静态博客生成器,均可以知足上面大部分的条件,我没有使用的缘由主要是如下几点:webpack
看到这些需求,其实重点不在于你要用什么框架来写。vue也好react也好甚至Jquery或者原生的JS,均可以。git
重点在于你如何处理Markdown文件,把它转换成你须要的对象,而且在你的页面中,能够经过路由来控制页面的内容的切换。github
简而言之,就是两点:
当你能够解决这两个问题,那就解决了全部的问题,由于剩下的就是撸页面了,天高任你飞,和太阳肩并肩。
或许也能够换一个小标题,怎样拿到Markdown里面的数据,而且在页面上读取数据呢?
须要这个数据是由于考虑到,在首页你可能须要展现全部的页面分类,和全部的Tags,甚至全部的文章的标题和内容,由于你须要作一个博客的检索?
我把以上提到的全部的博客框架的源码看了一遍,想看看对他们是怎么处理这个问题的。
而后在我首先在React-static的元am里面,找到了这个:Jdown
这是一个解析Markdown的包,甚至一开始我都是用这个来解析个人Markdown文件中的YAML标签的内容,而且我还和包的做者DanWebb聊了不少关于搭建我的站的问题。
直到我项目的最后才发现,这个包使用起来会有一些问题,对于一些过长的中文,可能他会解析失败,我也找不到规律,对于我来讲,要去阅读他的源码来定位问题,须要太多的时间,而后我想找一个替代的包,来实现一样的功能。
而后我就找到了gray-matter
我用这个包成功的把Markdown文件的YAML头解析为一个JSON对象。我是怎么作的呢?
在项目(打包/编译)的JS中:
data.js
的文件中(这个你能够本身定义目录)至此,全部页面获取数据的过程就结束了。
在页面上使用的时候,就只须要引入这个data.js
的文件而后就能够拿到页面的数据啦~
页面路由是咱们实现这个博客系统的关键,由于在上一步,咱们只是拿到了YAML
的信息,可是咱们并无拿到这个文档内容,就算咱们拿到了内容,也须要咱们把他解析为HTML以后,才能够展现出来,那如今怎么作呢?
其实用过webpack的人都知道,webpack有一个loader,咱们就是用到markdown的loader来作这样一件事情,loader就像是一个翻译工具,把源文件的内容处理以后,返回新的结果,甚至能够多重翻译以后再返回。那咱们就须要用Markdown的loader.
那咱们能够在路由中设置,把component设置成对应的md文件,这时候Webpack就会使用loader来解析这个md文件,变成咱们须要的HTML页面,同时咱们也能够在解析的过程当中,加入自定义的语法,加强和自定义咱们的markdown。
在router文件中的设置相似于下面这样
{ path: "/post/2018-05-20-first", component: () => import('../posts/2018-05-20-first.md') }
你觉得就这样简单的结束了吗?
太天真了少年,由于webpack是不支持import的动态参数的,也就是说,页面跑起来以后,想要经过YAML的信息,来拼接出router的值,是不可行的,就算你能够拿到文件名。
咱们总不能写一篇文章,就往这个router里面加入一条记录吧?
这一步也困扰了我好久,经过资料的搜集和查看其它人的源码,我在Vuepress的源码中找到了答案。尤大大是怎么作的呢?
有兴趣的朋友能够阅读一下Vuepress的源码,关键文件的路径是~/lib/prepare/codegen.js
代码贴出来(关键的信息我已经打上了注释):
exports.genRoutesFile = async function ({ siteData: { pages }, sourceDir, pageFiles }) { function genRoute ({ path: pagePath, key: componentName }, index) { const file = pageFiles[index] const filePath = path.resolve(sourceDir, file) // 这一段实际上就是你的路由信息 let code = ` { name: ${JSON.stringify(componentName)}, path: ${JSON.stringify(pagePath)}, component: ThemeLayout, beforeEnter: (to, from, next) => { import(${JSON.stringify(filePath)}).then(comp => { Vue.component(${JSON.stringify(componentName)}, comp.default) next() }) } }` const dncodedPath = decodeURIComponent(pagePath) if (dncodedPath !== pagePath) { code += `, { path: ${JSON.stringify(dncodedPath)}, redirect: ${JSON.stringify(pagePath)} }` } if (/\/$/.test(pagePath)) { code += `, { path: ${JSON.stringify(pagePath + 'index.html')}, redirect: ${JSON.stringify(pagePath)} }` } return code } const notFoundRoute = `, { path: '*', component: ThemeNotFound }` return ( // 这里你能够放入不少其余的须要在路由文件里面引入的信息 `import ThemeLayout from '@themeLayout'\n` + `import ThemeNotFound from '@themeNotFound'\n` + `import { injectMixins } from '@app/util'\n` + `import rootMixins from '@app/root-mixins'\n\n` + `injectMixins(ThemeLayout, rootMixins)\n` + `injectMixins(ThemeNotFound, rootMixins)\n\n` + `export const routes = [${pages.map(genRoute).join(',')}${notFoundRoute}\n]` ) }
这个文件在作什么呢?既然import不支持动态的参数,那咱们就直接生成一个router文件,而后使用这个router来配置咱们的路由不就能够了吗?
在本身的代码里面,把这一步加入到解析markdown的YAML信息这个步骤里,这样我在拿到了页面基本信息的同时,也进行了路由的配置。
通过一些页面的设计,终于完成啦,这里也贴一下blog的源码,欢迎你们star
贴一波图:
首页:
Contact 页面:
Tags 页面:
Post页面:
这个blog系统,也零零碎碎花了接近一个月的时间,终因而告一段落了,固然这篇文章里面会有许多我没有提到的部分,好比怎么部署到域名下啊,怎么打包编译发布到github pages,怎么实现一些页面的效果。
为何我没有写这些呢?由于这些都有许多现成的答案啦。
最后新人求一波关注啦~关于这个blog系统,若是你有任何不清楚的地方,能够留下你的评论,或者与我联系~
转载请注明出处。