1

bgwd-deploy 前端部署工具

说到部署很多人想到 Jenkins docker 等, 但学习使用成本 可能让很多人望而却步.

倒不如试试我这个? 三步曲

项目github 地址

npm 地址

第一步

npm i bgwd-deploy -D

第二步

在你项目 package.json 文件 scripts 脚本下加上下面一行(比较粗暴,有更好的方法望不吝赐教)

"deploy": "node ./node_modules/bgwd-deploy/index"

image.png

第三步

在你项目根目录添加 deploy.config.js 文件 内容如下:
然后就可以 npm run deploy 部署了.

// 关于团队合作 成员 PRIVATE_KEY 不一致问题, 可以每个成员单独配置自己的 PRIVATE_KEY 然后在 .gitignore 添加 deploy.config.js 忽略上传
// 配置参考文件  实际配置文件需要用户在自己项目根目录 添加 deploy.config.js
module.exports = Object.freeze({
  development: {//测试
    SERVER_PATH: 'xx.xxx.xx.xx', // ssh地址 服务器地址
    SSH_USER: 'root', // ssh 用户名
  //登录方式 (二选一, 不用的方式注释掉)
  //方式一 用秘钥登录服务器(推荐), 
    // 把本机 公钥 .ssh目录下 id_rsa.pub 放服务器 authorized_keys 文件里, 多个电脑公钥换行分开
    //private 本机私钥文件地址(需要在服务器用户目录 一般是 ~/.ssh/authorized_keys 配置公钥 并该文件权限为 600, (.ssh文件夹一般默认隐藏)
    // 一般 .ssh在用户目录下  cd ~/.ssh/  复制路径放下面 pwd 可查看当前路径 路径用 / 别 \ 例如以下 C:/Users/Administrator/.ssh/id_rsa
    PRIVATE_KEY: 'C:/Users/Administrator/.ssh/id_rsa', 
  //方式二 用密码连接服务器
    // PASSWORD: '',
    PATH: '/test/h5', // 需要上传的服务器目录地址 如 /usr/local/nginx/html/prodName
    //(该参数可选) 默认为 arrow4 加载动画 有 dots 至 dots12 如 dots6,  line ,
    // pipe , star, arrow 至 arrow4 等等, 查看更多在该项目 src下的 spinner_style.js
    LOADINGSTYLE: 'arrow4',
    // SHELL: '' // 自定义打包命令(不用请注释), 默认 npm run build , 可自定义 如 npm run build:prd 等
  },
  production: {//正式
    SERVER_PATH: '', 
    SSH_USER: 'root',
    PRIVATE_KEY: '', 
    PATH: '/test/html' ,
    // LOADINGSTYLE: 'arrow4',
    // SHELL: '' 
  }
})

image.png
image.png
image.png
大功告成~~


项目代码

来看主要文件 index.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 那就非常感谢了
项目github 地址


波哥无敌
6 声望2 粉丝

被代码耽误的吉他爱好者