前端工程化之部署篇

前言
    部署简单来说就是将构建产出的代码部署到服务器上,在开发中我们通常的操作就是使用ftp将代码上传到服务器上固定目录下即可,所以这项工作在很多开发看起来是简单而又无聊的工作,这种部署方式从本质上来说没毛病,但是只适用于由少数人维护的规模较小的项目,如果这是个用户量庞大的产品,拥有多体系的技术团队,那么,我们在设计部署流程的时候就需要考虑许多其他的因素了,比如如何多人协作,提高部署效率,控制部署时的安全等等,这个时候就不再是一个简单的ftp上传代码这么简单了。

    要做到前端资源自动化部署首先需要的就是设计合适的部署流程,这个和前端项目的大小和部署的环境是有直接联系的,比如测试环境,准生产环境,生产环境,他们的部署流程差异是比较大的,一般测试环境我们开发人员可以随便造,准生产环境和生产环境就需要专门的运维人员,按照严格的发布流程来部署了,这个时候,我们开发人员一般只需要提供代码的仓库地址和版本号,其他的都交给类似jenkins这种集成化平台来进行统一集成,当然这里面可能需要用到一些脚本,比如我所在的公司每个项目中目录中都创建有一个文件夹里面全部是一些python脚本,用来给jenkis打包使用的,这里不是我们要讲的点,这里只提一下。

    前面提到了部署流程,规范的流程是保障事情有条不紊向前推进的基础,就像我们想去"浪漫的土耳其",那么我们就得首先办理护照,然后再购买机票,订酒店…然后去找土耳其小姐姐。其实我觉得首先还是得看看自己的钱包还剩多少和房贷还有多少没还。扯远了,回到前端自动化部署上来。在设计流程的时候我们需要考虑的三大因素:

  1. 快速部署
  2. 协同部署
  3. 保证部署安全

下面就一步一步简单总结一下。


快速部署

     前面提到的使用sftp工具这种简单粗暴的方式来上传构建好的前端代码到服务器,雖然也相对比較快速,但是手动部署和自动化部署毕竟level还是差很多的,就像坐绿皮車和坐高铁那档次还是有那么一点点的,所以我们需要用自动化部署来代替手动 ,这样一方面可以提高部署效率,另一方面开发人员可以少做一些他们以为的无用功,然后把时间多花点在改bug和写bug这种事上来。
大多数开发在后期都需要频繁的将修改后的代码部署到服务器上去,这个时候我们原始的部署流程是:

Created with Raphaël 2.2.0 开始 通过SSH登录服务器 打开sftp图形化界面上传代码 结束

看起来简单 ,但是手动去重复这种机械化的工作,不免让人感到乏味。这个时候就需要用代码来帮我部署。下面讲解一下我自己在vue-cli的基础上实现的本地快速部署方案

实现步骤:

  1. 配置需要部署的目标服务器信息
  2. 实现部署行为
  3. 实现命令行
配置需要部署的目标服务器信息:

    在部署的时候我们需要做到目标服务器地址的信息可配置化,所以我在config目录下的index.js文件中增了服务器的相关配置项:

{
 ...
 publish:{
      remoteDir:'/xxx/xxx/xxx/target',//远程上传目录(服务器)
      localSourcePath:"",//本地需要上传的资源路径(默认项目根目录下的dist文件夹)
      serverConfig:{//服务器验证信息
          host: '',
          username: '***',
          password: '***',
          algorithms: {
              "kex": [
                "diffie-hellman-group1-sha1",
                "ecdh-sha2-nistp256",
                "ecdh-sha2-nistp384",
                "ecdh-sha2-nistp521",
                "diffie-hellman-group-exchange-sha256",
                "diffie-hellman-group14-sha1"
              ],
              "cipher": [
                "3des-cbc",
                "aes128-cbc",
                "aes192-cbc",
                "aes256-cbc",
                "aes128-ctr",
                "aes192-ctr",
                "aes256-ctr",
                "[email protected]",
                "[email protected]",
                "arcfour",
                "arcfour128",
                "arcfour256",
                "blowfish-cbc",
                "cast128-cbc",
              ],
              "serverHostKey": [
                "ssh-rsa",
                "ecdsa-sha2-nistp256",
                "ecdsa-sha2-nistp384",
                "ecdsa-sha2-nistp521"
              ],
              "hmac": [
                "hmac-sha2-256",
                "hmac-sha2-512",
                "hmac-sha1"
              ]
          }
      }
 }

这里algorithms这个配置项主要是解决在使用node-ssh2模块连接目标服务器的时候出现的服务器和客户端 加密方式不一致的问题,如果你在使用node-ssh2模块时也可能会遇见相同的错误,所以把这个配置项加上就解决了。这里个配置项配置好后就不需要在改变了。其他的配置项基本都是需要部署的服务器信息。

实现部署行为

    实现部署行为主要是基于sftp协议,这里使用到了node-ssh2中实现的sftp相关的方法。我在这里实现流程主要是分以下几步:

  1. 构建,压缩构建后的代码
  2. 通过node-ssh2连接目标服务器
  3. 通过node-ssh2中的sftp相关方法上传压缩文件,解压,删除压缩文件
  4. 上传失败时执行回滚操作

    大致的流程图:
前端工程化之部署篇_第1张图片
实现代码在build文件夹里面的publish.js

const uploadBySftp = require("./modules/ssh.js");
let config = require("../config/index.js");
const path = require("path");
const chalk = require("chalk");
const ora = require("ora");
async function startUpload(config){
      config = initOption(config);
      const localPath = config.publish.localSourcePath;
      const targetPath = config.publish.remoteDir;
      let desc =  "*******************************************\n"
                 +"***              开始部署               ***\n"
                 +"*******************************************\n"
    //1 压缩
    let localZipPath = await uploadBySftp.zipLocalFile(localPath,targetPath);
    //2 连接ssh
     let upload = new uploadBySftp(config.publish.serverConfig);
     await upload.connect();
     try {
            //3 上传文件
            let remotePath = await upload.startUploadFile(localZipPath,targetPath,true);
            //4 解压
            let remoteZipPath = await upload.unzipRemoteFile(remotePath,targetPath,false);
            //5 删除远程压缩文件
            await upload.deleteZipFile(remoteZipPath);
            //删除原先已经存在的文件夹
            await upload.deleteFolder(upload.newName);
            let desc =  "\n******************************************\n"
                        +"***              部署成功              ***\n"
                       +"******************************************\n"
            console.log(chalk.green(desc));
     
     } catch (error) {
            console.error(chalk.red("文件部署失败"));
            await upload.rolUp();//开始回滚
     }
     //关闭连接
     upload.close();
}
/**
 * 初始化参数
 */
function initOption(config){
   let hostPattern = /(?:(?:(?:25[0-5]|2[0-4]\d|(?:(?:1\d{2})|(?:[1-9]?\d)))\.){3}(?:25[0-5]|2[0-4]\d|(?:(?:1\d{2})|(?:[1-9]?\d))))/ig;
   let remoteHost = process.argv[2];
   let dirPattern = /(\/opt\/dss\/client\/){1}/ig
   let dir = process.argv[3];
  if(remoteHost){
    if(hostPattern.test(remoteHost)){
      config.publish.serverConfig.host = remoteHost;
    }
  }

   if(dir){
      config.publish.remoteDir = path.join(path.dirname(config.publish.remoteDir),dir).split(path.sep).join("/");
      console.log(config.publish.remoteDir);
   }
   //校验输出地址是否合法
   if(!dirPattern.test(config.publish.remoteDir)){
      throw new Error("上传地址非法");
      return
  }
   if(config.publish){
      if(!config.publish.remoteDir){
        throw new Error("请配置远程文件夹地址")
        return
      }

      if(!config.publish.localSourcePath){
          config.publish.localSourcePath = path.join(process.cwd(),"dist");
      }

      if(!config.publish.serverConfig.host||!config.publish.serverConfig.username||!config.publish.serverConfig.password){
        throw new Error("请配置远程服务器信息")
        return
      }

      return config;
   }else{
      return;
   }
};
startUpload(config);

这里没有实现代码构建,这是因为vue-cli构建的vue项目已经幫我们实现了,只需要在npm run build之后执行这个部署操作就OK了,在后面实现发布命令的时候再讲;
initOption方法主要时为了对服务器配置信息进行校验。

    具体的方法实现在build/modules/ssh.js里面

实现命令行

    在使用vue-cli构建的项目中,我们可以使用npm run dev来启动本地开发环境,npm run build构建输出代码,这里我们实现一个npm run publish命令来实现部署本地代码到服务器的操作。首先需要在项目根目录下的package.json中新增npm run publish命令

 {
  ...
  "scripts":{
    ...
    "publish""npm run build&&node ./publish.js"
  }
 }

配置完之后,我们就可以使用

npm run publish

来实现快速部署了,在运行命令前我们需要要不正配置文件中服务器的相关信息已经配置完成。这在一定程度上降低了我们部署的灵活性,在真实开发中我们一般不只有一台测试换服务器,有时候我们需要向不同的服务器部署,这时候就需要去改变配置参数,显得有点麻烦。所以这里新增了命令行注入参数的方式,来实现灵活部署,例如:

  1. npm run publish 172.25.20.xxx 实现向不同的服务器来部署代码
  2. npm run publish 172.25.20.xxx dirname 实现不是到服务器上某个文件夹里面面去。

这样我们就可以在在开发中是先快速的向服务器部署了。
    快速部署其实就是将上面的手动上传代码变成了用程序来帮助我们实现上传,但是本质上还是一个简单的代码上传和替换,这只适合在本地开发环境到开发测试环境的部署,并且只适合单人或极少数人维护和技术体系简单的前端项目。如果是前端结构复杂,技术团队众多的前端项目,就需要考虑协同部署了。


协同部署

    协同部署主要是解决多人同时开发的问题,因为你提交代码后会覆盖别人的代码,导致别人开发的功能模块失效。这个时候,就需要一个统一的管理平台来执行部署

前端工程化之部署篇_第2张图片

从流程图上可以看出,协同部署需要统一管理平台来实现统一部署,当所有开发人员都提交版本后,这个时候在平台上触发打包部署,然后就可以继续去写bug了…。当然,统一管理平台会消耗一定的资源,所以需要根据项目自身的情况来决定了是否使用了,不过现在云管理平台已经非常普遍了,所以使用起来也是非常方便和简单的。

安全部署

    简单来说就是需要保证部署操作的安全,避免误操作。就比如前一段时间阿里云宕机事件,据说就是某个"实习生"错误的执行了delete脚本,导致用户无法登陆,这种影响可想而知。当然我们前端部署不会涉及到对用户数据的操作,最严重的就是页面无法访问,恢复起来也是相对容易。但是这不是我们不重视前端安全部署的理由,比如那天一觉醒来天猫的页面无法访问了那问题就大条了。当然这对广大已婚男士来说可能这就是福音了,媳妇儿可以消停一下了。但是作为开发来说这就是严重的事故了,前两天顺丰程序猿误操作事件可以了解一下。所以在进行部署的时候一定要考虑到安全,要做到安全部署主要从三个方面下手,一方面是部署权限,另一方面就是有专门的人员负责审核部署请求,最后就是版本回退。

部署权限

    正常情况下生产环境都是由专门的运维人员负责部署,我们开发人员就不需要吓操那份心了,最多就是熬夜打辅助,站在他们旁边陪着他们部署。至于运维人员那边怎么实现安全部署,我就不知道了。下面我们主要说一下准生产环境和开发测试环境的部署。

部署请求审核

    准生产环境也叫仿真环境,对于我们开发来说它就是生产环境,它的部署流程也是要严格按照生产环境的部署要求来。通常情况下发起部署请求后,需要专门的人员来审核你的部署请求是否合理合法,只有请求通过后才能执行部署,这里需要专门的审核人员,这个人一般是经验非常丰富的开发人员,有可能就是我们常说的大牛。当然要是最后出了问题,他也是要陪你一起背锅的…。

版本回退

    说完了前面部署权限和部署审核后下面就来说所版本回退,一般当你使用到版本回退的时候,也基本上宣布你这次部署失败了,部署失败意味着可能又要多加几个班了。版本回退一般是在升级的时候用到的。回退一方面是在部署后发现有严重bug的时候,需要回退到之前的稳定版本;保证生产正常;另一种情况就是在自动化部署过程中发生错误了,部署无法继续进行,需要回退到上一个版本。要做到回退关键就是需要在部署前对上一个版本在进行备份,所以第一次发版就不存在什么回退了,因为无路可退,没有上一个版本怎么回退呢。
    这里就拿我自己实现的本地自动部署方案说一下,因为我的部署对象是开发测试环境,所以安全性就要低的多,一方面对部署的地址进行校验,因为在部署的过程中需要对服务器上存在的相同路径文件进行重命名,为了防止错误的将其他重要文件重命名所以我们一般将上传的路径是固定的,因为代码在服务器上位置是固定了的,在上传的时候校验一下,有没有输入非法路径。另一方面如果部署过程中失败,就执行回退操作。


本地自动化部代码 github地址,有心兴趣的可以看看。


总结

    这篇文章算是是在看了《前端工程化设计与实践》部署篇以后的一个简单总结记录吧,目前前端工程化的书籍不是太多,大多都是以博客的形式存在,讲的内容只集中在工程化的某个环节或者讲的比较粗线条,就像我这里只总结了一下部署,这只是工程化中的一角,后面我会结合书籍的讲解和自己的实践分享工程化的脚手架,构建…。如果有兴趣的朋友可以购买这本书来看看,我不是打广告,我作者没半毛钱关系,只是我看完一遍后对于前端工程化清楚的理解,书读三遍其义自见,我打算再读几遍,然后结合书中讲解运用到工作中来,毕竟实践是检验真理的唯一标准。好了,收工,还是那句话请忽略文中的"通假字"。明天是国庆节了,祝大家国庆快乐!祝祖国富强,繁荣!祝自己一切安好!

你可能感兴趣的:(webpack,nodejs,前端工程化)