写代码如何摆脱搬砖写代码

最近我有一些新的领悟,想要与大家分享。

我最近一直在开发一个基于混合技术的 H5 页面的 Web 应用程序,它是一个多功能产品,需要在许多地方进行手动打点。例如,我们经常使用的 adjust.adjust 打点需要两个参数:token 即应用程序的 ID,key 则是对应事件的 ID。之前,我通常是将应用程序的 token 和事件的 key 保存在一个文件中,然后在需要的地方进行引用,类似于这样:

<code>'My App Name': { appToken: 'xxxxx', event1: 'yyyy' }</code>

这样在使用时,只需要按照我的应用程序的名称进行取值就可以了,如果不存在则不记录事件。但是这种方式存在一个问题,每次需要新增一个应用程序时,就需要重新打包上传,这样非常麻烦,于是我产生了解耦的想法。

虽然 token 和 key 不算是敏感信息,但也不能随意暴露,因为如果有人获取到这两个数据就可以记录事件,可能会导致事件记录不准确。因此,我自然而然地想到了加密。

<code><strong>const</strong> keys = require('./adjustKeys.config') <strong>const</strong> AES = require("crypto-js/aes") <strong>const</strong> utf8 = require('crypto-js/enc-utf8') <strong>const</strong> path = require('path') <strong>const</strong> fs = require('fs') <strong>const</strong> encryptKey = 'test' <em>// 加密key,可以随便设置</em> <strong>function</strong> <strong>encryptString</strong>() { <strong>let</strong> <strong>let</strong> str = '' <strong>for</strong> (<strong>const</strong> k <strong>in</strong> keys) { <strong>const</strong> obj = keys[k] str += `${k}|` + `${obj.appToken}|` + `${obj.event1}|` } <strong>const</strong> willEncrypt = utf8.<strong>parse</strong>(str) <strong>let</strong> encrypted = AES.<strong>encrypt</strong>(willEncrypt, encryptKey) encrypted = encrypted.<strong>toString</strong>() }</code>

加密完成后,难道还需要手动复制一遍吗?这可不像是程序员该做的事情。于是,我添加了一个写入文件的功能。

<code><strong>function</strong> <strong>writeFile</strong>(str) { <strong>const</strong> filePath = path.<strong>join</strong>(__dirname, './dist', './js', './events.js') <strong>try</strong> { fs.<strong>writeFileSync</strong>(filePath, `window.keyOfAdjust='${str}'`) console.<strong>log</strong>('写入文件成功') } <strong>catch</strong> (error) { console.<strong>log</strong>('写入文件出错') console.<strong>log</strong>(error) } <strong>if</strong> (process.env.NODE_ENV === 'development') { process.<strong>exit</strong>(0) } }</code>

这样一来,就更加方便地实现了解耦,并保护了敏感信息。

为了简化每次修改配置文件后的流程,只需重新加密并写入一次。我们可以在 package.json 中添加一个 npm 命令,以便在每次更新完成后自动进行加密并写入操作:

<code>"scripts": { "adjust": "cross-env NODE_ENV=development node encryptAdjustKey.js" }</code>

由于该文件会自动写入 dist 文件夹,每次更新只需更新该单个 JavaScript 文件即可,无需重新打包。这使得操作变得更加方便。当然,在 index.html 中也需要提前引入相关内容:

<code><<strong>head</strong>> <<strong>script</strong> src="/js/events.js"></<strong>script</strong>> </<strong>head</strong>></code>

在项目中,只需解密一次即可:

