likes
comments
collection
share

为什么就这个文件的 ESLint 检查失效了?

作者站长头像
站长
· 阅读数 11

最近写代码遇到一件烦心事儿。

项目临近上线,来了几个大需求,其他人要么忙,要么 hold 不住,只能我硬着头皮上。

要改内部的一个最核心的组件包,虽然之前我都做过很多这个包的需求了,但是因为这块真的很复杂,很多时候我都需要重新看代码。

这次改的这部分,核心组件 3000+ 行,总行数近 10000 行。

问题就在于,我的项目中其它文件的 eslint 都是正常的,唯独这个核心文件的 eslint 崩了,整个文件功能非常复杂,这种地方的代码,改一处就牵一发动全身,导致很多莫名其妙的问题。

问题来了,我的需求每次都是大改。。。

我这人稍微有点代码洁癖,if 里的代码一多,就想着拆出来,这不拆不要紧,拆了问题一大堆。

其他文件因为有 eslint 检查,有点问题就提示了,但是这个文件很奇怪,eslint 不检查!!

我改动面积又大,每次手动检查完没有问题了,我就推分支上去打包,打完包部署线上再一看,功能又不生效。

就这样人肉检查了很久,代码推了好几个版本,但是因为改动比较大,人肉检查疏漏还是很多,拆出来的代码很多时候不在原来的作用域了,找不到对应的声明,就报错走不下去了。

一直改到差不多了,改到最后代码也没报错,但是功能还是没生效,最关键的是,我打的 console.log 也没出来!

这难搞哦。

那原因到底是啥呢?

问题1:代码没报错,console.log 为啥不执行?

这里其实原因很简单,因为我习惯使用可选链操作符 ?.,这能有效防止属性不存在时代码报错导致线上白屏。但是正是因为这个操作符,导致我错误代码没报错,又不往下执行,所以我的功能不生效,打的 log 也出不来。

那这和 ?. 到底啥关系?为啥没有属性你还访问呢?

前面提到,我把打码拆出来了,因为以前都是挤在一个 if 分支里,代码非常臃肿,这回还加功能,更加臃肿了,所以不得不拆。但是拆出来的代码重新组成一个函数,代码都是复制粘贴的,不在原来的作用域后,代码自然报错了。加上我 eslint 刚好在此文件里失效了,没有提示,我遗漏了好几个变量,导致此次问题的产生。

那解决办法是啥呢?

办法1:不要写 ?. 操作符,有问题就暴露(这要是线上直接白屏了,算生产事故了就)。

办法2:最外层加一个 try catch,捕获一下代码报错。

最后呢就是采用了方案2,发现了几个隐秘的变量,最终功能正常上线。

不过,我气不打一处来,这凭啥和你同级的组件文件都能被检查,就你不行???要是有检查,我也不至于耽误那么多功夫。这必须得查个清楚。

问题2:为什么 eslint 检查会单独在此文件失效?

其实 eslint 已经很早就把问题暴露给我了,每次我在 commit 时,git hook 都会执行 eslint --fix,但是每次都报了下面的这个错误。

为什么就这个文件的 ESLint 检查失效了?

这个报错的意思似乎是说某段代码是 unreachable,也就是不能到达的意思。

不能到达是指?暂时不知道,但是我需求紧急诶,不想管,我只想尽快提测。

怎么解决呢?我一般直接 git commit -m 'feat: xxxx' --no-verify,加一个 --no-verify 参数也就忽略了检查。

但是就是因为每次都忽略,导致我没有去仔细检查代码,追溯 eslint 失效的原因,导致我问题代码上线运行,功能不生效。

那回到标题,为什么 eslint 在其它文件都生效,为啥就这个文件不行?

那么我的排查思路来了。

排查文件首行是否存在禁用注释

可以在代码的最顶部通过注释 /** eslint-disabled */ 来对该文件进行 eslint 全局禁用。

但我检查了之后,并没有发现,那看来不是这个原因。

此类注释还可以单独针对某一条规则进行禁用,例如,我写了一个表达式,用了下划线:__test_url__,这时候 eslint 会报错,我既不希望它在此处校验我的代码,也不希望在配置文件里禁用该规则 —— 因为可能其他人需要该规则,我就可以使用注释对该条 eslint 规则进行禁用。

