宝哥软件园

嘿 快给我打个小程序的预览码

编辑:宝哥软件园 来源:互联网 时间:2021-12-08

需求

开发小程序的朋友随时会听到一句话:“嘿,给我打一个xxx环境的预览代码”,不管你在做什么,你都要快速回复:“等一下,我给你打一个代码……”

然后你在xxx环境下搭建一个包,打开微信开发者工具,点击预览,等了一会,预览代码出来了,你复制了一下,扔给你爸。

终于有一天,当你全神贯注在做一件无法形容的事情时,“嘿,给我打一个xxx环境的预览码”,这时你的内心怒吼:“我不会给你打的!自己打电话吧!”

所以有了这个需求,我们需要做一些东西让爸爸独立编码。嗯,应该是只有一个按钮,点一下就能看到预览二维码的东西。应该是这样的:

没错!这样做!

规划一下

:要做大事,必须从做白日梦开始。现在,让我们想想我们需要做什么准备来实现这个功能。

找到微信开发者工具的界面最重要的是看微信开发者工具有没有给我们提供这样的界面让我们操作。查阅文件后,我们会发现确实如此!

我们会发现文档为我们提供了两个接口:命令行调用和HTTP调用。有了界面,一切都好办了,只需调整界面,获取二维码,粘贴到页面上即可。很简单。

为了梳理开发流程,我们用一个流程图来解释一下这个简单的事情喂,快给我打一个小程序预览码(图1)

所需技术

如果工人想干得好,他们必须先磨工具。如果我们想做这件事,我们仍然需要首先整理使用的技术。

微信开发者工具:一个小程序项目(这里以一个mpvue项目为例)前端vue vux,在前端没有事情做的地方,这种搭配纯粹是因为移动端已经有事情在做了,直接使用。后端koa2当然,任何东西都可以用于后端。这里选择koa2纯粹是因为我不能使用其他任何东西.前端和后端的HTTP请求用axios统一,涉及节点操作命令行。似乎除了shelljs没有别的可以用了。用了再说吧。

撸起袖子从后端开始

为了省事,直接把前后东西放在一起。项目目录:

喂,快给我打一个小程序预览码(图2)

您可以看到服务器目录中的所有东西都是后端的。

Server/index.js首先看入口文件index.js,从中我们可以知道后端应该做两件事,第一,它应该能够访问前端构建的静态资源,第二,它应该能够通过HTTP接口与前端进行交互。参见代码:

const path=require(' path ')const Koa=require(' Koa ')const koaStatic=require(' Koa-static ')const body parser=require(' Koa-body parser ')const router=require('。/router ')const app=new Koa()const port=9871 app . use(BodyParser())//处理静态资源这里构建目录app . use(Koastatic(path . resolve(_ dirname,/dist ')//路由处理接口app.use (router.routes())。使用(router . allowed methods())//监听端口app . listen(9871)console . log(`[demo]Start-quick是从端口$ {port}开始的)`)对于静态资源,可以使用koa-static。关键是如何向前端提供接口,这取决于路由。

服务器/路由器/index.js

Const router=require(' KOA-router ')//业务逻辑Const WX=require('./控制器/WX') Const路由器=newro

