前端自動化部署服務器, 告別繁瑣部署過程

永恆的前言


簡單實用的前端部署, 一條命令搞定, 省去繁瑣的步驟!
主要是 nodejs shelljs(命令行命令) node-ssh(鏈接服務器)
項目git 地址
(這個git項目是我本身搭的一個比較low的vue腳手架,集成ts)
(第一次寫文章, 文筆不行, 多多包涵,有不對的地方儘管指出)html

(主要看 自動部署 在 upload 目錄 )前端

如何在你項目中使用( 五步曲 )

第一步, 把項目裏 upload 文件夾複製到你項目根目錄

image.png

第二步, 下載該js相關依賴

npm 或 cnpm i chalk ora shelljs node-ssh inquirer compressing -Dvue

第三步, 打開 upload/config.js 配置文件, 配置ssh地址, 用戶名, 驗證方式,須要上傳的目錄

image.png

第四步, 在你項目中 package.json 文件中 加上 "deploy": "node ./upload/upload.js"

image.png

最後 在命令行輸入 npm run deploy 選擇發佈環境 而後就ojbk了

image.png
image.png
image.png
image.png

大功告成~~node


來看主要文件 upload.js

項目依賴

const chalk = require('chalk') //命令行顏色
const ora = require('ora') // 加載流程動畫
const spinner_style = require('./spinner_style') //加載動畫樣式
const shell = require('shelljs') // 執行shell命令
const node_ssh = require('node-ssh') // ssh鏈接服務器
const inquirer = require('inquirer') //命令行交互
const zipFile = require('compressing')// 壓縮zip
const fs = require('fs') // nodejs內置文件模塊
const path = require('path') // nodejs內置路徑模塊
const CONFIG = require('./config') // 配置

一些常量,變量和logs

const SSH = new node_ssh();
let config; // 用於保存 inquirer 命令行交互後選擇正式|測試版的配置

//logs
const defaultLog = log => console.log(chalk.blue(`---------------- ${log} ----------------`));
const errorLog = log => console.log(chalk.red(`---------------- ${log} ----------------`));
const successLog = log => console.log(chalk.green(`---------------- ${log} ----------------`));

//文件夾目錄
const distDir = path.resolve(__dirname, '../dist'); //待打包
const distZipPath = path.resolve(__dirname, `../dist.zip`);
//打包後地址(dist.zip是文件名,不須要更改, 主要在config中配置 PATH 便可)

打包

首先 執行項目打包命令
//項目打包代碼 npm run build 
const compileDist = async () => {
  const loading = ora( defaultLog('項目開始打包') ).start();
  loading.spinner = spinner_style.arrow4;
  shell.cd(path.resolve(__dirname, '../'));
  const res = await shell.exec('npm run build'); //執行shell 打包命令
  loading.stop();
  if(res.code === 0) {
    successLog('項目打包成功!');
  } else {
    errorLog('項目打包失敗, 請重試!');
    process.exit(); //退出流程
  }
}

壓縮

而後 對打包的代碼 /dist 目錄打包 (若是不是dist, 請更改上面的 disDir 常量結尾的dist)
//壓縮代碼
const zipDist = async ()=>{
  defaultLog('項目開始壓縮');
  try {
    await zipFile.zip.compressDir(distDir, distZipPath)
    successLog('壓縮成功!');
  } catch (error) {
    errorLog(error);
    errorLog('壓縮失敗, 退出程序!');
    process.exit(); //退出流程
  }
}

鏈接服務器

再而後 經過ssh鏈接服務器 有兩種方式: 一是經過祕鑰鏈接(推薦), 二是密碼鏈接
祕鑰鏈接須要把本機公鑰放服務器指定目錄 (在upload/config.js 有說明)
image.png
//鏈接服務器
const connectSSH = async ()=>{
  const loading = ora( defaultLog('正在鏈接服務器') ).start();
  loading.spinner = spinner_style.arrow4;
  try {
    await SSH.connect({
      host: config.SERVER_PATH,
      username: config.SSH_USER,
      // privateKey: config.PRIVATE_KEY, //祕鑰登陸(推薦) 方式一
      password: config.PASSWORD // 密碼登陸 方式二
    });
    successLog('SSH鏈接成功!'); 
  } catch (error) {
    errorLog(error);
    errorLog('SSH鏈接失敗!');
    process.exit(); //退出流程
  }
  loading.stop();
}

