前端工程化实践二——实现一个项目发布系统

0 前言

上一篇博客介绍了前端工程化实践的第一部分内容——搭建含有单元测试的脚手架工具,本篇博客继续前端工程化的实践,实现一个项目发布系统,以便代码编写测试完成后能够方便地将目标代码部署到线上服务系统中

1 实现一个线上Web服务

1.1 发布系统的组成

  1. 线上服务系统:Web服务器
  2. 发布系统:用于将项目发布到线上服务系统中
  3. 发布工具:和发布系统相连接的发布工具

1.2 初始化Server

找一台服务器(可以是真实的或者利用虚拟机代替)依次安装上node,npm,express等环境

1.3 利用Express框架编写服务器

  1. 初始化express项目: npx express-generator
  2. 安装依赖:npm install
  3. 将项目代码远程拷贝到server,然后执行npm start,开发环境是linux系统可以用scp命令(注意利用scp将项目代码拷贝到虚拟机服务器时需要设置虚拟机的端口转发规则),如果是Windows系统可以用SecureCRT软件

2 实现一个发布系统

2.1 用node.js启动一个简单的server

const http = require("http")

http.createServer((req, res)=>{
  console.log(req)
  res.end("Hello world")
}).listen("8082")

2.2 编写简单的发送请求功能

const http = require("http")

let request = http.request({
  hostname: "127.0.0.1",
  port: 8082
}, response =>{
  console.log(response)
})

request.end()

2.3 了解Node.js流

  1. readableStream
  • fs.createReadStream():创建可读的文件流
  • Event:“data”,可读流有数据可读
  • Event:“end”,可读流数据已读完
  • Event:“close”,可读流数据被关闭
let file = fs.createReadStream("package.json")
file.on("data", chunk=>{
  console.log(chunk.toString())
})
file.on("close", ()=>{
  console.log("read finished")
})
  1. writableStream
  • fs.createWriteStream(): 创建可写的文件流。
  • writable.write(chunk[,encoding][,callback])
  • writable.end()

2.4 改造server

  1. publish-server与线上服务系统server部署在同一台服务器上,用于接收publish-tool的文件上传请求并存储到线上服务系统server项目路径下
  2. publish-server和server都可以在package.json文件中配置一个publish命令,用于将本地代码拷贝到远端
  "scripts": {
    "publish": "scp -r ./* ygj@192.168.43.145:/home/ygj/server", 
  }

2.5 实现多文件发布

  1. 利用流的pipe方法将输入流和输出流相连接简化代码
  2. 利用archiverunzipper包实现多文件的压缩上传和接收解压
  • 上传部分关键代码
const archive = archiver('zip', {
  zlib: { level: 9 } // Sets the compression level.
})
archive.directory('./resources', false); // 从resources目录中追加文件,false表示追加时不改变文件夹名称
archive.finalize() // 结束文件追加
archive.pipe(request)
  • 接收解压
  req.pipe(unzipper.Extract({ path: '../server/public/resources' }))

2.6 用github OAuth做一个具有鉴权功能的登录实例

