众所周知,前端发展到现在已经形成了完整的体系,除了框架的提高效率外,还有一系列的工程化操作。前端工程化离不开npm或yarn等管理工具,通过script串联起各个职能部分,让独立的环节自动运转起来。我们知道无论是npm还是yarn等管理工具的体积都是比较大的,那么实际使用过程中就会出现几个疑问:
- 删除node_modules和lockfiles文件,再重新install,这样操作是否会存在风险呢?
- 把所有依赖都安装在dependencies中,不区分devDependencies会有什么问题呢?
- 应用依赖了公共库A和公共库B,同时A依赖了B,那么B会被多次进行安装或重复打包吗?
- 一个项目中,既有人用npm,又有人使用了yarn,这会引发什么问题呢?
- 我们是否应该将lockfiles文件push到项目仓库中?
1.npm的内部机制和核心原理
我们知道npm的核心目标就是给你和你的团队、你的公司带来最好的开源库和依赖。我们知道在使用npm进行项目启动最重要的环节就是安装相关包和依赖,而在安装过程中出现相关问题,最好的解决方法就是删除node_modules,重新进行npm install。
npm的安装机制优先安装依赖包到当前项目目录,使得各个项目依赖的包形成体系,可以减轻包的兼容性压力,但是缺点是同一个依赖包可能在电脑上安装多次。但是supervisor和gulp等可以使用全局安装模式,方便注册path环境变量,可以直接使用supervisor、gulp等命令。
当构建依赖树时,不管是当前依赖还是依赖的子依赖时,都应该按照扁平化原则优先将其放置node_modules根目录。在此过程 中,遇到相同模块就判断已放置在依赖树中的版本是否兼容此模块,符合则跳过,不符合则在当前node_modules目录下放置该模块。
前端工程中,依赖嵌套依赖,如果每个依赖包都从网络中获取安装,那么就增加了时间成本,如果node_modules安装包通过缓存进行获取,就提升了安装效率。对于一个依赖包的同一个版本进行本地化缓存,是当前依赖包管理工具的一个常见设计,可以通过命令npm config get cache进行获取缓存。当我们打开本地缓存_cache文件时,npm缓存有三个目录:
- content-v2 二进制文件
- index-v5 content-v2里文件索引
- tmp 临时文件
2.npm缓存机制
那么这些缓存是如何存储并被利用的呢?
当npm install执行时,通过pacote把相应的包解压到对应的node_modules下面
pacote依赖npm-registry-fetch来下载包,在给定的路径下根据IETF RFC 7234生成缓存数据
在每次安装资源时,根据package-lock.json中存储的integrity、version、name信息生成一个唯一的key
如果发现有缓存资源,就会找到tar包的hash,再次通过pacote把对应的二进制文件解压到对应的项目node_modules下面
注意:缓存策略是从npm v5版本开始的,在npm v5版本前每个缓存的模块在~/.npm文件夹中以模块名的形式直接存储,存储结构是:{cache}/{name}/{version}
3.如何验证组件的可行性
自定义npm init命令:npm init命令调用shell脚本输出一个初始化的package.json文件。
倘若在开发组件库时,某个组件开发完成后,如何验证该组件能在实际业务项目中正常运行呢?可以在组件库开发中,设计examples目录或者一个playground启动一个开发服务,以验证组件的运行情况。此外,还可以手动复制粘贴组件并打包产出到业务项目的node_modules中进行验证。
如何高效率在本地调试以验证包的可用性?使用npm link,将模块链接到对应的业务项目中运行。npm link的本质就是软链接,主要做了两件事情:
为目标npm模块(npm-package 1)创建软链接,将其链接到全局node模块安装路径/usr/local/lib/node_modules/中
为目标npm模块(npm-package 1)的可执行bin文件创建软链接,将其链接到全局node命令安装路径/usr/local/bin/中
简而言之,npm lick能够在工程中解决依赖包在任何一个真实项目中进行调试的问题,并且操作起来更加方便快捷。
4.npx的作用
在传统项目中使用eslint插件,需要先在命令行进行npm install eslint save-dev,然后再在项目进行命令行调用:
- ./node_modules/.bin/eslint --init
- ./node_modules/.bin/eslint yourfile.js
而使用npx操作就非常便捷,只需要:
- npx eslint --init
- npx eslint yourfile.js
之所以npx如此之便捷,是因为:
可以直接执行node_modules/.bin文件夹下的文件
可以自动去node_modules/.bin路径和环境变量$PATH里面检查命令是否存在
nox在执行模块时会优先安装依赖,但是在安装执行后便删除次依赖,这就避免了全局安装模块带来的问题。
5.npm多源镜像和企业级部署私服原理
例如:npm中的源(registry)对应地址是https://registry.npmjs.org/,我们在开发中常用nrm(npm的镜像源管理工具)进行源的切换和管理。为什么官方源有那么安全,公司还要自己进行部署内部使用的镜像源?原因有两点:
部署镜像后,可以确保高速、稳定的npm服务,使得发布私有模块更加安全
审核机制,保障私服上的npm模块质量和安全
如果我们要部署一个私有npm镜像,有三个工具分别是:
npm的配置优先级:
6.参考
《前端基础设施建设与架构30讲》