cige-deploy v1.2.0
CIGE-deploy
第一步
npm i CIGE-deploy -D
第二步
在你项目 package.json 文件 scripts 脚本下加上下面一行(比较粗暴,有更好的方法望不吝赐教)
"deploy": "node ./node_modules/CIGE-deploy/index"
第三步
在你项目根目录添加 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 等
RENGINX: 'nginx -s reload', //ng重启命令,默认 nginx -s reload
NAME: 'dist', //打包包名
DIST_PATH: 'dist/build/h5', //dist所在目录
DIST_NAME: 'H5' //dist别名
},
production: {//正式
SERVER_PATH: '',
SSH_USER: 'root',
PRIVATE_KEY: '',
PATH: '/test/html' ,
// LOADINGSTYLE: 'arrow4',
// SHELL: ''
}
})
来看主要文件 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('CIGE-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 有说明)**
![avatar](https://segmentfault.com/img/bVbAfI1?w=871&h=102)
//连接服务器 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 = it0;
if(key === 'PATH' && confkey === '/') { //上传zip前会清空目标目录内所有文件
errorLog('PATH 不能是服务器根目录!');
process.exit(); //退出流程
}
if(!confkey) {
errorLog(
配置项 ${key} 不能为空
); process.exit(); //退出流程 } }) }
> **执行交互 选择发布环境 然后启动发布程序**
// 执行交互后 启动发布程序 inquirer .prompt([{ type: 'list', message: '请选择发布环境', name: 'env', choices: { name: '测试环境', value: 'development' },{ name: '正式环境', value: 'production' } }]) .then(answers => { config = CONFIGanswers.env; checkConfig(config); // 检查 runUploadTask(); // 发布 });
> **大功告成**