我寫書都是采用markdown格式,所以在這里我介紹幾款md相關(guān)的寫書系統(tǒng)。
寫書的工具有很多gitbook,mkdocs等。
gitbook,是github推出的,目前已經(jīng)不更新了,安裝使用都會遇到一些版本兼容的bug。所以導(dǎo)致我無法使用。gitbook采用的編程語言是JavaScript。
mkdocs ,目前維護(hù)的非常好。material主題也很漂亮,采用Python語言編寫。showdoc
showdoc 是php語言編寫,
目前支持在線直接書寫,免費(fèi)版本有些限制。畢竟他們也是團(tuán)隊(duì)在開發(fā)。也需要支付服務(wù)器成本。所以收費(fèi)也是必然的。
我沒有試過收費(fèi)版本。也無法評價(jià)。mrdoc
mrdoc 采用python編寫,比較符合我的需求。開源可以安裝使用。
并且支持在線寫文檔。也有開源版本和專業(yè)版。mindoc
是一款基于go語言編寫的在線文檔系統(tǒng)。MinDoc 的前身是 SmartWiki 文檔系統(tǒng)。SmartWiki 是基于 PHP 框架 laravel 開發(fā)的一款文檔管理系統(tǒng)。
如果要使用在線的系統(tǒng),上面的都可以考慮。
自己打造一個(gè),不是為了和他們競爭,是為了自己使用。
我寫了幾本書都是采用的mkdocs。非常喜歡使用mkdocs。
但是出現(xiàn)了一個(gè)問題,就是插入圖片操作不方便。所以我想借助一個(gè)現(xiàn)成的在線系統(tǒng)去完成。
因?yàn)槲医?jīng)常使用strapi來做網(wǎng)站系統(tǒng)。strapi后臺功能非常強(qiáng)大,并且支持markdown編寫。所以我想讓他們結(jié)合起來。
mkdocs是python,strapi是nodejs(javascript)。所以估計(jì)很多人也不愿意折騰。
不過在這里mkdocs僅僅需要安裝即可,安裝命令也簡單
pip install mkdocs
strapi改造支持mkdocs需要2個(gè)步驟
- 創(chuàng)建一個(gè)表 支持 mkdocs.yml (ebook)
- 創(chuàng)建一個(gè)表支持mk文件 (file_md)


這就創(chuàng)建一條記錄可以把mkdocs.yml 放到ebook表里面
再創(chuàng)建多條記錄 *.md 房主 file_md表里
數(shù)據(jù)的表如何變成mkdocs需要的文件呢?
我寫了一個(gè)解釋代碼
const fetch = require('node-fetch');
const YAML = require('yaml');
const fs = require('fs')
const path = require('path')
var exec = require("child_process").exec;
var host = "http://127.0.0.1:1337"
//var host = "http://119.91.153.63:1337"
// bookid
var bookid = 1
var filelist = []
// AIDocs/ oWriter/src/api/ebook/controllers
var father = path.resolve(__dirname,'../../../../')
var bookpath = path.resolve(father,'../tmp')
var bookdocpath = path.resolve(bookpath,'docs')
function parse_nav(n){
var val = Object.values(n)[0]
// filename
if(typeof val === 'string'){
console.log(val)
filelist.push(val)
} else{
//二級子目錄,需要再次循環(huán)
val.forEach(function(item){
parse_nav(item)
})
}
}
async function make_filecontent(filename){
const file_parse = path.parse(filename)
const res = await fetch(host+"/api/file-mds?filters[filename][$eq]="+filename+"&filters[ebook][id][$eq]="+bookid)
const datas = await res.json()
if (datas.meta.pagination.total == 0) return
let content = datas.data[0].attributes.content
//console.log(file_parse.dir,file_parse.base)
let filepath = path.resolve(bookdocpath,file_parse.dir)
console.log(filepath)
//如果目錄不存在創(chuàng)建目錄,支持創(chuàng)建多級目錄
if (!fs.existsSync(filepath)) fs.mkdirSync(filepath,{ recursive: true });
fs.writeFileSync(path.resolve(filepath,file_parse.base),content,{flag:"w+"})
return
}
async function bookupdate(ctx){
// 讀取書的信息
const res = await fetch(host+"/api/ebooks")
var datas = await res.json()
var objdata = ""
for (var i = 0; i < datas.data.length;i++){
var data = datas.data[i]
if(data.id == bookid){
objdata = data
break
}
}
if (objdata == "") return
var buffer = objdata.attributes.yml
var name = objdata.attributes.name
var folder = objdata.attributes.folder
let config = YAML.parse(buffer);
var nav = config['nav']
if (folder != ""){
bookpath = path.resolve(father,'../'+folder)
bookdocpath = path.resolve(bookpath,'docs')
}
//創(chuàng)建mkdocs 項(xiàng)目配置文件
if (!fs.existsSync(bookpath)) fs.mkdirSync(bookpath,{ recursive: true });
fs.writeFileSync(path.resolve(bookpath,'mkdocs.yml'),buffer,{flag:"w+"})
nav.forEach(function(item){
parse_nav(item)
})
//創(chuàng)建所有的markdown 文件
console.log("---------------------------")
filelist.forEach(async function(item){
await make_filecontent(item)
})
exec("cd "+ bookpath +";mkdocs build",function(err,stdout,stderr){
if(err){
console.error(err);
}
console.log("stdout:",stdout)
console.log("stderr:",stderr);
});
}
strapi 編輯預(yù)覽界面
