Node全解02_01node命令行程序

CRM学习 Node.js 之文件模块

目标 完成一个命令行工具

001 新建目录 node-todo-1

  • 打开这个目录终端 yarn init -y
  • 修改package.json 的版本号为 0.0.1
  • 新建 index.js 内容为console.log('hi')

002 使用库 commander.js

  • 抄文档开始干
  • npm install commander 或者你 yarn add commander
  • 安装后,继续抄

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    const program = require('commander');

    program
    .option('-d, --debug', 'output extra debugging')
    .option('-s, --small', 'small pizza size')
    .option('-p, --pizza-type <type>', 'flavour of pizza');

    program.parse(process.argv);

    // 额外加一行
    console.log('hi')
  • 项目根目录运行 node index.js 只打印了 hi

  • 此时你运行 node index -h 会显示如下内容

    1
    2
    3
    4
    5
    6
    7
    Usage: index [options]

    Options:
    -d, --debug output extra debugging
    -s, --small small pizza size
    -p, --pizza-type <type> flavour of pizza
    -h, --help output usage information
  • 修改 index.js

    1
    2
    3
    4
    5
    6
    7
    // 修改后然后运行  node index -h 就会显示你修改的内容
    const program = require('commander');

    program
    .option('-x, --xxx', 'what the x')

    program.parse(process.argv);
  • 继续抄文档, 实现一个子命令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    const program = require('commander');

    // 设置它的选项
    program
    .option('-x, --xxx', 'what the x')

    // 设置子命令
    program
    .command('add <taskName>')
    .description('add a task')
    .action((x,y) => {
    console.log(x)
    console.log(y)
    });


    program.parse(process.argv);



    // 运行 node index add 会提示缺少一个 taskName

    // 运行 node index add aa 打印
    aa
    Command {
    commands: [],
    options: [],
    _execs: Set {},
    _allowUnknownOption: false,
    _args: [ { required: true, name: 'taskName', variadic: false } ],
    _name: 'add',
    _optionValues: {},
    _storeOptionsAsProperties: true,
    _passCommandToAction: true,
    _actionResults: [],
    _helpFlags: '-h, --help',
    _helpDescription: 'output usage information',
    _helpShortFlag: '-h',
    _helpLongFlag: '--help',
    _noHelp: false,
    _exitCallback: undefined,
    _executableFile: undefined,
    parent: Command {
    commands: [ [Circular] ],
    options: [ [Option] ],
    _execs: Set {},
    _allowUnknownOption: false,
    _args: [],
    _name: 'index',
    _optionValues: {},
    _storeOptionsAsProperties: true,
    _passCommandToAction: true,
    _actionResults: [],
    _helpFlags: '-h, --help',
    _helpDescription: 'output usage information',
    _helpShortFlag: '-h',
    _helpLongFlag: '--help',
    Command: [Function: Command],
    Option: [Function: Option],
    CommanderError: [Function: CommanderError],
    _events: [Object: null prototype] {
    'option:xxx': [Function],
    'command:add': [Function: listener]
    },
    _eventsCount: 2,
    rawArgs: [
    '/Users/hjx/.nvm/versions/node/v12.14.1/bin/node',
    '/Users/hjx/Desktop/node-todo-1/index.js',
    'add',
    'aa',
    'bb',
    'cc'
    ],
    args: [ 'aa', 'bb', 'cc' ]
    },
    _description: 'add a task',
    _argsDescription: undefined
    }
    // 你就可以自己领会了
  • index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const program = require('commander');

// 设置它的选项
program
.option('-x, --xxx', 'what the x')

// 设置子命令
program
.command('add <taskName>')
.description('add a task')
.action((firstArg,info) => {
let args = info.parent.args;
console.log(args);
});


program.parse(process.argv);

// node index aa bb cc dd
// 打印 aa bb cc dd

003 修改目录结构

cli.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const program = require('commander');
const api = require('./index.js')
// 设置它的选项
program
.option('-x, --xxx', 'what the x')

// 设置子命令
program
.command('add <taskName>')
.description('add a task')
.action((firstArg,info) => {
let words = info.parent.args;
console.log(words);
api.add(words);
});

program
.command('clear')
.description('clear all tasks')
.action(() => {
console.log('this is clear');
});


program.parse(process.argv);

index.js

1
2
3
module.exports.add = (title)=>{
console.log('add ' + title);
}

运行 node cli add aa bb cc 会显示相应的任务被添加

004 持久化任务内容

  • 但是没有数据库~
  • 使用一个文件吧! 存到用户home目录里 打算存在~/
  • google 搜索 nodejs get home directory
  • 得到答案const homedir = require('os').homedir()
  • 获取用户设置的 home 目录 const home = process.env.HOME

  • 修改 index.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const homedir = require('os').homedir()
    const home = process.env.HOME || homedir;
    module.exports.add = (title)=>{
    console.log('add ' + title);
    // 读取之前的任务
    fs.readFile(dbPath,{});
    // 往里面添加一个任务
    // 存储任务到文件

    }

005 如何拼目录 path

1
2
3
// 专门用来拼路径的 windows 是 \  mac 是 /
const p = require('path');
const dbPath = p.join(目录,目录');

006 利用https://devdocs.io/查fs模块使用

  • 搜索 fs.readFile 查看api
  • 看到 参数里 options 有个 flag 点进去
  • 得到各种模式 a / ax / a+ ...

007 实现创建任务功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
const homedir = require('os').homedir()
const home = process.env.HOME || homedir;
// 专门用来拼路径的 windows 是 \ mac 是 /
const p = require('path');
const dbPath = p.join(home,'.todo');
const fs = require('fs');

module.exports.add = (title)=>{
// 读取之前的任务
fs.readFile(dbPath,{flag:'a+'},(error,data)=>{
if(error){
console.log(error)
}else{
let list;
try{
list = JSON.parse(data.toString())
}catch(error2){
list = []
}
const task = {
title: title,
done: false
}
list.push(task);
const string = JSON.stringify(list);
fs.writeFile(dbPath,string + "\n",(error3)=>{
if(error3){
console.log(error3)
}
});
console.log(list)
}
});
// 往里面添加一个任务
// 存储任务到文件
}

007 优化代码 面向接口编程

index.js

1
2
3
4
5
6
7
8
9
10
const db = require('./db.js');

module.exports.add = async (title) =>{
// 读取之前的任务
const list = await db.read();
// 往里面添加一个任务
list.push({title,done:false});
// 存储任务到文件
await db.write(list);
}

db.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
const homedir = require('os').homedir()
const home = process.env.HOME || homedir;
// 专门用来拼路径的 windows 是 \ mac 是 /
const p = require('path');
const dbPath = p.join(home,'.todo');
const fs = require('fs');

const db = {
read(path = dbPath){
return new Promise((resolve,reject)=>{
fs.readFile(path,{flag:'a+'},(error,data)=>{
if(error){ return reject(error); }
let list;
try{
list = JSON.parse(data.toString())
}catch(error2){
list = []
}
resolve(list);
});
})
},
write(list, path = dbPath){
return new Promise((resolve,reject)=>{
const string = JSON.stringify(list);
fs.writeFile(path,string + "\n",(error)=>{
if(error){ return reject(error); }
resolve();
});
})

}
}

module.exports = db;

代码仓库