更新说明:对文章目录排版做了调整。
更新时间:2022-05-04

第一章 本周导学

1-1 本周整体内容介绍和学习方法

  • 云构建原理、架构和实现
  • WebSocket入门到实战
  • Redis入门实战

第二章 云架构模块架构设计

2-1 详细分析为什么需要设计云构建系统

为什么需要云构建

  • 减少发布过程中的重复劳动
    • 打包构建
    • 上传静态资源服务器
    • 上传CDN
  • 避免不同环境造成的差异
  • 提升构建性能
  • 对构建过程进行统一管控
    • 发布前代码统一规则检查
    • 封网日统一发布卡口

2-2 云构建系统架构设计
点击查看【processon】

第三章 WebSocket 快速入门

3-1 WebSocket基本概念及同HTTP协议对比

WebSocket概念

  • HTTP:请求响应的单向。
  • WebSocket:只需发起一次请求,双向发起请求,双向接收响应。常用为聊天工具、云构建请求。
  • 客户端开发WebSocket与浏览器开发WebSocket是不同的。
  • 如何通过NodeJs搭建一个WebSocket服务。

相关基本概念:https://www.runoob.com/html/html5-websocket.html

3-2 egg集成WebSocket服务

基础介绍

基础教程:https://eggjs.org/zh-cn/tutorials/socketio.html
demo仓库:https://github.com/eggjs/egg-socket.io/tree/master/example

代码在lesson01分支基础上继续开发:cloudscope-cli-server/leeson01
在lesson01分支基础上,新建分支 lesson30,本周最终代码在lesson30分支上。

WebSocket服务开发流程

  1. 安装依赖
  1. 更新配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// config.default.js
config.io = {
namespace: {
'/': {
connectionMiddleware: ['auth'],
packetMiddleware: ['filter'],
},
'/chat': {
connectionMiddleware: ['auth'],
packetMiddleware: [],
},
},
};

// plugin.js
exports.io = {
enable: true,
package: 'egg-socket.io',
};

  1. 修改路由配置
1
2
3
4
5
6
7
8
// router.js

// app.io.of('/')
app.io.route('chat', app.io.controller.chat.index);

// app.io.of('/chat')
app.io.of('/chat').route('chat', app.io.controller.chat.index);

  1. 开发middleware
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// app/io/middleware/auth.js
'use strict';

module.exports = () => {
return async (ctx, next) => {
const say = await ctx.service.user.say();
ctx.socket.emit('res', 'auth!' + say);
await next();
console.log('disconnect!');
};
};

//app/io/middleware/filter.js
'use strict';

module.exports = () => {
return async (ctx, next) => {
console.log(ctx.packet);
const say = await ctx.service.user.say();
ctx.socket.emit('res', 'packet!' + say);
await next();
console.log('packet response!');
};
};
  1. 开发controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// app/io/controller/chat.js
'use strict';

module.exports = app => {
class Controller extends app.Controller {
async index() {
const message = this.ctx.args[0];
console.log('chat :', message + ' : ' + process.pid);
const say = await this.ctx.service.user.say();
this.ctx.socket.emit('res', say);
}
}

return Controller;
};

3-3 WebSocket客户端开发

代码分支在 cloudscope-cli/lesson30上。

  • lerna create cloudbuild models/
  • cd models/cloudbuild
  • npm i -S socket.io-client
  • cloudbuild/lib/index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
'use strict';

// or http://127.0.0.1:7001/chat
const socket = require('socket.io-client')('http://127.0.0.1:7001');

socket.on('connect', () => {
console.log('connect!');
socket.emit('chat', 'hello world!');
});

socket.on('res', msg => {
console.log('res from server: %s!', msg);
});

3-4 WebSocket客户端与服务端交互流程分析

