前言
本篇文章主要围绕如何正确的实现一个合格的npm
包的教学。不会在具体的代码实现上花太多的时间。定位是偏授渔风格的,主要是让同学们知道如何该正确的处理代码实现以外的一些工作。有兴趣的小伙伴,可自行前往参考 monitor-event-emitter,麻雀虽小,五脏俱全。demo 在控制台可演示每次事件处理器执行时的日志信息。
背景
今年的目标之一是想深入学习下 Typescript
。
之前一直是以vue
技术栈为主,去年公司开始用react
antd
typescript
开发一个新后台。这对于一直以来习惯了javascript
松散类型的我,是一个不小的挑战。很多时候,习惯性的用any
去规避一切问题。现在回过头来看之前的一些业务代码,飘红一片,自己都禁不住的嫌弃
我不禁开始思考之前学习typescript
的方式,大部分都是停留在看的阶段。官方文档也好,技术文献也罢,看了一大堆,到最终自己实操的时候还是捉襟见肘
所以我决定痛改前非,准备尝试自己用 typescript
写一个库。正好,之前接触的业务代码中,经常能看到一个之前我司大牛用javascript
写的事件触发器,所以准备着手推翻重新用typescript
实现一遍。一来是为了加深对 typescript
的理解和运用,二来是为了弥补很长时间以来,没有技术输出的空缺,同时寄希望于丰富下该库的功能
千好万好,不如动手撸一遍好
概述
由于涉猎的面比较广,对于一些老生常谈的东西,我会一笔带过。对于一些难以理解的点,可以参考 git commit 提交记录看我做了哪些工作,有兴趣的且不明白的地方可自行前往查阅官方文献。并且有些东西,我可能也是第一次接触,所以说的不对的地方,还请见谅。请给我多一些温柔
认真看完这篇文章后,我相信你一定能够有所收获,主要有以下几点
- 大局观 知道从零开发一款属于自己的库的必经之路
- 工程化思想 知道除了写功能代码,还有哪些是你必须要去关注和实现的工程化配置,它们将反哺你进行更加规范和标准的开发
- 如何去写一个比较规范的文档
- 了解一些有意思的技术点
- excalidraw 手绘风格设计图,风格别具一格,程序猿必备
- github action 大厂出品,必属精品。平时可以几行代码很多实现有意思的事,写博客必备
- shields.io 让自己的库看起来更加正式的图标设计库
实现
第一步:创建项目
没什么好说的,先创建一个仓库,这里由于后面我们写的库要发布到npm
官网上,让其他人可以自由的下载和使用,所以重点是起一个好名字,何为好名字,我的理解是有两点
- 避免包名重复
- 见名知意
mkdir monitor-event-emitter // 创建文件夹
cd monitor-event-emitter // 进入文件夹
git init // 变成git 仓库
npm init -y // 初始化包,会生成一个package.json包配置文件
这里我刚开始的包名并不叫这个,发布了第一版本之后,随着我的库的核心功能(控制台实时打印日志快照)的实现,我才重新改了名字。为了就是让别人看到这个包名的时候,就能大概知道它是什么,有什么特点,有没有吸引我去下载使用的欲望
第二步:完善包配置文件
完善package.json
文件,这个文件的意义非凡,它是别的人从了解你的包到能正确使用你的包的核心,挑几点说下
- main库的入口文件,你配置了啥,最终别人安装使用该库的时候,就会去寻找该文件,避免冗余的文件路径引入
- description库的描述文件,一句话,越精炼越好,突出库的亮点,吸引别人用它才是关键
- types该库的声明文件,由于是typescript开发的包,别人用的时候,为什么会有代码提示和参数类型纠错功能,就是该文件提供的能力
- files上传到 npm 上的文件包括哪些。没必要将你的所有文件和文件夹都推上去吧,里面的文件,能够让库正常使用且方便用户理解的前提下,越少越好
- repository填写你的 github 项目仓库,这样别人在使用库的过程中出现问题了,或者就是想看看你的个人主页,至少能够找到入口
- keywords该库类型的关键字,比如我的库主要是实现事件实时监听,我就用了这几个
monitor
、event
、emitter
第三步:工程配置
具体功能实现前的重要步骤,工程化领域不可或缺的部分,大致讲一下
- husky在我们自己的仓库目录下,有一个叫
.git
的目录,里面放了一些脚本hook
,为了方便在执行git
的步骤过程中,前置或者后置执行一些额外的脚本,从而让我们可以干预它的流程,做一些有意思的事。比如pre-commit
,也是最常用的脚本,主要用来在commit
之前,做一些检查工作,比如你的提交信息是不是符合规范,别人是否能够根据你的提交信息窥见你本次提交的代码意图等。还有一个就是代码风格和质量校验,配合上eslint
、prettier
、stylelint
简直不要太爽。你可以自己写一些脚本,比如我之前尝试自己用node
实现了一个小功能,在sentry
版本号同changelog
版本号不匹配的情况下,拒绝本次提交的逻辑。但是更方便的是用一下现成的库husky
吧 - lint-staged一句话阐述就是,约束了
husky
脚本执行范围。只去校验我本次提交的内容,它的意义可能在你重构一个旧项目或者添加代码质量及风格校验时,能够得到更好的体现。毕竟,没有人想只提交一行代码,会把前人写的骨灰级代码的风格或者质量问题都暴露出来吧,虽然有自动修复的问题,但是仍然有的是编辑器不能自动帮我们修复的,尤其是有强迫症的老哥,估计心态瞬间爆炸 - eslint主要用来管理代码质量问题。拜托你用
let
,用var
我就给你报错!但是我也可以很细心的帮你纠正错误,修复不了的,还得劳烦你自己手动操作一下 - prettier主要用来管理代码风格问题。约束大家开发风格统一,避免每个人的风格不统一而导致的合并冲突或报错问题,比如语句末尾要不要用分号,单个参数的函数需不需要有括号包裹、用双引号还是单引号。这个并没有好坏之分,自己团队商量着出一套大家都能接受的规范即可
- stylelint主要用来管理样式代码的质量和风格问题。比如颜色应该用
#000
还是#000000
亦或是black
,还有就是样式属性的顺序问题等。虽然任意一种方式都不会影响页面的展示效果,但是从长远的维护角度来看,它是非常有意义的。而且就上面提到的顺序问题,也是解决性能优化的一个小点,因为它可以减少浏览器的重排或是重绘 - commitlint约束提交信息规范,别整天只会来一句
git commit -m 'update'
了,你倒是告诉我,你update
了什么呀?涉及到的范围有哪些呀?是重构还是删除?永远记住一句话,提交信息是给人看的,不是给神看的,没有哪个人能够通过你那微弱的update
六个字母,窥见你的大脑思路。同时我也敢保证回过头的你自己再去看提交信息时,也是一脸懵逼
第四步:本库特点
到这里,我们已经可以正式着手实现我们的功能代码了。该库 核心文件 不算注释大概 400 行代码。实现了一个轻量级的事件监测触发器。个人认为,如果你熟悉ES6
语法,还是很容易读懂的。具体的实现有兴趣的可以参考git commit提交记录,有更好的实现思路的可以给我提 issue 或者通过 pr 参与到项目中来。
每次当接收到一个事件执行命令且函数执行后,控制台就会实时的将日志以表格的形式打印出来,方便调试进行问题定位。实际效果请参考 demo 控制台。大致思路请参考该图:
该库的主要特点有
- 没有太多的约束。因为我的个人认知就是约束越少,使用起来越方便,就越愿意有人去用它和了解它。有一种普遍场景就是,虽然你写的东西很好用,但是约束太多了,实例化的时候,需要传递
N
个参数才能触及它的灵魂,那么我很大可能性会放弃使用它。记住一点,使用成本越高,弃用它的概率就越大。但是话说回来,很多库看起来使用方式非常自由,用起来没有太多的心智负担,那是因为它的很多逻辑被高内聚
了。说直白点,就是开发者预判了你的一切使用习惯和场景,在库中实现的时候大部分都考虑到了 - 设计之初考虑过用对象还是用
map
来维护我的事件中心,由于涉及到频繁的add
、remove
、check
等逻辑。自认为选择用map
更加合适,毕竟它自带的一些方法着实好用。这里我想表达的是,有很多种方式都能够实现功能,但是在设计之初,你就要有一定的大局观念。你应该考虑怎么样去更好,更方便,更直观的实现它,而不是实现一半了,发现自己输在了起跑线上,推翻从头再来简直头皮发麻 - 支持实时监测能力。大致意思就是我们的业务代码中,可能有
N
处不起眼的地方,注册了N
个事件监听器,也可能在N
个角落中,默默的触发了它们。如果没有监测机制的话,很难弄情况它们执行的真实环境和情况,比如是什么类型的函数处理器?执行参数是什么?返回结果是啥?执行顺序是什么等。但是有了实时观测的能力后,你就可以很方便的在控制台中,实时观测到事件的触发,包括它们的入参、出参、类型。这样更加方便定位问题,做到有迹可循 - 大部分能用表格或者图片呈现意图的事,就不要用苍白无力的文字去表达。因为这是个快节奏的社会,人们大多数没有耐心。所以我将复杂(这里的复杂是指map类型的数据,在控制台打印后看上去不太清晰)的
map
结构的事件执行快照,转换成数组模型,在控制台中以表格的形式呈现给大家,更加容易阅读和调试。同时支持mode
参数,也可以让你自由的选择,你需要什么看到样的数据。目前支持default
、cool
- 做了定制化的提示信息,根据你使用时传入的
scope
字段,实现在控制台中相关日志信息的分类展示。这样就可以做到方便地区分不同业务下出现的问题,从而快速定位及修改问题
然后就是不断的优化功能代码的实现,同时记得保持代码的易读性...
第五步:单元测试
当你认为你写的核心逻辑已经实现的时候,你就要去开展单元测试了。你要确保你的代码在别人使用之前,出现问题的概率降到最低。大部分的功能使用场景,你都需要通过单元自测的方式提前演练一遍。几乎所有优秀的库,都有单元自测模块。它的意义并不仅仅是发现错误并纠正,更有价值的是,它能测出一些你在实现时没有考虑到的地方,驱使你去重新完善业务逻辑。
- jest单元测试框架。我之前也没用过,但是跟着文档尝试用了下,发现还是挺好理解和使用的。_这里有一些尴尬,不太会写异步的,虽然看了文档的用法,但是具体到结合我的一步场景时还是不太理解该怎么去写,有擅长的小伙伴可以帮忙完善下,提个 PR,磕头致谢_
第六步:写一份合格的README
当你觉得一切准备就绪准备发布npm
时。且慢,最重要的一步来了。那就是写一个标准格式的README.md,什么叫标准,我提炼几点我的理解:
- 大纲清晰,主要包含以下几部分
demo
能用一个实际演示场景展示给别人你的库的特点,就不要用苍白无力的文字why
为什么用这个包。可以阐述下该包的用途,以及它与现存的一些同类型包的区别,重点解决了什么问题install
该如何才能安装你的包,支持哪些环境下使用usage
最基本的使用方式api
支持的 api 有哪些,举一些例子,让人知道该怎么用config
该包支持的参数有哪些,都有什么意义,类型是什么todo
接下来要实现的功能,以及记录下目前做的不好的点,后期待优化
- 正式、重视起来。如果你认为你要做的事,是一件有意义的事。那么就去把它做好,且让它看起来像那么回事。
- 一些小图标shields.io,比如你的库用了什么语言,单元测试覆盖率是多少,打包后的体积是多少。这些都是影响到别人是否愿意使用你的库的关键点,且看起来逼格满满。想要提示小伙伴的是,这里的图标,有的并不仅仅只是一个
icon
展示静态的数据。比如我的codecov
图标中的单元自测覆盖率,是在提交代码时通过github action
实时将测试覆盖率报告上报到第三方的,还是很有意思的。这里想安利大家去学习下github action
,真的是太香了。我就是个前端小仔,你让我搞定一些太深的后台服务器相关的专业配置,比如nginx
、jenkins
配置,臣妾真的不一定能搞定呀。而学会了它,简直就是赛神仙,你想实现的一切都能通过简单的几行代码实现。比如部署网站,定时执行任务,拦截单元测试,有人提交issue
的时候通知我等等,有利用github pages
写博客的小伙伴,一定要去学着用它一下,难道当你只用执行一下push
命令后,你的本地博客最新内容已经部署到线上为他人所知,它不香吗?
- 一些小图标shields.io,比如你的库用了什么语言,单元测试覆盖率是多少,打包后的体积是多少。这些都是影响到别人是否愿意使用你的库的关键点,且看起来逼格满满。想要提示小伙伴的是,这里的图标,有的并不仅仅只是一个
第七步:写博客推广
写博客,推广你的库。你要能够用干练通俗的语言,告诉大家你做了一件什么事,它有什么意义?给你带来了什么成长,同时又解决了什么问题。让大家能够从你的文章中,有所收获,同时也能吸引大家参与到你的项目中来
这里我想借用一个梗,那就是:
不写博客的程序猿不一定是不合格的程序猿,但是愿意去写博客的程序猿将来一定会成为一名合格的程序猿
落笔
原创不易,且赞且珍惜。看官至此,何不来一波mark三连。
monitor-event-emitter 源码
demo 效果演示