前言

什么? 你不了解G2Plot? 没关系, 今天咱们要分享的内容和G2Plot的关系, 就像雷锋和雷峰塔的关系. 因此, 不必担心听不懂. 我一直觉得, 如果我写的文章有人看不懂, 那一定是我写的不够好. 而不是读者的问题.

业务背景

最近在使用G2Plot双轴图开发业务. 大概长下面这个样子.

既然要开发双轴图, 那么先看一遍文档是正常操作. 于是我就打开了他的官网, 看到了这样的一段话, 以及demo链接.

看完后似懂非懂, 这不有DEMO吗? 那我们就点击看看效果.

兄弟们! 好像不太对啊. 虽然我才刚刚开始看双轴图, 对它的业务不是特别了解. 但是我不瞎啊. 这标题不是写着面积图吗? 而且左侧分类也属于面积图. 好家伙, 在我眼皮底下狸猫换太子?

显然, 这是路由跳转有问题. 要不然我就提个PR帮他们改了吧. 这种链接错误、错别字的PR, 本来我是不屑提的. 但是不知道为什么, 冥冥之中就觉得这个PR和我八字相克, 那就不好意思了, 老夫今天就替天行道了!

找到链接错误之处

那么既然要提PR, 首先我得知道这个正确的链接应该是啥样的. 于是我观察了下面积图的第一个demo的链接

显然, 路由里面主要有3个部分area/basic#basic, area/basic其实大家都好理解, 为什么最后还要+个哈希参数呢? 简单思考后很容易想到, 因为basic下面有好多的例子, 不同的demo对应不同的哈希. 我们戳第二个demo试试看.

果然! 只有#后面的东西变化了. 接下来我们找到一开始时, 我们点击文档跳转的链接https://g2plot.antv.vision/zh/examples/dual-axes/dual-line显然, 就是少了哈希参数. 我们为其+上小尾巴应该就可以正常访问了.

大功告成! 接下来我们要做的就是找到源码中的跳转之处替换链接即可.

事情好像没有那么简单

打开github, clone仓库后, 搜索结果, 一气呵成. 接下来我要做的事情就是替换这个markdown中的地址. 一想到就这样轻轻松松的解决了一个bug, 我露出了邪恶的笑容.

等等! 我发现了什么!

这是个女孩子的名字?! 不对, 这不是重点, 重点是这样的写法居然是17个月前提交的? 如果说我刚刚+哈希路由的方式是正确的解法, 那么这个bug已经存在了17个月了!? 我继续翻阅着源代码. 发现了令人细思恐极的细节.

在19个月前, 同样有人使用了不带哈希值的路由写法. 为什么明明不正确的写法, 那么多人要用呢? 难道...难道他们在代码中下毒? 不对! 我唯一能想到的可能, 那就是他们的写法在当初是正确的!

想到这, 我的笑容凝固了. 所以我们来复盘一下. 如果一个路由链接dual-axes/dual-line, 缺少了哈希那一部分, 那么作者希望的正常表现是啥样的呢? 再看一下文档的描述

第一个demo链接是dual-axes/dual-line, 作者只是想表达这里是双轴折线图, 至于具体是哪种双轴折线, 重要吗? 不重要. 因此没必要指定哈希参数, 也就是具体的demo. 而第二个demo链接是dual-axes/column-line原理同上.

通过以上分析, 我们可以确定, 不带哈希参数的链接是合法的! 他默认应该定位二级菜单的第一个demo. 只是这个功能在后来的迭代中被改坏了.

你以为的真相只是你以为

按理说, 好不容易发现了真相, 我应该是无比的兴奋与开心的. 事实上, 确实很开心, 但是开心中又夹杂着抑郁. 开心是因为发现了更深层的原因, 而抑郁的点是"我咋知道他路由跳转是咋弄的? G2Plot又不是我开发的!"

我像刚刚奖励完自己一样呆坐在电脑前, 不知所措. 好不容易挖掘到的线索就此中断了. 突然间, 我的脑海中闪过几个antv产品的模样.

这几个antv产品, 不能说十分相似, 只能说一模一样. 等等! 一模一样? 难道说...又一个猜想浮现在我的脑海中: 这些网站的构建是不是用的同一套系统? 那么问题会不会和G2Plot没有半毛钱关系, 而是这个构建系统上?