目的是为了实现发布系统的鉴权功能,具体包括以下几步:

  1. 创建github app获取client-id,client-secret
    在这里插入图片描述
  • 在github创建页面依次将GitHub App name、Home Page URL(http://localhost)、Callback URL(http://localhost:8082/auth)、Webhook URL(https://github.com)填写上
  • 然后点击“Create Github app"按钮
  • 成功创建后查看client-id,client-secret
    在这里插入图片描述
  1. 在publish-tool端,打开https://github.com/login/oauth/authorize?client_id=步骤1中的client-id(该链接有时无法访问)
  2. 在publish-server端,auth路由:接受github返回的code,用code+client_id+client_secret跟github换认证token,然后向publish-tool端返回一个发布链接
function auth(req, res) {
  let query = querystring.parse(req.url.match(/^\/auth\?([\s\S]+)$/)[1])
  getToken(query.code, function(info){
    console.log(info)
    //res.write(JSON.stringify(info))
//    res.write(`<html><head></head><body><a href='http://localhost:8083/?token=${info.access_token}'>publish</a></body></html>`)
    res.write(`<html><head></head><body><a href='http://localhost:8083/?token=${info.access_token}'>publish</a></body></html>`)
    res.end()
  })
}

function getToken(code, callback) {
  let request = https.request({
    hostname: "github.com",
    path: `/login/oauth/access_token?code=${code}&client_id=Iv1.28dda5cca6020d5e&client_secret=394ae94b88c4b165c1fadfef1b10a06012a9a366`,
    port: 443,
    method: "POST",
  }, function(response){
    let body = ""
    response.on("data", chunk => {
      body += chunk.toString()
    })
    response.on("end", chunk => {
      callback(querystring.parse(body))
    })
  })
  request.end() // 将请求发出
}
  1. 在publish-tool端,创建server,接受发布链接请求中的token,并向publish-server发送带token的publish请求
http.createServer((req, res)=>{
  let query = querystring.parse(req.url.match(/^\/\?([\s\S]+)$/)[1])
  console.log(query)
  publish(query.token)
}).listen(8083)

function publish(token) {
  let request = http.request({
    //  hostname: "192.168.43.145",
      hostname: "127.0.0.1",
      port: 8082,
      method: "POST",
      path: "/publish?token="+token,
      headers: {
        "Content-Type": "application/octet-stream",
      }
    }, response =>{
      console.log(response)
    })
    
    const archive = archiver('zip', {
      zlib: { level: 9 } // Sets the compression level.
    })
    archive.directory('resources', false);
    archive.finalize() // 为压缩工具填好了压缩的内容
    archive.pipe(request)
    archive.on("close", chunk=>{
      request.end(chunk)
    })
  1. 在publish-server端,publish路由:向github发送带token的请求获取用户信息,检查权限,接受发布

function publish(req, res) {
  let query = querystring.parse(req.url.match(/^\/publish\?([\s\S]+)$/)[1])
  getUser(query.token, info=>{
    if(info.login === "blateyang") {
      let fws = fs.createWriteStream("../server/public/resources.zip")
      req.pipe(fws)
//      req.pipe(unzipper.Extract({ path: '../server/public/resources' }))
      req.on("end", function(){
        res.end("success!")
        fws.close()
        // 下面两句需要放在req.on("end")的回调中,而不能放在req.on("end")的后面,因为是异步的
        let fsReadable = fs.createReadStream("../server/public/resources.zip")
        fsReadable.pipe(unzipper.Extract({ path: '../server/public/resources' }))
      })
    }
  })
}

function getUser(token, callback) {
  let request = https.request({
    hostname: "api.github.com",
    path: `/user`,
    port: 443,
    method: "GET",
    headers: {
      Authorization: `token ${token}`, 
      "User-Agent": "blateyang-toy-publish-auth"
    }
  }, function(response){
    let body = ""
    response.on("data", chunk => {
      body += chunk.toString()
    })
    response.on("end", chunk => {
      console.log(body)
      callback(JSON.parse(body))
    })
  })
  request.end() // 将请求发出
}

详细代码请参考我的github

3 小结

本篇博客主要介绍了如何搭建一个项目发布系统,首先需要搭建一个线上服务系统,然后编写项目发布系统和发布工具,最后利用一个github OAuth,实现项目发布系统的授权登录。整个过程还介绍了node可读、可写流的使用、多文件压缩库archiver和解压库unzipper以及github OAauth鉴权API的使用。

ps:如果觉得此文对你有帮助或启发,请不要吝惜你的点赞和分享,你的支持就是对我最大的鼓励。如有疑问,请留言或私信交流

  • 0
    点赞
  • 0
    收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论 2

打赏作者

Blateyang

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值