uter({ // 接口前缀 比如open接口 请求路径就是/api/open prefix: '/api'})router.get('/open', wx.open) .get('/login', wx.login) .get('/preview', wx.preview) .get('/build', wx.build)module.exports = router

这里可以清晰看到,后端提供了四个接口,但具体每个接口的业务逻辑则封装在controller里的wx.js,如果以后还有别的业务逻辑,就在controller加相应的模块即可。

server/controller/wx.js

// 微信开发者工具接口调用逻辑const {open, login, preview, build} = require('../utli/wxToolApi')// 处理成功失败返回格式的工具const {successBody, errorBody} = require('../utli')class WxController {  /**   * 根据环境对mpvue项目进行打包   * @returns {Promise<void>}   */  static async build (ctx) {    // 前端传过来的get参数    const query = ctx.request.query    if (!query || !query.env) {      ctx.body = errorBody(null, '构建项目失败')      return    }    const [err, data] = await build(query.env)    ctx.body = err ? errorBody(err, '构建项目失败') : successBody(data, '构建项目成功')  }  /**   * 打开微信开发者工具   * @returns {Promise<void>}   */  static async open (ctx) {    const [err, data] = await open()    ctx.body = err ? errorBody(err, '打开微信开发者工具失败') : successBody(data, '打开微信开发者工具成功')  }  /**   * 登录微信开发者工具   * @returns {Promise<void>}   */  static async login (ctx) {    const [err, data] = await login()    ctx.body = err ? errorBody(err, '登录二维码返回失败') : successBody(data, '登录二维码返回成功')  }  /**   * 查看预览码   * @returns {Promise<void>}   */  static async preview (ctx) {    const [err, data] = await preview()    ctx.body = err ? errorBody(err, '预览二维码返回失败') : successBody(data, '预览二维码返回成功')  }}module.exports = WxController

为了代码更加清晰,这里将具体操作微信开发者工具的接口逻辑抽到util/wxToolApi.js里去了,仅仅处理怎样以统一格式返回给前端。util/wxToolApi.js

const {promiseWrap, successBody, errorBody} = require('../utli')const {INSTALL_PATH, PROJECT_PATH, PORT_PATH, PORT_FILE_NAME, HOST} = require('../const')const {readFile} = require('../utli/nodeApi')const shell = require('shelljs')const axios = require('axios')module.exports = {  /**   * 根据环境对mpvue项目进行打包   * @param env [doc, pre, prd]   * @returns {*}   */  build (env) {    return promiseWrap(new Promise((resolve, reject) => {      // 进入项目目录      shell.cd(PROJECT_PATH)      // 执行打包命令      shell.exec(`npm run build:${env}`, function (code, stdout, stderr) {        resolve(stdout)      })    }))  },  /**   * 打开微信开发者工具   * @returns {*}   */  open () {    return promiseWrap(new Promise((resolve, reject) => {      // 进入项目目录      shell.cd(INSTALL_PATH)      // 执行微信开发者工具接口“命令行启动工具”      shell.exec(`cli -o ${PROJECT_PATH}`, function (code, stdout, stderr) {        if (stderr) return reject(stderr)        resolve(stdout)      })    }))  },  /**   * 获取微信开发者工具端口号   * @returns {Promise<*>}   */  async getPort () {    shell.cd(PORT_PATH)    // http 服务在工具启动后自动开启,HTTP 服务端口号在用户目录下记录,可通过检查用户目录、检查用户目录下是否有端口文件及尝试连接来判断工具是否安装/启动。    const [err, data] = await readFile(PORT_FILE_NAME)    return err ? errorBody(err, '读取端口号文件失败') : successBody(data, '读取端口号文件成功')  },  /**   * 微信开发者工具进行登录   * @returns {*}   */  login () {    return promiseWrap(new Promise(async (resolve, reject) => {      // 获取端口号      const portData = await module.exports.getPort()      if (portData.code !== 0) {        reject(portData)        return      }      const port = portData.data      axios.get(`http://${HOST}:${port}/login?format=base64`)        .then(res => {          resolve(res.data)        })        .catch(e => {          reject(e)        })    }))  },  /**   * 微信开发者工具获取预览码   * @returns {*}   */  preview () {    return promiseWrap(new Promise(async (resolve, reject) => {      const portData = await module.exports.getPort()      if (portData.code !== 0) {        reject(portData)        return      }      const port = portData.data      axios.get(`http://${HOST}:${port}/preview?format=base64&projectpath=${encodeURIComponent(PROJECT_PATH)}`)        .then(res => {          resolve(res.data)        })        .catch(e => {          reject(e)        })    }))  }}

这里有一点需要注意,为什么只有open接口需要用命令行调用方式?那是因为HTTP调用方式必须加端口,比如open接口

# 打开工具http://127.0.0.1:端口号/open# 打开/刷新项目http://127.0.0.1:端口号/open?projectpath=项目全路径

如果你根本都没有打开微信开发者工具,在以下地方就会找不到端口:

端口号文件位置:macOS : ~/Library/Application Support/微信web开发者工具/Default/.ideWindows : ~/AppData/Local/微信web开发者工具/User Data/Default/.ide

所以作为一个全自动化打码工具,怎么可能还要自己去手动打开微信开发者工具呢!

前端

后端的东西基本就那么多,终于到前端了,前端十分简单,就不多说了:

<template>  <div>    <group title="请选择环境">      <radio :options="envOption" v-model="env"></radio>    </group>    <x-button class="btn" type="default" @click.native="handlePreviewProject">点击预览</x-button>    <div v-if="loginImg" class="code">      <divider>请先登录</divider>      <img class="code-img" :src="loginImg" alt="">    </div>    <div v-if="preImg" class="code" id="preImg">      <divider>预览二维码</divider>      <img class="code-img" :src="`${base64Prefix}${preImg}`" alt="">    </div>  </div></template><script>import {openProject, login, previewProject, buildProject} from 'SERVICES/index'import {showLoading, hideLoading} from 'UTILS'import { Divider, XButton, Radio, Group } from 'vux'export default {  data () {    return {      // data表示取得数据的协定名称,image/png 是数据类型名称,base64 是数据的编码方法,逗号后面就是这个image/png文件base64编码后的数据。      base64Prefix: 'data:image/png;base64,',      // 登录二维码      loginImg: '',      // 预览二维码      preImg: '',      // 环境 默认为doc      env: 'doc',      // 所有的环境选项      envOption: ['doc', 'pre', 'prd']    }  },  components: {    Divider,    XButton,    Radio,    Group  },  methods: {    handleError (msg) {      alert(msg)    },    async login () {      const {data: {code, data, msg}} = await login()      if (code !== 0) {        this.handleError(msg)        return code      }      this.loginImg = data      return code    },    async previewProject () {      const {data: {code, data, msg}} = await previewProject()      if (code !== 0) {        this.handleError(msg)        return code      }      this.preImg = data      return code    },    async handlePreviewProject () {      showLoading()      // 重置二维码      this.resetImg()      // 打开微信开发者工具      const {data: {code}} = await openProject()      if (code !== 0) {        // 登录微信开发者工具        await this.login()        hideLoading()        return      }      // 根据环境打包      await buildProject(this.env)      // 预览      await this.previewProject()      hideLoading()    },    resetImg () {      this.loginImg = ''      this.preImg = ''    }  }}</script><style lang='less'>  .btn {    width: 90%!important;    margin: 30px auto 30px auto;  }  .code {    display: flex;    align-items: center;    flex-direction: column;    .code-img {      width: 300px;      height: 300px;    }  }</style>

这里有一个坑就是,login返回的base64是带了data:image/jpeg;base64,前缀的,所以可以直接放到img的src里,但是获取预览码的preview返回的却没有这个前缀!所以需要自己加上去,就是那个base64Prefix:'data:image/png;base64,'

最后

其实到这里已经基本实现了整个打码功能,但如果真的要可以用还有很多事情没做。

  1. 部署到测试机器上。虽然可以直接用自己的机子作为部署这个工具的机器,但这实在是有点……如果要部署到测试机器上,有一个问题就是,微信开发者工具依赖图形界面,而服务器一般是命令行,虽然有这样的项目移植微信开发者工具到linux,但这种部署方式似乎还是怪怪的。
  2. 假设完成了上述部署,进行小程序项目打包的环节需要修改一下,变成根据选择的环境,到相应的代码仓库(比如gitlab)拉取该环境的最新代码,然后进行安装依赖才能执行打包命令。
  3. 既然都做到这一步了,也不差把上传小程序也加上去,微信开发者工具接口也有提供,这样一来整个测试打码到上线的步骤都有了。
更多资讯
游戏推荐
更多+