想到这, 我迫不及待地打开了X6(蚂蚁金服的图编辑器, 反正也是个可视化项目), 随便点开了个示例, 观察他的URL结构.

好! 很好!! 非常好!!! 这个链接和我们前面的案例一样, 表现一切正常! 我屏住呼吸, 把哈希值去掉, 按下回车!

挖槽! X6也有这个问题! 这证明我的猜想没错! 他们师出同门, 一定是公共的网站构建体系出了问题! 事情变得越来越有趣了! 我们理一下思路, 从一开始的文档错误的方向一路推理到现在.

我撸起了袖子, 准备大干一场. 今天, 老夫就算拿出全部的本领, 掘地三尺也要把这个bug挖出来!

那么这个神秘的公共构建体系, 到底是在哪呢? 确实没什么想法, 但是不管他在哪里, 他总归要体现在运行时吧? 接下来, 我clone了G2Plot的仓库, 简单看了下项目结构, 这些目录一看就知道是干嘛的, 挺不错.

装好了依赖, 念出了咒语.

npm run start

接下来咱们故技重施, 看看效果.

还是原来的配方, 还是熟悉的味道. 只不过这次访问的是迷你图而不是面积图了. 再看一眼仓库文件

哦豁! 无中生有! 一眼就看到了public目录, 我在里面一顿搜寻. 发现只有一个看起来像双轴图的东西. 大几十个图表, 为什么只有双轴图呢? 难道是因为我刚刚访问过?

于是我随便点了个折线图, 再观察下目录

可以确定, 当我访问哪个类别的时候, 他就会生成该类别的page-data.json, 那么这到底是何方神圣呢? 我们打开dual-line/page-data.json, 看看他到底卖的什么药. 打开这个文件, 我们对其格式化后, 随便翻翻, 就能找到一个叫allDemos的东西. 通过名字可以判断, 好像是所有demo的集合.

再随便翻翻, 发现还有个exampleSections的东西, 看起来好像是该类别的所有demo.

等等! 再看一眼本地开发模式下的错误重定向页面

这个demo不就是allDemos里的第一个demo吗? 而他应该导向的地址, 不就是exampleSections.examples里的第一个demo吗? Soga! 那么我们可以推断, 当路由不带哈希值时, 构建系统应该读的是exampleSections.examples[0], 而不是allDemos[0]

有意思! 太有意思了! 现在我们来更新下咱们的破案手册.

锁定目标, 精准打击!

接下来, 我们得找找到底这个公共构建体系在什么地方? 我们翻看G2Plotpackage.json, 看看有没有啥线索.

"devDependencies": {
"@antv/data-set": "^0.11.5",
"@antv/gatsby-theme-antv": "^1.1.15",
"@babel/core": "^7.10.4",
"@babel/plugin-transform-runtime": "^7.11.5",
"@babel/preset-env": "^7.10.4",
"@babel/runtime": "^7.11.2",
"@commitlint/cli": "^8.2.0",
"@commitlint/config-angular": "^8.2.0",
"@types/jest": "^25.2.1",
"@typescript-eslint/eslint-plugin": "^2.0.0",
"@typescript-eslint/parser": "^2.0.0",
"all-contributors-cli": "^6.20.0",
"antd": "^4.8.4",
"babel-loader": "^8.1.0",
"chroma-js": "^2.1.2",
"conventional-changelog-cli": "^2.0.34",
"cross-env": "^7.0.2",
"eslint": "^6.1.0",
"eslint-config-prettier": "^6.0.0",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-prettier": "^3.1.0",
"gatsby": "^2.24.63",
"gatsby-plugin-webpack-bundle-analyser-v2": "^1.1.27",
"generate-changelog": "^1.8.0",
"gh-pages": "^3.1.0",
"husky": "^4.2.3",
"jest": "^26.0.1",
"jest-electron": "^0.1.7",
"jest-extended": "^0.11.2",
"jest-matcher-deep-close-to": "^2.0.1",
"limit-size": "^0.1.3",
"lint-md-cli": "^0.1.2",
"lint-staged": "^10.0.7",
"miz": "^1.0.1",
"npm-run-all": "^4.1.5",
"prettier": "^2.0.1",
"rc-for-plots": "^0.0.1",
"react": "^16.11.0",
"react-dom": "^16.11.0",
"react-i18next": "^11.7.0",
"rimraf": "^3.0.0",
"ts-jest": "^25.4.0",
"ts-loader": "^7.0.0",
"typescript": "^3.5.3",
"webpack": "^4.44.2",
"webpack-bundle-analyzer": "^3.9.0",
"webpack-cli": "^3.3.7",
"webpack-dev-server": "^3.9.0"
},

