返回顶部
首页 > 资讯 > 前端开发 > node.js >Node中怎么实现一个自动化部署平台
  • 720
分享到

Node中怎么实现一个自动化部署平台

2024-04-02 19:04:59 720人浏览 薄情痞子
摘要

node中怎么实现一个自动化部署平台,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。业务需求这个jsSDK,主要作用是在后端了为

node中怎么实现一个自动化部署平台,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

业务需求

这个jsSDK,主要作用是在后端了为业务方分配appKey之后,前端将appKey写死在JSSDK中,上传到CDN后,为业务方提供数据采集服务的脚本。

有的同学可能有疑问,为什么不像一些正常的SDK一样,appKey是以参数的形式传入到JSSDK中,这样就可以统一所有业务方使用同一个JSSDK,而不需要为每个业务业务方都提供一个JSSDK。其实我刚开始也是这么想的,于是我向我的leader提出了我的这个想法,被拒绝了,拒绝原因如下:

  •  appKey如果以参数形式传入,对业务方的接入成本有所增加,会出现appKey填错的问题。

  •  业务方接入JSSDK之后,希望每次JSSDK版本迭代对业务方来说是无感知的(也就是版本迭代是覆盖式发布),如果所有业务方使用同一个JSSDK,每次JSSDK的版本迭代,一次发版会一次性对所有业务方都有影响,会增加风险。

由于我的leader现在主要是负责产品推广,经常和业务方打交道,可能他更能站在业务方的角度来考虑问题。所以,我的leader选择牺牲项目的维护成本来降低SDK的接入成本和规避风险,可以理解。

那既然我们改变不了现状,那就只能适应现状。

项目痛点

那么针对原来没有任何工程化情况的胖脚本,每次新增一个业务方,我需要做的事情如下:

  •  打开一个胖脚本和JSSDK接入文档,拷贝一份新的。

  •  找后端要分配好的appKey,找对对应的appKey那一行代码手动修改。

  •  手动混淆修改完好的脚本并上传到CDN。

  •  修改JSSDK接入文档中CDN的地址,保存后发送给业务方。

整个过程都需要手动进行,相对来说非常繁琐,并且一不小心就会填错,每次都需要对脚本和接入文档进行检查。

针对以上情况,得到我们需要解决的问题:

  •  怎样针对一个新的业务方快速输出一份新的JSSDK和接入文档?

  •  怎样快速对新的JSSDK进行混淆并上传到CDN。

自动化方案

介绍方案之前,先上一张平台截图,以便先有一个直观的认识:

Node中怎么实现一个自动化部署平台

SDK自动化部署平台主要实现了JSSDK的编译,发布测试(在线预览),上传CDN功能。

服务端技术栈包括:

  •  框架 Express

  •  热更新 nodemon

  •  依赖注入 awilix

  •  数据持久化 sequelize

  •  部署 pm2

客户端技术栈就不介绍了,Vue全家桶 + vue-property-decorator + vuex-class。

项目搭建参考:

Vue+Express+Mysql 全栈初体验

https://juejin.im/post/5ce96694f265da1bc5523f69

自动化部署平台主要依赖于 git + 本地环境 + 私有NPM源 + mysql,各环节之间进行通信交互,完成自动化部署。

Node中怎么实现一个自动化部署平台

主要达到的效果:本地环境拉取git仓库代码后,进行需求开发,完成后发布一个带Rollup的SDK编译器包到私有NPM仓库,自动化部署平台在工程目录安装指定版本的SDK,并且备份到本地,在SDK编译时,选择特定版本的Rollup的SDK编译器,并传参(如appKey,appId等)到编译器中进行编译,同时自动生成JSSDK接入文档等后打包成带描述文件的Release包,在上传到CDN时,将描述文件的对应的信息写入MYsql中进行保存。

版本管理

由于JSSDK原本只是一个脚本,我们必须实现项目的工程化,从而完成版本管理,方便快速版本切换进行发布,回滚,进而快速止损。

首先,我们需要将项目工程化,使用Rollup进行模块管理,并且在发包NPM包的时候,输入为各种参数(如appKey)输出为一个Rollup Complier的函数,然后使用rollup-plugin-replace在编译时候替换代码中具体的参数。

