如何实现并部署自己的npm解析服务
liuian 2025-06-28 15:15 26 浏览
大家好,我卡颂。
你是否好奇 —— codesandbox是如何在线运行代码的?
要回答这个问题,我们先看看前端项目是如何在本地跑起来的。简单来说分为3步:
- 执行npm install安装依赖
- 使用打包工具(比如webpack)打包、编译代码(如果使用Vite会省去打包的步骤,但会执行「预构建」)
- 将步骤2的产物通过script标签注入页面
codesandbox能在线运行代码,显然他也实现了上述步骤,具体来说,codesandbox内置了2个在线服务:
- npm解析服务 —— 用于实现上述步骤1
- 在线打包服务 —— 用于实现上述步骤2、3
本文我们来聊聊如何实现并部署自己的npm解析服务。
codesandbox简要工作原理
下面是一个常见的codesandbox界面,包含两部分:
- 左边的文件系统、代码编辑器
- 右边的效果预览区域
其中「效果预览区域」是一个iframe,对于上图中的例子,iframe的地址是https://pjdp86.csb.app/。如果你打开这个地址,会发现他就是代码的预览效果:
但这并不意味着codesandbox帮我们部署了项目。实际上,这个地址中前端代码是在页面打开后再编译、打包的。
打开codesandbox项目时经常看到的下述界面,就是前端编译代码的画面:
具体来说,当我们打开一个codesandbox项目,iframe对应地址初始化时,会执行如下操作:
- 下载项目代码(即编辑器中显示的代码)
- 根据项目package.json中指明的依赖,从「npm解析服务」下载项目依赖的代码
- 下载在线打包器(一个mini webpack)、编译器(babel)相关代码
- 在线打包、编译
- 运行打包后的代码
正是有了在线打包、编译的流程,codesandbox才能在线运行:
- React项目(需要编译JSX)
- TS项目(需要编译TS语法)
- Vue项目(需要编译SFC文件)
回到本文的主题 —— 「npm解析服务」。当我们从项目package.json中获取到依赖库的名称后,完全可以从CDN直接请求依赖库对应的代码,为什么还需要一个独立的「npm解析服务」呢?
npm解析服务的作用
之所以需要独立的「npm解析服务」,主要是因为 —— npm包本身可能还依赖别的npm包,如果每次初始化iframe时依次下载:
- package.json中指定的依赖
- 依赖的依赖
- 依赖的依赖的依赖
- ...
那会极大拖慢项目初始化的时间。同时,这样做也可能会下载大量实际不会使用的代码。
所以,需要一个「npm解析服务」,当第一个用户第一次请求某个库时,依次完成:
- 从库的入口代码解析AST,分析其中的require语句,递归的解析这个库的依赖
- 下载依赖代码,将所有依赖的代码汇总到一个JSON文件
- 将步骤2的JSON文件保存在对象存储中
- 返回步骤2的JSON文件
那么,后续所有用户在请求这个库时,都能直接从对象存储中直接获取解析好的JSON文件,这能极大提高在线安装依赖的速度。
比如,react@18.2.0经由「npm解析服务」解析后会返回如下JSON:
{
"contents": {
"/node_modules/react/index.js": {
// 库的代码
"content": "...省略",
"isModule": false,
// 依赖的其他模块
"requires": [
"./cjs/react.production.min.js",
"./cjs/react.development.js"
]
},
"/node_modules/react/cjs/react.production.min.js": {/*省略*/},
"/node_modules/react/cjs/react.development.js": {/*省略*/},
"/node_modules/js-tokens/package.json": {/*省略*/},
"/node_modules/loose-envify/package.json": {/*省略*/},
"/node_modules/react/package.json": {/*省略*/}
},
// 库的版本信息
"dependency": {
"name": "react",
"version": "18.2.0"
},
"peerDependencies": {},
// 依赖的依赖
"dependencyDependencies": {
"loose-envify": {/*省略*/},
"js-tokens": {/*省略*/}
},
"dependencyAliases": {}
}
上述JSON中,入口代码在/node_modules/react/index.js,通过递归分析他的AST,发现他依赖了:
- "./cjs/react.production.min.js"
- "./cjs/react.development.js"
于是,这2个文件对应代码也包含在JSON中。
当下一个用户加载的项目依赖react@18.2.0,就能直接从对象存储中获取上述JSON。
npm解析服务的实现
codesandbox在线打包相关的代码都是开源的,比如:
- 编辑器的部分对应sandpack-react
- npm解析服务对应dependency-packager
- 在线打包服务对应codesandbox-client
所以,我们可以基于dependency-packager部署自己的「npm解析服务」。
dependency-packager是一个serverless服务,通过AWS Lambda部署。由于采用的是开源的serverless框架,所以我们可以很方便的将项目中AWS Lambda的部分替换成其他serverless服务商(比如阿里云函数计算)。
整个dependency-packager包含两个serverless函数:
- api:实际对外提供的服务
- packager:根据包名和版本号生成JSON的服务
他们的关系如下:
其中,生成的JSON保存在AWS S3中。同样,这里也可以替换成其他云服务厂家的存储方案。
packager服务的工作流程如下:
其中,「验证依赖的入口文件」会尝试下面这些文件后缀:
const found = [
path.join(basedir, pkg.module),
path.join(basedir, pkg.module + ".js"),
path.join(basedir, pkg.module + ".cjs"),
path.join(basedir, pkg.module + ".mjs"),
path.join(basedir, pkg.module, "index.js"),
path.join(basedir, pkg.module, "index.mjs"),
].find((p) => {
try {
const l = fs.statSync(p);
return l.isFile();
} catch (e) {
return false;
}
});
验证完成后,会以package.json中的module或main字段作为入口文件,将代码转换为AST,分析AST中的require语句(cjs语法中引入模块的语法),找到依赖的模块。最终将这些模块汇总在JSON中。
总结
codesandbox在线打包相关的代码都是开源的,包括:
- 编辑器
- npm解析服务
- 在线打包服务
其中,npm解析服务作为一个serverless服务包括两部分:
- api服务
- packager服务
packager服务代码量不多,如果想尝试部署自己的serverless服务,是个不错的选择。
相关推荐
- isofix接口(isofix接口怎么拆卸)
-
isofix接口上有isofix的字样,它的图标是一个类似人坐在座椅上。在汽车座椅靠垫与坐垫之间的连接处有2个接口,那就是isofix接口,是一种硬连接方式,为了防止撞击时发生座椅翻转,一些座椅在IS...
- 无线路由器怎么设置不让别人连接
-
要设置无线路由器不让别人连接,可以采取以下措施:1.配置路由器密码:在路由器设置中,可以设置密码,限制只有授權的人才能连接到网络。2.配置防火墙:可以安装防火墙软件,如OpenDNS,限制...
- fast迅捷路由器(fast迅捷路由器配置上网教程)
-
http://www.fastcom.com.cn/上面这个就迅捷官网的网址老版本的迅捷路由器默认登录地址为“192.168.1.1”,新版本的迅捷路由器默认登录地址为“falogin.cn”。02...
- 手机天梯图2025最新版(手机天梯图cpu2020快科技)
-
一般情况下而言,手机处理器的性能越强,功耗也就越高。有网友制作了一张手机处理器功耗排名图,高通骁龙888位8.34W,是榜单中功耗第二的处理器。而海思麒麟9000则位列第三,功耗为8.3W。一般情况下...
- pe系统下载官网手机版(pe系统之家)
-
打开手机应用商店,选择windowspe,下载安装PE系统是一种维护用的系统,本身是很简陋的,什么常用功能都没有,后经一些爱好都修改、完善,现在成为可当临时系统用的精简系统。但PE系统当前种类很多,...
- 云骑士装机大师怎么激活win7
-
回答如下:要激活Windows7操作系统,您可以按照以下步骤进行操作:1.确保您的计算机已连接到互联网。2.打开“开始”菜单,点击“计算机”右键,选择“属性”。3.在系统属性窗口中,向下滚动到...
- vmware workstation使用教程
-
VMwareWorkstation15是一款虚拟机软件,可以在主机上模拟多个虚拟计算机环境。以下是使用VMwareWorkstation15的基本步骤:1.下载和安装软件:从VMware官方...
- windows7旗舰版64位多少钱(windows7旗舰版64位多少钱合适)
-
这两个都是64位的,唯一区别是后者集成SP1。win7旗舰版64位玉米系统比较稳定,不但稳定,运行速度也很快!WIN764位系统需要的电脑配置。最低配置CPU:1GHz32位或2G...
- 电脑黑屏了怎么重装系统(电脑黑屏怎么重装系统win10)
-
我觉着吧,题主的判断可能是不正确的黑屏开不了机指的是开机后显示屏无任何信号接入首先从电源出发,电源的cpu供电,主板供电,显卡供电,硬盘供电,每一项都要确保接触完整再到主板,主板上呢,cpu散热必须接...
- 三星官网正品查询(三星全新正品查询网站)
-
三星服务中心地址:http://support-cn.samsung.com/support/ServiceLocations.asp国家工信部电信设备进网管理网站查询移动设备真伪方式:方法一:网站查...
- 显示windows许可证即将过期
-
电脑提示Windows许可证即将到期,可以采取以下措施:检查许可证状态:首先需要确认许可证是否真的即将过期。可以在Windows设置中查看许可证状态,或者运行命令“slmgr/xpr”来检查许可证到...
- u盘看不到第二个分区(u盘不显示第二个分区)
-
u盘分区后不显示出来原因一般为以下三种:第一种情况:对于windows系统是只能识别U盘分区的。第二种情况:关于U盘的diskgenius分区是只能看到一个分区的第三种情况:这个U盘分区已经被隐藏了,...
- 小马激活重启电脑开不了机(小马激活重启后蓝屏怎么办)
-
1.无法激活2.小马激活工具可能无法激活的原因有很多,可能是因为软件本身存在bug或者与操作系统不兼容,也可能是因为网络连接问题或者输入的激活码有误。此外,小马激活工具可能需要特定的硬件或软件环境...
- windows7 破解版(windows 7旗舰版破解密码)
-
步骤/方法按Windows徽标键+R(运行窗口),打开cmd运行窗口。输入slmgr.vbs-xpr后回车。这时会弹出一个窗口显示Win7的激活状态。Windows7旗舰版属于微软公司开发的...
- 专业数据恢复(专业数据恢复需要什么设备)
-
1、移动硬盘损坏以后,电脑无法识别到硬盘信息,那么整个硬盘数据将全部丢失。2、如果能够换一台电脑识别到,即使打不开,只要能够格式化,就有希望回复数据。可以尝试制作U盘系统盘的方法,打开u盘系统盘制作程...
- 一周热门
-
-
飞牛OS入门安装遇到问题,如何解决?
-
如何在 iPhone 和 Android 上恢复已删除的抖音消息
-
Boost高性能并发无锁队列指南:boost::lockfree::queue
-
大模型手册: 保姆级用CherryStudio知识库
-
用什么工具在Win中查看8G大的log文件?
-
如何在 Windows 10 或 11 上通过命令行安装 Node.js 和 NPM
-
威联通NAS安装阿里云盘WebDAV服务并添加到Infuse
-
Trae IDE 如何与 GitHub 无缝对接?
-
idea插件之maven search(工欲善其事,必先利其器)
-
如何修改图片拍摄日期?快速修改图片拍摄日期的6种方法
-
- 最近发表
- 标签列表
-
- python判断字典是否为空 (50)
- crontab每周一执行 (48)
- aes和des区别 (43)
- bash脚本和shell脚本的区别 (35)
- canvas库 (33)
- dataframe筛选满足条件的行 (35)
- gitlab日志 (33)
- lua xpcall (36)
- blob转json (33)
- python判断是否在列表中 (34)
- python html转pdf (36)
- 安装指定版本npm (37)
- idea搜索jar包内容 (33)
- css鼠标悬停出现隐藏的文字 (34)
- linux nacos启动命令 (33)
- gitlab 日志 (36)
- adb pull (37)
- python判断元素在不在列表里 (34)
- python 字典删除元素 (34)
- vscode切换git分支 (35)
- python bytes转16进制 (35)
- grep前后几行 (34)
- hashmap转list (35)
- c++ 字符串查找 (35)
- mysql刷新权限 (34)