虽然密密麻麻的, 但是这里面绝大部分其实都是眼熟的. 咱们想一想, 这套构建体系可能是蚂蚁金服以外的人写的吗? 完全没有可能! 第一, 这个难度非常大, 一定要非常了解他们的需求才行. 第二, 我们都知道做开源是用爱发电的. 但是这样庞大的构建体系需要的电量极大, 如果不是拿着工资, 我想电量是不足以支撑的. 那么既然是蚂蚁的人写的, 那这个仓库最有可能是放在@antv下面的. 这样想来, 那么最有可能的就是下面这个了.

"@antv/gatsby-theme-antv": "^1.1.15",

然后我们去github上搜一下这个仓库

不仅可以搜到, 还不打自招了. 通过readme部分, 我们完全确认了这个货就是始作俑者! 接下来又开始头疼了, 我怎么调试呢? 要知道, G2并没有使用monorepo的方式去管理, 关于G2的架构, 我在之前的一篇文章中简单描述过, 在这里我就不赘述了. 感兴趣的可以访问: 使用antv/G2生态半年有感

在多仓库管理模式下, 也不是没有办法调试, 我们可以借助yalc. 但是我们都知道, 项目依赖是个神奇的东西, 坦白说, 把G2Plot跑起来就花了俩小时. 而这个构建系统gatsby-theme-antv我本地则是完全跑不起来.

什么? 你问我是什么开发环境? 既然你诚心诚意的问了, 那我就大发慈悲地告诉你吧.

论配置, 谁能与之一战? 但就是跑不起来. 似乎线索又断了...怎么办呢? 既然我们能把G2Plot跑起来, 要不然我们去G2Plotnode_modules里看看?

可以看到, 这个gatsby-theme-antv也是比较简洁的目录, 我们想要的东西应该就在这个里面. 我的预感告诉我, 我想要的东西大概率就在components文件夹里, 于是我就点开随便看了看

坦白说, 我不是这个项目的开发者, 我对这个项目是完全没概念的, 这真的非常艰难. 就算核心bug在某一个文件里, 对我来说也和大海捞针差不多了. 其实之前我们在分析的时候也数次遇到束手无策的情况. 每当这个时候, 我们要尝试转换思路, 不要在一棵树上吊死. 不管他的文件结构有多复杂, 最终不都得打包到一起吗? 所以我打开了G2Plot的控制台, 找到了commons.js, 我们想要找的东西, 一定在这49万行的代码中...

嗯, 49万行代码. 更绝望了...

于是, 我又去读node_modules里的源码了, 碰碰运气, 随便点几个文件到处看看, 边看边分析依赖关系和渲染逻辑. 于是, 我终于看到了下面这段代码:

其实我不是随便点开文件看的, 我是通过在common.js中打断点的方式找到这个地方的, 但是这个过程充满了试探与分析, 而且会在多个组件中跳来跳去, 又绕又繁琐. 所以就一笔带过吧~

兄弟们! 当我看见这段代码的时候, 比看见黑丝都兴奋呐! 这currentExample是啥? 从语义上来说, 就是当前展示的demo. 那么现在的问题不就是URL没有带哈希值的时候导致currentExample不对吗? 当然, 这只是我的猜想. 还需要更进一步的证据. 此时, 我利用react的dev-tool来查找这个PlayGrounds组件, 看看是不是渲染的部分.

哎, 只是个菜单组件啊? 不是渲染区域的组件啊...空欢喜一场. 等等! 就算渲染区域想正确渲染, 不也得保证左侧菜单选到正确的demo吗? 所以是不是可以理解为, 就是因为左侧菜单没有选到正确的demo, 才导致的渲染区域不是正确的demo? 好! 证据确凿, 严查PlayGrounds组件!

但稍加思考后我就确定了, PlayGrounds只是一个傀儡罢了, 他是接收currentExample的, 并没有权利决定currentExample是谁. 因此我们应该把矛头对准调用这个组件的地方.

