Skip to content
大纲

UNPKG源码分析,私有化部署及性能优化

以下内容转载自我的原创文章UNPKG源码分析,私有化部署及性能优化

简介

unpkg 是一个前端常用的公共 CDN,它通过 URL语法完成了别人web 界面内才能达到的效果,简洁而优雅,在流行的类库、框架文档中常常能看到它的身影。

我发现这个项目很有趣,可以在线预览目录及文件。在网上寻找了相关资料,很少有对这个项目详细分析解读的,所以决定仔细分析一下实现原理并尝试私有化部署。

国内一些公司也私有化部署了UNPKG,比如:

先看一下UNPKG官网的访问效果;

https://unpkg.com/browse/react@17.0.2/ 效果如下:

https://unpkg.com/browse/react@17.0.2/index.js 效果如下:

相关链接

源码分析

先分析一下源码

目录视图

这里的pm2.config.js是我为了启动服务和记录日志及方便添加process.env参数所以加上的。

主要文件注释

我根据自己的理解,给主要的目录及文件添加了一些注释。

我添加了部分打印信息,帮助理解:

在浏览器可以通过打印全局变量window.DATA 查看相关参数:

UNPKG的接口请求

主要请求镜像源的API,比如https://registry.npmjs.org 镜像源,可以通过https://registry.npmjs.org/react?meta 或者https://registry.npmjs.org/react/17.0.2 进行接口请求,获取相关npm包的信息及文件路径。

UNPKG通过对用户请求URL的解析获取请求参数packageName、packageVersion、packageSpec、filename。然后请求镜像源接口,获取到信息和stream。然后通过该SSR渲染到前端页面中预览。

工作流程

通过对源码的阅读,UNPKG的主要工作流程是这样的:

私有化部署

知道工作原理后,想私有化部署到我自己的服务器上。这里需要做少许改定。一方面是因为有cloudflare接口鉴权校验,所以需要注释掉。另一名面我不想用一级域名直接被占用,所以增加Nginx配置。

去掉接口鉴权校验:

链接替换成第三方链接或者自己的链接:

增加PM2配置,记录相关日志:

增加启动脚本:

Nginx配置

如果服务直接部署到指定域名一级入口的可以忽略Nginx这部分。

我的域名信息是https://timesky.top 不想一级域名被占用,只想代理/browse/开头的路径代理到我的服务端口8091就可以了,另外包请求类似https://timesky.top/react@17.0.2/index.js 这种path第一部分包含@的也代理到8091端口即可。

这里我的域名http和https都有,所以Nginx 80和443都需要配置

nginx
 location ~ ^/.+@.+/.+$ {
        proxy_pass http://127.0.0.1:8091$uri;
        proxy_set_header Host $proxy_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Cookie $http_cookie;
}
 location ~ ^/.+@.+/.+$ {
        proxy_pass http://127.0.0.1:8091$uri;
        proxy_set_header Host $proxy_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Cookie $http_cookie;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

nginx转发示意图:

pm2配置

为了增加服务稳定性,以及方便采集记录日志信息,我配置了pm2来启动node服务。pm2来启动两个实例来做复杂均衡和失败重启。

javascript

// pm2 start pm2.config.js
module.exports = {
  apps: [
    {
      name: 'unpkg',
      script: './server.js',  // 启动的服务js文件路径
      cwd: './', // current workspace
      watch: [
        // watch directorys and restart when they change
        // '.next'
      ],
      ignore_watch: [
        // ignore watch
        'node_modules',
        'logs',
        'static'
      ],
      max_memory_restart: "1024M",
      instances: 2,  // 为了保证稳定向,开启了2个实例
      node_args: '--harmony',
      env: {
        NODE_ENV: 'production',
        PORT: 8091
      },
      out_file: './logs/out.log', // 日志输出目录
      error_file: './logs/err.log', // 报错日志输出
      merge_logs: true,
      log_date_format: 'YYYY-MM-DD HH:mm Z' // 日志时间格式
    }
  ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

服务器部署代码,启动pm2服务

大功告成,请看效果:

我私有化实现效果:

访问格式: https://timesky.top/browse/{包名}@{版本号}/ 如:https://timesky.top/browse/dayjs@1.11.0/

目前使用的镜像是:https://registry.npmjs.org/

性能优化

部署是成功了,就是访问速度很慢,难以接受。所以想做一下优化,Redis是一个很好的优化手段,因为只要路径固定下来,内容其实每次都是不变的,只需要把内容存到Redis中,下次请求相同的路径直接返回就好了。

Redis中间件接入及部署

目前只用来个人使用所以只用了单例Redis,如果是企业级别后流量更高的场景可以采用Redis集群的方式部署。

  • 本地和服务器安装Redis参考官网,npm包新增ioredis。

  • 新增中间件getCache用于查询Redis

  • 保存文件的时候保存在Redis中

  • 在路由中新增查询Redis

调整后的工作流程是这样的:

本地调试

本地启动后,可以通过可视化客户端查看Redis缓存。

查看Redis客户端:

部署服务器

服务器Linux安装Redis并修改配置,启动服务。 我们可以发现访问速度明显快了很多。 我们访问https://timesky.top/nest@0.1.6/index.js

查看服务器请求日志:

查看服务器Redis记录:

Redis成功存取成功,而且网站二次三次访问速度急速提升!。

在网站中查看build ID 为Build: c5df54a

刚好对应上git提交记录ID c5df54a :

总结

至此,UNPKG的私有化部署和性能提升告一段落,目前这个服务只能支撑个人使用,还不能应用于大流量的场景。如果是企业级别的私有化服务,还需要考虑上Redis集群,以及CDN服务。整个弄下来收货挺多,后期也可以考虑优化一下,比如协商缓存和配置CDN。

备注:对于公司的私有镜像,大家可以切换成自己的私有仓库镜像地址,另外针对企业私有镜像可能要处理重定向问题,这里就不再展开细说。如有需要可以私信或者评论区一起讨论。