博客地址: https://tianyong90.com
github 倉庫地址:https://github.com/tianyong90/blogcss
其實本身的博客上線沒多久,以前閒時會寫些亂七八糟的玩意兒,一來看成總結和備忘,二來分享一些我的經驗,也是種頗有趣的經歷。而後幾個月前,想着本身手裏有個註冊但閒置好久的域名,又正好有臺服務器,就乾脆折騰個博客。html
不就是個博客嘛?能有多難?也沒多想就用了以前使用過的 Hexo 擼了起來,只花了一夜就弄上線了。不過上線一時爽,維護火葬場。以後花上它上面的時間要遠多於此,由於 hexo 若是想要充分的自定義模板或者功能,仍是很麻煩的,特別是由於模板用的 pug 以及寫樣式用的 stylus 都是本身不擅長且不太喜歡的語言。幾番折騰下來總不得勁,終於心一橫,不如重構吧。vue
重構時要比當初選擇 hexo 時要謹慎多了,對比了下本身瞭解的一些工具,最終選擇了 Nuxt.js。webpack
最主要的緣由就是本身用 Vue 好久了,學 Nuxt 的成本也就小得多。Nuxt 可讓我用最熟悉的姿式來寫代碼,同時又能解決博客在靜態化、SEO 等方面的一些要求,它的佈局、自動路由、插件、中間件等特性讓我大有相見恨晚的感受。git
其實在做決定以前也試過 Vuepress,但 Vuepress 的出發點是文檔類的站,並不太適合寫博客。雖然 1.0 版中加入了博客的支持,但目前仍在 alpha 階段,體驗不太好,更新進度又不理想,等到正式穩定可用的版本出來,估計黃花菜也涼了。github
此外也考慮過用 hugo,甚至想過用 Laravel 來弄。但 hugo 基於 Go,本身徹底不懂,而用 Laravel 寫博客彷佛大材小用了,畢竟我只須要一個靜態的小站,也不會給服務器增長多少壓力。web
首先固然是建立項目,根據 Nuxt 文檔使用 yarn create nuxt-app
命令建立一個新項目,根據須要配置好 eslint、typescript 等。typescript
肯定目錄結構(路由)、文章文件名命名規範數據庫
由於以前用 hexo 部署的也是純靜態的站,只要以前所部署的舊文件不刪除,那麼使用原來的連接仍然能訪問舊版的文章。因此也不用太糾結重構後路由的變化。固然這並不意味着不須要進行規劃。json
爲此,我新建了一個 posts 目錄,用於保存 markdown 文件,文件夾內建與 markdown 文件同名的文件夾用來存文章中用到的圖片等。
-| posts/ ----| hello-中國/ ----| hello-中國.md
這裏要注意一下的是,文件名將一些特殊字符和空格替換成了連詞符,而實際訪問用的路由是將文件名拼音化。爲何不直接用拼音化文件名或者英文呢?主要是方便往後管理。
而後在 pages
目錄下建立 psots/_slug.vue
頁面。這樣文章就能夠用 https://tianyong90.com/psots/... 這樣形式來訪問了。
安裝並配置 @tianyong90/vue-markdown-loader
@tianyong90/vue-markdown-loader 是本身以前從 vuepress 中提取的 markdown-loader 部分代碼改寫出來的一個 webpack loader。它的主要功能是加載 markdown 文件,進行一些處理,如解析 emoji、代碼高亮等,最後返回能夠供 vue-loader 的內容。最近又進一步優化,讓它能夠返回 html 而被 html-loader 處理,或者直接返回一個包含 markdown 文件信息的對象。
配置以下:
build: { extend(config, ctx) { // frontmatter-markdown-loader config.module!.rules.push({ test: /\.md$/, include: path.resolve(__dirname, 'posts'), use: [ { loader: '@tianyong90/vue-markdown-loader', options: { mode: 'raw', // 這裏表示 import md 文件後直接返回一個對象 contentCssClass: 'markdown-body', markdown: { lineNumbers: true, // enable line numbers }, }, }, ], }) }, }
文章頁的一些處理
有了前面的這些,就能夠開始動手處理文章頁了,這也是博客的關鍵部分。而其中最爲重要的工做就是根據 url 中拼音化的文章標題正確加載 posts 目錄中的 markdown 連接半渲染顯示,這些基本都在 asyncData 方法中完成。
async asyncData({ params }) { // 這裏的 posts.json 是用腳本生成的保存 posts 目錄中文章列表信息的 // 至關於一個小的數據庫 const { default: posts } = await import('~/posts/posts.json') // 連接中拼音化的文件名 const slugifiedFilename = params.slug const thePost: any = posts.find((item: any) => { return item.slugifiedFilename === slugifiedFilename }) // posts 目錄中 markdown 實際文件名 const filename = thePost.filename // 解析渲染都交給前面提到的 @tianyong90/vue-markdown-loader 完成 // 這裏的 html 就是渲染出來的 html,能夠直接應用於 v-html 指令 // attributes 則是 markdown 文件頭部的 frontmatter 數據如標題、日期等 const { html, attributes } = await import(`~/posts/${filename}.md`) return { ...attributes, html: html.replace(/src="\.\//g, `src="/_nuxt/posts/${filename}/`), // markdown 內容中圖片地址引用替換 } },
而後在模板中顯示這些數據,其中 html 使用 v-html 指令就能夠了。
<div class="container-fluid py-4"> <div class="row post-info-sm"> <div class="col-12"> <h1 class="post-title" v-text="title" /> <div class="post-date">{{ date }}</div> </div> </div> <div class="row"> <div class="col-xs-12 col-md-10 col-xl-6 mx-auto"> <div class="markdown-body" v-html="html" /> </div> </div> </div>
博客並不僅是文字內容,所以還須要在佈局、樣式等方面下些功夫。由於本身設計水平實在有限,因此直接使用了 bootstrap 和 github-markdown-css,擼完文章列表頁以及文章內容頁就夠用了,其它的頁面看須要再加吧。
生成、部署以及自動化
最後要生成靜態頁,而博客所使用的又是動態路由,就須要在 nuxt.config.js 中的 genarate 薦中進行配置。
以下,根據當前 posts 目錄下的 markdown 文件名來肯定該生成哪些頁面。
generate: { routes: ['404'].concat(posts.map(post => `/posts/${post.slugifiedFilename}`)), },
執行 yarn run generate
後能夠看到下面的結果,dist
目錄裏也出現了靜態文件,剩下的就只是部署了。
對於部署,配置上 Circle CI,當推關新內容上 master 分支時由 CI 進行構建並部署到本身服務器簡直不能更爽。
此外,爲了省事,還寫了幾個腳原本建立新的 markdown 文件和相應的文件夾,雖然這也不是必須的,但使用腳本顯然要比手動建立要省事得多。
Nuxt.js 確實是個好東西,寫了近三年 Vue 了纔開始盤它,確實是有點兒遲了。Nuxt 利用 SSR 等機制能很好地彌補 SPA 應用在 SEO 等方面的不足,其自帶的生成靜態站的功能也很是適合平時寫一些博客之類的應用。
感謝 Hexo 陪伴多年(雖然期間也沒用它寫出什麼東西來),但之後可能不會再用它了…… 😄