不说废话,直接上货。
webpack
打包后自动部署插件:webpack-auto-upload-j
插件项目地址:https://github.com/jiangji1/w...
在项目中安装该模块
npm i webpack-auto-upload-j --save-dev
webpack导入插件并配置
const WebpackAutoUploadJ = require('webpack-auto-upload-j')
{
plugins:
[ new WebpackAutouploadJ({
path: path.resolve(__dirname, '../serviceConf.json'),// 服务器配置文件路径
key: 'web' }), // 服务器配置文件对象key值
]
}
// serviceConf.json配置文件,根目录下配置
{
"web": {
// 测试环境服务器配置
"build_upload_test": {
"host": "xxx.xxx.xxx.xxx",
"port": 22,
"user": "xxx",// 服务器用户名
"password": "xxxx",// 服务器远程连接密码
"entryDir": "dist",// 打包目录文件,会将该目录下所有文件上传到服务器serviceDir变量指定路径下
"serviceDir": "/usr/local/tomcat/webapps/test" // 服务器web存放目录
},
// 生产环境服务器配置
"build_upload_pro": {
"host": "xxx.xxx.xxx.xxx",
"port": 22,
"user": "xxx",
"password": "xxxx",
"entryDir": "dist",
"serviceDir": "/usr/local/tomcat/webapps/test"
}
}
}
// package.json
"up": {
"kaiguan": 2 // 0:表示不上传部署,1:表示部署到测试环境,2:表示部署到生产环境
}
插件源码解析:
// index.js
var tool = require('./tool.js')
var path = require('path')
var fs = require('fs')
var readAndDelEvery = tool.readAndDelEvery
var readAndPut = tool.readAndPut
var opt // 服务器配置变量
function Gouzi(options) {
if (!fs.existsSync(options.path)) {
return
}
opt = JSON.parse(fs.readFileSync(options.path))[options.key] // 读取服务器配置文件
}
Gouzi.prototype.apply = function(compiler) {
compiler.plugin("beforeRun", function() {
handle({ compiler, type: 'beforeRun' })
})
compiler.plugin("done", function(params) {
// 当webpack打包完后会执行这个钩子
handle({ compiler, type: 'done' })
});
};
function handle ({ compiler, type }) {
let opt2 = JSON.parse(JSON.stringify(opt))
if (!opt2) {
process.exit()
return
}
const pajp = path.resolve(compiler.context, 'package.json') // 读取package.json中up配置
if (fs.existsSync(pajp)) {
const config = JSON.parse(fs.readFileSync(pajp))
if (Object.prototype.hasOwnProperty.call(config, 'up')) {
// 判断打包到哪个环境
if (config.up.kaiguan === 0) {
return
} else if (config.up.kaiguan === 1) {
opt2 = opt2.build_upload_test
} else if (config.up.kaiguan === 2) {
opt2 = opt2.build_upload_pro
} else {
return
}
}
}
opt2.serviceConfig = {
host: opt2.host,
port: opt2.port,
user: opt2.user,
password: opt2.password,
}
// 可以多入口上传部署
if (Array.isArray(opt2.entryDir)) {
var arr = []
opt2.entryDir.forEach((v, i) => arr.push({
entryDir: v,
serviceDir: opt2.serviceDir[i],
serviceConfig: opt2.serviceConfig
}))
arr.forEach(v => (
type === 'done'
? readAndPut(v, compiler.context)
: readAndDelEvery(v, compiler.context)
))
} else {
if (Array.isArray(opt2.serviceDir)) {
var arr = []
opt2.serviceDir.forEach((v, i) => arr.push({
entryDir: opt2.entryDir,
serviceDir: v,
serviceConfig: opt2.serviceConfig
}))
arr.forEach(v => (
type === 'done'
? readAndPut(v, compiler.context)
: readAndDelEvery(v, compiler.context)
))
} else {
type === 'done'
? readAndPut(opt2, compiler.context)
: readAndDelEvery(opt2, compiler.context)
}
}
}
module.exports = Gouzi
// tool.js
const fs = require('fs')
const path = require('path')
const cc = require('ssh2-sftp-client') // node的ftp包,用于上传下载
function readAll (dirPath, currentPath) {
dirPath = path.resolve(
currentPath,
dirPath
)
const paths = [dirPath]
const aaa = []
let res = []
while (paths.length) {
const head = paths.shift()
aaa.push(head)
if (!fs.existsSync(head)) continue
const f = fs.statSync(head)
if (!f.isDirectory()) res.push(head)
const d = fs.readdirSync(head)
d.forEach(v => {
const p = path.resolve(head, v)
if (!fs.existsSync(p)) return
const f = fs.statSync(p)
if (!f.isDirectory()) res.push(p)
else paths.push(p)
})
}
const reg = new RegExp(dirPath.replace(/\\/g, '\\\\'), 'g')
return res.map(v => v.replace(reg, '').replace(/\\/g, '/'))
}
// 将指定目录文件上传到服务器指定目录
async function uploadAll ({ serviceDir, allFiles, config, entryDir }, currentPath) {
const successArr = []
const failArr = []
const c = new cc(config)
let a
await c.connect(config)
for (const i in allFiles) {
const v = allFiles[i]
const localDir = path.resolve(currentPath, entryDir, v.slice(1))
const remoteDir = serviceDir + v
try {
const a = await c.exists(remoteDir.slice(0, remoteDir.lastIndexOf('/')))
if (!a) {
await c.mkdir(remoteDir.slice(0, remoteDir.lastIndexOf('/')), true)
}
const p = await c.put(
localDir,
serviceDir + v
)
successArr.push(`${localDir} to: ${remoteDir}`)
} catch (e) {
failArr.push({
failFile: `${localDir} to: ${remoteDir}`,
reason: e + ''
})
}
}
c.end()
successArr.length && console.log(`
\x1B[32m[
上传完毕. uploaded \n
成功列表.successFiles \n
${successArr.map(v => `success: ${v} \n`)}
]\x1B[39m
`)
failArr.length && console.log(`
\x1B[31m[
失败列表.failedFiles \n
${failArr.map(v => `failed: ${JSON.stringify(v, 0, ' ')} \n`)}
]\x1B[39m
`)
}
async function delEvery ({ serviceDir, allFiles, config, entryDir }, uploadAfterDel) {
const c = new cc(config)
await c.connect(config)
for (const i in allFiles) {
const v = allFiles[i]
const remoteDir = serviceDir + v
try {
const a = await c.exists(remoteDir.slice(0, remoteDir.lastIndexOf('/')))
if (a) {
await c.delete(remoteDir)
}
} catch (e) {
}
}
c.end()
uploadAfterDel()
}
var delObj
function readAndDelEvery (item, currentPath) {
const allDelFiles = readAll(item.entryDir, currentPath)
delObj = {
entryDir: item.entryDir,
serviceDir: item.serviceDir,
allFiles: allDelFiles,
config: item.serviceConfig,
}
}
function readAndPut (item, currentPath) {
const allFiles = readAll(item.entryDir, currentPath)
var obj = {
entryDir: item.entryDir,
serviceDir: item.serviceDir,
allFiles,
config: item.serviceConfig,
}
delEvery(obj, () => uploadAll(obj, currentPath))
}
module.exports = {
readAndDelEvery,
readAndPut,
}