跳至主要內容

微信小程序多环境打包发布配置

Mr.Chen开发日志微信项目总结大约 4 分钟约 1075 字

通过读写 manifest.json 等文件实现动态配置化

1.src 目录下创建文件 modifyManifest.js,写入如下内容:

// modifyManifest.js

const fs = require('fs')
//此处如果是用HBuilderX创建的项目manifest.json文件在项目跟目录,如果是 cli 创建的则在 src 下,这里要注意
//process.env.UNI_INPUT_DIR为项目所在的绝对路径,经测试,相对路径会找不到文件
const revert = process.argv[process.argv.length - 1]
// 根据还原参数区分使用原路径(最后执行命令的时候已经没有UNI全局变量了)
const root = revert == 'revert' ? 'src' : process.env.UNI_INPUT_DIR
const manifestPath = root + '/manifest.json'
let Manifest = fs.readFileSync(manifestPath, {
  encoding: 'utf-8'
})

// pages/index/index.vue 文件修改
const pageIndexPath = root + '/pages/index/index.vue'
let pageIndex = fs.readFileSync(pageIndexPath, {
  encoding: 'utf-8'
})

function replaceManifest(path, value) {
  const arr = path.split('.')
  const len = arr.length
  const lastItem = arr[len - 1]

  let i = 0
  let ManifestArr = Manifest.split(/\n/)

  for (let index = 0; index < ManifestArr.length; index++) {
    const item = ManifestArr[index]
    if (new RegExp(`"${arr[i]}"`).test(item)) ++i
    if (i === len) {
      const hasComma = /,/.test(item)
      ManifestArr[index] = item.replace(
        new RegExp(`"${lastItem}"[\\s\\S]*:[\\s\\S]*`),
        `"${lastItem}" : ${value}${hasComma ? ',' : ''}`
      )
      break
    }
  }

  Manifest = ManifestArr.join('\n')
}

// 动态配置appid
if (process.env.VUE_APP_ENV === 'A环境标识参数') {
  // A环境
  replaceManifest('mp-weixin.appid', '"A环境appid"')
  fs.writeFileSync(pageIndexPath, pageIndex.replace('文案B', '文案A'), {
    flag: 'w'
  })
} else if (process.env.VUE_APP_ENV === 'B环境标识参数') {
  // B环境
  replaceManifest('mp-weixin.appid', '"B环境appid"')
  fs.writeFileSync(pageIndexPath, pageIndex.replace('文案A', '文案B'), {
    flag: 'w'
  })
} else {
  // C环境
  replaceManifest('mp-weixin.appid', '"C环境appid"')
}
const lastParam = process.argv[process.argv.length - 1]
if (lastParam == 'revert') {
  // 还原appid
  replaceManifest('mp-weixin.appid', '"默认appid"')
  // 文案还原
  fs.writeFileSync(pageIndexPath, pageIndex.replace('环境下文案', '默认文案'), {
    flag: 'w'
  })
}

fs.writeFileSync(manifestPath, Manifest, {
  flag: 'w'
})
  1. 在 vue.config.js 中引入。
require('./src/modifyManifest.js')

接入 miniprogram-ci

1. 简介

miniprogram-ci 是从微信开发者工具中抽离的关于小程序/小游戏项目代码的编译模块。开发者可不打开小程序开发者工具,独立使用 miniprogram-ci 进行小程序代码的上传、预览等操作。

  • 文档:https://www.npmjs.com/package/miniprogram-ci

2. 平台设置

使用 miniprogram-ci 前应在微信公众平台登录小程序,访问“开发-开发管理-开发设置”后下载“代码上传密钥”,并配置 IP 白名单。

开发者可选择打开 IP 白名单,打开后只有白名单中的 IP 才能调用相关接口。

代码上传密钥拥有预览、上传代码的权限,密钥不会明文存储在微信公众平台上,一旦遗失必须重置,请开发者妥善保管 示例

3. 脚本调用:

npm install miniprogram-ci --save

4. 项目对象

const ci = require('miniprogram-ci')
// 注意: new ci.Project 调用时,请确保项目代码已经是完整的,避免编译过程出现找不到文件的报错。
const project = new ci.Project({
  appid: 'appid',
  type: 'miniProgram',
  projectPath: 'the/project/path',
  privateKeyPath: 'the/privatekey/path',
  ignores: ['node_modules/**/*']
})

上传代码

const ci = require('miniprogram-ci')
;(async () => {
  const project = new ci.Project({
    appid: 'wxsomeappid',
    type: 'miniProgram',
    projectPath: 'the/project/path',
    privateKeyPath: 'the/path/to/privatekey',
    ignores: ['node_modules/**/*']
  })
  const uploadResult = await ci.upload({
    project,
    version: '1.1.1',
    desc: 'hello',
    setting: {
      es6: true
    },
    onProgressUpdate: console.log
  })
  console.log(uploadResult)
})()

详细参数配置,见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/ci.html

5.实际使用

看下目录结构:下面 2 个 key 是不同 appid 环境的代码上传秘钥 示例

我们主要看下 autoUpload.js

// 自动将代码上传到小程序
const ci = require('miniprogram-ci')
const path = require('path')
const mainfest = require('../src/manifest.json')
const slog = require('single-line-log').stdout
const robot = Number(process.env.ROBOT) || 1
const buildVersion =
  process.env.npm_config_build_version || mainfest.versionName

function getUploadDesc() {
  // dev
  if (robot === 1) {
    return 'build by robot --dev'
  }
  // test
  if (robot === 2) {
    return 'build by robot --test'
  }
  // release
  if (robot === 3) {
    return 'build by robot --release'
  }
  // uat
  if (robot === 4) {
    return 'build by robot --uat'
  }
  return mainfest.description
}

async function main() {
  const project = new ci.Project({
    appid: mainfest['mp-weixin'].appid, //appid
    type: 'miniProgram',
    projectPath: path.resolve(__dirname, '../dist/build/mp-weixin'), //项目路径
    privateKeyPath: path.resolve(
      __dirname,
      `./private.${mainfest['mp-weixin'].appid}.key`
    ), //小程序后台的上传密匙
    ignores: ['node_modules/**/*']
  })

  let slogIndex = 0
  try {
    await ci.upload({
      project,
      version: buildVersion,
      desc: getUploadDesc(),
      setting: mainfest['mp-weixin'].setting,
      robot,
      onProgressUpdate: () => {
        slog(
          '上传中' +
            (slogIndex === 0 ? '.' : slogIndex === 1 ? '..' : '...') +
            '\n'
        )
        slogIndex++
        if (slogIndex === 3) {
          slogIndex = 0
        }
      }
    })
    console.log(`上传成功 版本${buildVersion}`)
  } catch (error) {
    console.error(`上传失败 版本${buildVersion}`, error)
  }
}

main()

我们还有个 prebuild.js 用于不同的环境设置不同的 appid

const fs = require('fs')
const process = require('process')

function outputManifest() {
  const manifest = require('../src/manifest.json')
  manifest['mp-weixin'].appid =
    process.env.BUILD_ENV === 'uat' ? 'wx***' : 'wx***'
  fs.writeFileSync(
    './src/manifest.json',
    JSON.stringify(manifest, null, 2) + '\n',
    'UTF-8'
  )
}

outputManifest()

那么在 package.json 的 scripts 设置命令如下

{
  "script": {
    "build-dev": "cross-env BUILD_ENV=dev node ./ci/prebuild.js && cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin vue-cli-service --mode dev uni-build --minimize && cross-env ROBOT=1 node ./ci/autoUpload.js"
  }
}
上次编辑于: