分类
npm

使用 GitHub Registry 托管私有 NPM 源

我厂有不少私有仓库,都是日常开发中提炼出来的,在几个项目中共享,比如 UI、Vuex、网络请求(axios 封装)等。以前的主要形式是使用 npm 安装 GitHub 仓库,即

npm i openresty/some-repo

这样 npm 会自动去 GitHub 查找对应的仓库,然后 clone 下来完成安装。项目中的 .npmignore 文件也会正常生效,安装后的目录会忽略不需要的文件。这样做的好处就是简单,只要仓库存在,安装依赖的系统有足够的权限(比如 ssh key),就能顺利安装。在过去的三年时间里,我们一直都这样做。

但是这样会有一些问题:

  1. package-lock.json 里记录的是 commit hash,只看这个值无法判断版本,npm 也没法使用版本号解决依赖冲突的问题。换言之,比如 A 仓库需要 C 仓库的 1 版本,B 仓库需要 C 仓库的 2 版本,那么就只能同时安装两个版本,因为 npm 无法判断两个版本是否兼容。
  2. 安装的时候要走 git clone,下载量很大,速度很慢,经常被同事吐槽。也会影响 CI 的效率。
  3. git 仓库里要提交编译后的代码,一方面浪费时间和空间,另一方面大量编译后的代码也影响 code review

所以,考虑之后决定改用 GitHub Registry。GitHub Registry 是 GitHub 提供的私有源,感兴趣的同学可以访问这个页面了解详情。这个服务需要收费,不过我厂本来就是 Team 用户,额度比较富裕,所以并没有阻力。

经过一段时间的摸索,终于搞成了,下面简单说一下做法。

对依赖项目

修改 package.json,把项目名称改成 @openresty/some-repo,即“@公司名/仓库名”。然后增加 publishConfig 字段,设置源为 GitHub registry:

{
  "publishConfig": {
    "registry": "https://npm.pkg.github.com/"
  },
}

接下来,正常使用 npm publish 发布依赖即可。不过在发布之前,最好使用 .npmignore 忽略掉开发时的源文件和配置文件,一方面这些文件对于其它项目的开发没有价值,另一方面无论是存储还是下载消耗流量,都要收费,能省则省嘛。

对业务项目

因为这些依赖仓库都是私有项目,所以我们先得解决身份认证的问题。GitHub 提供了 Personal access tokens 方式,生成 token 后,添加到 ~/.npmrc 文件即可:

//npm.pkg.github.com/:_authToken=<TOKEN>

接下来,在业务项目中,添加 .npmrc 文件,指名依赖源:

registry=https://registry.npmjs.org/
@openresty:registry=https://npm.pkg.github.com

这段配置分两部分:其它域的依赖,直接从 npm 的源下载;@openresty 域下的依赖,从 GitHub Registry 下载。

最后,正常使用 npm i @openresty/some-repo 安装依赖即可。


最后的最后附上修改前后的效果对比,可以看出,改造后效果明显:

国内修改前real 0m39.543s
user 0m17.768s
sys 0m3.944s
阿里云
修改后real 0m16.450s
user 0m15.204s
sys 0m3.380s
阿里云
国外修改前real 0m49.350s
user 0m22.352s
sys 0m4.144s
阿里云
修改后real 0m30.807s
user 0m15.780s
sys 0m3.936s
阿里云
分类
npm

几步简单的操作解决 `npm audit` vulnerabilities

NPM 是 JavaScript 生态最重要的组成部分,我们的项目中会大量使用 NPM 安装第三方包(安装后就称为“项目依赖”)解决问题。这些第三方包也会带来他们的依赖,最终一个项目里可能安装成百上千个依赖。

有道是:没有完美的代码,代码里一定藏有隐患。所以用的依赖多了,其中有问题的概率也提升了,三五不时的,npm 就会提示我们:found N low/medium/high severity vulnerabilities

npm 提供命令 npm audit fix,理论上可以修复这些隐患,但在实际操作中,以我的经验来看,并不容易生效。我猜测可能是因为依赖间的复杂关系,想彻底解决并升级不太容易。所以我一般是这样做的:

分类
npm

解决新机不能 npm install 私有仓库的问题

前些天换了电脑,从 iMac 27 Retina 2014 late 升级到 iMac 27 2019。关于前因后果,我写在张大妈,感兴趣的同学可以看下:《肉山的电子产品 篇九:机不如新,人不如故——iMac 27 换新记》

换机器要搭环境。有两个选择:

  1. 整盘复制,利用 Time Machine 之类的工具
  2. 自己慢慢搭

考虑到老电脑已经工作了 5 年,经历了小十个系统版本,各种软件删装无数,里面的垃圾很多;再加上我的环境并不复杂,所以我决定自己慢慢搭。

然后遇到一个问题:npm install 会卡住,没有明显的提示信息,只有一段比较可疑:

The authenticity of host 'GitHub.com (1.1.1.1)' can't be established.
ECDSA key fingerprint is SHA256:abcdefg.
Are you sure you want to continue connecting (yes/no)? 

因为项目中用到一些私有仓库的依赖,所以我怀疑是它们的问题。于是我把私有仓库从 package.json 里移除,再安装,成功。看来猜的没错。

