1

不说废话,直接上货。

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:表示部署到生产环境
  }

上传服务器显示结果:
image.png

image.png

插件源码解析:

// 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,
}

项目地址:https://github.com/Revelation...

参考:
https://juejin.im/post/5de38e...


记得要微笑
1.9k 声望4.5k 粉丝

知不足而奋进,望远山而前行,卯足劲,不减热爱。


引用和评论

0 条评论