วันพุธ, มิถุนายน 24, 2558

สร้าง Technical Document แบบ minimal ด้วย markdown และ gulp.js

TL;DR

มี project java web application ตัวหนึ่ง ที่กำลังจะเอาออกไปใช้งาน มันยังขาดงานเอกสารอยู่ โดยเฉพาะ Technical document ซึ่งจะต้องให้ implementor
ใช้เวลาเค้าเอา software ไป build หรือไปติดตั้ง

ทีแรกก็เขียนเป็น README ธรรมดาๆ แต่หลังจากถูกเอาไป implement มาครั้งหนึ่งแล้ว
ก็พบว่าเอกสาร README มันไม่สมบูณณ์เอาซะเลย

โจทย์ของ Technical document ของตัวผมเองก็คือ

  1. ต้อง minimal ดูเรียบง่าย
  2. ไม่ต้องเสียเวลาทำมาก
  3. มีสารบัญด้วย (Table Of Contents)
  4. ถ้าได้ใช้ markdown ด้วยยิ่งดี

ลอง google ดูก็เจอ

  • mkDocs แต่มันใช้ python ซึ่งทำให้คนที่เอาไปใช้ต้องไปติดตั้ง python อีก ถ้าเป็น Window ก็งานงอก

project นี้ใช้ javascript อยู่แล้วเลยมองๆตัวที่ใช้ javascript ได้เลยมาเจอ

  • Hexojs เป็น static site generator ลองเอามาเล่นแล้ว ก็ติดขัดที่ว่า theme ที่มีมันไม่ถูกใจ และมันออกแบบมาให้ทำเป็น blogging framework มากกว่า
  • ยังมีตัวอื่นๆ ที่น่าสนใจอีกเยอะเลยพวก site generator เช่น

แต่ว่ามันขัดกับโจทย์ที่ตั้งเอาไว้ เสียเวลา วันนี้คงไม่จบ

มาลงตัวที่ solution นี้ project นี้ใช้ javascript อย่างที่บอก และมีการใช้ npm อยู่แล้ว อย่ากระนั้นเลย ลองหา node module มาช่วยแปลง markdown file ให้เป็น html ซึ่งจะเป็นเอกสารที่เปิดอ่านผ่าน browser ได้

ขั้นตอนที่ใช้/Solution

ผมสร้างไฟล์ README.md เอาไว้ที่ root folder ของ project (ก็เหมือน open sources ที่เห็นได้ตาม github นี่แหละ)

เปิด markdown reference ไปด้วย เพราะยังไม่คล่องเท่าไหร่
- ต้นตำรับ Darling fireball
- ยอดนิยม github flavored markdown (GFM)

ใช้ editor เป็น Sublime text ลง plugin 2 ตัวนี้
- Markdown Editing
- Markdown Preview

วิธีทำสารบัญ ก็คือใช้ anchor link เช่น

...  
### Table of contents

