在我轉前端以來,一直想要實現一個願望: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的源碼裏面,找到了這個: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
貼一波圖:
All Post頁面:
Contact 頁面:
Tags 頁面:
Post頁面:
Resume頁面:
這個blog系統,也零零碎碎花了接近一個月的時間,終因而告一段落了,固然這篇文章裏面會有許多我沒有提到的部分,好比怎麼部署到域名下啊,怎麼打包編譯發佈到github pages,怎麼實現一些頁面的效果。
爲何我沒有寫這些呢?由於這些都有許多現成的答案啦。
最後新人求一波關注啦~關於這個blog系統,若是你有任何不清楚的地方,能夠留下你的評論,或者與我聯繫~
轉載請註明出處。