如何统计前端项目中npm包的使用率

最近接了个需求, 需要统计公司前端项目中, 自研 npm 包的普及度&包内函数使用量. 解决过程比较有意思, 这里分享下.

项目的基础思路比较简单, 大致如下图所示.

基础流程

对于获取所有前端项目问题, 由于我司有一套自建的公共前端打包平台, 可以直接调用平台接口拉取项目源码.

所以剩下的难点只有一个: 如何解析 js 文件, 得到目标 npm 包内导出对象的使用次数.

其实方法也很简单: babel 怎么做, 我们就怎么做.

用过 babel 的人都知道: babel 可以读取 ES6 代码, 先将 js 文件整体转化为抽象语法树, 然后遍历语法树, 调用插件对代码内容进行调整, 剔除/转换语法结构, 并最终输出为 ES5 代码. 而我们需要做的, 就是编写一个插件, 在 babel 遍历语法树时, 识别目标 npm 包, 统计从包中引出的变量使用情况. 流程如下.

解析流程

然后剩下的就是体力活: babel 解析出的所有语法树节点类型都在babel-types包中, 需要做的, 就是针对包中的每一种语法结构(导入/变量解构/重命名/函数调用/…)编写处理函数, 最后将所有结果输出为一个 json.

代码比较冗长, 全文可以翻看这个Github 项目, 这里只展示一下用于统计的数据解构

项目数据汇总: SummaryCollection

针对每个项目创建一个SummaryCollection对象. 调用 add 方法登记每个文件的解析结果

函数签名 功能 备注
constructor() 初始化汇总类 汇总项目内所有文件的分析记录
add(target: UsedSummaryInFile) 添加文件分析数据
toJson(): TypeUiLibReport[] 输出汇总结果

文件数据汇总: UsedSummaryInFile

针对单个 js 文件, 统计目标 npm 的使用记录

函数签名 功能 备注
constructor(fileUri: string) 初始化文件分析记录 记录文件fileUri中的 npm 包使用数据
addLib(libName: string) 发现目标 npm 后, 登记 npm 包名
addLibAlias(libName: string, aliasName: string) 登记目标 npm 包的别名
addComponent(libName: string, componentName: string) 登记目标 npm 包下组件
addComponentAlias(libName: string, componentName: string, componentNameAlias: string) 登记目标 npm 包下组件的别名
incrComponentUseCount(libName: string, componentName: string) npm 包下组件使用次数+1
incrLibUseCount(libName: string) npm 包直接使用次数+1
isRegistedLibName(targetName: string) 检查是否登记过该 npm 包
isRegistedComponentName(targetName: string) 检查是否登记过该组件
getComponentNameBelongToLib(targetName: string) 根据组件名, 查找其隶属的 npm 包名

统计 npm 使用情况: UsedLib

记录 npm 包使用记录, 以及 npm 包内组件使用记录

函数签名 功能 备注
constructor(libName: string) 初始化 npm 记录, npm 包名为libName 记录 npm 包使用数据
addComponent(componentName: string) 登记 libName 包中的组件 -
addComponentAlias(componentName: string, componentAliasName: string) 登记 libName 包中组件的别名 -
incrComponentUseCount(componentName: string, fileUri: string) 组件在文件fileUri中使用次数+1 -
incrLibUseCount(fileUri: string) npm 库在文件fileUri中使用次数+1 npm 包可能本身就是一个函数
isRegistedComponentName(testComponentName: string) 检查组件名testComponentName是否在libName包中注册过 -

统计组件使用情况: UsedCompontent

记录组件使用次数

函数签名 功能 备注
constructor(name: string) 初始化组件记录对象, name 为被统计组件的名字 记录组件使用数据
addAliasName(aliasName: string) 登记组件别名 -
incrUseCount(fileUri: string) 在文件fileUri中使用次数+1 -

参考资料

👇 介绍了 babel 处理语法树的流程(Visitor 模式), 抽象语法树概念, babel 工作原理, 必读

深入 Babel,这一篇就够了

👇 同上, 也是对 babel 的介绍.

前端工程师需要了解的 Babel 知识

👇 babel 使用 @babel/babel-parser 解析 js 代码, 而 @babel/babel-parser 则是 fork 的acorn. 处理 babel 生成的抽象语法树时, 必然需要理解每个语法树节点 type 字段的含义(如VariableDeclaration, ImportDefaultSpecifier).

标准文档在这里, 不过是英文的, 下边是一份汉语版, 开发过程中可以参考

使用 Acorn 来解析 JavaScript

👇 在线将 js 代码转换为 AST. 编写相关代码时的必备佳品

抽象语法树预览


如何统计前端项目中npm包的使用率
https://www.yaozeyuan.online/2021/01/10/2021/01/如何统计前端项目中npm包的使用率/
作者
姚泽源
发布于
2021年1月10日
许可协议