以日志的打出分析流程
30-1
30-2

  • 首先服务端(cloudscope-cli-server)启动服务:npm run dev
  • 客户端启动服务:node models/cloudbuild/lin/index.js
  • 客户端启动后:
    • socket on 连接成功,监控connect事件:打印出日志** connect!**
    • 接着客户端emit chat事件:socket.emit(‘chat’, ‘hello world!’);
  • 服务端接收到chat事件后
    • 首先会现在服务端config.default.js中找到 / 的 connectMiddleWare的 auth.js去执行
      • auth.js中触发res事件
      • 客户端监听res事件,打印日志:res from server:auth! Hello Man!!
    • 接着服务端在config.default.js中 找到 / 的packetMiddleWare 的 filter.js去执行
      • 服务端打印 ctx.packet日志:[‘chat’,‘hello world!’]
      • filter.js触发res事件
      • 客户端监听res事件,打印日志:res from server:packet! Hello Man!!
    • 服务端通过route匹配到 chat,于是去Controller中找 chat.js
      • 服务端打印日志:chat:hello world! : 10826
      • 接着服务端调用service服务,拿到值,触发 res事件
      • 客户端监听到res事件,打印日志:res from server:Hello Man!!
    • 服务端等待 next执行完毕后,最后在 filter.js中,打印出:packet response!

第四章 Redis 快速入门

4-1 redis基本概念+安装方法+基本命令

  • 该项目应用redis是要:存储任务信息
  • redis安装
  • 常用命令redis-cli[进入终端服务]和redis-server[启动redis服务]

4-2 阿里云redis服务配置和远程连接方法讲解
我这里实在腾讯云领了一个月的redis免费试用版本,下面记录为课程的讲解,腾讯云相关redis见读书笔记。

  • 购买完数据库后,第一个设置是白名单设置,0.0.0.0/0 如果不设置,会出现远程无法连接的问题
  • 创建账号:使用默认账号或创建账号连接
  • 连接成功后 AUTH

4-3 egg集成redis方法讲解
redis为使用本地

  • 首先在npm官网上查看 egg-redis这个插件
  • 在server安装:npm i egg-redis --save
  • 根据npm官网上关于egg-redis的代码讲解,分别在plugin.js和config.default.js中添加相关代码。
  • 添加一个新路由:/redis/test,并在project的controller中测试
  • 添加 await app.redis.get(key)获取key值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
async getRedis(){
const { ctx, app } = this;
const num = await app.redis.get('number')
console.log(num)
ctx.body = 'hello redis'
}


