01|JS包管理工具和原理分析:npm安装机制及企业级部署私服原理
前端工程化离不开npm或者yarn管理工具
通过script串联起各个职能部分,让独立的环节自动运转起来。
课程介绍
- 删除node_modules和lockfiles,再重新install,这样操作是否存在风险?
- 把所有依赖都安装到dependencies中,不区分devDependencies会有问题吗?
- 应用依赖了公共库A和公共库B,同时公共库A也依赖了公共库B,那么公共库B会被多次安装或重复打包吗?
- 一个项目中,既有人用npm,也有人用yarn,这会引发什么问题?
- 我们是否应该提交lockfiles文件到项目仓库呢?
Bring the best of open source to you, your team and your company.
给你和你的团队、你的公司带来最好的开源库和依赖。
—— Npm的核心目标
“删除node_modules,重新npm install”
解决npm安装类问题的方法
npm的安装机制
优先安装依赖包到当前项目目录=>同一个依赖包可能在电脑上进行多次安装
对于supervisor和gulp
使用全局安装模式,方便注册path环境变量,以便可以直接使用superviso、gulp这些命令。
- npm v5.0.x:根据package-lock.json下载
- Npm v5.1.0-v5.4.2:当package.json声明的依赖版本规范有符合更新版本时,忽略package-lock.json,按照package.json安装,并更新package-lock.json
- Npm v5.4.2以上:当package.json声明的依赖版本规范与package-lock.json安装版本兼容,则根据package-lock.json安装;如果package.json声明的依赖版本规范与package-lock.json安装版本不兼容,按照package.json安装,并更新package-lock.json
构建依赖树时,应该按照扁平化原则,优先将其放置在node_modules根目录
npm 缓存机制
前端工程中,依赖嵌套依赖
node_modules安装包,通过缓存获取
对于一个依赖包的同一版本本地化缓存
当代依赖包管理工具的一个常见设计
npm config get cache
使用以下命令清除/Users/cehou/.npm/_cacache中的文件:
# 清除缓存
npm cache clean --force
打开_cacache文件,npm缓存的3个目录:
- content-v2——>二进制文件
- index-v5——>content-v2里文件索引
- tmp
这些缓存如何被储存并被利用的呢?
- 当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}
npm不完全指南
npm init 命令调用 shell脚本输出一个初始化的package.json文件。
const desc = prompt('请输入项目描述', '项目描述')
module.exports = {
key:'value',
name:prompt('name?', process.cwd().split('/').pop()),
version: prompt('version?', '0.0.1'),
description: desc,
main: 'index.js',
repository: prompt('github repository url', function(url) {
if (url) {
run('touch README.md');
run('git init');
run('git add README.md');
run('git commit -m "first commit"');
run(`git remote add origin ${url}`)
run('git push -u origin master');
}
return url;
})
}
自定义npm init
npm config set init-module ~\.npm-init.js
npm config set init.author.name "Lucas"
npm config set init.author.email
"lucasXXXXXX@gmail.com"
npm config set init.author.url "lucasXXXX.com"
npm config set init.license "MIT"
利用 npm link,高效率在本地调试以验证包的可用性
假如我开发一个组件库,某个组件开发完成之后
如何验证该组件能在我的业务项目中正常运行呢?
- 在组件库开发中,设计examples 目录或者一个 playground 启动一个开发服务,以验证组件的运行情况。
如何高效率在本地调试以验证包的可用性?
-
使用npm link,将模块链接到对应的业务项目中运行
-
示例:
npm 模块包名称是 npm-package1
-project1
--package1 feature A
调试package1的新功能featureA
- 在package1目录中执行npm link(链接目录和可执行文件)
- 在project1 目录中创建链接,执行npm link npm-package 1命令
npm link 的本质就是软链接,主要做了两件事:
- 为目标npm模块(npm-package1)创建软链接,将其链接到全局node模块安装路径
usr/local/lib/node_modules/
中- 为目标npm模块(npm-package1)的可执行bin文件创建软链接将其链接到全局node命令安装路径
/usr/local/bin
中
npm link 能够在工程上解决依赖包在任何一个真实项目中进行调试的问题,并且操作起来更加方便快捷
npx的作用
传统操作:
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里面检查命令是否存在
- npx执行模块时会优先安装依赖,但是在安装执行后便删除此依赖,这就避免了全局安装模块带来的问题
npx create-react-app cra-project
npx 会将 create-react-app 下载到一个临时目录,使用后删除
npm多源镜像和企业级部署私服原理
"scripts":{
"preinstall":"'node./bin/preinstall.js"
}
require('child_process').exec('npm config get registry'
function(error,stdout,stderr){
if(stdout.toString(.match(/registryl.xl.com/)){
exec('npm config set @xscope:registry
https://xxx.com/npm/)
}
})
nrm是npm的镜像源管理工具
- 部署镜像后,确保高速、稳定的npm服务是发布私有模块更加安全
- 审核机制,保障私服上的npm模块质量和安全
如何部署一个私有npm镜像呢?
- nexus
- verdaccio
- cnpm