全国免费咨询:

13245491521

VR图标白色 VR图标黑色
X

中高端软件定制开发服务商

与我们取得联系

13245491521     13245491521

2024-07-23_我写了一个ESLint插件,解决了团队棘手问题

您的位置:首页 >> 新闻 >> 行业资讯

我写了一个ESLint插件,解决了团队棘手问题 ?本文为稀土掘金技术社区首发签约文章,30 天内禁止转载,30 天后未获授权禁止转载,侵权必究! ?点击关注公众号,“技术干货”及时达!在工作中,我们沉淀了一些最佳实践,一般工作中的一个项目可能由多个开发者负责,在这样的背景下,很难做到每个开发者对最佳实践都了然于胸,在遇到人员更迭的时候,就更难受了。 虽然可以通过代码审查发现问题,但是代码审查存在两个问题:一个是滞后问题,代码审查时已经开发完了;另一个是靠人来审查,难以 100%保证质量。 如何保障团队代码风格,最佳实践的一致性,让代码看起来就是一个人写的,本身就是一个难题。 如果能有一个智能助手,实时提示代码中的哪些部分可以使用工具库中的函数代替就好了。对于前端来说,这个助理就是 ESLint。 那么如何让 ESLint 支持我们的最佳实践呢,这可以通过 ESLint 的自定义插件来实现。要开发 ESLint 插件需要一些知识储备和经验,本文我将通过一个实例来教大家如何写一个 ESLint 插件。 本文通过一个真实案例来讲解,这个案例来源于我的实际工作,通过编写 ESLint 插件,并集成到项目,帮我解决了最佳实践的推广落地问题。 背景知识下面先来介绍下背景知识,在我之前的文章《破解面试题,在 JavaScript 中如何判断变量类型?》中,提到过使用 typeof 和 instanceof 来判断变量类型是存在很多坑的,不信你看下面的例子,如果你对这个问题感兴趣,欢迎阅读我上面的文章: typeof//'object' typeof//'object'typeof//'object' []instanceofArray//true []instanceofObject//true注意这里 下面将写两个 ESLint 插件来解决对上面两个问题的校验。 插件创建 ESLint 插件,ESLint 推荐使用 Yeoman generator。首先需要安装 Yeoman,安装命令如下: $npmi-gyo Yeoman 是一款通用的初始化工具,想要初始化 ESLint 插件,需要安装 ESLint 模板,安装命令如下: $npmi-ggenerator-eslint 接下来,新建一个目录,目录名字按照自己喜好就行,命令如下: $mkdireslint-plugin-utils 切换到上面新建的目录,执行“yo eslint:plugin”命令会进入交互界面,询问作者、插件名字等,输入如图所示的内容即可。 稍等片刻即可完成自动初始化,初始化成功后的目录结构如下所示。其中,lib/rules 目录存放自定义规则,tests/lib/rules 目录存放规则对应的单元测试代码。 . ├── .eslintrc.js ├── README.md ├── lib │ ├── index.js │ └── rules ├── package-lock.json ├── package.json └── tests └── lib └── rules ESLint 推荐使用测试驱动开发,要求每个规则都有完整的单元测试。 type-typeof-limit使用 typeof 操作符判断一个变量为对象时可能存在问题,如下面的 3 行代码都返回 true: typeof{}==='object'; typeof[]==='object'; typeofnull==='object'; 下面写一个新规则,当发现“typeof * === 'object'”时给出报错提示。首先使用“yo eslint:rule”命令新建一个规则,在询问界面中输入如图所示的内容。 完成上述操作后,会生成两个文件,分别是 lib/rules/type-typeof-limit.js 和 tests/lib/ rules/type-typeof-limit.js。打开前一个文件,其内容如下: module.exports={ meta:{ type:null,//`problem`,`suggestion`,or`layout` docs:{ description:'typeof不能用于对象和数组,请使用@jsmini/type', category:'Fillmein', recommended:false, url:null,//URLtothedocumentationpageforthisrule }, fixable:null,//Or`code`or`whitespace` schema:[],//Addaschemaiftherulehasoptions }, create(context){ return{ //visitorfunctionsfordifferenttypesofnodes }, }; 其中,meta 是规则的元数据,这里需要关注的字段的含义如下,更多字段可以查看 ESLint 官网。 type:规则的类型,problem 代表报错,这里需要将 type 的值修改为 problem。docs:存放规则文档信息。description:指定规则的简短描述,需要填写。category:指定规则的分类信息,包括 Possible Errors、Best Practices、Variables 等,这里可以填入 Best Practices。fixable:表示这个规则是否提供自动修复功能,当其值被设置为 true 时,还需要提供自动修复的代码。create 函数里面是具体的逻辑,其返回一个对象,该对象的属性名表示节点类型,在向下遍历树时,当遍历到和属性名匹配的节点时,ESLint 会调用属性名对应的函数。例如,我们要写的这个规则的 create 函数如下,其含义是每次遇到 BinaryExpression 节点,都会调用传递给 BinaryExpression 属性的函数。 module.exports={ create(context){ return{ BinaryExpression:(node)={}, }, }; 现在读者可能还不理解 BinaryExpression 的含义,这里需要介绍 ESLint 的原理。ESLint 会将每个 JavaScript 文件解析为抽象语法树(Abstract Syntax Tree,AST),简称语法树。ESLint 官网提供了一款工具,可以查看指定代码解析后的 AST。例如,下面的代码: typeofa==='object'; ESLint 解析上述代码后会返回一个嵌套的 AST,每个节点中的 type 属性表示当前节点的类型,观察下面的 AST,上面的判断表达式可以用下面的逻辑来判断: BinaryExpression 节点。left.operator 为 typeof。operator 为===或==。right 为 Literal,并且 value 为 object。ESLint 会把 JavaScript 代码解析为 AST,该 AST 使用 JSON 格式表示的代码如下: { "type":"Program", "start":0, "end":21, "body":[ { "type":"ExpressionStatement", "start":0, "end":21, "expression":{ "type":"BinaryExpression", "start":0, "end":21, "left":{ "type":"UnaryExpression", "start":0, "end":8, "operator":"typeof", "prefix":true, "argument":{ "type":"Identifier", "start":7, "end":8, "name":"a" } }, "operator":"===", "right":{ "type":"Literal", "start":13, "end":21, "value":"object", "raw":"'object'" } } } ], "sourceType":"module" } ESLint 遍历到 BinaryExpression 节点后会执行传递给 BinaryExpression 属性的函数,并将 BinaryExpression 节点传递给这个函数,然后进行上面的逻辑判断,如果为 true,则使用 context.report 报告错误。示例代码如下: module.exports={ create(context){ return{ BinaryExpression:(node)={ constoperator=node.operator; constleft=node.left; constright=node.right; if( (operator==='=='||operator==='===')&& left.type==='UnaryExpression'&& left.operator==='typeof'&& right.type==='Literal'&& right.value==='object' ){ context.report({ node, message:'typeof不能用于对象和数组,请使用@jsmini/type', } }, }, }; 前面提到了 ESLint 推荐使用测试驱动开发,上面的代码可以通过写单元测试来快速验证结果,修改 tests/lib/rules/type-typeof-limit.js 文件中的内容如下,其中包括三个单元测试:一个合法的单元测试和两个非法的单元测试。 construle=require('../../../lib/rules/type-typeof-limit'), RuleTester=require('eslint').RuleTester; constmsg='typeof不能用于对象和数组,请使用@jsmini/type'; construleTester=newRuleTester(); ruleTester.run('type-typeof-limit',rule,{ valid:[{code:'typeofa=="number"'},{code:'a=="object"'}], invalid:[ { code:'typeofa=="object"', errors:[ { message:msg, }, ], }, { code:'typeofa==="object"', errors:[ { message:msg, }, ], }, ], }); 写好单元测试后,执行“npm test”命令即可运行测试,如果看到如图所示的输出,则表示单元测试通过了。 下面在真实实验环境下新建插件,由于我们的插件还没有发布,因此需要通过 link 的方式使用。 首先在插件目录下执行如下命令,这会将本地的插件链接到本地的 npm 全局目录。 $npmlink 新建一个空项目 eslint-plugin-utils-demo,并初始化 ESLint 配置,接下来,在 eslint- plugin-utils-demo 根目录下执行下面的命令,这会在 node_modules 目录下创建一个软链接。 $npmlink@jsmini/eslint-plugin-utils 接下来,修改 eslint-plugin-utils-demo 根目录下的.eslintrc.js 文件,添加如下代码: module.exports={ plugins:['@jsmini/utils'], rules:{ '@jsmini/utils/type-typeof-limit':2, }, }; 在本地新建一个 xxx.js 文件,并在该文件中输入如下代码: typeofa==='object'; 如果能够看到如图所示的红色波浪线,当将鼠标指针悬停到波浪线上时,显示如图所示的错误信息,则表示成功了。 type-instanceof-limit参考上面 type-typeof-limit 插件的内容,可以实现校验如下的代码: ainstanceofObject; 新建一个名字为 type-instanceof-limit 的插件,这部分就不再展开介绍了,该插件的核心代码如下: module.exports={ create(context){ functioncheck(node){ constoperator=node.operator; if(operator==='instanceof'){ context.report({ node, message:'instanceof操作符可能存在问题,请使用@jsmini/type', } } return{ BinaryExpression:check, }, }; recommended现在已经有 2 个规则了,随着规则的增多,需要用户手动修改 rules。ESLint 配置示例如下: module.exports={ plugins:['@jsmini/utils'], rules:{ '@jsmini/utils/type-typeof-limit':2, '@jsmini/utils/type-instanceof-limit':2, }, }; 其实插件可以提供推荐的配置,类似 eslint:recommended,用户直接使用推荐的配置即可。修改 lib/index.js 文件中的 exports,添加 configs 配置,示例代码如下: module.exports={ rules:requireIndex(__dirname+'/rules'), configs:{ plugins:['@jsmini/utils'], rules:{ '@jsmini/utils/type-typeof-limit':'error', '@jsmini/utils/type-instanceof-limit':'error', }, }, }; 接下来,用户就可以直接像下面这样使用,而不需要单独配置 plugins 和 rules 了。 module.exports={ extends:['@jsmini/utils:recommended'], }; 总结在本文中,我们探讨了如何通过编写自定义 ESLint 插件来保障团队代码风格和最佳实践的一致性。我们首先介绍了 ESLint 插件开发的背景知识,然后详细讲解了如何使用 Yeoman generator 创建 ESLint 插件。通过具体案例,我们编写了两个 ESLint 插件:type-typeof-limit 和 type-instanceof-limit,并展示了如何在项目中集成和测试这些插件。此外,我们还讨论了如何为插件提供推荐配置,以简化用户的配置过程。 通过这些步骤,我们可以确保团队代码风格统一,减少代码审查中的问题,提高代码质量。 欢迎大家阅读和分享这篇文章,如果有任何疑问或建议,欢迎在评论区留言。感谢大家的支持和阅读! 点击关注公众号,“技术干货”及时达! 阅读原文

上一篇:2022-11-12_「转」从Velodyne的没落,看激光雷达的「冰火两重天」 下一篇:2023-09-06_硅谷工程师年薪曝光,谷歌工程师平均年薪134万!

TAG标签:

17
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设网站改版域名注册主机空间手机网站建设网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。
项目经理在线

相关阅读 更多>>

猜您喜欢更多>>

我们已经准备好了,你呢?
2022我们与您携手共赢,为您的企业营销保驾护航!

不达标就退款

高性价比建站

免费网站代备案

1对1原创设计服务

7×24小时售后支持

 

全国免费咨询:

13245491521

业务咨询:13245491521 / 13245491521

节假值班:13245491521()

联系地址:

Copyright © 2019-2025      ICP备案:沪ICP备19027192号-6 法律顾问:律师XXX支持

在线
客服

技术在线服务时间:9:00-20:00

在网站开发,您对接的直接是技术员,而非客服传话!

电话
咨询

13245491521
7*24小时客服热线

13245491521
项目经理手机

微信
咨询

加微信获取报价