# road\_to\_bookdown

## road\_to\_bookdown

陳鍾誠老師的一個專案，目前性質看起來和 gitbook 有點類似，正在觀望他的發展。因為這個教學專案還滿仔細的，所以有空的時候會來複習一下

* <https://github.com/ccckmit/road_to_bookdown>
* [bookdown 書籍撰寫平台開發過程 (採用 markdown 格式） - YouTube](https://www.youtube.com/watch?v=Tf5PJIJgUro)
* [bookdown 書籍撰寫平台開發過程 (採用 markdown 格式）(完整長版） - YouTube](https://www.youtube.com/watch?v=FCDoWvjPIKA)

\[TOC]

* 01-showdown
* 02-staticServer
* 03-showdownServer
* 04-routeServer
* 05-purecss
* 06-handlebarsTemplate
* 07-templateServer
* 08-bookdown001modulized
* 09-katexMathRender
* 10-editServer

## 01-showdown

* [showdownjs/showdown: A Markdown to HTML converter written in Javascript](https://github.com/showdownjs/showdown)
* 將 markdown 轉換成 html，介紹 showdown 怎麼用
* markdown2html.js

```javascript
/**********markdown2html.js***********/
// 載入套件
var fs        = require('fs');
var showdown  = require('showdown');
var converter = new showdown.Converter();

showdown.setFlavor('github');
converter.setOption('tables', true);

var md        = fs.readFileSync("markdown.md", "utf8");
var html      = converter.makeHtml(md);
fs.writeFileSync("markdown.html", html);

/**********markdown2html.js***********/
```

## 02-staticServer

* [koajs/koa: Expressive middleware for node.js using generators](https://github.com/koajs/koa)
* 靜態伺服器，公開某個資料夾，查看目錄底下的檔案
* staticServer.js
* listening on port 3000
* localhost:3000/markdown.md

```javascript
/**********staticServer.js***********/

// 載入套件
var koa = require('koa');
var serve = require('koa-static');
var path = require('path'); // 把字串用斜線接起來
var app = koa(); // 建立一個叫 koa() 的物件

app.use(serve(path.join(__dirname, ''))); // 公開當前目錄
app.listen(3000);
console.log('listening on port 3000');

/**********staticServer.js***********/
```

## 03-showdownServer

* 顧名思義，能看 markdown、又有靜態伺服器

```javascript
/*************showdownServer.js*************/

var fs = require('mz/fs');
var showdown  = require('showdown');
var koa = require('koa');
var serve = require('koa-static');
var path = require('path');

var app = koa();
var converter = new showdown.Converter();
converter.setOption('tables', true);

function *view(next) {
    yield next;
    if (this.path.startsWith("/view/")) { // convert *.md to html
      var tpath = this.path.replace("/view/", "/user/"); // 用view看user
        var fullpath = path.join(__dirname, tpath);
        var fstat = yield fs.stat(fullpath);
        if (fstat.isFile()) {
            if (this.path.endsWith(".md")) {
                this.type = "html";
                var md = yield fs.readFile(fullpath, "utf8"); // 讀檔案
                this.body = converter.makeHtml(md); // 轉成 html        
            } else {
                this.type = path.extname(this.path);
                this.body = fs.createReadStream(fullpath);
            }
        }
    }
}

var rootpath = path.join(__dirname, '');
console.log("rootpath=%s", rootpath);
app.use(serve(rootpath)); // 靜態伺服器

app.use(view);

if (!module.parent) app.listen(3000);
console.log('listening on port 3000');

/*************showdownServer.js*************/
```

## 04-routeServer

* 看不懂

```javascript
/************routeServer.js*************/

var fs = require('mz/fs');
var showdown = require('showdown');
var koa = require('koa');
var serve = require('koa-static');
var route = require('koa-route');
var path = require('path');

function *view(book, file) { // view(mdFile):convert *.md to html
    var fullpath = path.join(__dirname, "/user/"+book+"/"+file);
    var fstat = yield fs.stat(fullpath);
    if (fstat.isFile()) {
        if (this.path.endsWith(".md")) {
            this.type = "html";
            var md = yield fs.readFile(fullpath, "utf8");
            this.body = converter.makeHtml(md);
        } else {
            this.type = path.extname(this.path);
            this.body = fs.createReadStream(fullpath);
        }
    }
}

var app = koa();
var converter = new showdown.Converter();
converter.setOption('tables', true);

app.use(serve(path.join(__dirname, '')));

app.use(route.get('/view/:book/:file', view)); // 引入 route
// :book, :file 是參數，丟給 view

if (!module.parent) app.listen(3000);
console.log('listening on port 3000');

/************routeServer.js*************/
```

## 05-purecss

* 簡單提到 ccckmit.gitbooks.io/javascript-web/content/，但有些內容已經不合時宜，像是 jQurey
* 雅虎出了 purecss
* 聽說引用這段 css，就可以使用它的語法

`<link rel="stylesheet" href="https://unpkg.com/purecss@0.6.0/build/pure-min.css">`

* BSD 授權，很寬鬆
* 專案使用了 Responsive Side Menu: <http://purecss.io/layouts/side-menu/>

## 06-handlebarsTemplate

* 樣板引擎
* 因為 Swig 樣板引擎不維護了，所以老師想換一個
* 結果找到這個:鬍子 <http://handlebarsjs.com/>
* 用處: 套樣本。例如

```markup
<!------- 樣本範例 ------->

<div class="entry">
  <h1>{{title}}</h1>
  <div class="body">
    {{body}}
  </div>
</div>

<!------- 樣本範例 ------->
```

* 範例程式

```javascript
/************ helloHandlebars.js ************/

var Handlebars = require("Handlebars");
var source = "<p>Hello, my name is {{name}}. I am from {{hometown}}. I have " +
             "{{kids.length}} kids:</p>" +
             "<ul>{{#kids}}<li>{{name}} is {{age}}</li>{{/kids}}</ul>";
var template = Handlebars.compile(source);

var data = { "name": "Alan", "hometown": "Somewhere, TX",
             "kids": [{"name": "Jimmy", "age": "12"}, {"name": "Sally", "age": "4"}]};
var result = template(data);
console.log("result=%s", result);

// Would render:
// <p>Hello, my name is Alan. I am from Somewhere, TX. I have 2 kids:</p>
// <ul>
//   <li>Jimmy is 12</li>
//   <li>Sally is 4</li>
// </ul>

/************ helloHandlebars.js ************/
```

* 確認樣本引擎正不正確的測試程式

```javascript
/**************bookHandlebars.js*************/

var fs = require("fs");
var handlebars = require("handlebars");
var showdown  = require('showdown');
var converter = new showdown.Converter();

var md = fs.readFileSync("user/markdown/markdown.md", "utf8");
var viewHtml   = fs.readFileSync("view.html", "utf8");
var viewRender = handlebars.compile(viewHtml);

var bookJson = fs.readFileSync("user/markdown/book.json", "utf8");//讀取
var book = JSON.parse(bookJson); // 轉成一個物件，被用在側邊欄
book.html = converter.makeHtml(md); // 轉成 html

var html = viewRender(book);  
fs.writeFileSync("user/markdown/markdown.html", html); // 套樣板

/**************bookHandlebars.js*************/
```

## 07-templateServer

* 套樣板
* 靜止伺服器

```javascript
/************** templateServer.js ****************/

var fs = require('mz/fs');
var showdown = require('showdown');
var handlebars = require('handlebars');
var koa = require('koa');
var serve = require('koa-static');
var route = require('koa-route');
var path = require('path');

var render = { 
  view:handlebars.compile(fs.readFileSync("view.html", "utf8")),
}

function *view(book, file) { // view(mdFile):convert *.md to html
  var bookPath = path.join(__dirname, "/user/"+book);
    var filePath = path.join(__dirname, "/user/"+book+"/"+file);
    var fstat = yield fs.stat(filePath);
    if (fstat.isFile()) {
        if (this.path.endsWith(".md")) {
            this.type = "html";
            var md = yield fs.readFile(filePath, "utf8");
            var bookJson = yield fs.readFile(bookPath+"/book.json", "utf8");
            var book = JSON.parse(bookJson);  // 建立 book 物件
            book.html = converter.makeHtml(md); // 轉換成 html
            var page = render.view(book);　// 拿去套樣板
            console.log("page=", page);
            this.body = page;
        } else {
            this.type = path.extname(this.path);
            this.body = fs.createReadStream(filePath);
        }
    }
}
/*
var md = fs.readFileSync("user/markdown/markdown.md", "utf8");
var viewHtml   = fs.readFileSync("view.html", "utf8");
var viewRender = handlebars.compile(viewHtml);
var bookJson = fs.readFileSync("user/markdown/book.json", "utf8");
var book = JSON.parse(bookJson);
book.html = converter.makeHtml(md);
var html = viewRender(book);
fs.writeFileSync("user/markdown/markdown.html", html);
*/
var app = koa();
var converter = new showdown.Converter();
converter.setOption('tables', true);

app.use(serve(path.join(__dirname, '')));

app.use(route.get('/view/:book/:file', view));


if (!module.parent) app.listen(3000);
console.log('listening on port 3000');


/************** templateServer.js ****************/
```

## 08-bookdown001modulized

* 想讓這個專案真的能發布到 github 等地方
* 因此加入 package.json。一定需要這個東西，才能發布到 npm
* server.js 好像沒什麼變，只是模組化程度更高了一點
* 好像只是在說有成功上傳的 npm 的樣子 ...

```javascript
{
  "name": "bookdown",
  "version": "0.0.1",
  "description": "Book Editing System for Markdown",
  "main": "server.js",
  "dependencies": {
    "handlebars": "^4.0.6",
    "koa": "^1.2.4",
    "koa-route": "^2.4.2",
    "koa-static": "^2.0.0",
    "mz": "^2.6.0",
    "showdown": "^1.5.1"
  },
  "devDependencies": {},
  "scripts": {},
  "bin": {},
  "keywords": [],
  "homepage": "https://github.com/ccckmit/bookdown",
  "repository": {
    "type": "git",
    "url": "http://github.com/ccckmit/bookdown.git"
  },
  "author": {
    "name": "Chung-Chen Chen",
    "email": "ccckmit@gmail.com",
    "url": "http://ccc.nqu.edu.tw"
  },
  "license": "MIT"
}
```

```javascript
/************** server.js *****************/

var fs = require('mz/fs');
var showdown = require('showdown');
var handlebars = require('handlebars');
var koa = require('koa');
var serve = require('koa-static');
var route = require('koa-route');
var path = require('path');

var userPath = path.join(__dirname, 'user');

var render = { 
  view:handlebars.compile(fs.readFileSync("render/view.html", "utf8")),
}

function *view(book, file) { // view(mdFile):convert *.md to html
  var bookPath = path.join(userPath, "/book/"+book);
    var filePath = path.join(userPath, "/book/"+book+"/"+file);
    var fstat = yield fs.stat(filePath);
    if (fstat.isFile()) {
        if (this.path.endsWith(".md")) {
            this.type = "html";
            var md = yield fs.readFile(filePath, "utf8");
            var bookJson = yield fs.readFile(bookPath+"/book.json", "utf8");
            var book = JSON.parse(bookJson);
            book.html = converter.makeHtml(md);
            var page = render.view(book);
            this.body = page;
        } else {
            this.type = path.extname(this.path);
            this.body = fs.createReadStream(filePath);
        }
    }
}

var app = koa();
var converter = new showdown.Converter();
converter.setOption('tables', true);

app.use(serve(path.join(__dirname, 'web')));
app.use(serve(userPath));

app.use(route.get('/', function*() { this.redirect('/view/markdown/README.md') }));
app.use(route.get('/view/:book/:file', view));


if (!module.parent) app.listen(3000);
console.log('listening on port 3000');

/************** server.js *****************/
```

## 09-katexMathRender

* 渲染數學式

## 10-editServer

* cmd 提示少安裝套件
* `npm install co-body --save`
* MangoDB 用的 port 27017
* http 預設 80