例如:

/** eslint-disabled no-underscore-dangle */
const testURL = window.__test_url__;

如果将注释放在文件最顶部,则对整个文件都生效,该条规则在整个文件中将被禁用。

排查 .eslintignore 文件是否忽略了本文件

如果不希望 eslint 对某些文件进行代码检查,我们配置忽略文件:.eslintignore。写法和其它的 ignore 文件是一样。

build/
dist/
lib/
...

但是我并没有在此文件中看到相关的配置。

不过既然都讲到这里了,顺带讲讲这个配置规则是怎么写的。

一般我们的 ignore 文件都是配置在根目录下的,不管你是 gitignore 还是 eslintignore

但是其实这些忽略文件,我们可以写在任意位置,它查找匹配的位置一般是基于其所在位置进行,也局限在其所在目录范围

记住这个特性,虽然一般没人会将配置文件放在目录内部,但是这对理解此类配置文件很关键。

我们就假设都是配置在根目录下。

如果直接书写一个单词,那么意思就是匹配文件及文件夹,不管你层级嵌套多深。

这里会命中 lib 同名的文件夹及文件,且不管你层级多深,只要你在这个项目里都给你命中。

为什么就这个文件的 ESLint 检查失效了?

如果是书写类似 /lib 的规则,那么其匹配的是 lib 文件夹下的所有文件。那其它目录,例如什么 a/libb/libc/libd/lib 的文件夹或者文件则不会去匹配。

为什么就这个文件的 ESLint 检查失效了?

那如果我书写的规则就是 a/lib 呢?那它匹配的就是 a 目录下的 lib 文件夹下的所有文件。

为什么就这个文件的 ESLint 检查失效了?

如果我书写的规则是 lib/ 呢?那它会匹配项目下所有名为 lib 的文件夹。

为什么就这个文件的 ESLint 检查失效了?

那还有类似 *** 的匹配规则,这种匹配规则在很多配置里都是很常见的,* 差不多可以理解为任意文件名,** 则能理解为任意层级,匹配多级文件夹。

为什么就这个文件的 ESLint 检查失效了?

为什么就这个文件的 ESLint 检查失效了?

问题到底出在哪里呢?

既然能排查的点都查了,到底问题出在哪里呢?

当我白丝(百思)不得其姐(解)的时候,我忽然想到 unreachable 这个报错。

eslint 是静态分析,本质上也是 AST 语法树,靠词法来分析代码的错误,那它说不可到达,也就是说,eslint 去解析代码的时候,发现了一些它不认识的代码,导致他解析不通过。

另一个支撑这个观点的现象是,我看到项目里的 eslint 还是 4 的大版本,而现在的最新版都已经是 8 了,加上最近在项目里用了类似 ?? 操作符,很多新语法,极有可能是新语法导致的。

所以为了验证猜想,我立即升级 eslint 至最新版,果然!代码检查出现了,文件里一堆报红,可喜可贺。

但是代码提交还是遇到了问题,为什么呢?eslint 太新了,但是配套的插件之类的没有更新,版本跨度过大,导致 eslint 和插件之间的配合出现了问题。

怎么办呢?

那当然就是渐进升级啦,先试试 5 的大版本是否可行。

下载大版本 5 后代码检查出现,代码提交也正常,完美解决问题!

写在最后

如果你在网上搜这个问题的答案,几乎清一色都是告诉你执行 --no-verify 参数,但是没人告诉你真正的解决办法。然后这种答案治标不治本,希望我的文章对你解决问题有所帮助。

敬请三连~

欢迎加群

最近新建了一个前端交流群,群里目前都是我的朋友,基本都是高学历的刻苦人士,个个都能带你卷~

群里写 ReactVueNode 的小伙伴都有,大多是两三年经验的同学,群里很希望有新鲜血液融入。

群里还很需要一位资深的前端大佬坐镇,有没有大佬愿意来指教一二的?

欢迎大家加入。

关注我,后台私信 VX 二维码拉你进群。

往期推荐