这是真假美猴王吗? 区别就是有没有s? 不纠结了, 那么我们就开始探寻究竟在PlayGround组件中, 是如何定义currentExample的.

首先我们找到这个组件定义的地方, 看到他接收的参数包含了exampleSectionsallDemos. 很好! 非常好! 不出意外的话, 他会在某一个地方, 取allDemos的第一个元素, 所以我们在这个组件中搜一下allDemos[0]看看能不能搜到. 其实是搜不到的, 但是搜[0]却可以搜到.

其实这里的examples就是allDemos, 为什么这么说呢, 我们看看调用Playground的地方是如何传参的

看着这命名, 我悟了! 这波啊, 我愿称之为最强幻术! 其实通过打断点的方式, 也能确定这里的examples就是我们一开始看到的allDemos

接下来就好办了! 只要让读取的默认值取自exampleSections.examples即可!

然后我们保存后, G2Plot会重新触发HMR, 再试一下看看是否正常了

果不其然! 接下来就是给antv提PR了. 老夫花了一天的时间费了九牛二虎之力, 就改了2行代码...

真正的真相, 不得而知

突然, 我很好奇, 到底是什么原因, 导致这样的bug存在呢? 于是我通过git log查找到上一次更改这一行的人.

显然, 不是这次的提交导致的, 她只是优化了下写法, 我又往前翻了几十个commits, 发现其实从一开始, 就是examples[0]的写法.

看来, 我又错了...看着自己推演的过程, 我不禁开始思考, 问题到底出在哪?

我唯一能想到的, 就是构建系统的人, 一开始就是希望强制+上哈希路由的. 而后面写文档的人, 则是对此并不知情, 在写完文档后也没有去检查效果. 不知道这个推断是否正确, 但其实不重要了. 我的PR使得这种写法变得合法.

结语

其实这个过程还蛮有趣的. 从一开始以为是文档错误, 到化身侦探一路推理排查找到关键点. 其实这个和工作内容很像, 很多问题浮现出来的都是表面问题, 而解决表面问题其实并没有什么难度, 对症下药即可. 但是想要药到病除, 那是不现实的. 唯有多加思考、 推理、 分析, 找到核心问题所在, 从根本上解决问题才是一劳永逸的. 当然, 二者的成本差距也非常大. 依据实际情况抉择即可.


我是前夕, 专注于前端和成长, 希望我的内容可以帮助到你. 公众号: 前夕小课堂

本文禁止转载!

给蚂蚁金服 antv 提个 PR, 以为是改个错别字, 未曾想背后的原因竟如此复杂!的更多相关文章

  1. 2019 蚂蚁金服java面试笔试题 (含面试题解析)

      本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.蚂蚁金服等公司offer,岗位是Java后端开发,因为发展原因最终选择去了蚂蚁金服,入职一年时间了,也成为了面 ...

  2. 我是如何拿到蚂蚁金服 offer 的 ?

    阅读本文大概需要 5.6 分钟. 作者:翟洪毅 一.梦想和被拒 二.积累 三.结语   首先介绍一下投稿作者 翟洪毅,16年华理计算机本科毕业.在年前拿到了蚂蚁金服Java开发的offer,P6. 工 ...

  3. 蚂蚁金服新一代数据可视化引擎 G2

    新公司已经呆了一个多月,目前着手一个数据可视化的项目,数据可视化肯定要用到图形库如D3.Highcharts.ECharts.Chart等,经决定我的这个项目用阿里旗下蚂蚁金服所开发的G2图表库. 官 ...

  4. 蚂蚁金服缘何自研Service Mesh?

    2018年,微服务方兴未艾,Service Mesh(服务网格)又快速崛起.有观点认为,2018年可被称之为“Service Mesh元年”,在未来两年中,Service Mesh将迎来爆发式增长,成 ...

  5. 蚂蚁金服研发的金融级分布式中间件SOFA背后的故事

    导读:GIAC大会期间,蚂蚁金服杨冰,黄挺等讲师面向华南技术社区做了<数字金融时代的云原生架构转型路径>和<从传统服务化走向Service Mesh>等演讲,就此机会,高可用架 ...

  6. 蚂蚁金服SOFAMesh在多语言上的实践

    在用一项技术前,一定要知道它的优点和缺点,它的优点是否对你有足够的吸引力,它的缺点不足你是否有办法补上.黄挺在CNUTCon全球运维大会上的分享也很不错. 黄挺,蚂蚁金服高级技术专家,蚂蚁金服分布式架 ...

  7. 蚂蚁金服 Service Mesh 实践探索

    SOFAMesh是蚂蚁金服在ServiceMesh方向上的探索,下面是它高级技术专家敖小剑在QCon上海2018上的演讲. Service Mesh 是一个 基础设施层,用于处理服务间通讯.现代云原生 ...

  8. 天下代码一大抄,整个案例的搬是什么鬼!疑似冒充蚂蚁金服高级Java开发工程师?你大爷

    写在开始 上班前的第一件事,就是码云看看有什么消息,回复下网友的问题.如果看到喜欢的项目会点进去瞅瞅,然后就开始一天的工作. 然而,这一天的工作并不开心,一个今日热门项目让自己很恼火,一开始感觉并没有 ...

  9. 最新 蚂蚁金服java校招面经 (含整理过的面试题大全)

    从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.蚂蚁金服等10家互联网公司的校招Offer,因为某些自身原因最终选择了蚂蚁金服.6.7月主要是做系统复习.项目复盘.Leet ...

  10. 胡喜:从 BASIC 到 basic ,蚂蚁金服技术要解决两个基本的计算问题

    摘要: 揭开 BASIC College 神秘面纱,蚂蚁金服首次揭秘人才培养机制. 导读:5 月 6 日,蚂蚁金服副 CTO 胡喜在 2019 年 QCon 上做了<蚂蚁金服十五年技术架构演进之 ...