然后我手动 git clone 一个项目到本地,clone 的过程中,会看到上面的提示,手动输入 yes,记录目标机器的指纹,视它安全可靠。clone 完成。再把私有仓库依赖加回 package.json,安装,成功。问题解决。

原因:使用 npm 安装 GitHub 仓库作为依赖,实际上等同于使用 git clone 将目标仓库 clone 到 node_modules 里。而 git 协议依托于 ssh 协议。在新机器上安装时,因为没有访问过目标机器,本地不信任目标机器,而 npm 又没有对这个异常做处理,所以就会卡住,不上不下。

分类
技术

npm 支持开发者添加募款链接

昨天随手升级个人首页的依赖,更新完之后,npm 提示:

6 packages are looking for funding
  run `npm fund` for details

如果你执行 npm fund,可以看到类似这样的信息:

your-repo@0.1.0
├─┬ core-js@3.4.2
│ ├── type: opencollective
│ └── url: https://opencollective.com/core-js
├─┬ eslint@6.7.0
│ └── url: https://opencollective.com/eslint
└─┬ swiper@5.2.1
  ├── type: patreon
  └── url: https://www.patreon.com/vladimirkharlampidi

opencollective 和 patreon 都是众筹网站,只不过众筹的内容不是实物商品,而是支持你喜欢的创作者,无论他是摄影师、画家,还是开源软件作者。据说 Vue 的作者尤雨溪每年可以从 Patreon 上获得将近 $20w 的捐赠,这笔钱可以帮助他以独立身份继续开发 Vue,还可以雇佣一名全职开发者帮助他把这份工作做得更好。

我去 NPM 官网找了一下,npm fund 的文档还没更新上去,只找到这篇 RFC: Add funding support to package.json,大意是包开发者可以在包的描述文件(package.json)里放上一段募款声明,这样包的用户在安装的时候,就会看到我开篇写的那些文字。提醒包的开发者:你们可以通过捐赠的方式,表达对依赖开发者的感谢。

我觉得这种形式挺好的。当然,有些人可能看不惯这种有“伸手嫌疑”的行为,但是,与其在无酬工作中纠结、放弃自己的项目、甚至被别有用心的人利用埋后门,任何不影响安全性、不增加使用负担的变现方式都是合理且值得鼓励的。

希望开源软件开发者越过越好,开源基建开发者越过越好,世界越来越好。

分类
技术

网站抓取工具 website-scraper

临时需要抓一个网站,搜索了一下,发现 website-scraper,用了一下感觉不错。它有如下优点:

  1. 基于 Node.js 和 NPM,系统无关
  2. 可以根据链接抓取整个网站
  3. 文档齐全,仓库还有人维护
分类
桌面开发

使用 Electron 开发桌面应用

这个标题比较大,先挖个坑,日后再填。

忘记哪里看来的:nw(原 node-webkit)的作者从 Intel 离职后,无法继续维护 nw,此时 Github 向他抛来橄榄枝,请他去做 Electron(主要是为 Atom 做基础),于是便有了 Electron。

这两个东西虽然基础架构不一样,不过大体上都是 V8 + Chromium,实现使用 JavaScript 构建系统交互,使用 Web 提供 UI。简单对比了一下我觉得明显 Electron 好多了嘛,所以选择用它来开发桌面应用。

经过几天摸索,开发出来一个应用。不过太小,可分享的东西不多,所以先记几条 Tips。

封装 Electron 应用

打包工具

Electron 构建了一套完整的环境,只需要替换里面的 Web 部分就可以发布。这样最大的好处是每次发布的时候只需要简单压缩一下网页部分,放到包里,不用构建整套系统,对开发机的要求大大降低。

坏处就是,对于我们墙内用户而言,安装 Electron 必须用小水管拉一个将近 100M 的包回来,简直痛苦的要死。更别提后面如果享用 [electron-packager] 之类的工具封装的话还要再下一遍……每到这个时候,都要给病魔加油,愿他早日战胜方校长。

这里建议使用淘宝的 cnpm 镜像,速度会好很多。不过它似乎和 npm 有点冲突。

npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm install electron -g

至于 electron-packager,因为它使用 [electron-download] 下载 Electron 运行包,可以按照提示,修改下载的源,走淘宝镜像,这样也会快很多:

npm config set ELECTRON_MIRROR https://npm.taobao.org/mirrors/electron/

环境选择

至少在我这里,在 Mac 下只能打包 Mac 应用;在 Windows 下只能打包 Windows 应用。所以需要多平台的话,请准备多台开发机。

分类
nodejs

npm start, npm stop

使用 npm 可以直接调用 package.json 里面 scripts 标签里定义的脚本。比如,Astinus 项目中,index.js 是入口JS,并且需要 ES6 支持,就可以这样:

    // package.json
    {
      "scripts": {
        “start": "node index --harmony"
      }
    }

然后直接运行

    npm start

即可。

那么怎么终止进程呢?

首先要在 index.js 里增加一句

    process.title = 'astinus';

声明该应用的标题是“astinus”,然后增加脚本:

    {
      "scripts": {
        "start": "node index --harmony",
        "stop": "killall SIGINT astinus"
      }
    }

之后就可以

    npm stop

参考: