[Node.js] 在Linux上安裝Verdaccio並匯入npm packages

  • 614
  • 0
  • 2018-12-10

node.js版本請用10.X.X以上的!

原本用8.X的有時跑到一半會卡住!有bug!

bash script都放在 https://github.com/TzyHuan/offline-local-npm

1.安裝verdaccio

先在連網環境「sudo npm install -g verdaccio」安裝好verdaccio

 

2. 啟用verdaccio

安裝完的verdaccio資料路徑在「/usr/lib/node_modules/verdaccio」

可以不用sudo執行,先直接用一般使用者

可以由CLI執行「verdaccio」或 直接對檔案執行「/usr/lib/node_modules/verdaccio/bin/verdaccio」

verdaccio storage路徑:「/home/{user}/.local/share/verdaccio/storage」

verdaccio config路徑:「/home/{user}/.config/verdaccio/config.yaml」

 

3. 註冊adduser

npm adduser --registry http://127.0.0.1:4873

如果自己用不想註冊權限控管,就把「config.yaml」裡packages的「publish」權限改成「$all」

 

4. 透過Nginx proxy代理

「nano /usr/local/nginx/conf/nginx.confog」設定nginx的proxy

將連來server 80 port的請求都導向本機的4873 port

切記,header一定要設定!

server {
    listen 80;
 
    server_name localhost;
 
    location / {
        proxy_pass http://127.0.0.1:4873;        
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
    }
}

 

5. 下載Package的套件

以leaflet為例,「npmDownload -p leaflet -a -o ./」

載完後解壓縮「tar xvzf leaflet-1.3.4.tgz」

 

6. 發佈開源套件到verdaccio

進入解壓縮的資料夾「cd ./package」找到package.json檔。

因為verdaccio會判斷開源套件的版本資訊,若有重複就error跳出。經過觀察,開源軟體初始版本號不是從「0.1.0」就是「1.0.0」開始,所以把json檔中的「"version"」改成「"0.0.0"」繞過他的判斷。

預設npm service改為本機「npm set registry http://127.0.0.1:4873」

在/home/{user}/package底下「npm publish --registry http://127.0.0.1:4873」,將解壓縮的開源套件發佈到自己的privated npm server。

verdaccio會將套件重新壓縮成.tgz放入套件名稱的資料夾「/home/{user}/.local/share/verdaccio/storage/{packageName}」

同時資料庫「/home/{user}/.local/share/verdaccio/storage/.sinopia-db.json」也會寫入套件名稱。

重點是在我們publish的同時,要讓verdaccio上去「https://registry.npmjs.org/」抓此開源套件版本歷史的json格式詳細資料!

 

7. 修正最新版本號

「/home/{user}/.local/share/verdaccio/storage/{packageName}/package.json」json格式詳細資料也會記載這次publish的版本號「0.0.0」同時變為最新版本,所以「npm install {package}」要是沒指定版本就自動抓「0.0.0」版

我的懶人做法是把檔案中收尋到的「"0.0.0"」全部取代為「這次package的版本號」,這樣會讓最新版本有兩個同樣的資料衝突!

聰明的verdaccio解讀package.json時,會自動把衝突資料舊的部分移從package.json中移除掉!太棒了!

verdaccio要讓package可以運作此套件必須在「.sinopia-db.json」清單中、有「json格式詳細資料」。

如果滿足以上兩個條件,從其他server直接複製貼上過來也可以

 

8. 把流程1~7寫成shell script大量匯入

先到 all-the-package-names 下載names.json,這是人家整理好npm上所有packages的名稱json檔。

然後寫個bash script ,大概流程如下:

1. 利用「cat ./names.json」搭配「awk」一列一列的讀取names.json裡面的套件名稱

2. 搭配npmDownload下載package

3. 重新命名下載好的package folder路徑,因為npmDownload下載的路徑符號是按照Windows的反斜線「\」,Linux路徑只能辨識「/」

4. 隨便抓一個壓縮檔,解壓縮後用「sed」指令修改「./package/package.json」檔案的版本號

5. 「./package/package.json」裡面的"script"若有"prepublishOnly"、"prepublish"、"prepare"、"prepack"、"postpack"的話會影響到npm publish,用「sed」把他們清掉。(反正最後進去verdaccio的壓縮檔才是真的,這邊都只是為了向npm server自動索取package詳細資料的json檔)

原本想把整個"scripts"清掉,有時會遇到排版問題出錯!

6. 將此package publish到verdaccio上後,更改「/home/{user}/.local/share/verdaccio/storage/{packageName}/package.json」中所有版本號為「0.0.0」=>「這次下載的版本」

7. 將下載套件所有版本的{.tgz}壓縮檔移動到verdaccio的存放路徑,「/home/{user}/.local/share/verdaccio/storage/{packageName}」

