准备工作
yarn add ssh2 commander archiver
开搞
在项目根目录建一个文件夹publish
新增两个文件publish-zip.js ,publish.js
publish-zip.js内容如下
const fs = require('fs')
const archiver = require('archiver')
const env = require('../config/prod.env')
module.exports = function () {
var output = fs.createWriteStream(`publish/${env.DEFAULT_HOST.name}.zip`)
var archive = archiver('zip')
output.on('close', function () {
console.log('compress completed...ready upload')
require('./publish.js')()
})
output.on('end', function () {
})
archive.on('error', function (err) {
throw err
})
archive.pipe(output)
archive.glob('./dist' + '/**')
archive.finalize()
}
publish.js内容如下
const env = require('../config/prod.env')
const chalk = require('chalk')
var Client = require('ssh2').Client
var conn = new Client()
var fs = require('fs')
const user = {
host: env.DEFAULT_HOST.host,
port: 22,
username: env.DEFAULT_HOST.user,
// password: env.DEFAULT_HOST.password
privateKey: fs.readFileSync('./publish/id_rsa')
}
/**
* 1.进入目录
* 2.删除旧的备份项目
* 3.将原项目名称加上bak标志为备份文件
* 4.解压缩上传的zip文件并将名称改为项目名称
* 5.删除zip文件
* 6.退出
* @type {string[]}
*/
const uploadShellList = [
`cd ${env.DEFAULT_HOST.path}\n`,
`rm -rf ${env.DEFAULT_HOST.name}.bak\n`,
`mv ${env.DEFAULT_HOST.name} ${env.DEFAULT_HOST.name}.bak\n`,
`unzip ${env.DEFAULT_HOST.name}.zip\n`,
`mv dist ${env.DEFAULT_HOST.name}\n`,
`rm -rf ${env.DEFAULT_HOST.name}.zip\n`,
`exit\n`
]
const params = {file: `./publish/${env.DEFAULT_HOST.name}.zip`, target: `${env.DEFAULT_HOST.path}/${env.DEFAULT_HOST.name}.zip`}
/**
* 上传文件
* @param conn
* @param params
* @constructor
*/
function UploadFile (conn, params) {
const file = params.file
const target = params.target
if (!conn) {
return
}
conn.sftp(function (err, sftp) {
if (err) {
throw err
}
sftp.fastPut(file, target, {}, function (err, result) {
if (err) {
console.log(chalk.red(err.message))
throw err
}
Shell(conn)
})
})
}
function Ready () {
conn.on('ready', function () {
console.log('Client :: ready')
UploadFile(conn, params)
}).connect(user)
}
/**
* 上传完成后服务器需要执行的内容
* 删除本地压缩文件
* @param conn
* @constructor
*/
function Shell (conn) {
conn.shell(function (err, stream) {
if (err) throw err
stream.on('close', function () {
console.log('Stream :: close')
conn.end()
fs.unlinkSync(`./publish/${env.DEFAULT_HOST.name}.zip`)
}).on('data', function (data) {
console.log('STDOUT: ' + data)
}).stderr.on('data', function (data) {
console.log('STDERR: ' + data)
})
stream.end(uploadShellList.join(''))
})
}
module.exports = function () {
try {
Ready()
} catch (err) {
console.log(err)
}
}
这里登陆方式分两种 密码登陆和秘钥登录
// password: env.DEFAULT_HOST.password
privateKey: fs.readFileSync('./publish/id_rsa')
在config/prod.env.js 修改如下
"use strict";
const REMOTE_SERVER = '0.0.0.0'
const DEFAULT_HOST = { host: REMOTE_SERVER, user: 'root',password:'', key: '', name: 'demo', path: '/home' }
module.exports = {
REMOTE_HOST: REMOTE_SERVER,
DEFAULT_HOST: DEFAULT_HOST,
};
name是项目名,path是服务器路径
build/build.js修改如下
'use strict'
require('./check-versions')()
const program = require('commander')
process.env.NODE_ENV = 'production'
const ora = require('ora')
const rm = require('rimraf')
const path = require('path')
const chalk = require('chalk')
const webpack = require('webpack')
const config = require('../config')
const webpackConfig = require('./webpack.prod.conf')
const spinner = ora('building for production...')
spinner.start()
program
.version('0.0.1')
.option('-p, --publish', 'Publish Remote')
.parse(process.argv)
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
if (err) throw err
webpack(webpackConfig, (err, stats) => {
spinner.stop()
if (err) throw err
process.stdout.write(stats.toString({
colors: true,
modules: false,
children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
chunks: false,
chunkModules: false
}) + '\n\n')
if (stats.hasErrors()) {
console.log(chalk.red(' Build failed with errors.\n'))
process.exit(1)
}
console.log(chalk.cyan(' Build complete.\n'))
console.log(chalk.yellow(
' Tip: built files are meant to be served over an HTTP server.\n' +
' Opening index.html over file:// won\'t work.\n'
))
if (program.publish) {
console.log('-----');
require('../publish/publish-zip')()
}
})
})
新增内容
const program = require('commander')
==========================
program
.version('0.0.1')
.option('-p, --publish', 'Publish Remote')
.parse(process.argv)
============================
if (program.publish) {
console.log('-----');
require('../publish/publish-zip')()
}
在package.json 新增命令
"publish": "node build/build.js -p"
执行命令npm run publish 就可以自动打包上传到服务器了
还没完
在服务器执行命令
ssh-keygen -t rsa
# Enter file in which to save the key (/root/.ssh/id_rsa): #默认即可
# Enter passphrase (empty for no passphrase): #输入密码 为空就行
# Enter same passphrase again: #再输入一遍保护密码 为空就行
会生成两个文件/root/.ssh/id_rsa.pub (公钥),/root/.ssh/id_rsa(私钥)
如果输入密码秘钥文件就有被加密了需要转成ppk文件
导入公钥
cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys
在/etc/ssh/sshd_config文件修改配置
RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
然后重启服务器
把/root/.ssh/id_rsa(私钥)文件下载到本地用于登录
完