背景
去年的时候针对自己的线上项目搞过jenkins,但是jenkins一直获取不到github上的项目,加上自己的项目迭代比较慢(两个月一推代码),平常的公司需求又比较多,所以就搁置了。
这两天想起来这个事,又在复习webpack,突然想到我可不可以实现一个webpack plugin,在打包的时候上传webpack的产物到线上node服务上,然后node服务把产物写入服务器的指定nginx文件夹 ,这样的话不也实现CD(持续部署)了吗,感觉理论上是可行的。
一些方案
- 本地打包后的产物被压缩为zip,使用axios formdata形式上传到node服务,node服务解压写入nginx对应目录,这也是我这次的方案,缺点很明显,新增接口,速度可能比其他方案稍微慢一点点。
- 本地打包后的产物通过scp直接写入线上nginx对应目录,缺点,需要提供服务器IP,密码,写入路径。
- 阿里云OSS
- jenkins CICD
过程
首先实现一个脚本uploadScript
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"report": "vue-cli-service build --report",
"buildUploadScript": "vue-cli-service build & node uploadScript"
},
脚本内容就是,读取dist文件夹下内容,压缩为一个zip,通过axios上传到一个node服务接口
// 依赖
const fs = require('fs')
const { zip } = require("compressing");
const {
resolve
} = require("path");
const axios = require('axios')
const FormData = require('form-data')
// 读文件,生成dist压缩包
const dist = fs.readdirSync('./dist')
const writePath = './dist.zip'
if(dist && dist.length > 0) {
zip.compressDir(resolve("dist/"), writePath).then(res=>{
console.log('压缩包写入本地根目录成功')
readDistZipAndUpload()
},err=>{
console.log('压缩包写入本地根目录失败',err)
})
}else {
console.log('dist目录不存在或dist下无产物')
}
// 读压缩包并且上传
function readDistZipAndUpload() {
let res = fs.readFileSync('./dist.zip')
if(res) {
const formdata = new FormData();
formdata.append("blob", fs.createReadStream('./dist.zip'))
console.log('开始上传压缩包')
axios({
url: "https://www.xxx.xxx/xxxx/xxxx",
method: "post",
data: formdata,
headers: {
'Content-Type': `multipart/form-data; boundary=${formdata.getBoundary()}`
}
})
.then((res) => {
console.log('上传压缩包成功')
})
.catch(function (err) {
console.log('上传失败, 请检查网络问题');
});
}else {
console.log('压缩包不存在')
}
}
对应我们node服务接收文件流,转化为zip文件,解压,并且将解压后的内容移动到nginx静态资源文件夹。
const express = require("express");
const router = express.Router();
const fs = require("fs")
const multiparty = require("multiparty")
const compressing = require('compressing');
const rimraf = require('rimraf');
var fsExtra = require('fs-extra')
router.post("", function (req, result, next) {
var form = new multiparty.Form({uploadDir: "./uploads", maxFieldsSize: 30000 * 1024 * 1024, encoding:'utf-8'})
form.uploadDir = "./uploads"
form.parse(req, function (err, fields, files) {
try {
// uploads存放dist压缩文件
console.log(files)
let upfile = files.blob[0]
let newpath = form.uploadDir + '/' + 'dist.zip'
fs.renameSync(upfile.path, newpath);
//清空dist文件夹
rimraf("./uploads/dist", function (res) {
//解压dist压缩文件到dist文件夹
compressing.zip.uncompress(newpath,'./uploads').then(()=>{
//清空nginx目录
rimraf("./test", function (res) {
//写入nginx目录
fsExtra.copy("./uploads/dist", './test', function(error) {
if (error) {
throw error;
} else {
result.send({
message:'上传到nginx成功',
code:'0'
})
}
});
})
})
});
} catch (error) {
console.log(err)
}
})
});
module.exports = router;
通过脚本实现了,我们将他移植到webpack plugin
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"report": "vue-cli-service build --report",
"buildUploadScript": "vue-cli-service build & node uploadScript",
"buildUploadPlugin": "vue-cli-service build --mode test"
}
webpack plugin
module.exports = class RemoveLogs {
constructor(options){
this.options = options
}
apply(compiler) {
compiler.hooks.done.tap("AnalyzePlugin", (compilation) => {
require('../../../uploadScript/index')
})
}
};
非常简单的过程