1. 程式人生 > >如何快速實現 markdown 轉 HTML 文件?

如何快速實現 markdown 轉 HTML 文件?

我想要在 Github 上開一個主題部落格,我希望通過 Markdown 語法寫作,然後生成 HTML 並附帶自定義樣式顯示在網頁上。

我找到了 gulp-markdown 這個庫,看起來符合我的需求場景。然而這個庫有一個問題,他只能將 Markdown 語法書寫的文字轉換為 HTML 標籤,但並不能自動新增 doctype 文件宣告,這就意味著生成的 HTML 文件並不合法。

# 標題

我是正文。

會被編譯為

<h1>標題</h1>
<p>我是正文</p>

而不是

<!doctype html>
<html>
    <head>
        <title>XXX<title>
    </head>
    <body>
        <h1>標題</h1>
        <p>我是正文</p>
    </body>
</html>

這就很尷尬了,我不知道這個庫的作者為什麼要這麼設計這個庫,我覺得它應該有一個配置引數可以自動新增 HTML 文件宣告等資訊,於是我去查詢其文件(注意,它的文件只能FQ才能看),然而呵呵並沒有。

這就很尷尬了,怎麼辦呢?首先我想到的是,使用其他類似 HTML 模版的庫來組合實現我想要的效果,然而搜了一圈發現,並沒有合適的。因為這類庫都需要首先在 HTML 文件中使用其模版語法標記 HTML 要插入的位置,然後在宣告要插入的內容。可是我們並沒有 HTML 模版,套路不同。

所以這個思路行不通,接下來我想到的方案是:

  1. 寫一個 Gulp 外掛解決這個問題;
  2. 這個問題肯定不是我第一次遇見,我先查查別人的解決方案;

懶惰是第一生產力,我當然先選擇方案二,果不其然,全網看下來,貌似只有一個臺灣小哥想到了一個解決方案,大體的思路是使用大陸前端娛樂圈知名人士方方老師寫的一個 gulp-html-extend 庫,實現一種類模版語言的 HTML 混入。為了實現這一點,你需要在每個 Markdown 文件裡寫下模版語言語法,類似這樣:

<!-- @ @master  = ../../layout/master.html-->
<!-- @ @block  =  content-->

# 我是標題
我是正文

<!-- @ @close-->

額,很顯然這個解決方案並不優雅。為什麼我要在每次開心書寫 Markdown 的時候先寫這堆奇怪的註釋啊。我拒絕。

那麼我們又回到了最初的起點,那個殘酷的方案一又縈繞在我心頭,要寫一個 Gulp 外掛嗎?不!我的懶惰不允許我就在這裡放棄!

當你不知所措的時候,不妨回到最初的起點,思考問題的本質是什麼,這通常會激發我的靈感。這次我也這麼做了,果不其然有所收穫。

讓我們一起想想,我實際要做的無非就是把由 gulp-markdown 生成的 HTML 標籤插入到一個這樣的「殼子」裡:

<!doctype html>
<html>
    <head>
        <title>XXX<title>
    </head>
    <body>
        <!-- 在這裡插入 -->
    </body>
</html>

所以我只需要在每個生成的 HTML 檔案的頭尾插入這些字元:

<!doctype html>
<html>
    <head>
        <title>XXX<title>
    </head>
    <body>

和這些字元:

    </body>
</html>

就行了,所以問題轉變為一個檔案字串拼接的問題,我很快就找到了 gulp-header 這個庫,它能實現我們在每個檔案頭部插入字元的需求,而根據「對稱就是美」定理,當然會有一個 gulp-footer 庫來解決我們後半部分的需求,這樣我們的問題就被完美解決了!

但是,老實講這樣的方案還是不夠優雅,因為我們給檔案前後插入太多字元了,我寫程式碼習慣遵照 make it simple and stupid 的原則,因此對這個方案並不滿意,我希望只插入最少的字元解決這個問題,因此接下來的問題就是:最少能插入多少字元保障 HTML 文件的規範性?

進過一番資料的查詢,我發現,原來 <html><head><body> 標籤都是可以省略的!只要一個 HTML 文件具備 <!doctype html> 文件宣告和 <title> 標籤,對於現代瀏覽器而言,就是一個合法合規的 HTML 文件!瀏覽器會自動生成 <html><head><body> 標籤,並且把第一個不能放入 <head> 標籤的標籤和隨後的標籤都插入 <body> 標籤中。沒想到瀏覽器這麼智慧吧,我也沒想到。

現在真相大白,解決這個問題的方案就很簡單了,我們就只用在生成的 HTML 文件中新增最少的字元,這是我的 gulpfile.js 的配置:

const gulp = require('gulp')
const markdown = require('gulp-markdown')
const header = require('gulp-header')

gulp.task('default', () =>
  gulp
    .src('blog/**/*.md')
    .pipe(header('<!doctype html><title>Blog</title>\n\r'))
    .pipe(
      markdown({
        headerIds: false,
      }),
    )
    .pipe(gulp.dest('html')),
)

搞定!

總結

通過這一番調研,我找到了解決 Markdown 生成規範的 HTML 文件的一種比較優雅的解決方案,並在調研過程中學到了關於 HTML 文件必備標籤的相關知識,可謂是獲益匪淺。希望閱讀這篇文章的你也能夠有所收穫。

最後我再囉嗦兩句,可能有人會問,為什麼不搞個瀏覽器同步渲染,所見即所得,同步編輯豈不是更加炫酷,這個其實我有想過,最終決定不搞這個的理由是我覺得既然使用了 Markdown 語法,我的目的就是專心寫作,我並不想因為要看到樣式而分心,因此我在編輯器中只管我要寫什麼,當我寫好 CSS 後,我就對內容如何呈現已經心中有數了,因此我認為「所見即所得」的功能沒什麼用。當然,如果你還是想要新增,相信對你而言也不是什麼難事,畢竟方法之前的那位臺灣小哥已經給出了。