Tips又更新啦!要来看看吗~

前言

Tips的重大更新又来了,如果不知道Tips是什么的你,可以移步这里Tips——将你从频繁的文案修改中解救出来,如果看过这篇文章或者使用过这个平台的,那就可以直接往下看了。今天将向大家介绍Tips的新功能——自动埋点,之前如果想要使用Tips都是手动在代码中埋点,现在可以使用我们提供的cli工具,使用简单的命令就可以自动埋点,然后就可以去修改你的文案了。感兴趣的你可以继续往下看哈,我将从如下几个方面来进行介绍。

1 设计初衷

如果使用过工具或看过之前的文章,你可能会因为如下几个问题而被劝退。

问题一

在平台创建了服务后,需要手动在自己的项目中进行埋点,任何文案都有被修改的可能,所以需要大量的埋点,无疑该操作是浪费时间的,所以可能因为手动埋点这个操作你放弃了这个便利的工具。

问题二

你接入平台的时候在第一次可能埋了大量的点,但是下次需要修改的并不是你之前埋点处的文案,你还需要在自己的代码中重新埋点,然后发起上线流程,重新打包上线,所以可能觉得这个平台并不能很好的解决目前遇到的问题而放弃使用它。

综上两个原因,就需要一个自动埋点的工具,代替手动埋点,从而进一步降低使用成本。

2 工具形态

首先Tips的使用方式就是在前端HTML标签上绑定特殊属性data-tip-id-"xxx",我们要实现的就是在标签上自动加上这个特殊属性。如下代码段所示:

<span>我是一个按钮</span>
埋点后变成
<span data-tip-id="xxx">我是一个按钮</span>

实现如上这个过程,我想很多人都想到了Babel,它可以帮我们去做这个工作,也就是需要去实现一个Babel Plugin来解析抽象语法树并修改节点。但是只有Plugin还是不够的,我们还要考虑到,如下几个问题:

  • 插件应该在什么时候触发去执行埋点操作

这个过程应该成为用户可控的,所以最合理的应该是用户自己去手动触发,所以就需要一个简单的命令行工具,用户执行相关命令去触发埋点操作。

  • 什么样的文件需要埋点,什么样的不需要

在项目中文件类型是多种多样的,就前端项目来说,我们的代码都在src目录下,但是也并不是所有的文件都需要被扫描埋点,因次就需要提供一个config文件来配置用户自己的埋点规则,比如埋点的入口和需要忽略的文件。

综上两个原因我们需要的是一个Babel Plugin + cli这样的工具。

3 如何实现

上面已经确定了工具的形态,接下来的重点就是如何实现了。下面将按照用户的使用流程来慢慢展开。其实也很简单,就是两步。

工具初始化
// 初始化配置文件
 fs.writeFileSync(
   './tips.config.js',
   prettier.format(
     `module.exports = ${JSON.stringify({
        entry: 'src',
        exclude: [],
      })}`,
      {
       parser: 'typescript',
       singleQuote: true,
       trailingComma: 'es5',
     }
   ),
   'utf8'
 );

在上面的示例代码中我们创建了一个名为tips.config.js的文件,在文件中配置了简单的埋点入口和忽略文件选项,然后将它写入当前项目中。这样就完成了初始化操作,用户可以去修改这个文件来配置简单的埋点规则。

开始埋点
const prettier = require('prettier');
const parser = require('@babel/parser');
const traverse = require('@babel/traverse');
const generate = require('@babel/generator');
const buryPointPlugin = require('../plugin');

function buryPoint(filePath, options) {
  const fileContent = fs.readFileSync(filePath, 'utf-8');
  const ast = parser.parse(fileContent, {
    sourceType: 'module',
    plugins: [
      'typescript',
      'jsx',
    ],
  });
  traverse(ast, buryPointPlugin());
  let { code } = generate(ast, {});
  code = prettier.format(code, options.prettier);
  fs.writeFileSync(filePath, code, { encoding: 'utf-8' });
}