lib/build.js,JSSDK中发包的入口文件,提供给SDK编译时使用

import * as rollup from 'rollup';  const replace = require('rollup-plugin-replace');  const path = require('path');  const pkgPath = path.join(__dirname, '..', 'package.JSON');  const pkg = require(pkgPath);  const proConfig = require('./proConfig');  function getRollupConfig(replaceParams) {      const config = proConfig;      // 注入系统变量      const replacereplacePlugin = replace({          '__JS_SDK_VERSION__': JSON.stringify(pkg.version),          '__SUPPLY_ID__': JSON.stringify(replaceParams.supplyId || '7102'),          '__APP_KEY__': JSON.stringify(replaceParams.appKey)      });      return {          input: config.input,          output: config.output,          plugins: [              ...config.plugins,              replacePlugin          ]      };  };  module.exports = async function (params) {      const config = getRollupConfig({          supplyId: params.supplyId || '7102',          appKey: params.appKey      });      const {          input,          plugins      } = config;      const bundle = await rollup.rollup({          input,          plugins      });      const compiler = {          async write(file) {              await bundle.write({                  file,                  fORMat: 'iife',                  sourcemap: false,                  strict: false              });          }      };      return compiler;  };

在自动化部署平台中,使用shelljs安装JSSDK包:

import {route, POST} from 'awilix-express';  import {api} from '../framework/Api';  import * as shell from 'shell';  import * as path from 'path';  @route('/supply')  export default class SupplyAPI extends Api {     // some code      @route('/installSdkVersion')      @POST()      async installSdkVersion(req, res) {          const {version} = req.body;          const pkg = `@baidu/xxx-js-sdk@${version}`;          const reGIStry = 'Http://registry.npm.baidu-int.com';          shell.exec(`npm i ${pkg} --registry=${registry}`, (code, stdout, stderr)  => {              if (code !== 0) {                  console.error(stderr);                  res.failPrint('npm install fail');                  return;              }              // sdk包备份路径              const sdkBackupPath = this.sdkBackupPath;              const sdkPath = path.resolve(sdkBackupPath, version);              shell.mkdir('-p', sdkPath).then((code, stdout, stderr) => {                  if (code !== 0) {                      console.error(stderr);                      res.failPrint(`mkdir \`${sdkPath}\` error.`);                      return;                  }                  const modulePath = path.resolve(process.cwd(), 'node_modules', '@baidu', 'xxx-js-sdk');                  // 拷贝安装后的文件,方便后续使用                  shell.cp('-rf', modulePath + '/.', sdkPath).then((code, stdout, stderr) => {                      if (code !== 0) {                          console.error(stderr);                          res.failPrint(`backup sdk error.`);                          return;                      }                      res.successPrint(`${pkg} install success.`);                  });              })          });      }  }

Release包

Release包就是我们在上传到CDN之前需要准备的压缩包。因此,打包JSSDK之后,我们需要生成的文件有,接入文档、JSSDK DEMO预览页面、JSSDK编译结果、描述文件。

首先,打包函数如下:

import {Service} from '../framework';  import * as fs from 'fs';  import path from 'path';  import _ from 'lodash';   export default class SupplyService extends Service {      async generateFile(supplyId, sdkVersion) {          // 数据库查询对应的业务方的CDN文件名          const [sdkInfoErr, sdkInfo] = await this.supplyDao.getSupplyInfo(supplyId);          if (sdkInfoErr) {              return this.fail('服务器错误', null, sdkInfoErr);          }          const {appKey, cdnFilename, name} = sdkInfo;          // 需要替换的数据          const data = {              name,             supplyId,              appKey,              'sdk_url': `https://***.com/sdk/${cdnFilename}`          };          try {              // 编译JSSDK              const sdkResult = await this.buildSdk(supplyId, appKey, sdkVersion);              // 生成接入文档              const docResult = await this.generateDocs(data);              // 生成预览DEMO html文件              const demoHtmlResult = await this.generateDemoHtml(data, 'sdk-demo.html', `JSSDK-接入页面-${data.name}.html`);              // 生成release包描述文件              const sdkInfoFileResult = await this.writeSdkVersionFile(supplyId, appKey, sdkVersion);                        const success = docResult && demoHtmlResult && sdkInfoFileResult && sdkResult;              if (success) {                  // release目标目录                  const dir = path.join(this.releasePath, supplyId + '');                  const fileName = `${supplyId}-${sdkVersion}.zip`;                  const zipFileName = path.join(dir, fileName);                  // 压缩所有结果文件                  const zipResult = await this.zipDirFile(dir, zipFileName);                  if (!zipResult) {                      return this.fail('打包失败');                  }                  // 返回压缩包提供下载                  return this.success('打包成功', {                      url: `/${supplyId}/${fileName}`                  });              } else {                  return this.fail('打包失败');              }          } catch (e) {              return this.fail('打包失败', null, e);          }      }  }

编译JSSDK

JSSDK的编译很简单,只需要加载对应版本的JSSDK的编译函数,然后将对应的参数传入编译函数得到一个Rollup Compiler,然后将 Compiler 结果写入Release路径即可。

export default class SupplyService extends Service {      async buildSdk(supplyId, appKey, sdkVersion) {          try {              const sdkBackupPath = this.sdkBackupPath;              // 加载对应版本的备份的JSSDK包的Rollup编译函数              const compileSdk = require(path.resolve(sdkBackupPath, sdkVersion, 'lib', 'build.js'));              const bundle = await compileSdk({                  supplyId,                  appKey: Number(sdkInfo.appKey)              });              const releasePath = path.resolve(this.releasePath, supplyId, `${supplyId}-sdk.js`);              // Rollup Compiler 编译结果至release目录              await bundle.write(releasePath);              return true;          } catch (e) {              console.error(e);              return false;          }      }  }

生成接入文档

原理很简单,使用JSZip,打开接入文档模板,然后使用Docxtemplater替换模板里的特殊字符,然后重新生成DOC文件:

import Docxtemplater from 'docxtemplater';  import JSZip from 'JSZip';  export default class SupplyService extends Service {      async generateDocs(data) {          return new Promise(async (resolve, reject) => {              if (data) {                  // 读取接入文档,替换appKey,cdn路径                  const supplyId = data.supplyId;                  const docsFileName = 'sdk-doc.docx';                  const supplyFilesPath = path.resolve(process.cwd(), 'src/server/files');                  const content = fs.readFileSync(path.resolve(supplyFilesPath, docsFileName), 'binary');                  const zip = new JSZip(content);                  const doc = new Docxtemplater();                  // 替换`[[`前缀和`]]`后缀的内容                  doc.loadZip(zip).setOptions({delimiters: {start: '[[', end: ']]'}});                  doc.setData(data);                  try {                      doc.render();                  } catch (error) {                      console.error(error);                      reject(error);                  }                  // 生成DOC的buffer                  const buf = doc.getZip().generate({type: 'nodebuffer'});                  const releasePath = path.resolve(this.releasePath, supplyId);                  // 创建目标目录                  shell.mkdir(releasePath).then((code, stdout, stderr) => {                      if (code !== 0 ) {                          resolve(false);                          return;                      }                      // 将替换后的结果写入release路径                      fs.writeFileSync(path.resolve(releasePath, `JSSDK-文档-${data.name}.docx`), buf);                      resolve(true);                  }).catch(e => {                      console.error(e);                      resolve(false);                  });              }          });      }  }

生成预览DEMO页面

与接入文档生成原理类似,打开一个DEMO模板HTML文件,替换内部字符,重新生成文件:

export default class SupplyService extends Service {      generateDemoHtml(data, file, toFile) {          return new Promise((resolve, reject) => {              const supplyId = data.supplyId;              // 需要替换的数据              const replaceData = data;              // 打开文件              const content = fs.readFileSync(path.resolve(supplyFilesPath, file), 'utf-8');              // 字符串替换`{{`前缀和`}}`后缀的内容              const replaceContent = content.replace(/{{(.*)}}/g, (match, key) => {                  return replaceData[key] || match;              });              const releasePath = path.resolve(this.releasePath, supplyId);              // 写入文件              fs.writeFile(path.resolve(releasePath, toFile), replaceContent, err => {                  if (err) {                      console.error(err);                      resolve(false);                  } else {                      resolve(true);                  }              });          });      }  }

生成Release包描述文件

将当前打包的一些参数存在一个文件中的,一并打包到Release包中,作用很简单,用来描述当前打包的一些参数,方便上线CDN的时候记录当前上线的是哪个SDK版本等

export default class SupplyService extends Service {      async writeSdkVersionFile(supplyId, appKey, sdkVersion) {          return new Promise(resolve => {              const writePath = path.resolve(this.releasePath, supplyId, 'version.json');             // Release描述数据              const data = {version: sdkVersion, appKey, supplyId};              try {                  // 写入release目录                  fs.writeFileSync(writePath, JSON.stringify(data));                  resolve(true);              } catch (e) {                  console.error(e);                  resolve(false);              }          });      }  }

打包所有文件结果

将之前生成的JSSDK编译结果、接入文档、预览DEMO页面文件,描述文件使用arcHive打包起来:

export default class SupplyService extends Service {      zipDirFile(dir, to) {          return new Promise(async (resolve, reject) => {              const output = fs.createWriteStream(to);              const archive = archiver('zip');              archive.on('error', err => reject(err));              archive.pipe(output);              const files = fs.readdirSync(dir);              files.forEach(file => {                  const filePath = path.resolve(dir, file);                  const info = fs.statSync(filePath);                  if (!info.isDirectory()) {                      archive.append(fs.createReadStream(filePath), {                          'name': file                      });                  }              });              archive.finalize();              resolve(true);          });      }  }

CDN部署

大部分上传到CDN都为像CDN源站push文件,而正好我们运维在我的自动化部署平台的机器上挂载了NFS,即我只需要本地将JSSDK文件拷贝到共享目录,就实现了CDN文件上传。

export default class SupplyService extends Service {      async cp2CDN(supplyId, fileName) {          // 读取描述文件          const sdkInfoPath = path.resolve(this.releasePath, '' + supplyId, 'version.json');          if (!fs.existsSync(sdkInfoPath)) {              return this.fail('Release描述文件丢失,请重新打包');          }          const sdkInfo = JSON.parse(fs.readFileSync(sdkInfoPath, 'utf-8'));          sdkInfo.cdnFilename = fileName;          // 将文件拷贝至文件共享目录          const result = await this.cpFile(supplyId, fileName, false);          // 上传成功          if (result) {              // 将Release包描述文件的数据同步到MYSQL              const [sdkInfoErr] = await this.supplyDao.update(sdkInfo, {where: {supplyId}});              if (sdkInfoErr) {                  return this.fail('JSSDK信息记录失败,请重试', null, jssdkInfoResult);              }              return this.success('上传成功', {url})          }          return this.fail('上传失败');      }  }

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注编程网node.js频道,感谢您对编程网的支持。

--结束END--

本文标题: Node中怎么实现一个自动化部署平台

本文链接: https://lsjlt.com/news/74215.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Node中怎么实现一个自动化部署平台
    Node中怎么实现一个自动化部署平台,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。业务需求这个JSSDK,主要作用是在后端了为...
    99+
    2024-04-02
  • Node中怎么实现自动化部署
    这期内容当中小编将会给大家带来有关Node中怎么实现自动化部署,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。配置脚本这段脚本内容是我们需要服务器自动执行的# a...
    99+
    2024-04-02
  • walle自动化部署平台安装
    博客更换地址为http://www.gergw.topWalle - 瓦力 是一个支持svn、git、多用户、多项目、多环境同时部署的上线部署系统。相比jenkins其项目配置更简单、回滚快速、权...
    99+
    2024-04-02
  • docker自动化部署怎么实现
    要实现Docker的自动化部署,可以采用以下步骤:1. 编写Dockerfile:根据项目需求编写Dockerfile文件,定义Do...
    99+
    2023-08-12
    docker
  • Jenkins中怎么实现Pipeline自动化部署
    本篇文章给大家分享的是有关Jenkins中怎么实现Pipeline自动化部署,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。使用Jenkins前的一些设置为了快速搭建Jenkin...
    99+
    2023-06-19
  • jenkins+shell自动化部署怎么实现
    这篇文章主要介绍了jenkins+shell自动化部署怎么实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇jenkins+shell自动化部署怎么实现文章都会有所收获,下面我们一起来看看吧。通过jenkins...
    99+
    2023-06-29
  • windows中python实现自动化部署
    目录一、python脚本二、windows部署定时任务这段时间遇到一个需求是如果库里面有没有图片的数据,则访问我们的网站生成图片数据并更新库,要求每隔一段时间就要检测。 该需求主要为...
    99+
    2024-04-02
  • 怎么搭建jenkins实现自动化部署
    要搭建Jenkins实现自动化部署,您需要按照以下步骤进行操作:1. 安装Jenkins:您可以从Jenkins官方网站下载适用于您...
    99+
    2023-08-12
    jenkins
  • 怎么在Springboot服务中实现自动化部署Docker
    怎么在Springboot服务中实现自动化部署Docker?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。微服务部署方式(1)手动部署:首先基于源码打包生成jar包(或war...
    99+
    2023-06-14
  • git自动化部署php脚本怎么实现
    本文操作环境:linux5.9.8系统、Git 2.30.0版、DELL G3电脑git自动化部署php脚本怎么实现git+php部署webhook自动化脚本 实现代码同步本文将介绍git+php部署webhook自动化脚本 实现代码同步 ...
    99+
    2014-07-13
    git php
  • PXE怎么实现自动化部署Linux系统
    本篇内容主要讲解“PXE怎么实现自动化部署Linux系统”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PXE怎么实现自动化部署Linux系统”吧!背景说明在数据中心,一次几十台甚至几百台服务器上...
    99+
    2023-06-22
  • 云服务器自动化部署怎么实现
    实现云服务器的自动化部署可以通过以下几个步骤来实现:1. 配置云服务器环境:首先需要在云平台上创建一个虚拟机实例,并配置好所需要的操...
    99+
    2023-09-16
    云服务器
  • 怎么用Python实现服务部署自动化
    这篇“怎么用Python实现服务部署自动化”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“怎么用Python实现服务部署自动化...
    99+
    2023-07-06
  • linux中jenkins自动部署怎么实现
    在Linux中,可以通过以下步骤实现Jenkins的自动部署: 安装Jenkins:通过在Linux系统上运行命令来安装Jenk...
    99+
    2023-10-27
    linux jenkins
  • 如何安装和配置pm2实现自动化部署node项目
    小编给大家分享一下如何安装和配置pm2实现自动化部署node项目,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!1、pm2简介pm2(process manager)是一个进程管理工具,维护...
    99+
    2024-04-02
  • 怎么用NFV+SDN实现VNF全自动化部署
    本篇内容介绍了“怎么用NFV+SDN实现VNF全自动化部署”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、某运营商期望通过数字化转型项目提...
    99+
    2023-06-03
  • vue中怎么实现一个自动化表单
    这期内容当中小编将会给大家带来有关vue中怎么实现一个自动化表单,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。通过json配置快速生成表单的vue plugin。设计目标...
    99+
    2024-04-02
  • 如何在PHP中实现自动化营销平台
    随着互联网时代的到来,越来越多的公司开始使用营销自动化平台来提高市场营销效率。营销自动化平台可以帮助企业自动跟进潜在客户、发送邮件和短信、创建营销活动、自动分发销售线索,以及收集数据并分析营销效果等等。而PHP作为一门广泛使用的Web开发语...
    99+
    2023-05-21
    自动化 PHP 营销平台
  • shell怎么实现jenkins自动部署
    要在Shell脚本中实现Jenkins自动部署,通常需要以下步骤: 编写一个Shell脚本,该脚本包含您希望Jenkins执行的...
    99+
    2024-04-02
  • Linux实现项目的自动化部署
    一、自动化部署git项目 #!/bin/bash # 清除项目进程和历史文件 pkill -f start.py sleep 1 cd /root/automation |rm -rf testProduce/ ...
    99+
    2022-07-08
    Linux 项目自动化部署
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作