//config.defualt.js
config.redis = {
client: {
port: REDIS_PORT,
host: REDIS_HOST,
password:REDIS_PWD,
db: 0,
},

//plugin.js
exports.redis = {
enable: true,
package: 'egg-redis',
};

第五章 云构建初始化流程开发

5-1 CloudBuild类开发

根据第二章 架构图,本节主要代码为 CloudBuild类的创建与引用,最终传入git对象

3-3节已经创建了cloudbuild,修改这里的代码为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
'use strict';

class CloudBuild {
constructor(git, props){
console.log('cloudbuild',git)
}
// or http://127.0.0.1:7001/chat
// const socket = require('socket.io-client')('http://127.0.0.1:7001');

// socket.on('connect', () => {
// console.log('connect!');
// socket.emit('chat', 'hello world!');
// });

// socket.on('res', msg => {
// console.log('res from server: %s!', msg);
// });
}
module.exports = CloudBuild

在modes/git下引入@cloudscope-cli/cloudbuild,并新建publish方法

1
2
3
4
5
6
7
8
9
10
11
async publish(){
await this.preparePublish()
const buildCmd = ''
const cloudBuild = new CloudBuild(this,{
buildCmd
})
}

async preparePublish(){
console.log('preparePublish')
}

在commands/publish/lib/index.js 文件中,接着上一周的 自动化提交代码,接着调用 git.publsih方法。

  • 这样从 commands/publish/lib/index.js中调用 git.publish()方法
  • 在 models/git/lib/index.js中开发publish方法,publish中会生成一个cloudbuild实例
  • 这个cloudbild实例为我们在models下新建的一个包,这样本节就形成了一个闭环。
  • 下节开始就是cloudbuild实例的开发,以及publish流程。

5-2 生成构建命令+构建命令检查开发

本节主要内容是,用于定制build命令,通过 --buildCmd参数,如果用户传入build命令,那么使用传入的build命令打包,如果不是则传入默认的打包命令。

  1. 首先在 core/cli/lib/index.js中传入 --buildCmd参数
1
2
3
4
5
6
program
.command('publish')
.option('--refreshServer','强制更新远程Git仓库类型和token')
.option('--refreshOwner','强制更新远程Git仓库用户类型')
.option('--buildCmd <buildCmd>','构建命令')
.action(exec)
  1. 然后在commands/publish/lib/index.js中接收这个参数
1
2
3
4
5
6
7
8
9
10
11
12
class PublishCommand extends Command {
init(){
// 处理参数
log.verbose('publish init',this._argv)
this.options = {
refreshServer:this._argv[0].refreshServer,
refreshOwner:this._argv[0].refreshOwner,
buildCmd:this._argv[0].buildCmd
}
}
…………
}
  1. 此时Git类接收并赋值该参数,然后在上节我们写的 [models/git/lib/index.js] publishPrepare中见检查这个命令
1
2
3
4
5
6
7
8
9
10
11
async preparePublish(){
if(this.buildCmd){
const buildCmdArray = this.buildCmd.split(' ')
if(!Object.is(buildCmdArray[0],'npm') && !Object.is(buildCmdArray[0],'cnpm')){
throw new Error('Build命令非法,必须使用npm或cnpm!')
}
}else{
this.buildCmd = 'npm run build'
}
console.log(this.buildCmd)
}
  • 最后测试一下:

终端命令:

cloudscope-cli publish --targetPath /Users/liumingzhou/Documents/imoocCourse/Web前端架构师/cloudscope-cli/commands/publish --buildCmd ‘anpm run build:prod’
**抛出异常:**Build命令非法,必须使用npm或cnpm

5-3 通过CloudBuild创建WebSocket连接

我们在第三章的学习当中已经大略的知道了 前后端如何建立起socket连接,本节就是对服务端代码修改以及客户端代码开发-传递git.repo参数到服务端。

  • 服务端
    • 将与service有关的代码先删掉
    • 将routes.js中与chat相关的修改为 build:app.io.route(‘build’, app.io.controller.build.index);
    • 服务端学习的核心代码为:const query = socket.handshake.query
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//app/controller/io/controller/build.js
'use strict';

module.exports = app => {
class Controller extends app.Controller {
async index() {
console.log('Controller build!')
}
}
return Controller;
};

//app/controller/io/middleware/auth.js

'use strict';

module.exports = () => {
return async (ctx, next) => {
const {socket,logger} = ctx
const query = socket.handshake.query
logger.info(query)
console.log('connect!')
await next();
console.log('disconnect!');
};
};
  • 客户端
    • Cloudbuild实例的init方法传入了一个参数:git.remote
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// models/cloudbuild/lib/index.js
'use strict';

const io = require('socket.io-client');
const TIME_OUT = 5* 60
const WS_SERVER = 'http://liugezhou.com:7001'
class CloudBuild {
constructor(git, options){
this.git = git
this.buildCmd = options.buildCmd
this.timeout = TIME_OUT
}

init(){
const socket = io(WS_SERVER,{
query:{
repo:this.git.remote
}
})
socket.on('connect', () => {
console.log('connect!');
// socket.emit('chat', 'hello world!');
});
}
}

最后测试一下:

  • 最后测试一下,将服务端启动,在客户端执行命令:

终端命令:

cloudscope-cli publish --targetPath /Users/liumingzhou/Documents/imoocCourse/Web前端架构师/cloudscope-cli/commands/publish --buildCmd ‘npm run build:prod’

  • 在客户端与服务端分别打印出日志,测试正确

5-4 WebSocket超时自动断开连接逻辑开发

本节比较简单,是解决连接不上服务端的问题–连接超时,抛出异常,部分代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

const CONNET_TIME_OUT = 5*1000
class CloudBuild {
constructor(git, options){
this.git = git
this.buildCmd = options.buildCmd
this.timeout = TIME_OUT
}

doTtimeout(fn,timeout){
this.timer && clearTimeout(this.timer)
log.info('设置任务超时时间:',`${timeout/1000}秒`)
this.timer = setTimeout(fn,timeout);
}
init(){
const socket = io(WS_SERVER,{
query:{
repo:this.git.remote
}
})
const disconnect = ()=>{
clearTimeout(this.timer)
socket.disconnect()
socket.close()
}
this.doTtimeout(()=>{
log.error('云构建服务连接超时,自动终止')
disconnect()
}, CONNET_TIME_OUT);

}
}

5-5 WebSocket客户端和服务端通信优化

在整个websocket连接成功之后,是可以发送一些标准化日志的。

  • 友好实现socket连接后的标准化日志,服务端改造
    • 第一个改造点,cloudscope-cli-server中auth.js添加try catch异常捕获
    • 第二个改造点:新建app/extend/helper.js,统一的返回格式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// app/extend/helper.js
'use strict';

module.exports = {
parseMsg(action,payload={},metadata={}){
const meta = Object.assign({},{
timestamp:Date.now()
},metadata);

return {
meta,
data:{
action,
payload
}
}
}
}

// app/controller/io/middleware/auth.js

const {socket,logger,helper} = ctx
socket.emit(id,helper.parseMsg('connect',{
type:'connect',
message:'云构建服务连接成功'
}))

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
const get =require('lodash/get')

function parseMsg(msg){
const action = get(msg,'data.action')
const message = get(msg,'data.payload.message')
return {
action,
message
}
}


socket.on('connect', () => {
clearTimeout(this.timer)
const {id} = socket
socket.on(id,msg=>{
const parsedMsg = parseMsg(msg)
log.success(parsedMsg.action,parsedMsg.message,`任务ID:${id}`)
})
});

socket.on('disconnect',()=>{
log.success('disconnect','云构建任务断开')
disconnect();
})

socket.on('error',(err)=>{
log.error('error','云构建错误',err)
disconnect()
})

5-6 云构建任务写入Redis

本节主要内容就是将云构建任务写入到redis中去【服务端】,核心代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
// app/controller/io/middleware/auth.js
const REDIS_PREFIX = 'cloudbuild'

const {app} = ctx
const {redis} = app
// 判断redis任务是否存在
let hashTask = await redis.get(`${REDIS_PREFIX}:${id}`)
if(!hashTask){
await redis.set(`${REDIS_PREFIX}:${id}`,JSON.stringify(query))
}
hashTask = await redis.get(`${REDIS_PREFIX}:${id}`)
logger.info(hashTask)

5-7 创建云构建任务功能开发
客户端添加build方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// models/cloudbuild/lib/index.js   
build(){
return new Promise((resolve,reject)=>{
this.socket.emit('build')
this.socket.on("build",msg=>{
const parsedMsg = parseMsg(msg)
log.success(parsedMsg.action,parsedMsg.message)
})
this.socket.on('building',msg=>{
const parsedMsg = parseMsg(msg)
log.success(parsedMsg.action,parsedMsg.message)
})

//commands/publish/lib/index.js
//publish方法中
await cloudBuild.init()
await cloudBuild.build()

在服务端,我们在已经建好的 app/controller/io/controller/build.js中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
'use strict';

const REDIS_PREFIX = 'cloudbuild'
const CloudBuildTask = require('../../models/CloudBuildTask')
async function createCloudBuildTask(ctx,app){
const { socket,helper } = ctx
const { redis } = app
const client = socket.id
const redisKey = `${REDIS_PREFIX}:${client}`
const redisTask = await redis.get(redisKey)
const task = JSON.parse(redisTask)
socket.emit('build',helper.parseMsg('create task',{
message:'创建云构建任务'
}))
return new CloudBuildTask({
repo:task.repo,
name:task.name,
version:task.version,
branch:task.branch,
buildCmd:task.buildCmd
})
}
module.exports = app => {
class Controller extends app.Controller {
async index() {
//创建云构建任务
const {ctx,app} = this
const cloudBuildTask = await createCloudBuildTask(ctx,app)
}
}
return Controller;
};

// app/models/CloudBuildTask.js
'use strict';

class CloudBuildTask {
constructor(options){
console.log(options)
}
}

module.exports = CloudBuildTask

测试,可在服务端打印出options。

第六章 云构建执行流程开发

6-1 云构建任务初始化流程开发

服务端云构建的初始化流程,主要内容为CloudBuildTask这个类

  • npm i -S user-home simple-git fs-extra
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 注意CloudBuildTask类需要传入的第二个参数为ctx
'use strict';

const path = require('path')
const fse = require('fs-extra')
const userHome = require('user-home')
const Git = require('simple-git')
class CloudBuildTask {
constructor(options,ctx){
this._ctx = ctx
this._name = options.name //项目名称
this._version = options.version //项目版本号
this._repo = options.repo
this._branch = options.branch
this._buildCmd = options.buildCmd //构建命令
this.logger = this._ctx .logger
// 服务器的用户主目录
this._dir = path.resolve(userHome,'.cloudscope-cli','cloudbuild',`${this._name}@${this._version}`) //缓存目录
this._sourceCodeDir = path.resolve(this._dir,this._name) //缓存源码目录
this.logger.info('_dir',this._dir)
this.logger.info('_sourceCodeDir',this._sourceCodeDir)
}

async prepare(){
fse.ensureDirSync(this._dir)
fse.emptyDirSync(this._dir)
this._git = new Git(this._dir)

}
}

module.exports = CloudBuildTask

6-2 云构建任务交互日志开发

本节在CloudBuildTask类中,还未进行开发前,现对错误日志,进行了升级或者说是友好的异常抛出。
首先在CloudBuildTask这个类中,对于返回的格式进行了统一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// app/models/CloudBuildTask.js

const {SUCCESS,FAILED} = require('../constant') //定义了常量

success(msg,data){
return this.response(SUCCESS,msg,data)
}
fail(msg,data){
return this.response(FAILED,msg,data)
}
response(code,message,data){
return {
code,
message,
data
}

然后在 app/io/controller/build.js中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
async function prepare(cloudBuildTask,socket,helper) {
socket.emit('build',helper.parseMsg('prepare',{
message:'开始执行构建前的准备工作'
}))
const prepareRes = await cloudBuildTask.prepare()
if(!prepareRes || Object.is(prepareRes.code,FAILED)){
const msg = prepareRes ? prepareRes.message : 'prepare返回为undefined'
socket.emit('build',helper.parseMsg('prepare failed',{
message: `执行云构建准备工作失败,失败原因:${msg}`
}))
return
}
socket.emit('build',helper.parseMsg('prepare',{
message:'构建前准备工作成功'
}))
}

然后在客户端的models/cloudbuild/lib/index.js,监听的build方法中做了一个优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
build(){
return new Promise((resolve,reject)=>{
this.socket.emit('build')
this.socket.on("build",msg=>{
const parsedMsg = parseMsg(msg)
if(FAILED_CODE.indexOf(parsedMsg.action)>-1){
log.error(parsedMsg.message)
clearTimeout(this.timer)
this.socket.disconnect()
this.socket.close()
}
log.success(parsedMsg.action,parsedMsg.message)
})
this.socket.on('building',msg=>{
const parsedMsg = parseMsg(msg)
log.success(parsedMsg.action,parsedMsg.message)
})
})
}

6-3 服务端源码下载 + 切换分支

在服务端 app/io/controller/build.js下,

  • 我们完成了 await prepare(cloudBuildTask,socket,helper),
  • 接着我们继续实现 await download(cloudBuildTask,socket,helper)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// app/io/controller/build.js

async function download(cloudBuildTask,socket,helper){
socket.emit('build',helper.parseMsg('download repo',{
message:'开始下载源码'
}))
const downloadRes = await cloudBuildTask.download()
if(!downloadRes || Object.is(downloadRes.code,FAILED)){ // downlod下载失败
socket.emit('build',helper.parseMsg('download failed',{
message:'源码下载失败'
}))
return
}else{
socket.emit('build',helper.parseMsg('download repo',{
message:'源码下载成功'
}))
}
}

// app/models/CloudBuildTask.js
async download(){
await this._git.clone(this._repo) //clone仓库
this._git = new Git(this._sourceCodeDir) //将git地址更改,生成新的simple git
// 切换分支 git checkout -b dev/1.0.2 origin/dev/1.0.2
await this._git.checkout(['-b',this._branch,`origin/${this._branch}`])
return fs.existsSync(this._sourceCodeDir) ? this.success() : this.failed()
}

然后在客户端执行命令:cloudscope-cli publish --targetPath /Users/liumingzhou/Documents/imoocCourse/Web前端架构师/cloudscope-cli/commands/publish

经过测试,在/User/username/.cloudscoe-cli/cloudbuild/test@1.0.2/test下安装了源码,执行git branch 看到切换到了 开发分支。

6-4 服务端源码依赖安装+命令执行功能封装

与上一节的download流程一样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

// app/io/controller/build.js
await install(cloudBuildTask,socket,helper)

async function install(cloudBuildTask,socket,helper) {
socket.emit('build',helper.parseMsg('install',{
message:'开始安装依赖'
}))
const installRes = await cloudBuildTask.install()
if(!installRes || Object.is(installRes.code,FAILED)){ // downlod下载失败
socket.emit('build',helper.parseMsg('install failed',{
message:'安装依赖失败'
}))
return
}else{
socket.emit('build',helper.parseMsg('install',{
message:'安装依赖成功'
}))
}
}

// app/models/CloudBuildTask.js
async install(){
let res = true
res && (res = await this.execCmd('npm install --registry=https://registry.npm.taobao.org'))
return res ? this.success(): this.failed()
}

execCmd(cmd){
// npm install ->['npm','install']
let command = cmd.split(' ')
if(command.length === 0){
return null
}
const firstCommand = command[0]
const leftCommand = command.slice(1) || []
return new Promise((resolve,reject)=>{
const p = exec(firstCommand,leftCommand,{
cwd:this._sourceCodeDir
},{stdio:'pipe'})
p.on('error',e=>{
this._ctx.logger.error('build error',e)
resolve(fasle)
})
p.on('exit',c=>{
this._ctx.logger.info('build exit',c)
resolve(true)
})
p.stdout.on('data',data => {
this._ctx.socket.emit('building',data.toString())
})
p.stderr .on('data', data =>{
this._ctx.socket.emit('building',data.toString())
})
})
}

function exec(command,args,options){
const win32 = process.platform === 'win32';
const cmd = win32 ? 'cmd': command
const cmdArgs = win32 ? ['/c'].concat(command,args) : args;
return require('child_process').spawn(cmd, cmdArgs,options || {})
}

6-5 云构建任务执行逻辑开发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

// app/io/controller/build.js

await build(cloudBuildTask,socket,helper)

async function build(cloudBuildTask,socket,helper) {
socket.emit('build',helper.parseMsg('build',{
message:'开始启动云构建'
}))
const buildRes = await cloudBuildTask.build()
if(!buildRes || Object.is(buildRes.code,FAILED)){ // downlod下载失败
socket.emit('build',helper.parseMsg('build failed',{
message:'云构建任务执行失败'
}))
return
}else{
socket.emit('build',helper.parseMsg('build',{
message:'云构建任务执行成功'
}))
}
}

// app/models/CloudBuildTask.js
async build(){
let res = true
if(checkCommand(this._buildCmd)){
res = await this.execCmd(this._buildCmd)
}else{
res = false
}
return false ? this.success():this.failed()
}

function checkCommand(command){
if(command){
const commands = command.split(' ')
if(commands.length === 0 || ['npm','cnpm'].indexOf(commands[0])<0){
return false
}
return true
}
return false
}

最后在客户端经过测试,看到 build的dist目录没有构建成功:这是因为我的test源码不是一个可以打包的项目。
于是重写创建项目,并且publish 的时候输入参数 --refreshServer --refreshOwner ,构建成功。