使用commander模块来编写一个命令行工具。
4.1 本章所使用到的第三方模块
1、commander:解析命令行参数
2、Express:Web框架
3、serve-static:静态文件服务中间件
4、markdown-it:渲染Markdown格式的文档
5、swig:swig语法模板引擎
6、rd:遍历目录下的所有文件,包括子目录
7、fs-extra:扩展了fs模块的一些方法
8、open:使用系统程序打开指定文件或网址
9、moment:解析、格式化日期时间
4.2 命令格式
定义命令的使用方法,比如:
$ myblog create表示创建一个空的博客;
$ myblog build表示生成整站静态HTML页面等。
常见的命令格式:
定义静态博客命令格式:
- 创建一个空的博客;
- 文章使用Markdown格式编写
- 本地实时预览
- 生成整站静态HTML
4.3 编写命令行工具
通过process.argv变量来取得当前程序启动时的参数,它是一个数组
首先创建一个空的项目文件夹,在通过npm init来初始化package.json文件:
$ mkdir myblog
$ cd myblog
$ npm init
接下来安装commander模块
$ npm install commander --save
创建bin/myblog
#!/usr/bin/env node
var program = require('commander');
//命令版本号
program.version('0.0.1');
//help命令
program
.command('help')
.description('显示使用帮助')
.action(function () {
program.outputHelp();
});
//create命令
program
.command('create [dir]')
.description('创建一个空的博客')
.action(function (dir) {
console.log('create %s', dir);
});
//preview命令
program
.command('preview [dir]')
.description('实时预览')
.action(function (dir) {
console.log('preview %s', dir);
});
//build命令
program
.command('build [dir]')
.description('生成整站静态HTML')
.option('-o, --output <dir>', '生成的静态HTML存放目录')
.action(function (dir, options) {
console.log('create %s, output %s', dir, options.output);
});
//开始解析命令
program.parse(process.argv);
在编辑文件package.json,增加bin属性,用来指定当前模块需要链接的命令,指定了myblog命令是执行文件./bin/myblog。
{
"name": "myblog",
"version": "1.0.0",
"description": "blog",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"bin": {
"myblog" : "./bin/myblog"
},
"dependencies": {
"commander": "^2.13.0"
}
}
为了让这个设置生效,需要执行
$ sudo npm link
执行以下命令
$ myblog help
4.4 实时预览
一个静态博客工具包含以下这些功能模块:
- 渲染文章内容页面和文章列表页面;
- 修改模板实时预览;
- 创建基本的博客模板;
启动Web服务器:
//preview命令
program
.command('preview [dir]')
.description('实时预览')
.action(require('../lib/cmd_preview'));
cmd_preview.js
var express = require('express');
var serveStatic = require('serve-static');
var path = require('path');
module.exports = function (dir) {
dir = dir || '.';
//初始化Express
var app = express();
var router = express.Router();
app.use('/assets', serveStatic(path.resolve(dir, 'assets')));
app.use(router);
//渲染文章
router.get('/posts/*', function (req, res, next) {
res.end(req.params[0]);
});
//渲染列表
router.get('/', function (req, res, next) {
res.end('文章列表');
});
app.listen(3000);
};
$ npm install express serve-static --save
$ myblog preview
打开http://127.0.0.1/3000/
渲染文章页面
使用markdown-it模块来解析并将其转为相应的HTML。模板引擎选用swig,其语法看起来比ejs更优雅,可读性会强很多。
文章源文件存储在_post目录下。
lib/cmd_preview.js
var express = require('express');
var serveStatic = require('serve-static');
var path = require('path');
var fs = require('fs');
var MarkdownIt = require('markdown-it');
var md = new MarkdownIt({
html : true,
langPrefix : 'code-',
});
module.exports = function (dir) {
dir = dir || '.';
//初始化Express
var app = express();
var router = express.Router();
app.use('/assets', serveStatic(path.resolve(dir, 'assets')));
app.use(router);
//渲染文章
router.get('/posts/*', function (req, res, next) {
var name = stripExtname(req.params[0]);
var file = path.resolve(dir, '_posts', name + '.md');
fs.readFile(file, function (err, content) {
if (err) return next(err);
var html = markdownToHTML(content.toString());
res.end(html);
});
});
//渲染列表
router.get('/', function (req, res, next) {
res.end('文章列表');
});
app.listen(3000);
};
//去掉文件名中的扩展名
function stripExtname (name) {
var i = 0 - path.extname(name).length;
if (i === 0) i = name.length;
return name.slice(0, i);
}
//将Markdown转换为HTML
function markdownToHTML(content) {
return md.render(content || '');
}
$ subl example/_posts/2015-06/hello-world.md
# hello, world
这是我写下的第一篇文章
$ npm install markdown-it --save
$ myblog preview example
打开http://127.0.0.1:3000/posts/2015-06/hello-world.html
文章元数据:一篇文章除内容外,一般还会带上一些元数据,比如文章标题、发表时间、标签等。我们假设每篇文章是以下格式:
---
title: hello, world
date: 2015-06-16
---
这是我写下的第一篇文章
"---"z之间的部分是文章的元数据
修改文件lib/cmd_preview.js
增加模板:只显示了文章的内容,也没有各种样式,显得略丑,给它接上一个模板。ib/cmd_preview.js
example/_layout/post.htmlexample/assets/style.css
$ npm install swig --save
$ myblog preview example
打开http://127.0.0.1:3000/posts/2015-06/hello-world.html
换一个模板在hell-world.md添加
layout: post2
新建模板文件example/_layout/post2.html
渲染文章列表:遍历所有文章,并且按照发表时间来排序,然后将其标题渲染出来。_post目录下格式为发表年月/文件名.md
$ npm install rd --save
4.5 生成静态博客
生成静态博客内容时渲染文章的程序与实时预览时基本一样,区别是这一步不是等待用户访问时再渲染文章,而是直接遍历所有文章并直接渲染,然后把渲染后的页面直接保存为文件,因此我们可以先把这些公共的程序提取出来。
新建lib/utils.js
build命令:修改bin/myblog
4.6 配置文件
在启动实时预览程序时希望可以自己指定要监听的端口和公共的数据,config.json
4.7 创建空白博客模板
创建一个新的博客项目时,自动创建一些必需的文件,比如页面模板和默认配置文件。
一个空的博客项目包含以下目录:
_layout目录,存放模板文件
_posts目录,存放文章内容源文件
posts目录,存放生成的博客页面;
assets目录,存放博客页面中引用到的静态资源。
create命令:
4.8 一些有用的第三方服务
评论组件:多说、Disqus等
分享组件:加网