【问题背景】
用Nexus搭建了内网的依赖仓库,需要将前端工程中node_modules中的依赖上传到Nexus上,但是node_modules中的依赖已经是解压后的状态,如果直接机械地将其简单地打包上传到Nexus,那么无法通过npm install下载使用。故有此文。
【解决思路】
前端工程中的所有npm依赖信息已经记录在package-lock.json文件中,包括依赖的下载地址,所以可以直接根据package-lock.json中记录的依赖地址逐个下载依赖的原始包,然后再上传到Nexus对应的仓库中。
【前置条件】
- Nexus上已创建好hosted类型的npm仓库,假设起名为:npm-local
- 本地前端工程所在PC可以连接互联网
- 本地前端工程已执行npm install且已生成package-lock.json
【编写脚本】
下述的NodeJS脚本可以下载package-lock.json文件中的依赖,将该脚本保存到一个名为downloadNpmPackage.js的文件中:
javascript
const fs = require('fs');
const path = require('path');
const request = require('request');
// 指定根据package-lock.json中记录的信息下载依赖
const packageLock = require('./package-lock.json');
// 指定将依赖下载到当前目录下的npm-dependencies-tgz目录
const downUrl = './npm-dependencies-tgz';
if (!fs.existsSync(downUrl)) {
fs.mkdirSync(downUrl);
}
// 收集依赖的下载路径
const tgz = [];
for (let pkg in packageLock.dependencies) {
let tgzUrl = packageLock.dependencies[pkg]['resolved'];
tgz.push(tgzUrl);
}
// 逐个下载
tgz.forEach((url) => {
const outUrl = url.split('/').pop()
let outUrl2 = [outUrl]
if(outUrl.indexOf('?') !== -1){
outUrl2 = outUrl.split('?')
}
const outputDir = path.join(downUrl, outUrl2[0])
let receivedBytes = 0;
let totalBytes = 0;
const req = request({
method: 'GET',
uri: url
});
req.on('response', function(data) {
totalBytes = parseInt(data.headers['content-length']);
});
req.on('data', function(chunk) {
receivedBytes += chunk.length;
showProgress(receivedBytes, totalBytes, outUrl2[0]);
});
req.pipe(fs.createWriteStream(outputDir));
});
// 依赖下载进度显示
function showProgress(received, total, filePath) {
const percentage = ((received * 100) / total).toFixed(2);
process.stdout.write(`${filePath} 下载进度:${percentage}% (${received}/${total} 字节)\r`);
if (received === total) {
console.log(`\n${filePath} 下载完成!`);
}
}
下述Bash脚本可以将下载好的前端依赖上传到Nexus上,将该脚本保存到名为UploadnpmPackage.sh的文件中。
bash
#!/bin/bash
# 获取命令行参数
while getopts ":r:u:p:" opt; do
case $opt in
r) REPO_URL="$OPTARG"
;;
u) USERNAME="$OPTARG"
;;
p) PASSWORD="$OPTARG"
;;
esac
done
# find 并批量上传
find . -type f -name '*.tgz' | sed "s|^\./||" | xargs -I '{}' \
curl -u "$USERNAME:$PASSWORD" -X 'POST' -v \
${REPO_URL} \
-H 'accept: application/json' \
-H 'Content-Type: multipart/form-data' \
-F 'npm.asset=@{};type=application/x-compressed' ;
【上传依赖】
1.将NodeJs脚本downloadNpmPackage.js置于前端工程目录下且与package-lock.json文件同级:
2.在当前目录运行Node命令:
|----------------------------|
| node downloadNpmPackage.js |
等待程序下载依赖包:
下载完成后会在package-lock.json同级目录生成一个名为npm-dependencies-tgz的文件夹:
里面存放的是当前工程所有依赖的tgz文件:
将npm-dependencies-tgz文件夹打包成tar压缩包。
3.z至此上一步压缩的tar包和名为UploadnpmPackage.sh的shell脚本如下,可以将这俩发给负责依赖上传的同事,由他们完成后面的上传操作。
4.上传依赖的同事收到上述两个文件后,解压npm-dependencies-tgz.tar压缩包,得到npm-dependencies-tgz目录,将UploadnpmPackage.sh剪切到npm-dependencies-tgz目录下与所有tgz依赖包同级:
5.若是linux操作系统,则需要使用如下命令将脚本中的换行符进行转换:
|------------------------------|
| dos2unix UploadnpmPackage.sh |
若没有dos2unix则需要安装一下:sudo yum install dos2unix。如果是windows则跳过本步。
6.在npm-dependencies-tgz目录下使用如下命令运行脚本UploadnpmPackage.sh将依赖包上传到nexus上,注意红字部分根据Nexus的实际情况填写:
|---------------------------------------------------------------------------------------------------------------------------------|
| sh UploadnpmPackage.sh -u admin -p nexusAdmin2023 -r http://172.24.105.249:8089/service/rest/v1/components?repository=npm-local |
7.登录Nexus网页,查看到npm-local仓库下已经存在刚才上传的依赖了:
【使用依赖】
1.完成上述上传操作后,查看并复制npm-local仓库地址:
9.CI工具中配置依赖拉取地址为上述复制的地址:http://172.24.105.249:8089/repository/npm-local/。或者离线编译前端源码时可以使用如下命令设置npm仓库地址:
|--------------------------------------------------------------------------|
| npm config set registry=http://172.24.105.249:8089/repository/npm-local/ |
10.到此便可正常运行npm install安装依赖了。