前端基于 scp2 的自动化部署方案
前端基于scp2 的自动化部署方案
写在前面
前端自动化部署的核心思路是:
- 1、构建前端项目(构建之前加入自动化代码检查和自动化测试)
- 2、上传到服务器
基于 node-scp2
方式的自动化部署是简单的,只需要在项目中创建一个配置文件,写好相关的配置和执行顺序即可,之后每次需要部署的时候,只需要执行部署命令。
scp2 简介
一个基于 ssh 的纯 JavaScript 安全复制程序。
优点: 可以在每个操作系统上执行,unix、Linux、windows等。
需要注意的是:在 windows 上执行需要依托 Node 环境,最低版本为 v0.8.7。
使用步骤
一、创建scp2相关的配置文件
【1】、在项目根目录下创建 deploy
文件夹, 在 deploy
文件夹下创建 config.js
文件用来保存服务器的配置信息。(示例如下:)
// config.js
/*
*读取env环境变量
*/
const fs = require('fs')
const path = require('path')
// env 文件 判断打包环境指定对应的服务器id
const envfile = process.env.NODE_ENV === 'prod' ? '../.env.prod' : '../.env.dev'
// env环境变量的路径
const envPath = path.resolve(__dirname, envfile)
// env对象
const envObj = parse(fs.readFileSync(envPath, 'utf8'))
const ENV_NAME = envObj['VUE_APP_SERVER_ENV']
/**
* 解析KEY=VAL格式的配置文件
* @Author Author
* @DateTime 2022-07-07T16:30:14+0800
* @param {[type]} src [description]
* @return {[type]} [description]
*/
function parse(src) {
const res = {}
src.split('\n').forEach(line => {
// matching "KEY' and 'VAL' in 'KEY=VAL'
// eslint-disable-next-line no-useless-escape
const keyValueArr = line.match(/^\s*([\w\.\-]+)\s*=\s*(.*)?\s*$/)
// matched?
if (keyValueArr != null) {
const key = keyValueArr[1]
let value = keyValueArr[2] || ''
// expand newlines in quoted values
const len = value ? value.length : 0
if (len > 0 && value.charAt(0) === '"' && value.charAt(len - 1) === '"') {
value = value.replace(/\\n/gm, '\n')
}
// remove any surrounding quotes and extra spaces
value = value.replace(/(^['"]|['"]$)/g, '').trim()
res[key] = value
}
})
return res
}
/*
*定义多个服务器账号 及 根据 SERVER_ID 导出当前环境服务器账号
*/
const SERVER_LIST = {
dev: {
id: 0,
name: 'A-生产环境',
domain: 'qq.zbc.com', // 网站域名
host: '110.42.130.82', // 服务器ip
port: 22, // 登录服务器端口
username: 'root', // 登录服务器的账号
password: 'prod123456', // 登录服务器的账号
path: '/www/wwwroot/site/dist', // 发布至静态服务器的项目路径
rootPath: '/www/wwwroot/site'
},
prod: {
id: 1,
name: 'B-测试环境',
domain: 'bms.aini.com',
host: '110.42.130.81',
port: 22,
username: 'root',
password: 'test123456',
path: '/www/wwwroot/site/dist',
rootPath: '/www/wwwroot/site'
}
}
module.exports = SERVER_LIST[ENV_NAME]
【1-1】、以 Vue 框架项目为例,项目根目录下一般会有 .env.dev
,.env.production
等之类的配置文件。
为了让我们的自动化部署更灵活:可以部署测试环境也可以部署生产环境或者其他的预发布环境之类的。
我们希望 config.js
可以根据我们执行命令时传入的环境变量 NODE_ENV
来选择载入对应的配置文件 ../.env.prod
或 ../.env.env
,然后加载对应 scp2
需要的服务器配置信息(包含:用户名、密码、前端目录等等…)
【2】、在 deploy
文件夹下创建 index.js
文件,用于存放自动化部署脚本(示例如下:)
const scpClient = require('scp2')
const ora = require('ora')
const chalk = require('chalk')
const server = require('./config.js')
const spinner = ora('正在发布到' + (process.env.NODE_ENV === 'prod' ? '生产' : '测试') + '服务器...')
spinner.start()
scpClient.scp(
'./dist/',
{
host: server.host,
port: server.port,
username: server.username,
password: server.password,
path: server.path
},
function (err) {
spinner.stop()
if (err) {
console.log(chalk.red('发布失败.\n'))
throw err
} else {
console.log(chalk.green('Success! 成功发布到' + (process.env.NODE_ENV === 'prod' ? '生产' : '测试') + '服务器! \n'))
}
}
)
二、添加执行命令
在 package.json
中注册执行命令,自定义命令名称:
"scripts": {
"serve": "vue-cli-service serve --mode dev",
"build": "vue-cli-service build --mode prod",
"deploy:dev": "cross-env NODE_ENV=dev node ./deploy",
"deploy:prod": "cross-env NODE_ENV=prod node ./deploy"
}
三、在命令行中输入命令,进行部署
执行命令之前,需要先安装相关依赖包:
"chalk": "^4.1.2",
"cross-env": "^7.0.3",
"ora": "^5.1.0",
"readline": "^1.3.0",
"scp2": "^0.5.0"
【注意】
关于 ora
和 chalk
包,如果你直接使用 npm i ora chalk
来安装的话。安装的就是最新的 ora
和 chalk
,可能或报错:
const chalk = require(‘chalk’)
^
Error [ERR_REQUIRE_ESM]: require() of ES Module
【解决方案】: 降低 ora
和 chalk
的版本。使用上面提供的依赖包的版本。
发布到开发环境
npm run deploy:dev
发布到生产环境
npm run deploy:prod
当控制台提示:“Success! 成功发布到 ‘生产’ : ‘测试’ '服务器!”时,表示文件上传成功,此时登录服务器可查看已上传文件;或者打开部署后的系统查看是否更新。
【注意事项】
- 由于我们是将服务器登录信息放到
deploy/config.js
文件中;所以,在上传 git 时一定要将服务器配置文件添加到.gitignore
文件中,避免服务器信息泄露。
改进/升级
一、交互性输入用户名和密码
交互型输入用户名和密码,指为了保密性不将服务器的用户名和密码直接明文写死在配置中,而是在上传文件时交互式的输入用户名和密码。
使用 node-readline
工具包,来支持输入用户名和密码。
获取到用户名和密码后动态赋值给 server
配置对象。
使用赋值后的 server
配置对象来连接服务器,从而实现自动化部署。
1、安装 readline 模块。
npm i readline
2、在代码 deploy/index.js
中引入 readline
,并创建 readline
实例。
const readline = require('readline')
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})
const questions = ['Please input publish environment(test\\prod\\dev): ', 'Please input server username: ', 'Please input server password: ']
const linelimit = 3
let inputArr = []
let index = 0
let server = null
// 依次执行命令行交互语句
function runQueLoop() {
if(index === linelimit) {
server = config[inputArr[0]]
server.username = inputArr[1]
server.password = inputArr[2]
deployFile()
return
}
rl.question(questions[index], as => {
inputArr[index] = as
index++
runQueLoop()
})
}
runQueLoop()
function deployFile() {
// 将前面的 scp2 上传文件到服务器代码,封装到这里。
}
二、上传前备份旧版文件
强烈建议,在上传文件前对旧版文件进行备份,方便版本回退或部署失败后能够保证生产环境能够正常运行。
对代码进行简单的修改,在上传文件前,使用 ssh
先对原文件进行拷贝,删除,之后再上传文件。
基本实现思路如下:
- 进入到上传文件的根目录下 — 即 server 配置中的 rootPath 属性
- 新建一个文件夹用于备份
_backUp/文件名
- 拷贝旧版部署包到备份文件夹下
- 删除旧版部署包
- 上传新版部署包
具体实现方案:
1、安装 ssh2 模块。
npm i ssh
2、导入 ssh2 模块,并声明要执行的命令。
// ssh2 传输
const Client = require('ssh2').Client
const conn = new Client()
// 声明要执行的命令
let cmd = `cd ${rootPath}\n
mkdir -p _backUp/${rootFolder}_${currentTime}\n
cp -r ${path} ${rootPath}/_backUp/${rootFolder}_${currentTime}/\n
rm -rf ${path}`
3、连接服务器,执行命令。
conn.on('ready', function() {
conn.exec(cmd, function(err, stream) {
// 备份命令执行后
console.log(chalk.green('已执行备份命令'))
if (err) throw err
// 在执行命令行成功后上传文件到服务器上
stream.on('close', function (code, signal) {
// 执行部署工作
deployFile()
})
})
})
.on('error',function(){})
.connect({
host: server.host,
port: server.port,
username: server.username,
password: server.password
})
—————————— 【正文完】——————————
前端学习交流群,想进来面基的,可以加群: 832485817,685486827;
写在最后: 约定优于配置 —— 软件开发的简约原则
——————————【完】——————————
我的:
个人网站: https://neveryu.github.io/neveryu/
Github: https://github.com/Neveryu
新浪微博: https://weibo.com/Neveryu
微信: miracle421354532
更多学习资源请关注我的新浪微博…好吗