前言
本人也是菜鸟一枚,现学现开发的,各个文档也尚未熟练,主要面向百度开发,因此文章中只会列出用到的API,更具体的API说明文档请参考最下边的参考链接部分, 如果有能力, 籍此可以尝试开发 CLI 工具
创建目录并初始化npm
mkdir auto_whs && cd auto_whs && npm init
在 git 创建仓库, 初始化项目, 代码仓库地址写入 package.json 中的 repository 下的 url 字段值
创建index.js 在开头写入以下代码, 然后就可以在Git命令行用 ./index.js
执行代码了
#!/usr/bin/env node
console.log('hello world')
去掉 ./
路径, 使用 bin
字段下的 auto_whs
执行
"name": "auto_whs",
"bin": {
"auto_whs": "index.js"
}
npm link
绑定就可以用 auto_whs
(package.json中的name) 直接执行了npm link 用来在本地项目和本地npm模块之间建立连接,可以在本地进行模块测试
npm WARN ka@1.0.0 No description
npm WARN ka@1.0.0 No repository field.
up to date in 1.026s
found 0 vulnerabilities
D:\nodejs\ka -> D:\nodejs\node_modules\ka\index.js // 建立的命令的位置
D:\nodejs\node_modules\ka -> C:\Users\Hollysys\Desktop\auto_whs // 建立的模块的位置
npm unlink
解除 link
绑定
npm link
后, 在本地就可以测试了, 当将包发布到npm.org后,如果要测试线上下载的包npm unlink
进行本地连接解除,where <命令>
如 where yarn
, 可以查找 link 后命令的位置(如 where auto_whs
), 如果 unlink 失败, 可以进入路径位置,手动删除,并且删除 node_modules 中的包npm uninstall <package> -g
在npm unlink成功后删除包
接着就是中间开发功能的过程, 过程后续部分来说, 假设已经开发完成,那么就要发布了
commit 所有代码更改到 git
注册npm用户 https://www.npmjs.com/
npm login
输入用户名/密码 登录npm
npm publish
发布包,成功后可在npm官网搜索查看
修改代码后,更新包的版本
npm采用语义化版本,共三位,以
.
隔开,从左至右依次代表:主版本(major)、次要版本(minor)、补丁版本(patch)。
npm version <patch|minor|major>
会自动修改包的版本加1, 就是将package.json中的version版本号加1, 根据更新内容决定更新的版本号npm publish
npm unpublish 包名@version
删除指定版本的包
npm unpublish 包名 --force
删除整个包
// child_process 模块是 Node的模块,如 fs,path 一样可以直接require
// util 模块是Node的模块, 封装了很多通用方法,其中promisify可以将异步方法包装成promise
const util = require('util')
const exec = util.promisify(require('child_process').exec);
(async () => {
// const res = await exec('这里是要执行的命令')
const res = await exec('echo hello world')
console.log(res) // { stdout: 'hello world\r\n', stderr: '' }
})()
npm i shelljs -S
/**
* 本地模式, 需要从shell调用方法
*/
const shell = require('shelljs');
// 调用shell的exec方法执行命令, 其实调用的child_process.exec
// 默认调用命令会在命令行中输出命令调用的信息, 通过 silent: true 可以不在命令行中输出命令调用的输出
let message = shell.exec(
`git log --no-merges --pretty=%s --author="${username}" --after="${startTime}" --before="${endTime}"`
, {silent: true}).toString().trim(); // commit说明信息
shell.cd(dir) // 切换目录
shell.echo('echo 输出内容') // echo输出内容
shell.chmod(755, <file|dir>) // 修改权限
shell.cat() // 查看
shell.cp() // 复制
shell.mkdir() // 创建目录
shell.pwd() // 查看当前所在目录
shell.mv() // 重命名或者移动文件、目录
shell.rm() // 删除
/**
* 全局模式, 可以直接在文件中写命令
*/
require('shelljs/global')
一个用户与命令行交互的工具
// npm i inquirer -S
const inquirer = require('inquirer');
/**
* 方法: inquirer.prompt(questions) -> promise questions 数组类型
*
* type: 表示提问的类型
* -- input 输入框
* -- password 密码输入框 密码不显示
* -- confirm 询问框 y/n
* -- list 选择列表 choices可用
* -- rawlist 带编号的选择列表 choices可用
* -- expand 带缩写选择列表 choices可用
* -- checkbox 多选 choices可用
* -- editor
* message 问题的描述
* name 存储当前问题回答的变量,即字段名
* validate 对用户输入的值或者做的选择做校验
* default 问题的默认结果值
* choices 列表选项,在某些type下可用,并且包含一个分隔符(separator)
* filter 对用户的回答进行过滤处理,返回处理后的值
* transformer 对用户回答的显示效果进行处理(如:修改回答的字体或背景颜色),但不会影响最终的答案的内容
* when 根据前面问题的回答,判断当前问题是否需要被回答
* pageSize 修改某些type类型下的渲染行数
* prefix 修改message默认前缀
* suffix 修改message默认后缀。
*/
// 说明: 字符串后跟 .red/green 等, 是用了 colors 插件 对命令行输出文字改变颜色
const initQuestions = [{
type: 'input',
message: 'whs用户名:'.green,
name: 'whsUser',
validate: (value) => {
if (!value) {
const {
whsUser = ''
} = readConfig();
if (whsUser) return true
return 'whs用户名不能为空'.red
}
return true
}
},
{
type: 'password',
message: 'whs密码:'.green,
name: 'whsPwd',
default: '',
validate: (value) => {
if (value) {
return true;
} else {
return '密码不能为空'.red
}
}
},
{
type: 'confirm',
message: '是否保存信息?'.magenta,
name: 'isSaveConfig',
default: true
},
{
type: 'list',
message: '请选择一种水果:',
name: 'fruit',
choices: [
"Apple",
"Pear",
"Banana"
],
filter: function (val) { // 使用filter将回答变为小写
return val.toLowerCase();
}
},
{
type: 'rawlist',
message: '请选择一种水果:',
name: 'fruit',
choices: [
"Apple",
"Pear",
"Banana"
]
},
{
type: "expand",
message: "请选择一种水果:",
name: "fruit",
choices: [
{
key: "a",
name: "Apple",
value: "apple"
},
{
key: "O",
name: "Orange",
value: "orange"
},
{
key: "p",
name: "Pear",
value: "pear"
}
]
},
{
type: "checkbox",
message: "选择颜色:",
name: "color",
choices: [
{
name: "red"
},
new inquirer.Separator(), // 添加分隔符
{
name: "blur",
checked: true // 默认选中
},
{
name: "green"
},
new inquirer.Separator("--- 分隔符 ---"), // 自定义分隔符
{
name: "yellow"
}
]
},
{
type: "editor",
message: "请输入备注:",
name: "editor"
}
]
const answers = await inquirer.prompt(initQuestions) // await 需要在async关键字下使用,此处未做
console.log(answers) // 交互完毕得到的结果,可以用来后续操作
完整的Node.js命令行(参数)解决方案
安装并引入
// npm install commander
// 声明 program 变量, 为简化使用,Commander 提供了一个全局对象
const { program } = require('commander');
简单使用
定义版本号
program.version('0.0.1') // version 定义版本
选项 program.option()
.option()
定义选项,同时可以附加选项简介 // <dir> 表示 -a或者 --auto 后边的参数传值必填
// [dir] 表示 -e或者 --exec 后边的参数传值可选
// 通过program.parse(arguments)方法处理参数,没有被使用的选项会存放在program.args数组中
// .option(arg1, arg2, [arg3]) arg1 定义选项、arg2定义说明, arg3定义默认值,
program
.option('-a, --auto', 'auto job_booking')
.option('-p, --project-path <dir>', 'project fulPath') // 项目目录路径
.option('-e, --exec [dir]', 'config and exec')
.parse(process.argv)
const program_opts = program.opts() // 获取命令行参数选项
const program_args = program.args // 获取命令行参数
console.log(program_opts) // 如 auto_whs -a 结果: { auto: true, projectPath: undefined, exec: undefined }
console.log(program_args) // 如 auto_whs config -a 可以解析到参数结果: ['config']
通过.command()或.addCommand()可以配置命令,有两种实现方式:为命令绑定处理函数,或者将命令单独写成一个可执行文件
.command()的第一个参数可以配置命令名称及参数,参数支持必选(尖括号表示)、可选(方括号表示)及变长参数(点号表示,如果使用,只能是最后一个参数)。
// 通过绑定处理函数实现命令(这里的指令描述为放在`.command`中)
// 返回新生成的命令(即该子命令)以供继续配置
program
.command('clone <source> [destination]')
.description('clone a repository into a newly created directory')
.action((source, destination) => {
console.log('clone command called');
});
// 通过独立的的可执行文件实现命令 (注意这里指令描述是作为`.command`的第二个参数)
// 返回最顶层的命令以供继续添加子命令
program
.command('start <service>', 'start named service')
.command('stop [service]', 'stop named service, or all if no name supplied');
// 分别装配命令
// 返回最顶层的命令以供继续添加子命令
program
.addCommand(build.makeBuildCommand());
command 自定义命令关联外部可执行文件
一个用于 node.js 终端 console.log 的颜色库,可以给命令行中输出不同颜色的文字
// npm install colors
var colors = require('colors');
console.log('hello'.green); // outputs green text
console.log('i like cake and pies'.underline.red) // outputs red underlined text
console.log('inverse the color'.inverse); // inverses the color
console.log('OMG Rainbows!'.rainbow); // rainbow
console.log('Run the trap'.trap); // Drops the bass
console.log(colors.green('这是绿色'))
colors 支持的样式
colors 不仅仅支持输出的文字颜色,还支持输出的背景颜色、字体样式等
Puppeteer 是一个 Node 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome。Puppeteer 默认以 headless 模式运行,但是可以通过修改配置文件运行“有头”模式。 由头模式 就是 { headless:false } 会启动chromium打开浏览器,而默认是不会打开的.
// 安装的过程会自动下载最新版的Chromium以保证API可以使用
// Chrominum 是从国外下载的, 所以一般会失败报错
// 可以通过环境变量类配置不下载chrominum,具体请百度或查看文档PUPPETEER_SKIP_CHROMIUM_DOWNLOAD
npm install puppeteer -S
// 另一种方式是 替换puppeteer插件,使用 puppeteer-chromium-resolver
// 这个插件会在下载的时候 自动切换下载源,比如 用cnpm下载过程中,走到下载chrominum时会自动切换到npm源
// 同样的,引入方式也会发生改变,具体请看下文
npm install puppeteer-chromium-resolver -S
// puppeteer 插件时候引用方式
(async () => {
const browser = await puppeteer.launch(); // 创建浏览器实例,会唤起chrominum 浏览器窗口
const page = await browser.newPage(); // 创建一个新tab页
await page.goto('https://www.baidu.com'); // 打开百度首页
await page.screenshot({path: 'example.png'}); // 截屏
await browser.close(); // 关闭浏览器实例
})();
// puppeteer-chrominum-resolver 插件时候引用方式
const PCR = require("puppeteer-chromium-resolver");
const stats = await PCR();
const browser = await stats.puppeteer.launch({headless: false,
args: ["--no-sandbox"],
executablePath: stats.executablePath,
defaultViewport: {
width: 1550, // 设置浏览器窗口大小
height: 722,
slowMo: 20 // 设置peppeteer操作的运行速度, 可以更清晰的看清运行过程
}
})
const page = await browser.newPage();
await page.goto('https://www.baidu.com'); // 打开网页
Page.setViewport()
await page.pdf({path: 'hn.pdf', format: 'A4'});
const el = await page.$(selector)
await el.uploadFile(...filePaths) // 设置输入这些路径的文件的值。如果某些 filePaths 是相对路径,那么它们将被解析为相对于 当前工作目录
page.on('console', msg => console.log('PAGE LOG:', msg.text())); // 捕获console输出
const el = await page.$(selector) // 获取一个元素
el.click() // 点击元素
page.$$(selector) // 获取一类元素
page.$eval(selector, pageFunction[...args]) // 获取元素后执行pageFunction,
page.waitFor(string|number|function>) // 选择器 方法 或超时时间, 就是 等待的意思,或者等待元素出现
// 自己写了个简单的 sleep() 等待函数
function sleep (timeStamp) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, timeStamp)
})
}
sleep(3000) // 利用js的单线程, 等待3秒以阻塞代码执行
nexe 可以将node应用打包成
exe
可执行程序
虽然只是一个简单的可以与命令行交互的npm包的开发,但是用到的插件也是比较多,重要的不是功能如何, 而且了解一个 CLI
的开发流程,npm包的开发、发布、更新流程,涉及的文档也有一定的量,还需要学习才能熟悉啊。
puppeteer
学习笔记nrm(npm registry manager) 是npm的镜像源管理工具, 可以迅速的在下载源地址之间切换
npm -------- https://registry.npmjs.org/
yarn ------- https://registry.yarnpkg.com/
cnpm ------- http://r.cnpmjs.org/
taobao ----- https://registry.npm.taobao.org/
nj --------- https://registry.nodejitsu.com/
npmMirror -- https://skimdb.npmjs.com/registry/
edunpm ----- http://registry.enpmjs.org/
* hollysys --- http://192.168.88.50:8081/repository/group-npm/