<code><strong>import</strong> AES <strong>from</strong> "crypto-js/aes" <strong>import</strong> utf8 <strong>from</strong> 'crypto-js/enc-utf8' <strong>export</strong> <strong>function</strong> <strong>getAdjustKeys</strong>(){ <strong>const</strong> a = 'default||,' <strong>const</strong> str = window.keyOfAdjust || a <strong>const</strong> keys = AES.<strong>decrypt</strong>(str, config.productId).<strong>toString</strong>(utf8) <em>// console.log('getAdjustKeys keys: ', keys);</em> <strong>return</strong> keys }</code>

为了更进一步简化操作,每次更新都手动输入命令可能有些繁琐。我考虑是否能在打包完成后自动进行加密和更新。经过查阅 webpack 文档,我发现了一个 done 钩子。基本思路如下:

<code>module.exports = <strong>class</strong> <strong>DonePlugin</strong> { <strong>apply</strong>(compiler) { compiler.hooks.done.<strong>tap</strong>('done', () => { <em>// 在这里执行加密和更新操作</em> }) } }</code>

于是我编写了一个名为 webpack-after-done 的 webpack 插件。在使用时,只需将该插件实例化即可。


const AfterDone = require('webpack-after-done')

config.plugins.push(new AfterDone({
        funcList:doneCallbacks,
        zipify:true,
        zipFileName:'dist.zip'
      }))

自动化流程的优化思考与实践

解耦adjust后,我思考了更新代码后如何通知测试。是完整打包测试,还是只更新adjust key而无需重新打包。于是我想到了飞书。

我们公司内部通讯使用飞书,其中有一个简单便捷的群机器人功能。在群设置中添加机器人后,会获得一个post接口地址。

基本使用方法如下:

<code><strong>axios</strong>({ url: "https://open.feishu.cn/open-apis/bot/v2/hook/xxxxx", data:{ msg_type: "post", content: { post: { "zh_cn": { "title": "【通知】代码push通知,请注意测试", "content": [ [ { "tag": "at", "user_id": "all" }, { "tag": "text", "text": `\r\n【项目】${projectName}\r\n【提交人】${userName}\r\n【测试类型】${testType}\r\n-----------\r\n【更新内容】:\r\n${text}` } ] ] } } } } })</code>

Git webhook触发

大部分Git托管都支持webhook。设置简单,基本上是一个GET或POST接口。每次push或merge时,都会调用回调函数,自动发送消息到你的接口地址。

这时候,你需要一个Web服务。

通过腾讯云开发转发消息

我选择了腾讯云开发,因为它有免费版,减少了配置环境的麻烦。具体操作可参考我之前的文章《腾讯CloudBase入门》。

在腾讯云开发中新建一个云函数,命名为webhook。主要功能是接收参数。

<code>'use strict'; <strong>const</strong> {sendFeishu} =require('./request') exports.main = <strong>async</strong> (event, context) => { console.<strong>log</strong>(event) <strong>let</strong> res = {} <strong>try</strong> { <strong>const</strong> body = <strong>JSON</strong>.<strong>parse</strong>(event.body) res = <strong>await</strong> <strong>sendFeishu</strong>(body) } <strong>catch</strong> (error) { console.<strong>log</strong>('error: ', error); } <em>// console.log(context)</em> <strong>return</strong> res };</code>

request.js负责发送飞书通知。

最后完成的效果就是这样了,还挺不错的

const axios = require('axios')const Service = axios.create({  method: 'post'})const sendFeishu = function (body) {  const userName = body.pusher.name  const projectName = body.project.display_name  if (body.ref.indexOf('dev') === -1 || projectName !== 'web_baseline_v2') {    return true  }  const commits = body.commits  let text = ''  let testType = ''  if (commits && commits.length) {    for (const k of commits) {      text += `${k.message.replace(/(^\s*)|(\s*$)/g, '')};\r\n`      if (k.modified.length <= 2 && k.modified.includes('adjustKeys.config.js')) {        testType = '仅测试adjust'      } else {        testType = '完整测试'      }    }  }  console.log('text: ', text);  const data = {    "msg_type": "post",    "content": {      "post": {        "zh_cn": {          "title": "【通知】代码push通知,请注意测试",          "content": [            [              {                "tag": "at",                "user_id": "all"              },              {                "tag": "text",                "text": `\r\n【项目】${projectName}\r\n【提交人】${userName}\r\n【测试类型】${testType}\r\n-----------\r\n【更新内容】:\r\n${text}`              }              // {              //   "tag": "a",              //   "text": "Worktile地址:Test SE04-001",              //   "href": "https://gpower.worktile.com/mission/projects/5c64fe098b65046aa29ea321/tasks/5efdbf279e60b004e401ad1c"              // }            ]          ]        }      }    }  }  console.log('data: ', data);  return Service({    url: "https://open.feishu.cn/open-apis/bot/v2/hook/xxxx",    data  })}module.exports = {  sendFeishu}

© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容