ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

uni-app多环境配置实战:基于HBuilderx实现开发、测试、正式三套环境发行

uni-app多环境配置实战:基于HBuilderx实现开发、测试、正式三套环境发行 刚接手uni-app项目的时候我最头疼的就是多环境发行这件事。HBuilderx开发着好好的本地接口调通了真机也能跑但一到要发测试包或者正式版就要心惊胆战地检查一遍代码里有没有漏改的接口地址。那时候团队就我一个前端所有环境相关的东西全靠手改结果某次上线忘了把baseUrl从测试环境切回线上域名用户打开App全是白屏被运维大哥连续diss了一周。自那之后我彻底把HBuilderx配置多环境发行当成一等一的大事来对待也整理出了一套能直接落地的实操方案。这篇文章就把这套方案完整拆给你看先讲清楚为什么要做多环境、常见方案怎么选再带你把配置一步步搭起来最后详细走一遍微信小程序、App、H5的发行流程和常见坑。不管你是刚用HBuilderx写demo的新手还是被环境切换折磨过的老开发这篇文章都值得你花十分钟看完。1. 为什么非要搞多环境配置1.1 多环境到底解决了什么痛点先聊点实际的。你的项目不可能只有一个接口地址在跑。本地开发的时候你可能连的是自己电脑上的后端服务地址是http://192.168.1.8:8080这种局域网IP前后端联调完了代码扔到测试服务器上接口地址变成了https://test-api.example.com最后上线又要换成正式域名https://api.example.com。这三个环境如果没有一套机制管理就会出现我开头说的那种问题每次发版前手动搜代码里的baseUrl逐个替换还得祈祷别漏。而且多环境不只是接口地址不一样。微信小程序的AppID测试环境用一个正式环境用另一个你要是用测试AppID去发正式包微信开放平台的接口全都调不通。再比如统计SDK的key、地图SDK的key、推送的AppKey、日志开关、调试模式开关这些都属于环境相关的配置项。越是项目做大这些东西越多手动去改的返工率就越高。多环境配置的本质就是把所有“会因为环境不同而变化”的参数集中管理起来在编译打包的环节自动注入正确的值。1.2 HBuilderx里多环境配置的底层逻辑要理解在HBuilderx里怎么做多环境配置得先明白前端工程和传统后端项目的区别。后端项目常见做法是配置文件放服务器上程序启动时去读取换环境只需要重新部署一套配置。但HBuilderx发行出来的小程序、App、H5都是静态资源代码在打包那一刻就被固化了你不可能让用户在打开小程序的时候动态去读取一个远程配置文件。所以前端的多环境配置本质上是“编译期注入”。我们要做到的是在发行打包时告诉编译器当前是哪个环境编译器把对应的配置值固化到产物里。HBuilderx其实给了我们两个天然的分界点——点“运行”和点“发行”走的是不同的编译流程。运行是开发调试发行是生产构建。理论上可以用这个来区分开发和生产两个大环境但实际项目中往往不止两个环境开发、测试、预发布、生产所以还得在此基础上靠一套自己的配置方案来兜底。2. 主流多环境配置方案怎么选2.1 方案一统一配置文件加环境开关这个方案是我最推荐也最稳妥的适合绝大多数uni-app项目也是这篇文章实操部分要展开讲的方案。思路非常简单在项目里建一个config目录维护一个环境配置对象里面放好dev、test、prod三套参数然后通过一个开关变量或者读取当前编译模式来决定到底导出哪一套配置。// src/config/index.js const config { dev: { baseUrl: http://192.168.1.8:8080, appid: touristappid, enableLog: true }, test: { baseUrl: https://test-api.example.com, appid: wx123456789012, enableLog: true }, prod: { baseUrl: https://api.example.com, appid: wx987654321098, enableLog: false } } // 当前环境标识发行前改成对应环境即可 const CURRENT_ENV dev export default config[CURRENT_ENV]这个方案最大的优势是直观你一眼就能看到当前打到哪个环境不容易出错。缺点是需要手动改这个CURRENT_ENV对确实不够自动化。但在我看来一个明确的“手动开关”比一个“看似自动但偶尔判断错的逻辑”要可靠得多尤其在多人协作或者着急发版的时候。2.2 方案二条件编译加环境区分条件编译是HBuilderx和uni-app的特色能力用// #ifdef和// #ifndef这种注释语法来包裹平台相关的代码。但要注意条件编译默认只能区分平台比如MP-WEIXIN、APP-PLUS、H5它本身是分不清开发环境和生产环境的。当然你可以在HBuilderx里配置自定义条件编译环境在项目右键菜单里找到“自定义条件编译”可以添加开发、测试、发布等环境名称然后在代码里用自定义的条件来区分。但实践下来这个方案更适合做平台差异化用来做环境差异化会让代码里到处都是#ifdef维护起来比较痛苦。我一般只在处理manifest.json级别的差异时或者某个SDK初始化代码必须要区分平台时才用条件编译环境切换的主力还是配置文件。2.3 方案三npm脚本加cli模式注入如果你的uni-app项目是用vue-cli方式创建的不是直接用HBuilderx新建的那种标准项目那你可以用标准的vue-cli多环境机制在项目根目录建.env.development、.env.production、.env.staging文件里面设置以VUE_APP_开头的变量然后在代码里通过process.env.VUE_APP_API_URL去读取。打包时通过--mode staging指定走哪套环境。npm run dev:mp-weixin -- --mode staging npm run build:mp-weixin -- --mode production这种方式的自动化程度最高完全是vue生态的标准玩法。但有一个很现实的问题如果你团队习惯直接在HBuilderx的图形界面里点“运行”和“发行”根本不会经过npm脚本那这套方案就使不上劲。而且HBuilderx标准项目里对process.env.VUE_APP_的支持也有限。所以它更适合命令行打包习惯的团队或者CI/CD流水线直接用CLI打包的场景。三种方案我做了个简单的对比方案自动化程度维护成本适合场景统一配置文件开关低手动切换低一目了然HBuilderx标准项目团队习惯图形界面操作条件编译中需自定义高代码侵入性强平台差异环境差异叠加时局部处理npm脚本cli模式高自动切换中需要熟悉vue-clicli创建的项目或CI流水线打包3. 实操从零搭建一套可用的多环境配置3.1 前置准备HBuilderx、Node、微信开发者工具开始动手之前先把需要的工具准备好。HBuilderx从3.x版本开始对uni-app支持得比较好建议直接下载最新稳定版。Node.js建议装14以上版本npm install的时候不容易出幺蛾子。如果你要发微信小程序微信开发者工具也得装上并且建议在微信开发者工具的安全设置里开启服务端口这样HBuilderx发行时可以自动唤起微信开发者工具打开项目。现在很多文章不讲这一步结果每次都要手动去导入目录效率低不少。3.2 创建config目录与环境参数在项目src目录下新建一个config文件夹里面创建一个index.js文件。先按前面讲的方式把三套环境参数写进去。这里我多说两句第一baseUrl一定要写对协议和端口http和https不要混否则小程序真机预览时协议不一致会踩坑第二appid对应的是你在微信公众平台注册的那个AppID不是HBuilderx的appid别搞混了。enableLog这个开关很实用开发环境打开正式环境关掉既能方便调试又避免线上环境日志刷屏。// src/config/index.js // 环境相关配置统一管理 // 切换环境请修改 CURRENT_ENVdev 开发 / test 测试 / prod 正式 const ENV_CONFIG { dev: { name: dev, baseUrl: http://192.168.1.8:8080, appid: touristappid, enableLog: true }, test: { name: test, baseUrl: https://test-api.example.com, appid: wx123456789012, enableLog: true }, prod: { name: prod, baseUrl: https://api.example.com, appid: wx987654321098, enableLog: false } } const CURRENT_ENV dev export default ENV_CONFIG[CURRENT_ENV]有的同学会问网上那么多教程都用process.env.NODE_ENV来自动判断环境为什么我这里不直接这么干我在几个项目里实测过HBuilderx标准项目直接点击“发行”按钮时process.env.NODE_ENV的值在不同版本、不同发行平台下的表现并不一致有时候是production有时候是undefined在小程序编译链路里尤其不稳定。如果你依赖这个变量去做精确到test/prod的切换很可能出现“我明明走的是测试环境程序却判断成了生产环境”这种诡异问题。所以我更倾向用显式的CURRENT_ENV虽然没有那么酷但绝对可控。3.3 封装request.js统一读取环境配置配置文件建好了下一步是最关键的把你项目里所有发起网络请求的地方统一收口。如果项目里到处都是uni.request裸调用那你就算配好了环境也得挨个去改等于没配。所以我强烈建议封装一个request.js工具函数在封装内部读取上面config/index.js导出的baseUrl上层业务代码完全不用关心当前是哪个环境。下面是我常用的封装稍微精简了一下你可以直接抄// src/utils/request.js import config from /config/index.js const request (options) { return new Promise((resolve, reject) { uni.request({ url: config.baseUrl options.url, method: options.method || GET, data: options.data || {}, timeout: options.timeout || 10000, header: { Content-Type: application/json, ...options.header }, success: (res) { // 这里根据你的后端返回结构调整 if (res.statusCode 200) { resolve(res.data) } else { uni.showToast({ title: 请求异常, icon: none }) reject(res) } }, fail: (err) { uni.showToast({ title: 网络异常请检查网络, icon: none }) reject(err) } }) }) } export default request封装好之后页面里的请求这样用就行import request from /utils/request.js request({ url: /api/login, method: POST, data: { username: admin } }) .then(res { console.log(登录成功, res) })这样做的好处是切换环境时你只需要动config/index.js里的CURRENT_ENV所有请求自动跟着变完全不需要去页面里改。3.4 项目启动时输出环境标识配置搭好了邮件发测试包之前怎么快速确认这个包跑的是哪个环境我建议你在App.vue的onLaunch里把当前环境名称和baseUrl打出来顺便正式环境把日志关掉。// App.vue import config from /config/index.js export default { onLaunch() { console.log(当前环境:, config.name, baseUrl:, config.baseUrl) if (config.enableLog) { console.log(已开启调试日志) } } }这个细节看起来不起眼实战中真的能救命。有一次我们打了一个预发布环境的包发给商务去演示演示现场接口全挂了所有同事都在排查是不是服务器崩了。结果我打开调试面板一看当前环境是testbaseUrl指到了测试服务器而演示环境的访问地址在另一个内网网段根本连不通。说白了就是把环境打错了但因为没有标识一群人排查了一个多小时。从那以后我要求项目启动必须打印环境标识。3.5 发行前如何确认走的是正确环境光有代码还不够我给自己定了一套发行前检查清单每次发包之前照着过一遍检查config/index.js里的CURRENT_ENV是否指向你要发的环境检查小程序的AppID是否和该环境对应尤其是从测试包切正式包时AppID最容易忘改检查微信小程序后台开发设置-服务器域名是否已经加入了该环境对应的request合法域名测试环境的域名如果没备案真机预览会直接失败检查服务器是否配置了正确的CORS跨域H5发行到线上时如果跨域没放开接口一样起不来。这四条看着简单每一条我都踩过。尤其第一条和第二条经常是“代码里全改对了但最后的包还是走了老地址”最后发现是HBuilderx编译缓存惹的祸。遇到这种问题先把项目里unpackage/dist目录删掉再重新发行能解决一大半灵异现象。4. 发行到不同平台的完整流程与关键细节4.1 发行到微信小程序的详细操作步骤HBuilderx发行小程序是整个流程里我用得最多的因为现在很多项目优先跑小程序端。具体操作是顶部菜单点“发行”选择“小程序-微信”。如果你是第一次发这个项目HBuilderx会弹窗让你填写微信小程序的AppID在这里填config里面对应环境的AppID就行。填完之后HBuilderx会自动编译编译产物会生成在unpackage/dist/dev/mp-weixin目录运行模式或者unpackage/dist/build/mp-weixin目录发行模式。注意dev和build两个目录的区分一定要搞清楚如果你之前开发时跑过“运行到小程序模拟器”dist/dev/mp-weixin里是旧代码很多人打包时导入错了目录改了半天看不到效果。编译完成后打开微信开发者工具选择“导入项目”目录选上面说的build/mp-weixin文件夹AppID会自动带上。在微信开发者工具的“详情-本地设置”里如果是测试开发阶段可以把“不校验合法域名、web-view业务域名、TLS版本以及HTTPS证书”勾上但上线前这个勾一定要去掉因为真机体验版和正式版都必须过域名校验。最后在开发者工具里点击“上传”到微信公众平台的版本管理里提交审核、发布就可以。这里要特别提醒一个细节如果你在HBuilderx里改了manifest.json的AppID或者页面代码最好把微信开发者工具完全关掉再重新导入或者至少在“清缓存-清除全部缓存”里操作一次。微信开发者工具对代码目录的监听偶尔会抽风导致你HBuilderx重新发行了它那边还是旧代码非常误导人。4.2 发行到Android/iOS App的云打包要点HBuilderx发App主要走云打包不用本地装Android Studio和Xcode适合大多数中小团队。操作路径是“发行-原生App-云打包”。打包前你必须在manifest.json里配置好应用名称、版本号、图标等基础信息。然后选择打包的平台Android、iOS或两者都选配置证书。测试阶段可以直接用DCloud的公共证书打一个测试包安装到手机上跑通全流程但要上架应用商店就必须用正式证书了。Android的正式证书需要你自己用keytool生成keystore文件iOS则需要p12描述文件和provisioning profile。多环境这块在App端要特别注意SDK参数的差异化比如微信登录、微信分享、地图、推送这类功能它们在初始化的时候需要AppID和AppSecret而这些Key在不同环境下是完全不同的。测试环境微信登录用的是测试应用正式环境用的是线上应用如果打包时用错了表现就是登录转圈、分享失败、推送收不到。我的建议是把各个环境的SDK参数统一收进config/index.js然后在初始化SDK的地方按环境读取。这里因为参数多建议单独维护一份app.config.js把微信、地图、推送、统计这些平台的Key集中管理每个环境一组不要散落在业务代码里。4.3 发行到H5的注意点H5发行相对简单菜单选择“发行-网站-H5手机版”。编译产物会生成到unpackage/dist/build/h5目录你需要把这个目录里的文件部署到Web服务器或者对象存储。H5端有一个优势它可以做到一定程度上的“后配置化”。如果你把配置放在一个独立的config.js文件里部署之后运维可以直接改这个文件来切换环境不必重新打包。不过这个方案需要你在index.html或者入口处手动引入外部脚本对常规项目来说有点麻烦。更成熟的团队会直接在构建流程里用nginx的sub_filter或者环境变量替换来动态注入但那属于高级玩法了这里不展开。如果你只是常规的H5部署跟着前面方案走就行但注意H5端的跨域问题比小程序严重得多。小程序至少有后台合法域名校验H5全靠服务器端CORS配置。你需要确保目标环境的服务器在响应头里加了Access-Control-Allow-Origin否则H5页面发出去的请求会被浏览器拦截你自己在PC上打开HTML文件测试时还容易见到跨域报错“CORS policy”之类的提示。4.4 发行完成后如何快速验证环境对不对验证环境有没有切对我有一套组合拳。第一看启动日志我在App.vue的onLaunch里打了环境名打开调试工具控制台就能看到第二看网络请求在小程序开发者工具的Network面板里随便点一个接口看请求URL的域名和你预期的是否一致第三如果你接入了日志监控系统发版后去监控后台看一眼新上线的用户设备报上来的环境字段这个最直接。如果这三步对不上那大概率是缓存或者配置没生效回到3.5节做排查。5. 常见问题与排查技巧实录问题现象可能原因解决办法改了config配置后发行接口还是老地址HBuilderx编译缓存未清理删除unpackage/dist目录重新发行微信开发者工具里的代码和HBuilderx源码不一致工具缓存或导入了dev目录完全关闭开发者工具清除所有缓存后重新导入build目录真机预览时接口请求失败提示域名不在合法列表小程序后台没有配置该环境的request合法域名在公众平台“开发管理-服务器域名”里添加对应域名本地可以先勾选“不校验合法域名”临时测试云打包的App能装但调不起微信登录包名/签名/AppID和微信开放平台不一致核对manifest.json里的包名和AppID用正式签名打包条件编译判断环境不生效HBuilderx自定义条件编译环境没有配置或者用了平台条件编译来分环境确认配置是否正确尽量用统一配置文件代替条件编译H5部署后跨域报错服务器没有开启CORS在nginx或后端网关配置Access-Control-Allow-Origin同一个包在测试环境正常正式环境白屏正式环境域名未备案/未绑定的可能性较大或者线上接口证书过期检查线上服务状态和证书用启动日志确认正式包确实走prod配置除了上面的表格我再补一条排查思路当发出去的包表现诡异时第一时间打开调试工具先确认当前环境标识对不对。很多人习惯先查服务器、查代码却忘了最简单的一步——看看这个包到底是哪个环境。这个经验看着朴素却是我一次一次踩坑踩出来的。另外一个印象很深的坑是HBuilderx和微信开发者工具的版本不匹配。有一阵子HBuilderx更新后编译的小程序基础库版本较新微信开发者工具还是旧版导致导入后编译报错页面白屏。遇到这种情况先别急着怀疑自己的代码检查一下微信开发者工具是否需要升级以及项目里manifest.json配置的“微信小程序基础库最低版本”是不是太激进。关于环境配置我还有一个压箱底的建议把当前环境名显示在项目某个不太起眼但又看得到的地方比如个人中心底部的版本号后面写上“v1.2.3test”。这样测试同学截图反馈bug的时候你能一眼看出他测的是哪个环境的包省去大量来回追问的时间。这个改动成本极低收益却极高我后来做每个项目都会加上。多环境配置这件事说到底就是一句话把容易变化的东西收拢到一处让切换变得可控、可预期。HBuilderx本身没有现成的多环境发行按钮但通过统一配置文件加环境开关的方式完全可以满足开发、测试、正式三套环境的日常使用。你可能会有更复杂的场景比如预发布环境、灰度环境思路是相同的无非是多加一组配置和几个判断。不管方案怎么变明确的切换入口和清晰的验证手段才是最重要的下次发版前先打开config看一眼比什么都强。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进