前言

手动发布小程序效率低还容易出错,本文就考虑如何用Jenkins来发布taro小程序。

手动打包小程序的问题

  1. 频繁发版 + 发版流程琐碎 + 可能存在的多个小程序,效率低
  2. 打包时经常固定一个人或者一台机器打包上传,不灵活
  3. 手动打包可能选错接口环境,导致线上问题

Jenkins打包好处

  1. 固定代码分支以及环境,打包过程由jenkins承担。效率高,减少环境错误的风险
  2. 所有人都可以自由打包

以上需求,整理成一个demo项目了,基于Taro 3.x

taro小程序打包示例地址

Jenkins如何发布小程序

微信小程序ci能力

开发者可不打开小程序开发者工具,独立使用 miniprogram-ci 进行小程序代码的上传、预览等操作

微信小程序ci官方文档

密钥及 IP 白名单配置

使用 miniprogram-ci 前应访问"微信公众平台-开发-开发设置"后下载代码上传密钥,并配置 IP 白名单 开发者可选择打开 IP 白名单,打开后只有白名单中的 IP 才能调用相关接口。

image.png

通过小程序管理员扫码,就可以获得上传密钥。IP白名单可以自己设置,限制指定IP地址操作。

我公司因为jenkins本身就做了内网访问限制,这里就没有重复限制了。

密钥的存放

一般下载的密钥,是放到项目根目录当中。考虑到密钥存放在项目中不太安全,就让运维在jenkins打包阶段,再注入到项目中。

image.png

使用Taro框架集成的ci发布

一般微信原生小程序直接使用miniprogram-ci的能力即可。因为项目使用了taro框架,这里就以taro插件来做为例子。taro兼容了各小程序平台ci(持续集成)的能力。

yarn add @tarojs/plugin-mini-ci -D

主要原理:通过小程序密钥进行身份鉴权。ci就具备上传或者预览小程序的权限

小程序持续集成 | Taro 文档

项目中进行ci配置

参数类型说明
appidstring小程序项目的 appid
privateKeyPathstring私钥文件在项目中的相对路径,在获取项目属性和上传时用于鉴权使用
robotnumber指定使用哪一个 ci 机器人,可选值:1 ~ 30(选填, 3.6.0 版本开始支持)
descstring描述
versionstring版本

上面都是自定义的,一般跟着具体打包脚本来自定义的。如果想要全局自定义version或者desc,可以在package.json下配置taroConfig参数

// package.json
{
  "taroConfig": {
    "version": "1.0.0"
  },
}

下面是项目中配置ci的过程,通过CIPluginFn配置密钥以及具体的参数

// config/index.js
const { robot = 1, desc } = argv
const CIPluginFn = {
  weapp: {
    appid: 'xxxx',
    privateKeyPath: 'private.xxxx.key', // 配置密钥的路径
    robot,
  },
  desc,
}

const config = { 
  plugins: [['@tarojs/plugin-mini-ci', CIPluginFn]],
}

自定义打包命令

这里自定义了test以及prod两个环境,test测试环境通过--env指定为development,prod默认为线上production


// package.json
{

  "scripts": {
    "build:weapp:test": "npm run build:weapp -- --env development",
    "build:weapp": "taro build --type weapp",
    "dev:weapp": "npm run build:weapp -- --watch",
    "release:weapp:test": "npm run build:weapp:test -- --upload --robot=1 --desc='test环境'",
    "release:weapp:prod": "npm run build:weapp -- --upload --robot=2 --desc='prod环境'"
  },

}

jenkins配置

jenkins是自动化打包项目的工具。平时我们需要使用微信开发工具,手动安装依赖,并执行打包、上传的动作。现在把这些动作配置到jenkins的流水线当中,以实现自动打包上传。

服务器配置jenkins教程可以自行查阅。

重点注意下java版本与jenkins的版本,版本不匹配会导致很多错误。

新建任务

安装完Jenkins就可以创建一个任务,来正式打包项目了

选择任务模版

image.png
jenkins任务配置:

  • 拉取项目代码
    image.png
  • 确定项目分支
    image.png
  • 执行自定义的打包命令
    image.png

配置好任务后,点击Build Now进行打包

image.png
打包结果如下:

image.png

上图打包过程中生成的二维码无法扫描,可扫的体验二维码存放在dist文件夹下的upload.png。

后续可自己优化,把生成的二维码发送到钉钉等。

image.png

小程序后台上传结果

Snipaste_2023-04-21_10-30-33.png

上面就完成了就enkins配置的流程,但还有如下几个问题需要解决。

  • [ ] 1. API环境变量如何配置
  • [ ] 2. 测试环境支持环境的切换。方便测试人员在测试接口或者线上接口切换
  • [ ] 3. 体验码确定。毕竟同时只能存在一个体验码

1. 环境变量配置以及打包命令配置

环境变量env配置

taro默认的打包命令是build:weapp,其对应的NODE_ENV为prodcution。而我们想要jenkins打包时也能出现test环境或者其他环境的变量,可以在script脚本中通过--env来指定环境

在tao-cli源码中提供了env的注入方式

可以看出主要注入了env变量,process.env.NODE_ENV就将会采用。

另外也可以理解我们加入了—watch后,其会将process.env.NODE_ENV置为development的过程。
// taro-cli/src/cli.ts

if (command) {
      ....

      // 设置环境变量
      process.env.NODE_ENV ||= args.env
      if (process.env.NODE_ENV === 'undefined' && (command === 'build' || command === 'inspect')) {
        process.env.NODE_ENV = (args.watch ? 'development' : 'production')
      }
      ...
}