上傳文件

緊接着 經過ssh執行線上命令 進行目標目錄清空, 而後上傳zip到服務器 並解壓 等操做
//線上執行命令
/**
 * 
 * @param {String} command 命令操做 如 ls
 */
const runCommand = async (command)=> {
  const result = await SSH.exec(command, [], { cwd: config.PATH})
  // defaultLog(result);
}

//清空線上目標目錄裏的舊文件
const clearOldFile = async () =>{
  const commands = ['ls', 'rm -rf *'];
  await Promise.all(commands.map(async (it)=>{
    return await runCommand(it);
  }));
}

//傳送zip文件到服務器
const uploadZipBySSH = async () =>{
  //鏈接ssh
  await connectSSH();
  //線上目標文件清空
  await clearOldFile();
  const loading = ora( defaultLog('準備上傳文件') ).start();
  loading.spinner = spinner_style.arrow4;
  try {
    await SSH.putFiles([{ local: distZipPath, remote: config.PATH + '/dist.zip' }]); //local 本地 ; remote 服務器 ;
    successLog('上傳成功!'); 
    loading.text = '正在解壓文件';
    await runCommand('unzip ./dist.zip'); //解壓
    await runCommand(`rm -rf ${config.PATH}/dist.zip`); //解壓完刪除線上壓縮包
    //將目標目錄的dist裏面文件移出到目標文件  
    //舉個例子 假如咱們部署在 /test/html 這個目錄下 只有一個網站, 那麼上傳解壓後的文件在 /test/html/dist 裏
    //須要將 dist 目錄下的文件 移出到 /test/html ;  多網站狀況, 如 /test/html/h5  或者 /test/html/admin 都和上面一樣道理
    await runCommand(`mv -f ${config.PATH}/dist/*  ${config.PATH}`); 
    await runCommand(`rm -rf ${config.PATH}/dist`); //移出後刪除 dist 文件夾
    SSH.dispose(); //斷開鏈接
  } catch (error) {
    errorLog(error);
    errorLog('上傳失敗!');
    process.exit(); //退出流程
  }
  loading.stop();
}

整合

把這些整合在一個函數
//------------發佈程序---------------
const runUploadTask = async () => {
  console.log(chalk.yellow(`--------->  歡迎使用 波哥牌 2020年自動部署工具  <---------`));
  //打包
  await compileDist();
  //壓縮
  await zipDist();
  //鏈接服務器上傳文件
  await uploadZipBySSH(); 
  successLog('大吉大利, 部署成功!'); 
  process.exit();
}

發佈前的檢查配置

// 開始前的配置檢查
/**
 * 
 * @param {Object} conf 配置對象
 */
const checkConfig = (conf) =>{
  const checkArr = Object.entries(conf);
  checkArr.map(it=>{
    const key = it[0];
    if(key === 'PATH' && conf[key] === '/') { //上傳zip前會清空目標目錄內全部文件
      errorLog('PATH 不能是服務器根目錄!'); 
      process.exit(); //退出流程
    }
    if(!conf[key]) {
      errorLog(`配置項 ${key} 不能爲空`); 
      process.exit(); //退出流程
    }
  })
}

發佈

執行交互 選擇發佈環境 而後啓動發佈程序
// 執行交互後 啓動發佈程序
inquirer
  .prompt([{
    type: 'list',
    message: '請選擇發佈環境',
    name: 'env',
    choices: [{
      name: '測試環境',
      value: 'development'
    },{
      name: '正式環境',
      value: 'production'
    }]
  }])
  .then(answers => {
    config = CONFIG[answers.env];
    checkConfig(config); // 檢查
    runUploadTask(); // 發佈
  });
大功告成

結尾

咳咳, 放心, 不會有公衆號啥廣告, 也不會求打賞, 若是您以爲對您有一點點幫助 點個贊或者去GitHub點個star 那就很是感謝了
項目git 地址git

相關文章
相關標籤/搜索