在上述代码中:

  • 首先用@babel/parserparse方法,并结合现成的babel plugin,来将需要转换的代码文件转换为AST(抽象语法树)
  • 然后用@babel/traverse来遍历该语法树,并利用buryPointPlugin来修改AST,将它改为想要的样子,也就是在JSX节点上加上data-tip-id属性;
  • 最后使用@babel/generator来将AST转化为最终的代码。
buryPointPlugin做了什么
const t = require('@babel/types');
// 构造属性节点
function buildAttribute(t, id) {
  return t.jsxAttribute(t.jSXIdentifier('data-tip-id'), t.stringLiteral(id));
}

// 构造openElement节点
function buildTipsIdAttributeOpeningElement(path, t, id) {
  let buildTagAttributes = path.node.attributes;
  return t.jSXOpeningElement(
    path.node.name, // object: JSXMemberExpression | JSXIdentifier
    buildTagAttributes,
    path.node.selfClosing // 是否自闭合,不设的话默认为false,需要根据标签原有特性去设置
  );
}

module.exports = function() {
  return {
    JSXOpeningElement: (path) => {
      const children = path.parent.children;
      const tipsUniqId = `${getSeconds()}-${_.uniqueId()}`;
      const newOpeningElement = buildTipsIdAttributeOpeningElement(path, t, tipsUniqId);
      path.replaceWith(newOpeningElement);
    },
  }
}

上述是最核心的一部分代码,也就是构造带有data-tip-id的新节点去替换原来的节点。有同学可能要问了,我怎么知道自己构造的节点类型需要哪些属性,其实这些都可以去babel官网查看。所以写插件时的重点工作应该是确定插件要做的事,然后将源语法树,修改为目标语法树,在这里推荐一个很好用的工具,可以很方便的查看语法树的结构:查看工具

4 如何定制规则

用过Tips的都知道,我们在编辑文案的时候会在页面上看到红色的编辑按钮,如果不做埋点控制,那么打开开关你将会看到满屏的红色按钮,那体验简直是灾难性的。所以在扫到的代码中,并不是所有的标签都需要埋点,所以需要定义一些特殊的规则,避免埋太多的无用点。这些规则考虑到通用性和实现的复杂度的问题,并没有开放在用户的配置文件中。

如下是所有的不埋点情况:

  • 1 标签的子节点只有JSXElement
<div>
  <span>我的父元素不埋点</span>
  <span>我的父元素不埋点</span>
</div>
  • 2、标签的子节点只有CallExpression
<div>{render()}</div>
  • 3、标签的子节点只有ConditionalExpression
<div>{a ? <span>我是真</span> : <span>我是假</span>}</div>

4、标签的子节点只有LogicalExpression

<div>
  {
    a && <span>我是真</span>
  }
</div>
  • 5、标签有特殊属性tips-bp-ignore的不埋点
<div tips-bp-ignore>
  我是被忽略的标签,不埋点
</div>

5 如何使用

说了这么多,那究竟如何使用呢?请往下看。

下载
npm i tips-burypoint-cli --save-dev
初始化
tips-bp init

初始化生成tips.config.js文件,可进行相关配置。

开始埋点
tips-bp start

6 总结

在上述总结了Tips自动埋点工具的整个实现过程, 也附上了一些插件的实现源码,可以看到具体的coding并不难,难的是整个设计和思考的过程,感谢团队小伙伴给的改进建议,文章就写到这里,目前工具已经上传在npm上,希望有需要的你可以试着用用哈。

具体如何使用,请戳这里:https://github.com/didi/Tips

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,002评论 6 509
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,777评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,341评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,085评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,110评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,868评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,528评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,422评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,938评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,067评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,199评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,877评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,540评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,079评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,192评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,514评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,190评论 2 357

推荐阅读更多精彩内容