当年在百度搜索团队的时候作的一个小工具,能够把一些平常工做自动化,确实解决了一些问题。正值五一,分享点有趣的东西。但愿能给你们一些启发。javascript
就在不久以前,我入职了百度的搜索团队,参与 pc 搜索的一些业务。搜索业务这么多年,历史积累的技术债务蛮多的,其中影响效率的主要是开发过程的问题。好比,首页常常要切换登陆态和非登陆态来看效果,每次切换都要手动输入用户名密码,并且由于有的 http 的资源会涉及跨域而失败,须要单独请求下。好比,每次上线以前都要过几遍 checklist,繁琐也花时间,因此几乎没人会认真的一遍遍过 checklist,等等,一些问题。并且由于咱们开发时也是直接代码推到服务器来看效果,因此常常登陆跳板机和切换不一样机器,须要记住一些机器名和密码,也很耗费时间。我在熟悉流程和架构之余就一直在想着怎么去解决这些痛点。有一次走查,UE 和 PM 说每次走查的登陆都好麻烦哦。听到这,发现这是个共性问题,就以为能够正式着手作了。前端
最开始的目标就是一键登陆和退出登陆,一键跑 checklist,还有一键登陆跳板机和一键切环境,涉及到浏览器的自动化,天然就想到了 puppeteer,一个用于前端自动化测试的库。而登陆跳板机和切换登陆的机器不在浏览器中,须要涉及到系统的自动化(鼠标和键盘事件等),最后选择了 robotjs。这俩库都是在node环境下才能跑的,而UE和PM的电脑不会装 node,加上功能多了之后有个图形界面会更好,就想到了 electron(提供node环境和图形界面)。vue
先简单介绍下这三门技术:java
Puppeteer 是一个 Node 库,它提供了一些高级API来经过 DevTools 协议控制 Chromium 或 Chrome。node
它能作的不少,好比:web
Most things that you can do manually in the browser can be done using Puppeteer!chrome
它提供了这些apinpm
Robotjs 是 nodejs 的第一个用于桌面自动化的库。他能自动化鼠标、键盘和读取屏幕,而且提供了 Mac, Windows, Linux 的跨平台支持。json
Electron 可让你使用纯 JavaScript 调用丰富的原生(操做系统) APIs 来创造桌面应用。 你能够把它看做一个 Node. js 的变体,它专一于桌面应用而不是 Web 服务器端。api
Electron进程分为主进程和渲染进程,Electron 运行 package.json 的 main 脚本的进程被称为主进程。 在主进程中运行的脚本经过建立web页面来展现用户界面。 一个 Electron 应用老是有且只有一个主进程, 每一个 Electron 中的 web 页面运行在它的叫渲染进程的进程中。因此作 electron 应用会常常用到 ipc 来作进程通讯,不少操做只能在主进程作。
以后界面的展现用任何组件方案均可以,原本想用 san(百度的前端框架),可是 san 没有 electron 的脚手架,考虑到效率,暂时选用了 electron-vue 来建立项目。
最初的版本的走查工具,界面是这样的:
输入 url,点击登陆,就是经过 puppeteer 来启动一个浏览器,而且自动跳转到登陆页面,输入用户名密码,以后点击登陆,跳转到输入的 url。这里只是 pc 的,移动端的话启动的时候设置下 ua 就行了。
browser = await puppeteer.launch({
executablePath: getConfig('chromePath'),
headless: false,
defaultViewport: {
width: 0,
height: 0
},
args: [
'--allow-running-insecure-content',
'--disable-web-security',
'--auto-open-devtools-for-tabs'
]
})
复制代码
启动浏览器的时候经过 headless 设置为 false,puppeteer 支持启动没有界面的浏览器,主要是用于自动化测试,但咱们这里须要界面。
而后经过 executablePath 指定一个本地的 chrome 的启动路径,能够在设置里面修改(通常 chrome 的路径是固定的),这样使用本地的 chrome 来跑,不用连 chrome 一块儿打包进去。
defaultViewport 设置为 width:0 和 height:0 是为了让内容自动适应窗口大小。
--allow-running-insecure-content 和 --disable-web-security 能够禁止同源策略,这样 https 网站加载 http 的跨域资源也不会报错。
--auto-open-devtools-for-tabs 能够打开新 tab 自动打开 dev tools(这个后续能够加到设置中去让用户本身设置)。
以后又顺手作了一个屏幕取色的功能,考虑到 ue 走查时可能会用到,实现是经过 ox-mouse 来监听系统鼠标事件,而后经过 robotjs 来获取鼠标所在位置的颜色,以后发送到 colorpicker 窗口作显示。
import mouseEvent from 'osx-mouse'
import robot from 'robotjs'
const mouseTrack = mouseEvent()
mouseTrack.on('move', (x, y) => {
let color = '#' + robot.getPixelColor(parseInt(x), parseInt(y))
const colorPickerWin = BrowserWindow.getAllWindows().filter(item => item.name === 'colorPickerWin')[0]
if (colorPickerWin) {
colorPickerWin.webContents.send('color', color)
}
})
复制代码
最初的两个用户(PM 和 UE)都给了一致的确定,这让我很开心。
由于有了最初的一个场景的成功实践,后面也就更有热情去作了。最初的目标更多仍是针对开发者,因此开发者版本独立作了一个工具。这方面能够应用的场景就多了。
最开始作的事自动登陆跳板机和自动切环境的功能,真实的流程是打开终端,输入ssh连接跳板机的命令,而后输入密码而且手机认证,手机认证这部分暂时没有作自动化,也最好不要去作自动化,把以前的那些都作了自动化。最终效果是一点登陆跳板机,就能够在如流手势认证登录了。实现仍是经过robotjs,先输入command + space打开spotlight,而后输入terminal.app,以后输入命令和密码。过程比较傻瓜式。
async function spolightOpen(appName) {
robot.keyTap('space', ['command'])
await delayPromise(500)
robot.keyTap('delete')
robot.typeString(appName)
await delayPromise(2000)
robot.keyTap('enter')
await delayPromise(1000)
}
async function sshLogin(params) {
await spolightOpen('terminal.app')
robot.typeString('ssh xxx@baiduxxx.com')
robot.keyTap('enter')
await delayPromise(1000)
robot.typeString('xxxxxx')
robot.keyTap('enter')
}
复制代码
自动跑 checklist 是自动化测试的范畴,puppeteer 很拿手,只要把操做步骤写成脚本,而后在一些状态下作效果的验证就能够了。
作完这些功能后,又会想到自动建立 icafe(百度内部的项目管理平台)卡片(把 mrd(需求描述文档) 的内容拿过来自动粘贴,自动输入一些信息以后建立卡片,而且把关联 cr 的代码复制下来),自动建立提测单,自动建立上线单,自动发排期邮件,自动发周报等等。
不少平时手动的作的事情均可以自动来完成,包括浏览器里的和系统级别的。
慢慢想到这一个个的功能都是围绕代码库的,那是否是应该作一个代码库的管理,而后围绕代码库的开发周期来作工具链的集成。
这个阶段我对开发工具的定义是作代码库的管理,(好比首页分了好多模块,能够经过分类把一些模块归到一块儿管理),而且围绕代码库的开发流程提供一系列提效工具。能够经过插件来扩展工具链。
大概设计的界面是这样的
每一个代码库均可以在建立时输入本地路径和 icode(百度内部的代码托管平台) 路径还有相关的开发和 pm 等信息,这样能够一键用 ide 打开本地代码库,在详情里能够看到相关的人员的信息,而且点击名字能够一键打开如流中对应人员的对话框(基于 robotjs)。
而后会扫描代码库下的 package.json 中的 npm scripts,能够在界面上执行,也能够选择在系统的 terminal 或者 ide 的 terminal 中执行。
选择开发流程会看到每一个阶段的tab,每一个tab下有这个阶段可能用到的工具,好比开发时的一键登陆跳板机和切环境,排期阶段的自动发排期邮件,自动建立icafe卡片,自测阶段的自动登陆退出,上线阶段的自动建立提测单等功能,实现方式同样,就是模拟用户的操做,经过浏览器自动化和系统的自动化来代替人来完成一些工做。
由于开发流程的入口藏得比较深却很经常使用,又单独提到了左侧。此外一些其余的工具也很经常使用,能够放到工具箱里面,好比可视化删除本地 node_modules,屏幕取色,屏幕尺子等等。
工具箱中工具备两种触发方式,一键触发和定时任务触发,好比每两周都自动列一下可用的会议室,而后准备好邮件,只须要确认下信息,而后点发送就能够自动订会议室,有的工具不须要定时功能。定时功能的实现是经过 node-schedule,它的api风格是这样的:
const schedule = require('node-schedule');
const scheduleCronstyle = ()=>{
//每分钟的第30秒定时执行一次:
schedule.scheduleJob('30 * * * * *',()=>{
console.log('scheduleCronstyle:' + new Date());
});
}
scheduleCronstyle();
复制代码
经过 * * * * * * 来指定时间间隔
* * * * * *
┬ ┬ ┬ ┬ ┬ ┬
│ │ │ │ │ |
│ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)
│ │ │ │ └───── month (1 - 12)
│ │ │ └────────── day of month (1 - 31)
│ │ └─────────────── hour (0 - 23)
│ └──────────────────── minute (0 - 59)
└───────────────────────── second (0 - 59, OPTIONAL)
复制代码
整个工具的思路是围绕代码库的开发流程的一些自动化工具,基于 puppeteer 和 robotjs,不一样的场景下须要的工具不一样,因此插件功能是颇有必要的,若是插件足够丰富之后,咱们能够在开发时选择适合本身场景的插件来安装,会自动添加一些阶段的工具。固然,这个尚未实现。
设置里面是设置各类帐号信息,和一些功能的开启关闭等。
锁屏就是利用了系统的锁屏,中午出去吃饭前点一下就能够了。
开发到这里时,距离刚开始的想法已通过去半个月了,虽然尚未开发完成,可是这个工具的定义有了比较清晰的认知。
把一个小工具作的比较大之后,会有些怀疑这个工具的必要性,但最终仍是以为它是有意义的。首先,他解决了我在pc场景下的痛点问题,自动登陆退出、自动跑checklist、一键登陆跳板机和切环境等,这是这个工具解决的比较痛点的问题,属于“雪中送炭”的功能。后面有些功能有更好,没有也不会影响很大,属于“锦上添花”的功能。
但提供插件机制以后,能够针对不一样场景的痛点问题作更多的扩展,集成更多“雪中送炭”的功能。因此提供了代码库管理和划分开发流程还有提供插件机制会使得这个工具更有想象空间。
那天群里开玩笑说你可能须要这个工具的20个理由,其实没有达到,如今也就三、4个用这个工具的理由,但随着不断地完善,可能他会成为开发时很重要的一个辅助工具呢。
不得不说,electron 的坑是真的多,我简单列一下几个重要的。
electron 提供的 node 环境中 node 版本和本地的 node 版本要分开,运行时若是报版本不兼容,你再怎么更新本地 node 版本也没用,要去更新 electron 版本,electon 版本和内置 node 版本的关系能够去官网查。由于包依赖的是 electron 版本,因此一些二进制包用 npm rebuild xxx 也是没用的,要用 electron-rebuild xxx。
electron 默认没有提供任何快捷键,因此打包后,你发如今输入框中 command + v 都无论用,这须要本身去设置。但不能触发别的应用的快捷键这一点对以前实现的系统自动化的功能有毁灭性的打击,由于实现系统自动化时时大量用到了别的应用的快捷键,但打包后发现不支持!绞尽脑汁思考后想出了一种方案,mac 应用内不支持触发别的系统的快捷键,父子进程都不行,那么两个独立的进程不久能够了,因此在本地起了一个单独的服务器,经过请求的参数来触发不一样的自动化功能。可是多了一个应用外的本地服务器的依赖,还没想好应用应该如何去分发和管理。但至少是可行的。
最初只是为了作个自动化的登陆的工具,但作着作着发现能够作更多,不少场景下是须要一些自动化工具的。他能把咱们工做中一些耗费时间却没有多大必要去手动作的事情给自动完成,释放咱们的时间作一些更有意义的事情。插件机制让它变得更有想象空间,也许能够围绕这个工具造成生态。