- [Overview](#overview)
- [Pre-requesite](#what-well-need)
- [How to Build](#how-to-build)  
...  
### Overview
...  

ตัว #overview จะทำให้ Overview กลายเป็น tag <a> ที่ link ไปหา anchor tag ที่อยู่ในเอกสารเดียวกัน ซึ่งก็คือ Overview ที่อยู่ด้านล่าง

header ทั้งหลายในเอกสารที่เรากำหนดเอาไว้ เมื่อ preview แปลง markdown เป็น html แล้วมันจะทำให้มี anchor tag ควบคู่ไปด้วยได้ เช่น จาก markdown ด้านบนเมื่อ generate แล้วจะได้แบบนี้

...  
<h3 id="table-of-contents">Table of contents</h3>
<ul>
<li><a href="#overview">Overview</a></li>
<li><a href="#what-well-need">Pre-requesite</a></li>
<li><a href="#how-to-build">How to Build</a>
...  
<h3 id="overview">Overview</h3>
... 

ผมเขียนๆไป ก็ทดสอบโดยใช้ Markdown Preview ใน Sublime Text ดูว่า link แล้วไปถูกหัวข้อหรือเปล่า หรือว่า เมื่อ generate เป็น html แล้วจะได้ anchor ชื่ออะไร สังเกตได้ว่ามันจะเอา - มาแทน space symbol อื่นๆ หรือภาษาไทยตัดทิ้งหมด

เมื่อเขียน Technical Document ครบตามหัวข้อที่ตั้งใจแล้ว ก็มานึกต่อว่าจะ generate เป็น html อย่างไรดี จะให้มาเปิด Sublime Text หรือเปิด website ที่รับ convert markdown online ก็ยุ่งยาก เสียเวลา

เมื่อเราใช้ javascript อยู่แล้ว และก็ใช้ node กับ gulp.js ช่วยทำงาน automate หลายอย่างอยู่แล้ว จึงมาหาวิธีแปลง markdown text ให้เป็น html ด้วยซะเลย

นั่งไล่ลองอยู่นานมาถูกใจตัวนี้ markdown-it เค้ารองรับ commonmarkdown ด้วย ทันสมัยมาก แต่เมื่อเราจะเอามาใช้กับ gulp จึงต้องใช้ module gulp-markdown-it

เราใช้ตอน build เท่านั้น อย่าลืมใส่ --save-dev ด้วย

$ npm install --save-dev gulp-markdown-it

วิธีใช้ตาม github ก็คือ ใส่ code แบบนี้ลงใน gulpfile.js. ไฟล์ README.md ผมอยู่ข้างๆ gulpfile.js อยู่แล้วจึงใส่แบบนี้

var gulp = require('gulp');
var md = require('gulp-markdown-it');

gulp.task('gen-docs', function () {
    gulp.src('README.md')
        .pipe(md())
        .pipe(gulp.dest("."));
});

เค้าจะสร้างไฟล์ readme.html ออกมาให้เลย

แต่มันยังไม่ใช่ ไม่ถูกใจ! syntax มันไม่ highlight, code block ก็ดูไม่แตกต่างจากเนื้อหาเลย เอ๊ นี่เราทำอะไรผิด พอเปิด source code ถึงได้รู้ว่า เค้า generate html ที่ไม่ใช่ไฟล์สมบูรณ์ เนื้อหาได้ประมาณนี้

<h1>Technical Documentation</h1>
<p>If you're open the README.md you can execute <code>$ mvn generate-resource -N</code> to view this document in HTML (readme.htm).</p>
<h3>Table of contents</h3>
<ul>
<li><a href="#overview">Overview</a></li>
<li><a href="#what-well-need">Pre-requesite</a></li>
<li><a href="#how-to-build">How to Build</a>
...  
<h3>Overview</h3>
...    

  • ไม่มี tag <html> <body>
  • ไม่มี stylesheet ที่ทำให้ดูสวยแบบใน github (ไม่เหมือนเวลา preview จาก Sublime เลย)
  • ไม่มี anchor tag
  • อ่าว.. :-(

งั้นเราจะต้องสร้าง html ส่วนที่เหลือเอง แล้วเอา content ส่วนนี้มาใส่เข้าไปสิ่นะ
อยากให้มี syntax highlight เพราะมีคำสั่ง และตัวอย่าง code ในเอกสารด้วย เราจะต้องใช้

เมื่อ download ไฟล์จาก link ข้างบนมาแล้ว extract zip ผมจับมันใส่ folder site จะมีหน้าตาแบบนี้ ส่วน github-markdown.css ที่โหลดมาได้ก็เอาไปไว้ใน styles ของ highlight ด้วย

+-- README.md
+-- gulpfile.js
|
+-- site 
    +-- readme.htm 
    +-- highlight
       +-- highlight.pack.js
       +-- styles
           +-- github-markdown.css
           +-- default.css 


ไฟล์ css อื่นๆ ใน styles ลบทิ้งหมด เหลือเอาไว้แต่ตัวที่ชอบ ซึ่งคือ default.css

มาลงเอยด้วย gulpfile.js แบบนี้

var gulp = require('gulp');
var mdit = require('gulp-markdown-it');
var inject = require('gulp-inject');

gulp.task('gen-docs', function() {
    var content = gulp.src('README.md')
        .pipe(mdit({
            preset: 'commonmark',
            options: {
                html: false,
                xhtmlOut: true,
                breaks: true,
                typographer: true,
                langPrefix: 'hljs-'
            },
            plugins: ['markdown-it-highlightjs', 'markdown-it-anchor']
        }));
    return gulp.src('site/readme.htm')
        .pipe(inject(content, {
            transform: function(filePath, file) {
                return file.contents.toString('utf8')
            }
        }))
        .pipe(gulp.dest('.'));
});

อธิบาย code ข้างบน

gulp-markdown-it ระบุ option ให้

  • generate html ตาม standard xhtml
  • ให้ใส่ tag <br/> เป็นตัวขึ้นบรรทัดแทน \n
  • หากมี markdown code block ที่ระบุภาษาให้ใส่ prefix hljs-

gulp-markdown-it ใช้ plugin markdown-it-highlightjs เพื่อให้มัน generate html ที่พร้อมให้ hilightjs เรียกใช้ ใส่ class ที่ tag code เพื่อพร้อมแสดงผลด้วย highlightjs

gulp-markdown-it ใช้ plugin markdown-it-anchor เพื่อให้มัน generate html พร้อม anchor ที่ tag <h?> ออกมาด้วย

gulp-inject เป็นตัวช่วยเอา content จากไฟล์หนึ่งไปใส่ยังไฟล์ที่เราทำเป็น template (site/readmd.htm) รอเอาไว้ได้ ในที่นี้คือเอา content ที่ markdown-it แปลงออกมาเป็น html เอาไปใส่ใน placeholder ที่ กำหนดไว้ด้วย inject:html

ตัวอย่างไฟล์ site/readme.htm

<html>
<head>
<link rel="stylesheet" href="site/highlight/styles/default.css">
<link rel="stylesheet" href="site/highlight/styles/github-markdown.css">
<style>
.markdown-body {min-width:200px;max-width:790px;
    margin:0 auto;padding: 30px;overflow: visible}
</style>
</head>
<body class="markdown-body">
<!-- inject:html -->
<!-- endinject -->
</body>
<script src="site/highlight/highlight.pack.js"></script>
<script>
  hljs.initHighlightingOnLoad();
</script>
</html>

style .markdown-body ผมแก้ไขไม่เหมือนกับที่บอกไว้ใน github ของคนทำนิดหน่อย คือผมใส่ overflow: visible เข้าไปด้วย

เมื่อรัน gulp gen-docs task แล้ว html ผลลัทธ์จะออกมาแบบนี้

<html>
<head>
<link rel="stylesheet" href="site/highlight/styles/default.css">
<link rel="stylesheet" href="site/highlight/styles/github-markdown.css">
<style>
.markdown-body {min-width:200px;max-width:790px;
    margin:0 auto;padding: 30px;overflow: visible}
</style>
</head>
<body class="markdown-body">
<!-- inject:html -->
<h1 id="technical-documentation">Technical Documentation</h1>
<p>If you're open the README.md you can execute <code>$ mvn generate-resource -N</code> to view this document in HTML (readme.htm).</p>
<h3 id="table-of-contents">Table of contents</h3>
<ul>
<li><a href="#overview">Overview</a></li>
<li><a href="#what-well-need">Pre-requesite</a></li>
<li><a href="#how-to-build">How to Build</a>
...
<h3 id="what-well-need">What we'll need</h3>
<ul>
<li>JDK 1.7 หรือใหม่กว่านั้น</li>
<li>Maven 3.1 หรือใหม่กว่านั้น</li>
</ul>
<h3 id="how-to-build">How to build</h3>
... 

เมื่อเปิด readme.htm ที่ถูก generate ขึ้น มาดูใน browser ก็สวยงามถูกใจแล้ว ตอนแก้ปัญหาก็ใช้เวลานานหน่อย เกือบวันนึง ตอนนี้ก็มีสูตรสำเร็จแล้ว ครั้งต่อไปก็จะเร็วขึ้นมากแล้วล่ะครับ

Happy Coding ^^

ไม่มีความคิดเห็น :