用Gulp實(shí)現(xiàn)模塊化文檔編寫(xiě)

最近在研究Backbone.jsUnderscore.js,也基于此編寫(xiě)了一下腳手架,需要寫(xiě)一個(gè)技術(shù)說(shuō)明文檔,風(fēng)格當(dāng)然也要類(lèi)似咯。

backbone.js

首先提煉一下需求

  1. 模塊化編寫(xiě)文檔,每個(gè)小節(jié)都是一個(gè)單獨(dú)的Markdown文件,便于修改維護(hù)
  2. 使用gulp進(jìn)行打包編譯,生成一個(gè)完整的HTML文件(單頁(yè)面模式),便于分享轉(zhuǎn)發(fā)
  3. 最終的展示效果和上圖類(lèi)似,即有導(dǎo)航欄和正文,字體風(fēng)格就直接照搬

需求完成了,接下了就是實(shí)現(xiàn)了。首先就是設(shè)計(jì)目錄結(jié)構(gòu),和標(biāo)準(zhǔn)的gulp項(xiàng)目類(lèi)似,我的目錄結(jié)構(gòu)如下所示。

目錄結(jié)構(gòu)

其中build和dist目錄分別用于存放編譯的中間文件和最終的輸出文件,src目錄下存放的是文檔模塊。

打包過(guò)程分為四個(gè)步驟

第一步 合并md文件,并生成TOC

這里用到了gitdown插件,具體代碼如下

// build whole markdown file
gulp.task('gitdown', function() {
    return Gitdown
        .readFile(abs(src_path + 'template.md'))
        .writeFile(abs(build_path + 'all.md'));
});

這步的作用是根據(jù)預(yù)約定義好的模版生成完整的md文件。
這里需要說(shuō)明的是由于文檔模塊的編排需要手工設(shè)置順序,因此采用模版手工填寫(xiě)各個(gè)模塊的方式,雖然有點(diǎn)麻煩,但可控性比較好,而且所有相關(guān)的模塊信息只出現(xiàn)在template.md文件中,因此也算合理。

模版的TOC部分

[Getting Started](#getting-started)
{"gitdown": "contents", "maxDepth": 2, "rootId": "getting-started"}
[Events](#events)
{"gitdown": "contents", "maxDepth": 2, "rootId": "events"}

模版的Body部分

# Getting Started
{"gitdown": "include", "file": "./model/01Getting-started/first.md"}
{"gitdown": "include", "file": "./model/01Getting-started/second.md"}

# Events
{"gitdown": "include", "file": "./model/02Events/click.md"}

第二步 分割md文件為兩個(gè)部分:導(dǎo)航欄/正文
這里用到了gulp-split-files插件,具體代碼如下

// split whole markdown file into TOC and BODY
gulp.task("split", ['gitdown'], function () {
    return gulp.src(build_path + "all.md")
                .pipe(splitFiles())
                .pipe(gulp.dest(build_path));
});

這步的作用很明顯,就是為了將TOC和Body分開(kāi),以便后續(xù)采用不同的方式進(jìn)行render,并且合并到最終HTML模版到不同位置去。這里同樣需要在template.md文件中指定切分的位置。

/*splitfilename=toc.md*/
...TOC...

/*split*/
/*splitfilename=body.md*/
...BODY...

第三步 將md文件轉(zhuǎn)換為HTML
這步用到的插件是gulp-markdown

TOC的Render

// TOC renderer
var renderer = new markdown.marked.Renderer();
renderer.list = function(body, ordered, start) {
  var type = ordered ? 'ol' : 'ul',
      startatt = (ordered && start !== 1) ? (' start="' + start + '"') : '';
  var sectionstart = '<div class="searchable_section">\n';
  var sectionend = '</div>\n';
  return sectionstart + '<' + type + startatt + ' class="toc_section">\n' + body + '</' + type + '>\n' + sectionend;
};

renderer.listitem = function (text) {
    return '<li>- ' + text + '</li>\n';
};

gulp.task('md2html:toc', ['split'], function() {
    return gulp.src(build_path + 'toc.md')
        .pipe(markdown({
            renderer: renderer
        }))
        .pipe(rename({ extname: '.html' }))
        // .pipe(concat('markdown.html'))
        .pipe(gulp.dest(build_path));
});

Body的Render

// Body render
gulp.task('md2html:body', ['split'], function() {
    return gulp.src(build_path + 'body.md')
        .pipe(markdown())
        .pipe(rename({ extname: '.html' }))
    .pipe(gulp.dest(build_path));
});

第四步 合并成最終的HTML
這里用的插件是gulp-file-include,模版文件為src/index.html。

// Merge split html into single one
gulp.task('mergeHtml', ['md2html:toc', 'md2html:body'], function() {
    return gulp.src(src_path + 'index.html')//主文件
        .pipe(fileInclude({
            prefix: '@@',//變量前綴 @@include
            basepath: './src/include',//引用文件路徑
            indent: true//保留文件的縮進(jìn)
        }))
        .pipe(gulp.dest(dist_path));//輸出文件路徑
});

index.html

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="chrome=1" />
  <meta name="viewport" content="width=device-width">
  <title>AWF</title>
  @@include('./css.html')
</head>
  <body>
      <div id="sidebar" class="interface">
          <a class="toc_title" href="#">
            AWF <span class="version">(2.1.0)</span>
          </a>
          @@include('../../build/toc.html')
      </div>
      <div class="container">
          @@include('../../build/body.html')
      </div>
  </body>
</html>

回顧一下用到的插件

const gulp = require('gulp');
const abs = require("abs");
const rename = require('gulp-rename');
const markdown = require('gulp-markdown');
const fileInclude = require('gulp-file-include');
const Gitdown = require('gitdown');
const splitFiles = require("gulp-split-files");

現(xiàn)在可以執(zhí)行gulp來(lái)進(jìn)行自動(dòng)化打包編譯了,最終效果如下

效果圖

是不是學(xué)得很像啊:)

最后給一個(gè)github的地址,本文的示例代碼在http://github.com/SagittariusZhu/gulp-docwrite-scaffold可以找到。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容