随机推荐

  1. 继续总结Python中那些简单好用的用法

    上一篇文章Python中那些简单又好用的特性和用法发出后,群里的小伙伴又给补充了几个好用的用法,结合生产实用经验汇总整理如下,各位看官如有需要请自取 反射,反射是一种机制,可以在运行时获取.检查和修改 ...

  2. MySQL 双主集群搭建

    搭建 MySQL 双主集群涉及多个配置步骤,以及对于可能出现的问题的理解和解决.下面将详细说明搭建过程的每个步骤. 前提条件 环境准备:准备两台服务器(物理或虚拟),并确保它们可以互相通信(例如,通过 ...

  3. Java取当前时间的一分钟后,并格式化输出

    1.Java1.8 以前 Calendar instance = Calendar.getInstance();//获取当前日期时间 instance.add(Calendar.MINUTE,1);/ ...

  4. L7结合Turf.js实现空间分析与数据可视化

    1. 概述 AntV L7 是蚂蚁集团 AntV 数据可视化团队推出的基于 WebGL 的开源大规模地理空间数据可视分析引擎,其特点是通过简单的代码进行配置,即可在前端网页中绘制精美的地图以及相关的图 ...

  5. 记录--vue3+setup+ts 知识总结

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 vue3 于 2020 年 09 月 18 日正式发布,2022 年 2 月 7 日 vue3 成为新的默认版本 距离 vue3 正式发布 ...

  6. Word文档最后一页空白页中换行符无法删除

    Word文档最后一页空白页中换行符无法删除 问题如题: 尝试了delete.backspace.backspace+delete都不行. 找到了这个方法: 选中最后一页的换行符,然后段落--间距--行 ...

  7. 我们正在被 DDoS 攻击,但是我们啥也不干,随便攻击...

    最近,一场激烈的攻防大战在网络世界悄然上演. 主角不是什么国家安全局或者黑客组织,而是一家名不见经传的创业公司--TablePlus. DDoS 攻击者们摩拳擦掌,跃跃欲试.他们从四面八方蜂拥而至,誓 ...

  8. 《写给程序员的Python教程》阅读随笔---python禅学(Zen_of_python)

    Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Comp ...

  9. GraphQl in ASP.NET Core

    GraphQl in ASP.NET Core https://graphql.cn/ https://graphql-dotnet.github.io/docs/getting-started/ar ...

  10. vue阻止冒泡事件 阻止点击事件的执行 结合div和组件阻止点击事件

    vue阻止冒泡事件 阻止点击事件的执行 <div @click="alerA1()" > <div @click.stop="alerA2()>& ...