用Gulp实现模块化文档编写
最近在研究Backbone.js
和Underscore.js
,也基于此编写了一下脚手架,需要写一个技术说明文档,风格当然也要类似咯。
首先提炼一下需求
- 模块化编写文档,每个小节都是一个单独的Markdown文件,便于修改维护
- 使用gulp进行打包编译,生成一个完整的HTML文件(单页面模式),便于分享转发
- 最终的展示效果和上图类似,即有导航栏和正文,字体风格就直接照搬
需求完成了,接下了就是实现了。首先就是设计目录结构,和标准的gulp项目类似,我的目录结构如下所示。
目录结构其中build和dist目录分别用于存放编译的中间文件和最终的输出文件,src目录下存放的是文档模块。
打包过程分为四个步骤
第一步 合并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'));
});
这步的作用是根据预约定义好的模版生成完整的md文件。
这里需要说明的是由于文档模块的编排需要手工设置顺序,因此采用模版手工填写各个模块的方式,虽然有点麻烦,但可控性比较好,而且所有相关的模块信息只出现在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文件为两个部分:导航栏/正文
这里用到了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分开,以便后续采用不同的方式进行render,并且合并到最终HTML模版到不同位置去。这里同样需要在template.md
文件中指定切分的位置。
/*splitfilename=toc.md*/
...TOC...
/*split*/
/*splitfilename=body.md*/
...BODY...
第三步 将md文件转换为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//保留文件的缩进
}))
.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");
现在可以执行gulp
来进行自动化打包编译了,最终效果如下
是不是学得很像啊:)
最后给一个github的地址,本文的示例代码在http://github.com/SagittariusZhu/gulp-docwrite-scaffold
可以找到。