项目中指定--env变量,比如指定了--env为development

"build:weapp:test": "npm run build:weapp -- --env development"

在config目录中,process.env.NODE_ENV的值就是我们指定的--env值。根据process.env.NODE_ENV就可以制定不同的脚本了,比如默认的dev,prod,当然这里也可以增加为pre等脚本。

// config/dev.js
module.exports = {
  env: {
    NODE_ENV: '"development"',
  },
}
//config/prod.js
module.exports = {
  env: {
    NODE_ENV: '"production"',
  },
}
//config/index.js
module.exports = function (merge) {
  if (process.env.NODE_ENV === 'development') {
    return merge({}, config, require('./dev'))
  }
  return merge({}, config, require('./prod'))
}

API环境变量确定

上面我们配置好了jenkins打包,下面就需要确定接口具体的环境变量了。因为小程序比较特殊,还需要手动提审小程序,还可能有测试环境切换接口环境的需求,因而需要确定下环境变量的优先级。当然如果没有兜底或者切换的需求,直接在config/dev.js或者prod.js下的env中配置接口地址即可。

环境变量env的优先级

为了避免线上环境出现测试接口,这里做了兜底的策略:只要是小程序release环境则一定是线上代码。另外为了支持测试环境切换环境,需要在本地进行env缓存。最后就是webpack注入的环境变量了process.env.NODE_ENV。

环境变量的优先级:

  1. 保底环境: 小程序release环境或者jenkins-线上环境
  2. 缓存storage存在的变量env:目的是支持测试环境切换环境
  3. Webpack注入的process.env.NODE_ENV变量:主要由Jenkins决定

具体的实现

实现优先级

getCurrentEnv函数的主要作用就是根据优先级获取当前的env变量

// utils/env.ts
import Taro from '@tarojs/taro'

/** 获取当前的环境变量 */
export const getCurrentEnv = (env: string | undefined) => {
  // 本地缓存的env
  const cacheEnv = Taro.getStorageSync(STORAGE_ENV_KEY)
  // 小程序release环境或者线上打包地址,默认都是线上地址
  if (isWeappRelease() || isProdEnv()) {
    return EEnvType.prod
  }
  // 存在缓存env,则采用
  if (cacheEnv && [EEnvType.dev, EEnvType.prod].includes(cacheEnv)) {
    return cacheEnv
  }
  // webpack注入的环境变量
  return env
}

根据确定的env来确定接口地址

通过getCurrentEnv获取了当前的环境变量env,就能拿到当前请求的域名地址API_CURRENT_HOST,此处直接将接口地址以枚举的形式列出来了。

// configs/env.ts
import { getCurrentEnv, EEnvType } from '~/utils/env'

/** api域名:实际使用替换成自己项目对应的域名 */
export const API_HOST = {
  [EEnvType.dev]: 'test',
  [EEnvType.prod]: 'prod',
}

/** 当前的环境变量 */
export const currentEnv = getCurrentEnv(process.env.NODE_ENV)

/** API 当前请求域名 */
export const API_CURRENT_HOST = API_HOST[currentEnv]

测试环境支持环境切换

切换环境组件EnvPopup

通过选择控件切换环境变量,因为我们的接口API_CURRENT_HOST是在编译阶段就确定了,这里在storage中切换env值并不会让接口变更,考虑到切换只是测试低频的需求,因而就简单处理为手动重启小程序的方式。

当然如果不想要这样做,可以将请求域名存到内存当中,比如小程序全局变量Taro.getApp()中,以实现在运行时切换的需求。
export const EnvPopup: React.FC<{}> = () => {
  const [visible, setVisible] = useState(false)

  const listData = [
    [
      { value: EEnvType.dev, text: '开发环境' },
      { value: EEnvType.prod, text: '正式环境' },
    ],
  ]
  const confirmPicker = (values: (string | number)[]) => {
    Taro.setStorageSync(STORAGE_ENV_KEY, values[0])
    Taro.showToast({
      title: '请点击右上角三个点,选择重新进入小程序后生效',
      icon: 'none',
    })
  }
  return (
    <>
      <View
        className={styles.btn}
        onClick={() => {
          setVisible(true)
        }}
      >
        切
      </View>     
    </>
  )
}

image.png

image.png

小程序体验码

小程序体验码是单例的,同一时间只会存在一个实例。也就是别人将体验码切走,扫旧的二维码也是指向最新的版本。

因为我们内部约定了test环境为ci机器人1,prod线上环境为ci机器人2。为了固定体验码,提供了以下建议

体验码切换约定

  1. 体验码:平时稳定在ci机器人1
  2. 提审:以机器人2提审,但体验码不变
  3. 线上测试回归:
  4. 单需求时,直接切到线上体验码:体验码可以先切到ci机器人2,之后切回机器人1
  5. 测试需要同时测试不同环境,可以考虑提供开发版:
    可以提供本地开发版,本地先执行npm run build:weapp打包线上包,然后小程序工具预览。因为预览码只有25分钟的有效期,可以给测试人员加开发者权限,在小程序:小程序助手 下能查看到了提交的开发版,这个是没有时效的。

    这一步可以自己在scripts中加入"build:weapp:preview": "taro build --type weapp --preview"

image.png

总结

以上就是jenkins打包taro小程序的过程了,具体过程可以查看demo,有任何问题欢迎留言


jason
13 声望2 粉丝

前端,跑步