8. 刪除路徑底下本次下載的套件與解壓縮的東西,不然幾十萬套載下來硬碟會炸掉。

9. 把成功的到紀錄log檔中,然後再迴圈跑一次流程

#!/bin/bash
# History:
# 	this program is to load npm all packages (name.json) file then 
# 	publish its into verdaccio(privated npm server)
# History:
# 	20181203 @Richard begin
#       20181205 @Richard 基本搞定整個流程架構,只怕npm publish那邊出事


# 讀取名單檔案,並透過npmDownload迴圈下載套件
cat ./name-small.json | awk '{

	# 提取json檔,移除特殊符號
	gsub(/"|\[|\]|\,/,"", $1);

	# 套件名稱處理並下載
	if ( length($1)>1){		
		print $1 "\t lines:" NR "\t length:" length($1);
		temp = substr($1,1,length($1)-1); 		# 移除字串尾端看不到的'\r\n'...		
		print temp "\t lines:" NR "\t length:" length(temp);		

		# 執行指令下載"最新的"版本
		system("npmDownload -p \"" temp "\" -o ./");		
		print temp;

		# 重新命名downloaded folder		
		renameCmd = "mv \\\\" temp "\\\\-\\\\ " temp;
		system(renameCmd);
		
		# 取得壓縮檔名稱
		cmd="ls " temp " | head -1";
		cmd | getline tgzName;
		print tgzName;
		close(cmd);

		# 從檔名解析出版本號
		cmd="file=$(ls "temp" | head -1);last=\"${file##*-}\";version=\"${last%.*}\";echo $version;"
		cmd | getline tgzVersion;
		print tgzVersion;
		close(cmd);

		# 解壓縮
		unzipCmd="tar xvzf ./" temp "/" tgzName;
		system(unzipCmd);

		# 修改"./package/package.json"檔
		# 修改「"version": "0.0.0"」
		versionCmd="sed -i \"s/\\\"version.*/\\\"version\\\": \\\"0.0.0\\\"\,/g\" ./package/package.json";
		system(versionCmd);
		# 刪除「"scripts": ...」直到遇到"}"符號,有些package.json格式沒排版會錯誤,改方法
		#scriptsCmd="sed -i \"/\\\"scripts\\\":/,/}/ d; /^$/d\" ./package/package.json";
		#system(scriptsCmd);
		# 刪除有「"prepublish", "prepare", "prepublishOnly", "prepack", "postpack"」字眼的列
		scriptsCmd="sed -i \"/\\\"prepublish\\\": / d; /\\\"prepare\\\": / d; /\\\"prepublishOnly\\\": / d; /\\\"prepack\\\": / d; /\\\"postpack\\\": / d; /^$/d\" ./package/package.json";
		system(scriptsCmd);
		print tgzVersion;

		# publish to privated npm server
		system("sleep 5s");
		system("cd ./package; npm publish --registry http://127.0.0.1:4873;");

		# 修改verdaccio store該package中「0.0.0」改成最新版本號
		reviseCmd="sed -i \"s/\\\"0.0.0\\\"/\\\"" tgzVersion "\\\"/g\" /home/pi/.local/share/verdaccio/storage/"temp"/package.json";
		system(reviseCmd);

		# 解壓縮完休息5秒後,刪除package資料夾
		system("sleep 5s");
		system("rm -r " temp);
		system("rm -r package");		
	}
	else{
		print "====wtf====";
	}
}'

#string="pre-string\\middle\\post-string";
#echo $string;
#string2=`echo $string | perl -pe 's/\\\\middle\\\\/in_the_middle/;'`;

# return 0 to system
exit 0

 

 

 

常用指令

npm root -g
找出linux下global node_modules擺放位置

npm unpublish --force {packageName}
移除package

sudo netstat -apn | grep 80
查看port被占用的情況

kill {pid}
殺掉占用程序

 

參考資料

1. [問題] 在 shell/shell script 下做斜線取代, https://www.ptt.cc/bbs/Perl/M.1308547412.A.39A.html

2. Assigning system command's output to variable, https://stackoverflow.com/questions/1960895/assigning-system-commands-output-to-variable

3. Advanced Chapter 3 : sed 和 awk, http://wanggen.myweb.hinet.net/ach3/ach3.html?MywebPageId=201851543969247374

4. npm-scripts, https://docs.npmjs.com/misc/scripts

5. How to delete a Json object from Json File by sed command in BASH, https://stackoverflow.com/questions/38028600/how-to-delete-a-json-object-from-json-file-by-sed-command-in-bash

6. cut string on last delimiter, https://unix.stackexchange.com/questions/217628/cut-string-on-last-delimiter

7. Extract filename and extension in Bash, https://stackoverflow.com/questions/965053/extract-filename-and-extension-in-bash