Windows 10 用於 Linux 子系統的一鍵構建、打包指令碼「 Node、Gradle 專案」
最近正在開發一個 Java & Vue.js 全棧專案,該專案由以下幾部分組成:Java 後端伺服器、基於 Vue.js 的單頁應用、基於 JavaFX 的 GUI 客戶端以及其他輔助工具等。
其中 Java 服務端及客戶端均依賴公共的 Jar 包,基於 Vue.js 構建生成的靜態檔案亦須轉移至後端模組的相關目錄中,由後端模組附帶的 Web 伺服器管理。如果對專案中的某個子模組進行修改,需要對其手動編譯、移動,再對父模組進行編譯,操作繁瑣,本文探討通過 Windows 10 的 Linux 子系統執行 Shell 指令碼簡化上述操作並進行擴充套件。
之前的一篇文章已探討過 Linux 子系統的使用及在該系統下,Java、Node.js、Gradle 等工具的配置,本文不再贅述。本文開篇首先優化 Linux 子系統「Windows Subsystem for Linux (WSL) 」的使用體驗,
1. 使用 wsl-terminal 增強 WSL 的使用體驗
wsl-terminal 是專門為 WSL 準備的終端模擬器,主體是 mintty,另外整合了一些相當友好的特性,使用起來非常方便,也是目前使用者體驗最好的,推薦使用。
感覺自從用上了 wsl-terminal,完全同時獲得了 Windows 10 優異的介面效果和娛樂性,以及 Linux 的專業性和效率,並且兩者能夠完美融合在一起,完全可以取得好於 macOS 的使用體驗「此處為 YY,我未深度使用過 macOS,坐等打臉」。
wsl-terminal 主要具有如下特性:
- 優秀的相容性(中文顯示/輸入、 24 位顏色、命令輸出等都正常了)。
- 體積小巧,壓縮包僅 1.7 M 多,解壓後不到 10 M 。
- 配置簡單, mintty 可以直接在標題欄右鍵配置, wsl-terminal 的配置檔案也很簡單。
- 可以直接在資源管理器右鍵開啟終端模擬器並定位到當前目錄。
- 可以將 .sh/.py/.pl 指令碼關聯到用 wsl-terminal 執行。
- 可以將文字檔案關聯到用 wsl-terminal 裡的 vim 執行。
- 支援 tmux ,可以在 tmux 裡開啟新目錄,恢復已有的 tmux 會話等。
- 支援在 WSL 裡直接執行 Windows 程式。
注: 本小節摘抄了 這篇部落格 的部分內容。
2. 全棧專案的整體架構
專案的整體架構如下圖所示:
3. 特定指令碼指令及其含義
3.1 獲取當前 Shell 指令碼所在的絕對路徑
dirname file # 獲取 file 檔案的相對路徑
echo $0 # 獲取當前執行的指令碼檔名
pwd # 顯示當前工作目錄
由以上命令可總結出,獲取當前 Shell 指令碼所在的絕對路徑的命令如下:
SH_PATH=$(cd `dirname $0`; pwd)
3.2 Web 靜態檔案
Gradle / Spring 工程中,./src/main/resources/static
目錄下可存放靜態檔案,在服務端程式執行時,即可獲取此目錄下的靜態檔案,所以需要將通過 Webpack 編譯、構建生成的靜態檔案存放在該目錄下。
cp -r ./dist/* $SERVER_PATH/src/main/resources/static # 將靜態檔案複製到指定位置
3.3 獲取 Gradle 構建生成的目標 Jar 檔案的檔名
執行 gradle build
後,即可在 $PROJECT/build/libs
中生成目標 Jar 檔案,獲取該檔案的檔名,以備之後生成 Jar 執行指令碼所用:
NAME=`ls $PROJECT/build/libs` # 獲取當前目錄下唯一的檔案的檔名
3.4 獲取該指令碼執行時的時間
各工程模組均編譯、構建完畢後,需要統一存放在同一個目錄中,各個時期生成的目錄以時間命名進行區分。
BUILD_TIME=`date "+%Y-%m-%d_%H-%M"` # 獲取指令碼執行時的時間
4. 該專案的一鍵構建、打包 Shell 指令碼
4.1 指令碼具體執行流程
- 清理各個工程的歷史構建快取
- 編譯 Web 工程生成靜態檔案,移入後端工程相應目錄。
- 編譯公共依賴 Jar 包,移入後端工程、客戶端工程相應目錄。
- 編譯後端工程、客戶端工程。
- 後端工程、客戶端工程編譯後生成的 Jar 檔案移入打包目錄中,該目錄以指令碼執行時的時間作為區分。
該指令碼的具體執行流程如下圖所示,具體步驟如下:
4.2 一鍵構建、打包指令碼
本文已經將指令碼的重點、流程等內容進行了詳細的介紹,現在貼出指令碼具體內容,如下所示:
#!/bin/bash
# 叢集裝置管理系統工程的 web 端、模擬客戶端、伺服器端等的整體清理、構建、打包、釋出
PROJECT_PATH=/mnt/d/project/ClusterDevicePlatform; # 主工程所在目錄
WEB_PATH=/mnt/d/project/cluster-device-platform-web; # Web 模組所在目錄
SH_PATH=$(cd `dirname $0`; pwd) # 指令碼所在目錄
BUILD_TIME=`date "+%Y-%m-%d_%H-%M"` # 指令碼執行時間
UTIL_JAR_PATH=$PROJECT_PATH/messageUtils; # 公共 Jar 模組所在目錄
SERVER_PATH=$PROJECT_PATH/ClusterDevicePlatform-server; # 伺服器模組所在目錄
CLIENT_PATH=$PROJECT_PATH/ClusterDevicePlatform-client; # 硬體模擬客戶端模組所在目錄
# 專案已編譯歷史檔案的清理
cd $UTIL_JAR_PATH;
rm -rf ./build;
cd $CLIENT_PATH;
rm -rf ./build;
cd $SERVER_PATH;
rm -rf ./build;
rm -rf ./src/main/resources/static;
cd $WEB_PATH;
rm -rf ./dist;
# Web 編譯並將靜態頁面檔案移入伺服器專案中
npm run build
if [ ! $? -eq 0 ]
then echo "Web 編譯出錯"
exit 1
fi
echo Web 編譯完畢
mkdir $SERVER_PATH/src/main/resources/static
cp -r ./dist/* $SERVER_PATH/src/main/resources/static
# Client、Server 的編譯
cd $UTIL_JAR_PATH;
gradle build
cd $CLIENT_PATH;
gradle build
cd $SERVER_PATH;
gradle build
# 組織並集中編譯生成的待發布檔案
mkdir -p $PROJECT_PATH/publish/release/serverRelease_$BUILD_TIME
cd $PROJECT_PATH/publish/release/serverRelease_$BUILD_TIME
cp $CLIENT_PATH/build/libs/* .
cp $SERVER_PATH/build/libs/* .
cp $SH_PATH/template/* .
# 組裝 Client、Server 的執行指令碼
CLIENT_NAME=`ls $CLIENT_PATH/build/libs`
SERVER_NAME=`ls $SERVER_PATH/build/libs`
echo chcp 65001 >> run-client.ps1
echo java -jar -\'Dfile.encoding\'=UTF-8 .\\$CLIENT_NAME cdg-pc 100 >> run-client.ps1
echo '$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")' >> run-client.ps1
echo chcp 65001 >> run-server.ps1
echo java -jar -\'Dfile.encoding\'=UTF-8 .\\$SERVER_NAME >> run-server.ps1
echo '$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")' >> run-server.ps1