内容简介:Markdown转HTML之Node篇
前言
之前用 Python 写过类似的工具,更能上来说一般般。而且实用性不是很强。 http://blog.csdn.net/marksinoberg/article/details/51863506
然后好巧不巧又看到了一个Node上的相关模块,看起来渲染效果比我那个好多了。联想到 hexo 这款静态博客生成工具,就思量着也大致的做一下。
环境及编码
接下来简单的模拟一下相关的实现。代码比较凌乱,思维比较混乱,还望海涵(虽然主要是作为我自己的笔记,但如果对你有些许帮助,那就不枉我码了这么多字咯)。
搭建环境
所依赖的第三方模块有如下几个:
-
express
: 开启本地服务, 预览生成效果。 -
Markdown-it
: 渲染md文件为HTML内容。 -
rd
: 一个读取文件夹内容的好帮手。 -
commander
: 制作命令行 工具 的一大利器。
下面简要对这几个模块进行阐述,以及相关的使用技巧。
express
express不仅作为对connect的高层封装,更包含了一些额外的处理。所以我们可以方便的进行路由控制,这对于本次的工具而言,是个不错的选择。
// 初始化服务器 var app = express(); var router = express.Router(); app.use('/assets', server_static(path.resolve(dir, 'assets'))); app.use(router); // 渲染文章 router.get('/posts/*', function(req, res, next){ var name = stripExtname(req.params[0]); // 渲染req.params[0]对应的文章,然后展示给前台 res.end(html); }); // res.end(req.params[0]); }); // 渲染列表 router.get('/', function(req, res, next){ // 读取源文件目录, 渲染出列表内容。 res.end('list of articles.'); }); app.listen(8080);
markdown-it
相对于Python中的那些第三方库,我倒是觉得Node中与其也没甚么两样。使用起来同样很简单。
第一步,引入依赖
let markdowner = require('markdown-it');
第二步, 配置构造器
var md = new markdowner({ html: true, prefix: 'code-', });
第三步, 调用渲染方法,获取渲染后内容
var html = md.render(sourcedata||'');
如此,便是markdown-it的基础内容了,待会将在代码中更加详细的运用。
commander
用过Python的 argparser 的估计都知道,很方便的一个处理命令行参数的第三方库。不过Node中的 commander 用起来更方便。
下面简单的介绍一下使用流程。详细内容还是看人家的官网吧,如下:
https://www.npmjs.com/package/commander第一步, 安装模块
npm install commander --save
第二步,编码
/** * 一个命令行工具库。 */ let commander = require('commander'); // help 命令 commander.command('help') .description('显示工具如何使用的帮助信息') .action(function(){ commander.outputHelp(); }); // create 命令 commander.command('create [dirname]') .description('创建一个空的博客') .action(function(dirname){ console.log(dirname+' 创建完成。') }); // preview 命令 commander.command('preview [dirname]') .description('预览获取到的Markdown文件夹内容') .action(function(dirname){ console.log(' preview of %s', dirname); }); // .action(require('./cmd_preview')); // build 命令 commander.command('build [dirname]') .description('根据给定的文件夹路径生成HTML内容.') .option('-o OR --output <dirname>', '导出生成的HTML存放的路径') .action(function(dirname){ console.log('build based on %s', dirname); }); // .action(require('./cmd_build')); // 解析相关命令 commander.parse(process.argv);
第三步, 查看效果
如果想更加方便一点,直接使用命令来操作。使用
npm link
当然了,还需要设置一下对应的 package.json
文件内容。这里不过多叙述了。
rd
我这里的需求是读取 _posts 文件夹下的Markdown源文件,所以只需要 readFile 方法即可。
具体代码如下:
rd.readFile(sourcedir, function(err, files){ if(err){ console.log('读取文件夹内容失败!'); return; } // 遍历文件夹列表,对每一个文件执行渲染操作。 files.forEach(function(file){ // 做自己的逻辑处理即可。 }); });
这个模块比较简单,有兴趣的可以参考下面的作者链接。
https://github.com/leizongmin/node-rd核心编码
下面正式开始今天的主题,做一个带预览功能的Markdown文件转HTML页面的工具。
cmd_preview模块
/** * 关于预览实现相关的代码。 */ let express = require('express'); let path = require('path'); let markdowner = require('markdown-it'); let fs = require('fs'); let rd = require('rd'); var md = new markdowner({ html: true, langPrefix: 'code-', }); module.exports = function(dir) { dir = dir || '.'; // 初始化服务器 var app = express(); var router = express.Router(); app.use(router); // 渲染文章 router.get('/posts/*', function(req, res, next){ var name = stripExtname(req.params[0]); var file = path.resolve(dir, '_posts', name+'.md'); console.log('---dir--', dir); console.log('---name--', name); console.log('---file--', file); fs.readFile(file, function(err, content){ if(err){ console.log('读取文件失败!'); res.end(JSON.stringify(err)+"\n"); return next(err); } res.writeHead(200, {"Content-Type": "text/html;charset=UTF-8"}); var html = markdownTOHTML(content.toString()); console.log('读取文件成功, 解析后的内容为:\n', html); res.end(html); }); // res.end(req.params[0]); }); // 渲染列表 router.get('/', function(req, res, next){ var sourcefolder = path.resolve(dir, '_posts'); rd.readFile(sourcefolder, function(err, files){ if(err){ console.log('读取文件夹内文件失败!'); return next(err); } res.writeHead(200, {"Content-Type": "text/html;charset=UTF-8"}); var html = "<html><h1>Markdown 转 HTML 实时预览</h1><hr><br />"; files.forEach(function(filepath){ html += "<a href='/posts/"+ get_file_name(filepath) +".md' target='_blank'>"+get_file_name(filepath)+"</a><br /><br />"; }); html += "</html>"; res.end(html); }); // res.end('list of articles.'); }); app.listen(8080); }; function stripExtname(name) { var i = 0-path.extname(name).length; if(i==0) i=name.length; return name.slice(0, i); } function get_file_name(fullname){ var ls = fullname.toString().split('\\'); var filename = ls[ls.length-1].split('.'); // console.log('ls--', ls); // console.log('filename--', filename); return filename[0]; } function markdownTOHTML(content) { return md.render(content||''); }
cmd_build模块
/** * 实现Markdown文件到HTML文件的转换。 */ let markdowner = require('markdown-it'); let rd = require('rd'); let path = require('path'); let fs = require('fs'); var md = new markdowner({ html: true, langPrefix: 'code-', }) module.exports = function(dir) { dir = dir || '.'; console.log('当前文件路径为:', dir); // 读取出给定目录下的所有的文件 // 将所有Markdown文件依次转成HTML页面,并进行保存操作。 get_files_by_dir(dir); } function get_files_by_dir(dir) { // 计算出源文件的路径 var sourcedir = path.resolve(dir, '_posts'); var publicdir = path.resolve(dir, 'public'); rd.readFile(sourcedir, function(err, files){ if(err){ console.log('读取文件夹内容失败!'); return; } // 遍历文件夹列表,对每一个文件执行渲染操作。 files.forEach(function(file){ var html = md2html(file); var filename = get_filename_by_path(file); var output = path.resolve(publicdir, filename+'.html'); console.log('保存路径为:', output); save_html_content(html, output); console.log('%s.html 生成成功!', filename); }); }); } function md2html(filepath){ var content = fs.readFileSync(filepath); var html = md.render(content.toString()||''); return "<html><head><meta charset='UTF-8'><title>"+get_filename_by_path(filepath)+"</title></head>"+html+"</html>"; } function save_html_content(content, outpath){ fs.writeFile(outpath, content, function(err){ if(err){ console.log('save_html_content: 保存文件内容失败!'); return; } console.log('save_html_content: %s 保存成功!', outpath); }); } function get_filename_by_path(filepath){ var paths = filepath.toString().split('\\'); return paths[paths.length-1].split('.')[0]; }
打造命令行工具
还是用刚才的 hello.js ,现在稍微修改一下 action 里面的内容,对应我们刚才做的那两个小模块,做下修改即可。完整代码如下:
/** * 一个命令行工具库。 */ let commander = require('commander'); // help 命令 commander.command('help') .description('显示工具如何使用的帮助信息') .action(function(){ commander.outputHelp(); }); // create 命令 commander.command('create [dirname]') .description('创建一个空的博客') .action(function(dirname){ console.log(dirname+' 创建完成。') }); // preview 命令 commander.command('preview [dirname]') .description('预览获取到的Markdown文件夹内容') // .action(function(dirname){ // console.log(' preview of %s', dirname); // }); .action(require('./cmd_preview')); // build 命令 commander.command('build [dirname]') .description('根据给定的文件夹路径生成HTML内容.') .option('-o OR --output <dirname>', '导出生成的HTML存放的路径') // .action(function(dirname){ // console.log('build based on %s', dirname); // }); .action(require('./cmd_build')); // 解析相关命令 commander.parse(process.argv);
写点xx.md
巧妇难为无米之炊, 现在先在 hello.js 的同级目录下建个文件夹 _posts ,里面写点 xx.md 文件,然后建一个 public 文件夹保存生成的HTML文件。比如我的目录结构是这样的。
E:\Code\Nodejs\learn\libs-learn\commander-related>tree /f . 卷 文档 的文件夹 PATH 列表 卷序列号为 0000-4823 E:\CODE\NODEJS\LEARN\LIBS-LEARN\COMMANDER-RELATED │ cmd_build.js │ cmd_preview.js │ hello.js │ ├─public │ └─_posts helloworld.md second.md
演示
首先是预览实现,在命令行里输入以下命令:
node hello.js preview . # .代表当前目录
结果如下:
然后是针对每一篇文章生成效果的演示。
最后就是看下 build 功能的实现。
现在在命令行里面输入以下命令:
node hello.js build . # .代表当前目录
然后看下效果。
总结
大致来说功能就算是完成了,但是目前这样子是没法直接应用的。很多东西都需要润色,比如:
- 模板化HTML页面处理。
- 命令行选项的 link 实现。
- 通过监测文件内容变化实现 实时预览 。
就先到这里吧,今天又发现了两个不错的网址,然后还是先去学一波,补充补充知识吧。很多时候,不是能力不够,而是 见识不足 。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。