如何通过markdown生成一个在线的电子书

前情提要
不知道大家有没有这样的时刻.
- 无聊时拿出手机, 想看书发现手机里现在没有在另一台设备里的书, 因此开始看短视频.
- 自己写了一些关联的内容, 想归类成册, 却不知怎么办, 只能让它们杂乱的存放在笔记软件中.
- 互联网上收集的内容, 觉得可以归类成册.
- 心中有个小小的梦想, 出版一本书.
- TBD: 更多时刻
如果你有这样的时刻, 我觉得下面的内容你就值得观看, 因为我将在后面介绍如何快速将已有的内容发布成一本在线电子书的教程.
工具准备
- npm: nodejs的包管理软件,用来安装docsify
- docsify: 本文的主角, 用这个软件就可以使用markdown文件生成电子书
- 一个文本编辑器, vscode或者其他的
物料准备
- 一张好看的封面图, 可以自己设计, 也可以网上搜索
- 自己写好的内容,或者收集的内容
实际操作
安装相关软件
先安装nodejs, 就会自动安装npm了, 参看nodejs官网的安装流程
使用各个系统的命令行软件安装docsify
# 全局安装docsify, 这样在任何地方都可以使用这个命令行工具了
npm i docsify-cli -g
安装文本编辑器, 这里不再赘述
初始化项目
创建一个新的目录, 比如就叫how-to-get-rich
在命令行中切换到这个目录, 执行初始化操作
docsify init
这时候目录下就会出现以下文件或者文件夹
- .nojekyll: 防止 GitHub Pages 忽略以下划线开头的文件
- index.html: 入口文件
- README.md : 首页内容在这编辑
这个时候,我们就可以测试运行下, 能不能跑起来了.
docsify serve
如果运行后显示了,Listening at http://localhost:3000, 那说明成功了, 复制这个网址在浏览器打开, 就能看见效果了
导入物料
这里的物料指的就是图片, 文字内容等, 我这里使用的是Notion, 因此我从Notion中导出相关的markdown文件,放到目录中
README.md中,编写介绍文字
index.html中可以配置的就比较多了.下面示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>How to get rich</title>
<link rel="icon" href="assets/images/swe_at_google.2.cover.jpg">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<meta name="description" content="Description">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css">
<!-- gitalk -->
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/gitalk/dist/gitalk.css">
</head>
<body>
<div id="app"></div>
<script>
window.$docsify = {
name: '如何致富' +
'',
repo: 'jimersylee/how-to-get-rich',
auto2top: true,
// 侧边栏
loadSidebar: true,
alias: {
'/.*/_sidebar.md': '/_sidebar.md'
},
subMaxLevel: 3,
// 自动为每个页面增加标题
// autoHeader: true,
// 封面
coverpage: true,
// 搜索支持
search: {
maxAge: 86400000, // 过期时间,单位毫秒,默认一天
paths: 'auto', // or 'auto'
// 支持本地化
placeholder: {
'/zh-cn/': '搜索',
'/': 'Type to search'
},
// 支持本地化
noData: {
'/zh-cn/': '找不到结果',
'/': 'No Results'
},
// 避免搜索索引冲突
// 同一域下的多个网站之间
namespace: 'how-to-get-rich',
// 使用不同的索引作为路径前缀(namespaces)
// 注意:仅适用于 paths: 'auto' 模式
//
// 初始化索引时,我们从侧边栏查找第一个路径
// 如果它与列表中的前缀匹配,我们将切换到相应的索引
pathNamespaces: ['/zh-cn'],
},
plugins: [
function (hook, vm) {
hook.beforeEach(function (html) {
if (/githubusercontent\.com/.test(vm.route.file)) {
url = vm.route.file
.replace('raw.githubusercontent.com', 'github.com')
.replace(/\/master/, '/blob/master');
} else if (/jsdelivr\.net/.test(vm.route.file)) {
url = vm.route.file
.replace('cdn.jsdelivr.net/gh', 'github.com')
.replace('@master', '/blob/master');
} else {
url =
'https://github.com/jimersylee/how-to-get-rich/blob/main/' +
vm.route.file;
}
var editHtml = '[:memo: Edit Document](' + url + ')\n';
return (
editHtml +
html
);
})
},
function (i) {
// 加载 Gitalk 元素
var e = Docsify.dom;
i.mounted(function (i) {
var n = e.create("div");
n.id = "gitalk-container";
var t = e.getNode("#main");
n.style = "width: " + t.clientWidth + "px; margin: 0 auto 20px;", e.appendTo(e.find(".content"), n)
}), i.doneEach(function (i) {
for (var n = document.getElementById("gitalk-container"); n.hasChildNodes();) n.removeChild(n.firstChild);
})
},
function (hook, vm) {
hook.doneEach(function () {
// remove gitalk-container
document.getElementById('gitalk-container').innerHTML = "";
// 渲染
NewGitalk().render('gitalk-container');
})
}
],
}
</script>
<!-- Docsify v4 -->
<script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
<script src="//cdn.jsdelivr.net/npm/docsify@4/lib/plugins/search.min.js"></script>
<!-- Pagination -->
<script src="//cdn.jsdelivr.net/npm/docsify-pagination/dist/docsify-pagination.min.js"></script>
<!-- gitalk -->
<script src="//cdn.jsdelivr.net/npm/gitalk/dist/gitalk.min.js"></script>
<!-- Medium's 风格的图片缩放插件 -->
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/zoom-image.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/crypto-js@4.1.1/crypto-js.js"></script>
<script>
function NewGitalk() {
// 除去param
const hashPath = location.hash.indexOf("?id=") === -1 ? location.hash : location.hash.substring(0, location.hash.indexOf("?id="));
const hrefPath = location.hash.indexOf("?id=") === -1 ? location.href : location.href.substring(0, location.href.indexOf("?id="));
// id 50字符限制
const md5Id = CryptoJS.MD5(hashPath).toString();
return new Gitalk({
clientID: '860d2cfa5e15a4d8e3f7',
clientSecret: '21e564b7c5a24170fca8385d2d73a620d7db1fde',
repo: 'how-to-get-rich',
owner: 'jimersylee',
admin: ['jimersylee'],
id: md5Id,
body: hrefPath,
distractionFreeMode: false
});
}
</script>
</body>
</html>
_coverpage.md 中设置书的封面,关于封面,准备写一篇新的文章介绍快速生成封面

# How to get rich <small>中文版</small>
> 经历教会我的那些课
[GitHub](https://github.com/jimersylee/how-to-get-rich)
[Get Started](#How-to-get-rich)
_sidebar.md中设置目录
- [**追求财富,而非金钱或身份《如何致富》译文连载1**](docs/追求财富,而非金钱或身份《如何致富》译文连载1%20f5e775df2a6f4f8fa29da6f1cb0b4c35.md)
等等
部署发布
虽然本地可以预览了,但是最终还是希望线上可看,因此,我们会使用到github.
创建一个仓库,名字就叫how-to-get-rich,然后把目录下所有文件加入版本管理,push到这个仓库中.
在这个仓库的Settings中找到Pages,Branch选项中选择代码所在的分支,然后等待自动部署.几分钟后,就会出现一个网址,就可以在线访问了.
总结
我使用这个方式, 构建了2本在线电子书, 分别是«数字时代的效率手册», «如何致富». 开源, 随时更新, 允许自由评论, 感觉很棒, 你们也可以试试.