如何获取 cnpm 的 packages 下载量
导读
在做前端技术调研的时候,github stars 和 npm downloads 这两个宏观指标是很重要的参考项。因此 star-history 和 npmtrends 两个网站就派上大用场了。前者可以列出 repo 在 github stars 的变化:
后者可以列出 package 在 npm 下载量的变化,还有很多其他信息:
宏观数据的对比可谓一目了然,非常方便。
但是众所周知的原因,国内用默认的 npm 源很多时候会有网络问题,这时候我们通常会使用 cnpm 来解决,所以其实国内的好多 package 的流量都没有被统计到 npm 数据中。
那么有没有什么办法能够统计到 cnpm 的下载量呢?像 npmtrends 一样的网站是没找着,但是机缘巧合之下,找到了 cnpm 获取下载量的 API。这不就完成 99% 了嘛!开搞!
正文
分析
偶然的机会,在一篇帖子的回复里找到了 cnpm downloads 的 API 信息:
// download times
app.get('/downloads/range/:range/:name', downloadTotal);
app.get(/^\/downloads\/range\/([^\/]+)\/(@[\w\-\.]+\/[\w\-\.]+)$/, downloadTotal);
app.get('/downloads/range/:range', downloadTotal);
从代码里我们能够猜到,只要知道 range
和 name
的正确格式,就能够获取到数据。name
好说,应该就是 package 的 name,跟 npm 当中一致,关键就是这个 range
。于是笔者按图索骥,找到了 dowloadTotal 的具体代码:
var DATE_REG = /^\d{4}-\d{2}-\d{2}$/;
module.exports = function* downloadTotal() {
var range = this.params.range || this.params[0] || '';
var name = this.params.name || this.params[1];
range = range.split(':');
if (range.length !== 2
|| !range[0].match(DATE_REG)
|| !range[1].match(DATE_REG)) {
this.status = 400;
const error = '[range_error] range must be YYYY-MM-DD:YYYY-MM-DD style';
this.body = {
error,
reason: error,
};
return;
}
// ...other code
}
很明显了,YYYY-MM-DD:YYYY-MM-DD
就是我们想要的 range 格式。最后就是 host 了,简单查一下就能得到结果: https://registry.npmmirror.com
。所以一个完整的请求 URL 会是下面这个样子:
https://registry.npmmirror.com/downloads/range/2022-11-01:2022-11-02/vue
各位可以在浏览器里打开这个地址,直接就能看到结果,如下:
{
"downloads": [
{ "day": "2022-11-01", "downloads": 77721 },
{ "day": "2022-11-02", "downloads": 79027 },
{ "day": "2022-11-03", "downloads": 36330 }
],
"versions": {
"0.0.0": [{ "day": "2022-11-02", "downloads": 1 }],
// ...other versions
"3.2.9": [
{ "day": "2022-11-01", "downloads": 6 },
{ "day": "2022-11-02", "downloads": 10 },
{ "day": "2022-11-03", "downloads": 6 }
]
}
}
请求地址、参数、返回数据结构都摸清楚了,接下来就是实现代码了,So Easy~
代码实现
既然把 cnpm 的 API 搞清楚了,我们就简单看下 npm 的 API,不难查到,npm 的 API 格式如下:
https://api.npmjs.org/downloads/point/2022-11-01:2022-11-02/vue
另外,如果不传 name,它会返回所有包的下载总量,这个功能 cnpm 好像还没有。
再说回代码实现。想做一个跟 npmtrends 一样的网站就不必了,我们只需要知道一段时间内(默认 1 年)总下载量的对比就可以了,所以一个最简的无第三方依赖的 nodejs 脚本就可以了。具体代码如下,复制到本地,修改参数,直接调用 getPackagesDownloads
方法就可以了:
const https = require("https");
const parseDownloadsData = (str) => JSON.parse(str).downloads;
const totalDownloads = (arr) =>
arr.reduce((prev, curr) => {
return prev + curr.downloads;
}, 0);
const downloadsPromise = (name, platform='cnpm', range) => {
let rangeStr; // YYYY-MM-DD:YYYY-MM-DD
let host = 'registry.npmmirror.com'
let apiPath = '/downloads/range'
if (platform == 'npm') {
host = 'api.npmjs.org'
apiPath = '/downloads/point'
}
if (range) {
rangeStr = range;
} else {
const todayDate = new Date().toISOString().split("T")[0]; // YYYY-MM-DD
const year = new Date().getFullYear();
const lastYearDate = todayDate.replace(year, year - 1);
rangeStr = `${lastYearDate}:${todayDate}`;
}
return new Promise((rev, rej) => {
https
.request(
{
host,
path: `${apiPath}/${rangeStr}/${name}`,
},
(response) => {
let str = "";
//another chunk of data has been received, so append it to `str`
response.on("data", (chunk) => {
str += chunk;
});
//the whole response has been received, so we just print it out here
response.on("end", () => {
rev(str);
});
response.on("error", (err) => {
rej(err);
});
}
)
.end();
});
};
const getPackagesDownloads = (pkgs) => {
const result = {};
return Promise.all(
pkgs.map((pkg) => Promise.all([
downloadsPromise(pkg, 'cnpm'),
downloadsPromise(pkg, 'npm')
]).then(resArr=> {
result[pkg] = {
cnpm: totalDownloads(parseDownloadsData(resArr[0])),
npm: parseDownloadsData(resArr[1])
}
})
)
).then(() => result);
};
/**
* Usage:
*
getPackagesDownloads(["react", "vue", "@angular/core", "angular"]).then(
(res) => {
console.log(res);
// {
// angular: { cnpm: 75264, npm: 26791859 },
// vue: { cnpm: 17878348, npm: 163975718 },
// '@angular/core': { cnpm: 730528, npm: 151297959 },
// react: { cnpm: 41750961, npm: 779385565 }
// }
}
);
*/
代码非常简单,没有多少好讲的。强调一点,代码中用了两个 Promise.all
,这个做法对于提高速度是立竿见影的,有兴趣的同学可以试试改成同步代码,效率差了不止一点半点。
中国 VS. 世界
代码写完了,我们来用一下看看效果,跑一些数据看看。基本上 cnpm 可以代表中国的情况,npm 当然就是全世界了,这种中国 VS 世界的事,想想还有点小兴奋呢~~
注意:以下结论极其不严谨,仅做娱乐
整体对比
我们先来看下 npm 和 cnpm 整体的数据对比。从 npm 的 API 我们可以获取到各个时段的总下载量。但是 cnpm 好像不太行,于是从 这篇帖子 和 官网 的 API 中获得了一些数据,整理如下:
2020 | 2021.1.1~2021.11.3 | 2022.1.1~2022.11.4 | |
---|---|---|---|
npm | 1,054 B | 1,324 B | 1,818 B |
cnpm | 17.6 B | 22.0 B | 29.3 B |
npm/cnpm | 59.89 | 60.16 | 62.03 |
可以看到,npm 的总下载量大概是 cnpm 的 60 倍左右,且比值逐年增大。世界总人口约 80 亿,中国人口约 14 亿,比值大概是 5.66。所以单从这个维度,简单粗暴的来看,可以得到以下结论:
- 近些年中国前端的发展增速要缓于全世界;
- 中国的程序员还是太少啊,有 10 倍的增长空间呢(是不是应该涨点工资啥的);
再次声明:结论极其不严谨,仅做娱乐,后文不再赘述
前端三大框架
注:以下数据均数据截止到 2022-11-03,取 1 年的数据
我们再来看看前端三大框架:
Recent 1 Year Downloads | react | vue | @angular/core | angular | Total |
---|---|---|---|---|---|
npm | 779,385,565 | 163,975,718 | 151,297,959 | 26,791,859 | 1,121,451,101 |
cnpm | 41,740,155 | 17,861,642 | 730,108 | 750,225 | 61,082,130 |
npm/cnpm | 18.7 | 9.2 | 207.2 | 35.7 | 18.4 |
有意思的事情来了,简单总结下三大框架的数据特点:
- npm 下载总量是 cnpm 的 18.4 倍,明显低于总体比例,证明中国的前端研发人数占比很高啊;
- Angular 在中国极其不流行啊,Vue 和 Angular2 在 npm 上的下载量几乎持平,但在 cnpm 上前者是后者的 250 多倍。终于对于 Vue 在中国流行程度有了量化上的概念了;
- React 与 Vue 的比值在 npm 和 cnpm 上分别为 4.8 和 2.3,还是从侧面映证了 Vue 在国内的火热,不过 React 还是强啊;
- Angular2 与 Angular1 在 npm 的下载量比率为 5.6,有意思的是在 cnpm 上二者数据几乎持平,也许这些流量都是老教程贡献的吧;
Nodejs 后端框架
Recent 1 Year Downloads | express | @nestjs/core | egg | koa | fastify | next | nuxt | midway | Total |
---|---|---|---|---|---|---|---|---|---|
npm | 1,205,982,176 | 69,710,234 | 2,483,607 | 64,789,828 | 28,077,027 | 135,010,940 | 21,462,416 | 63,485 | 1,527,579,713 |
cnpm | 18,892,661 | 376,093 | 591,050 | 2,575,526 | 160,469 | 997,533 | 499,819 | 10,852 | 24,104,003 |
npm/cnpm | 63.8 | 185.4 | 4.2 | 25.2 | 175.0 | 135.3 | 42.9 | 5.9 | 63.4 |
- npm 下载总量是 cnpm 的 63.4 倍,基本符合总体数据的比例,但是 Express 占的比重太大了,其实细看其它框架的详情,还是有很多额外信息的;
- egg、midway 果然只在中国很流行,毕竟是阿里出品嘛。而且后者的下载量其实很少,估计数据有不少是 Demo 和阿里内部自己贡献的;
- 估计受 Vue 在国内的流行影响,nuxt 相对来说在中国更流行,但是 next 的绝对值还是有明显的领先的,更流行只是相对全世界而言;
- 出乎意料的,nestjs 在中国竟然这么不流行,比值竟然是最高的,高出均值近 3 倍。个人猜测,可能国外的程序员通常都是全栈,有 Sprint 或 Angular 背景的相对较多,更容易接受 nestjs 的设计理念。而国内前端还是比较局限的,这也是国情不同的一个直接体现啊;
结语
本文的缘起是为了做技术调研,调研除了要考虑宏观因素,还要考虑是否符合团队当前的情况,这才是一个负责任的调研。所以,考虑中国国情还是很有必要的,之前一直没有一个靠谱的指标,现在好了,cnpm 的下载量还是有一定代表性的。
最后,还是要再强调一遍,本文总结的结论仅做娱乐,推论极其不严谨,各位勿要太当真~
你执行力的上限,不会超过你对最佳实践理解的下限。—— 一堂
转载自:https://juejin.cn/post/7162001243852767240