parent:
cf66833f
|
补丁 |
提交
| .. | .. |
|---|
| 2 | 2 | node_modules |
|---|
| 3 | 3 | /dist |
|---|
| 4 | 4 | |
|---|
| 5 | | -# local env files |
|---|
| 5 | +# 本地环境文件 |
|---|
| 6 | 6 | .env.local |
|---|
| 7 | 7 | .env.*.local |
|---|
| 8 | 8 | |
|---|
| 9 | +# 微信小程序上传密钥(机密,切勿提交) |
|---|
| 10 | +keys/ |
|---|
| 11 | + |
|---|
| 9 | 12 | # Log files |
|---|
| 10 | 13 | npm-debug.log* |
|---|
| 11 | 14 | yarn-debug.log* |
|---|
| .. | .. |
|---|
| 7 | 7 | // +---------------------------------------------------------------------- |
|---|
| 8 | 8 | // | Author: CRMEB Team <admin@crmeb.com> |
|---|
| 9 | 9 | // +---------------------------------------------------------------------- |
|---|
| 10 | | -//移动端商城API |
|---|
| 11 | | -let domain = 'https://acmall.bluedeer.com.cn/crmeb/front' |
|---|
| 12 | 10 | |
|---|
| 13 | | -module.exports = { |
|---|
| 14 | | - // 请求域名 格式: https://您的域名 |
|---|
| 15 | | - HTTP_REQUEST_URL:domain, |
|---|
| 16 | | - |
|---|
| 17 | | - // #ifdef MP |
|---|
| 18 | | - HTTP_REQUEST_URL: domain, |
|---|
| 19 | | - // #endif |
|---|
| 20 | | - HTTP_REQUEST_URL:'https://acmall.bluedeer.com.cn/crmeb/front', |
|---|
| 21 | | - HTTP_ADMIN_URL:'https://acmall.bluedeer.com.cn/crmeb/admin', |
|---|
| 22 | | - APPID:'wx15d029cdf2e92a9f', |
|---|
| 23 | | - GDP_ACCOUNT_ID:'8672f93377575ace', |
|---|
| 24 | | - GDP_DATASOURCE_ID:'b01182b2d4f73e45', |
|---|
| 25 | | - GDP_SERVER_URL:'https://giocollect.aviva-cofco.com.cn', |
|---|
| 26 | | - GDP_DEBUG:true, |
|---|
| 27 | | - THIRD_APPID:'wxa83daa550324ead8', |
|---|
| 28 | | - // #ifdef H5 |
|---|
| 29 | | - //H5接口是浏览器地址 |
|---|
| 30 | | - // HTTP_REQUEST_URL: window.location.protocol+"//"+window.location.host, |
|---|
| 31 | | - // http://api.java.crmeb.net:20001 |
|---|
| 32 | | - HTTP_REQUEST_URL:domain, |
|---|
| 33 | | - // #endif |
|---|
| 34 | | - |
|---|
| 11 | +// 环境相关参数(HTTP_REQUEST_URL/HTTP_ADMIN_URL/APPID/THIRD_APPID/GDP_* 等) |
|---|
| 12 | +// 统一维护在 config/env/ 下,本文件只做合并,对外导出名保持不变 |
|---|
| 13 | +const env = require('./env'); |
|---|
| 14 | + |
|---|
| 15 | +module.exports = Object.assign({}, env, { |
|---|
| 35 | 16 | HEADER:{ |
|---|
| 36 | 17 | 'content-type': 'application/json' |
|---|
| 37 | 18 | }, |
|---|
| .. | .. |
|---|
| 44 | 25 | EXPIRE:0, |
|---|
| 45 | 26 | //分页最多显示条数 |
|---|
| 46 | 27 | LIMIT: 10 |
|---|
| 47 | | -}; |
|---|
| 28 | +}); |
|---|
| .. | .. |
|---|
| 1 | +// +---------------------------------------------------------------------- |
|---|
| 2 | +// | 环境选择入口:一套代码跑多环境 |
|---|
| 3 | +// | 识别优先级:手动指定 > 小程序 appid 自动识别 > H5 域名识别 > 默认 prod |
|---|
| 4 | +// | 说明:小程序 appid 由 manifest.json -> mp-weixin.appid 决定, |
|---|
| 5 | +// | 所以“用哪个 appid 跑”就等于“用哪套接口”,不会出现接口与环境错配 |
|---|
| 6 | +// +---------------------------------------------------------------------- |
|---|
| 7 | +const envs = { |
|---|
| 8 | + prod: require('./prod.js'), |
|---|
| 9 | + sit: require('./sit.js') |
|---|
| 10 | +}; |
|---|
| 11 | + |
|---|
| 12 | +// 手动强制指定环境:'' = 自动识别(推荐);也可填 'prod' 或 'sit' |
|---|
| 13 | +const OVERRIDE_ENV = ''; |
|---|
| 14 | + |
|---|
| 15 | +// appid -> 环境名 映射 |
|---|
| 16 | +const APPID_ENV_MAP = {}; |
|---|
| 17 | +Object.keys(envs).forEach(function(key) { |
|---|
| 18 | + APPID_ENV_MAP[envs[key].APPID] = key; |
|---|
| 19 | +}); |
|---|
| 20 | + |
|---|
| 21 | +function detectEnv() { |
|---|
| 22 | + if (OVERRIDE_ENV && envs[OVERRIDE_ENV]) return OVERRIDE_ENV; |
|---|
| 23 | + |
|---|
| 24 | + // #ifdef MP |
|---|
| 25 | + try { |
|---|
| 26 | + const info = uni.getAccountInfoSync(); |
|---|
| 27 | + const appId = info && info.miniProgram && info.miniProgram.appId; |
|---|
| 28 | + if (appId && APPID_ENV_MAP[appId]) return APPID_ENV_MAP[appId]; |
|---|
| 29 | + } catch (e) {} |
|---|
| 30 | + // #endif |
|---|
| 31 | + |
|---|
| 32 | + // #ifdef H5 |
|---|
| 33 | + if (typeof location !== 'undefined' && location.hostname) { |
|---|
| 34 | + const host = location.hostname; |
|---|
| 35 | + if (/sit|tohours|localhost|127\.0\.0\.1/.test(host)) return 'sit'; |
|---|
| 36 | + } |
|---|
| 37 | + // #endif |
|---|
| 38 | + |
|---|
| 39 | + return 'prod'; |
|---|
| 40 | +} |
|---|
| 41 | + |
|---|
| 42 | +const ENV_NAME = detectEnv(); |
|---|
| 43 | +const current = envs[ENV_NAME] || envs.prod; |
|---|
| 44 | + |
|---|
| 45 | +module.exports = Object.assign({}, current, { |
|---|
| 46 | + ENV_NAME: ENV_NAME, |
|---|
| 47 | + IS_PROD: ENV_NAME === 'prod', |
|---|
| 48 | + IS_SIT: ENV_NAME === 'sit' |
|---|
| 49 | +}); |
|---|
| .. | .. |
|---|
| 1 | +// +---------------------------------------------------------------------- |
|---|
| 2 | +// | 生产环境(PROD)参数 |
|---|
| 3 | +// | 注意:新增环境参数时,请同步维护 prod.js 与 sit.js,保持键名完全一致 |
|---|
| 4 | +// +---------------------------------------------------------------------- |
|---|
| 5 | +module.exports = { |
|---|
| 6 | + ENV_NAME: 'prod', |
|---|
| 7 | + // 请求域名 |
|---|
| 8 | + HTTP_REQUEST_URL: 'https://acmall.bluedeer.com.cn/crmeb/front', |
|---|
| 9 | + HTTP_ADMIN_URL: 'https://acmall.bluedeer.com.cn/crmeb/admin', |
|---|
| 10 | + // 微信小程序 appid(需与 manifest.json -> mp-weixin.appid 保持一致) |
|---|
| 11 | + APPID: 'wx15d029cdf2e92a9f', |
|---|
| 12 | + // 跳转关联小程序 appid |
|---|
| 13 | + THIRD_APPID: 'wxa83daa550324ead8', |
|---|
| 14 | + // GrowingIO 埋点 |
|---|
| 15 | + GDP_ACCOUNT_ID: '8672f93377575ace', |
|---|
| 16 | + GDP_DATASOURCE_ID: 'b01182b2d4f73e45', |
|---|
| 17 | + GDP_SERVER_URL: 'https://giocollect.aviva-cofco.com.cn', |
|---|
| 18 | + GDP_DEBUG: true, |
|---|
| 19 | + // 活动页/内嵌 web 资源地址(替代代码里按域名判断环境) |
|---|
| 20 | + WEB_ACTIVITY_BASE: 'https://ossacmall.bluedeer.com.cn', |
|---|
| 21 | + // DCloud 应用标识(需与 manifest.json -> appid 保持一致) |
|---|
| 22 | + UNI_APPID: '__UNI__CE0C605' |
|---|
| 23 | +}; |
|---|
| .. | .. |
|---|
| 1 | +// +---------------------------------------------------------------------- |
|---|
| 2 | +// | 测试环境(SIT)参数 |
|---|
| 3 | +// | 注意:新增环境参数时,请同步维护 prod.js 与 sit.js,保持键名完全一致 |
|---|
| 4 | +// +---------------------------------------------------------------------- |
|---|
| 5 | +module.exports = { |
|---|
| 6 | + ENV_NAME: 'sit', |
|---|
| 7 | + // 请求域名 |
|---|
| 8 | + HTTP_REQUEST_URL: 'https://sit.tohours.com/crmeb/front', |
|---|
| 9 | + HTTP_ADMIN_URL: 'https://sit.tohours.com/crmeb/admin', |
|---|
| 10 | + // 微信小程序 appid(需与 manifest.json -> mp-weixin.appid 保持一致) |
|---|
| 11 | + APPID: 'wx7e443c60d08449de', |
|---|
| 12 | + // 跳转关联小程序 appid |
|---|
| 13 | + THIRD_APPID: 'wx64d2ecbbeb3eae79', |
|---|
| 14 | + // GrowingIO 埋点 |
|---|
| 15 | + GDP_ACCOUNT_ID: '83b2522b4d9c972a', |
|---|
| 16 | + GDP_DATASOURCE_ID: 'a1616a9a748d2c7f', |
|---|
| 17 | + GDP_SERVER_URL: 'https://collecttest.aviva-cofco.com.cn', |
|---|
| 18 | + GDP_DEBUG: true, |
|---|
| 19 | + // 活动页/内嵌 web 资源地址(替代代码里按域名判断环境) |
|---|
| 20 | + WEB_ACTIVITY_BASE: 'https://sit.tohours.com/crmeb_web', |
|---|
| 21 | + // DCloud 应用标识(需与 manifest.json -> appid 保持一致) |
|---|
| 22 | + UNI_APPID: '__UNI__3D0C5FE' |
|---|
| 23 | +}; |
|---|
| .. | .. |
|---|
| 1 | 1 | { |
|---|
| 2 | 2 | "name" : "CRMEB Java 商城", |
|---|
| 3 | | - "appid" : "__UNI__CE0C605", |
|---|
| 3 | + "appid" : "__UNI__3D0C5FE", |
|---|
| 4 | 4 | "description" : "CRMEB Java 商城", |
|---|
| 5 | 5 | "versionName" : "1.0.0", |
|---|
| 6 | 6 | "versionCode" : 1001, |
|---|
| .. | .. |
|---|
| 123 | 123 | "quickapp" : {}, |
|---|
| 124 | 124 | /* 小程序特有相关 */ |
|---|
| 125 | 125 | "mp-weixin" : { |
|---|
| 126 | | - "appid" : "wx15d029cdf2e92a9f", |
|---|
| 126 | + "appid" : "wx7e443c60d08449de", |
|---|
| 127 | 127 | "setting" : { |
|---|
| 128 | 128 | "urlCheck" : true, |
|---|
| 129 | 129 | "minified" : true, |
|---|
| .. | .. |
|---|
| 1 | 1 | { |
|---|
| 2 | + "scripts": { |
|---|
| 3 | + "env:prod": "node scripts/set-env.js prod", |
|---|
| 4 | + "env:sit": "node scripts/set-env.js sit", |
|---|
| 5 | + "release:sit": "node scripts/publish.js sit", |
|---|
| 6 | + "release:prod": "node scripts/publish.js prod" |
|---|
| 7 | + }, |
|---|
| 2 | 8 | "dependencies": { |
|---|
| 3 | 9 | "bignumber.js": "^9.3.1", |
|---|
| 4 | 10 | "vue-inset-loader": "^1.2.6" |
|---|
| .. | .. |
|---|
| 1 | 1 | { |
|---|
| 2 | | - "appid": "wx15d029cdf2e92a9f", |
|---|
| 2 | + "appid": "wx7e443c60d08449de", |
|---|
| 3 | 3 | "compileType": "miniprogram", |
|---|
| 4 | 4 | "libVersion": "3.1.4", |
|---|
| 5 | 5 | "packOptions": { |
|---|
| .. | .. |
|---|
| 1 | +@echo off |
|---|
| 2 | +chcp 65001 >nul |
|---|
| 3 | +cd /d "%~dp0" |
|---|
| 4 | +echo ============================================ |
|---|
| 5 | +echo 发布微信小程序 - 生产环境 PROD |
|---|
| 6 | +echo 接口: https://acmall.bluedeer.com.cn/crmeb/front |
|---|
| 7 | +echo ============================================ |
|---|
| 8 | +echo. |
|---|
| 9 | +node "scripts\publish.js" prod %* |
|---|
| 10 | +echo. |
|---|
| 11 | +if errorlevel 1 ( |
|---|
| 12 | + echo [发布失败] 请查看上方输出 |
|---|
| 13 | +) else ( |
|---|
| 14 | + echo [发布完成] |
|---|
| 15 | +) |
|---|
| 16 | +pause |
|---|
| .. | .. |
|---|
| 1 | +@echo off |
|---|
| 2 | +chcp 65001 >nul |
|---|
| 3 | +cd /d "%~dp0" |
|---|
| 4 | +echo ============================================ |
|---|
| 5 | +echo 发布微信小程序 - 测试环境 SIT |
|---|
| 6 | +echo 接口: https://sit.tohours.com/crmeb/front |
|---|
| 7 | +echo ============================================ |
|---|
| 8 | +echo. |
|---|
| 9 | +node "scripts\publish.js" sit %* |
|---|
| 10 | +echo. |
|---|
| 11 | +if errorlevel 1 ( |
|---|
| 12 | + echo [发布失败] 请查看上方输出 |
|---|
| 13 | +) else ( |
|---|
| 14 | + echo [发布完成] |
|---|
| 15 | +) |
|---|
| 16 | +pause |
|---|
| .. | .. |
|---|
| 1 | +/** |
|---|
| 2 | + * HBuilderX CLI 命令行发布:按环境发布微信小程序 |
|---|
| 3 | + * |
|---|
| 4 | + * 用法: |
|---|
| 5 | + * node scripts/publish.js sit # 编译 + 上传到 SIT 小程序(微信 CI,无需打开微信开发者工具) |
|---|
| 6 | + * node scripts/publish.js prod # 编译 + 上传到 PROD 小程序 |
|---|
| 7 | + * node scripts/publish.js sit --local # 只本地编译,不上传 |
|---|
| 8 | + * node scripts/publish.js sit --dry-run # 只打印将要执行的命令 |
|---|
| 9 | + * node scripts/publish.js sit --version 2.0.0 --robot 3 # 额外参数原样透传给 cli |
|---|
| 10 | + * |
|---|
| 11 | + * 环境相关的值统一取自 config/env/<env>.js(唯一数据源): |
|---|
| 12 | + * - 接口/埋点等运行时参数:包内自动按小程序 appid 识别,无需在此处理 |
|---|
| 13 | + * - APPID:作为 --appid 传给微信 CI 上传 |
|---|
| 14 | + * |
|---|
| 15 | + * 密钥文件:keys/private.<env>.key |
|---|
| 16 | + * 获取方式:微信公众平台 → 开发管理 → 开发设置 → 小程序代码上传 → 生成上传密钥 |
|---|
| 17 | + * 注意:密钥属于机密,已通过 .gitignore 排除,切勿提交 |
|---|
| 18 | + */ |
|---|
| 19 | +const { spawnSync } = require('child_process'); |
|---|
| 20 | +const fs = require('fs'); |
|---|
| 21 | +const path = require('path'); |
|---|
| 22 | + |
|---|
| 23 | +const ROOT = path.resolve(__dirname, '..'); |
|---|
| 24 | +const ENV_DIR = path.join(ROOT, 'config', 'env'); |
|---|
| 25 | + |
|---|
| 26 | +// HBuilderX cli.exe 路径:优先读环境变量,便于换机器 / 换安装位置 |
|---|
| 27 | +const HX_CLI = process.env.HBUILDERX_CLI || 'C:\\Users\\Administrator\\Desktop\\HBuilderX\\cli.exe'; |
|---|
| 28 | + |
|---|
| 29 | +const argv = process.argv.slice(2); |
|---|
| 30 | +const envName = (argv.find(function(a) { return a.charAt(0) !== '-'; }) || '').trim(); |
|---|
| 31 | +const localOnly = argv.indexOf('--local') > -1; |
|---|
| 32 | +const dryRun = argv.indexOf('--dry-run') > -1; |
|---|
| 33 | +// 默认不改 manifest.json:上传用 --appid 指定目标小程序,编译产物里的 appid 不参与校验。 |
|---|
| 34 | +// 若遇到上传失败/appid 不一致,加 --sync-manifest 先同步 manifest 再发布。 |
|---|
| 35 | +const syncManifest = argv.indexOf('--sync-manifest') > -1; |
|---|
| 36 | +const OWN_ARGS = ['--local', '--dry-run', '--sync-manifest']; |
|---|
| 37 | +// 透传给 cli 的额外参数(保留 "参数 值" 的成对关系,如 --robot 2) |
|---|
| 38 | +const passthrough = []; |
|---|
| 39 | +let envNameSkipped = false; |
|---|
| 40 | +argv.forEach(function(a) { |
|---|
| 41 | + if (OWN_ARGS.indexOf(a) > -1) return; |
|---|
| 42 | + if (!envNameSkipped && a === envName) { |
|---|
| 43 | + envNameSkipped = true; |
|---|
| 44 | + return; |
|---|
| 45 | + } |
|---|
| 46 | + passthrough.push(a); |
|---|
| 47 | +}); |
|---|
| 48 | + |
|---|
| 49 | +function fail(msg) { |
|---|
| 50 | + console.error('[publish] ' + msg); |
|---|
| 51 | + process.exit(1); |
|---|
| 52 | +} |
|---|
| 53 | + |
|---|
| 54 | +function gitShortHash() { |
|---|
| 55 | + const res = spawnSync('git', ['rev-parse', '--short', 'HEAD'], { cwd: ROOT, encoding: 'utf8' }); |
|---|
| 56 | + return res.status === 0 ? String(res.stdout).trim() : ''; |
|---|
| 57 | +} |
|---|
| 58 | + |
|---|
| 59 | +function readManifestVersion() { |
|---|
| 60 | + try { |
|---|
| 61 | + const txt = fs.readFileSync(path.join(ROOT, 'manifest.json'), 'utf8'); |
|---|
| 62 | + const m = txt.match(/"versionName"\s*:\s*"([^"]*)"/); |
|---|
| 63 | + return m ? m[1] : '1.0.0'; |
|---|
| 64 | + } catch (e) { |
|---|
| 65 | + return '1.0.0'; |
|---|
| 66 | + } |
|---|
| 67 | +} |
|---|
| 68 | + |
|---|
| 69 | +function main() { |
|---|
| 70 | + const available = fs.existsSync(ENV_DIR) |
|---|
| 71 | + ? fs.readdirSync(ENV_DIR).filter(f => f.endsWith('.js') && f !== 'index.js').map(f => f.replace(/\.js$/, '')) |
|---|
| 72 | + : []; |
|---|
| 73 | + |
|---|
| 74 | + if (!envName) fail('请指定环境名,可选:' + available.join(' / ') + '\n 例:node scripts/publish.js sit'); |
|---|
| 75 | + if (available.indexOf(envName) < 0) fail('未找到 config/env/' + envName + '.js,可选:' + available.join(' / ')); |
|---|
| 76 | + |
|---|
| 77 | + const env = require(path.join(ENV_DIR, envName + '.js')); |
|---|
| 78 | + |
|---|
| 79 | + // 1) 校验 cli.exe |
|---|
| 80 | + if (!fs.existsSync(HX_CLI)) { |
|---|
| 81 | + fail('未找到 HBuilderX cli.exe:' + HX_CLI + |
|---|
| 82 | + '\n 请确认 HBuilderX 安装路径,或设置环境变量 HBUILDERX_CLI 指向 cli.exe'); |
|---|
| 83 | + } |
|---|
| 84 | + |
|---|
| 85 | + // 2) 组装 cli 参数 |
|---|
| 86 | + const cliArgs = ['publish', '--platform', 'mp-weixin', '--project', ROOT]; |
|---|
| 87 | + |
|---|
| 88 | + if (!localOnly) { |
|---|
| 89 | + const keyFile = path.join(ROOT, 'keys', 'private.' + envName + '.key'); |
|---|
| 90 | + if (!fs.existsSync(keyFile)) { |
|---|
| 91 | + fail('未找到上传密钥文件:' + keyFile + |
|---|
| 92 | + '\n 获取方式:微信公众平台 → 开发管理 → 开发设置 → 小程序代码上传 → 生成上传密钥' + |
|---|
| 93 | + '\n 若只想本地编译不上传,请加 --local'); |
|---|
| 94 | + } |
|---|
| 95 | + const stamp = new Date().toISOString().slice(0, 16).replace('T', ' '); |
|---|
| 96 | + const hash = gitShortHash(); |
|---|
| 97 | + cliArgs.push('--upload', 'true'); |
|---|
| 98 | + cliArgs.push('--appid', env.APPID); |
|---|
| 99 | + cliArgs.push('--privatekey', keyFile); |
|---|
| 100 | + cliArgs.push('--version', readManifestVersion()); |
|---|
| 101 | + cliArgs.push('--description', '[' + env.ENV_NAME + '] ' + stamp + (hash ? ' ' + hash : '')); |
|---|
| 102 | + } |
|---|
| 103 | + |
|---|
| 104 | + console.log('[publish] 环境 : ' + envName + '(' + env.ENV_NAME + ')'); |
|---|
| 105 | + console.log('[publish] 小程序appid: ' + env.APPID); |
|---|
| 106 | + console.log('[publish] 接口地址 : ' + env.HTTP_REQUEST_URL); |
|---|
| 107 | + console.log('[publish] 产物目录 : ' + path.join('unpackage', 'dist', 'build', 'mp-weixin')); |
|---|
| 108 | + console.log('[publish] 模式 : ' + (localOnly ? '仅本地编译' : '编译 + 上传到微信平台')); |
|---|
| 109 | + console.log('[publish] DCloud标识 : ' + env.UNI_APPID + '(manifest.json 里的值,仅影响非小程序端与云服务识别)'); |
|---|
| 110 | + console.log('[publish] 命令 : "' + HX_CLI + '" ' + cliArgs.concat(passthrough).join(' ')); |
|---|
| 111 | + |
|---|
| 112 | + if (dryRun) { |
|---|
| 113 | + console.log('[publish] --dry-run,未执行'); |
|---|
| 114 | + return; |
|---|
| 115 | + } |
|---|
| 116 | + |
|---|
| 117 | + // 3) 可选:先把 appid 同步进 manifest.json(走 set-env 的同一套逻辑) |
|---|
| 118 | + if (syncManifest) { |
|---|
| 119 | + console.log('[publish] --sync-manifest:先同步 manifest.json 的 appid'); |
|---|
| 120 | + const sync = spawnSync(process.execPath, [path.join(__dirname, 'set-env.js'), envName], { cwd: ROOT, stdio: 'inherit' }); |
|---|
| 121 | + if (sync.status !== 0) fail('同步 manifest.json 失败'); |
|---|
| 122 | + } |
|---|
| 123 | + |
|---|
| 124 | + // 4) 执行(HBuilderX 会在其控制台输出编译与上传日志) |
|---|
| 125 | + const res = spawnSync(HX_CLI, cliArgs.concat(passthrough), { cwd: ROOT, stdio: 'inherit' }); |
|---|
| 126 | + |
|---|
| 127 | + if (res.error) fail('调用 cli.exe 失败:' + res.error.message); |
|---|
| 128 | + if (res.status !== 0) fail('cli.exe 退出码 ' + res.status + ',请查看 HBuilderX 控制台输出'); |
|---|
| 129 | + |
|---|
| 130 | + console.log('[publish] 完成。若上传成功,可在微信公众平台 → 版本管理 中看到对应版本'); |
|---|
| 131 | +} |
|---|
| 132 | + |
|---|
| 133 | +main(); |
|---|
| .. | .. |
|---|
| 1 | +/** |
|---|
| 2 | + * 环境切换脚本:把 config/env/<env>.js 里的 appid 同步到编译期配置文件 |
|---|
| 3 | + * |
|---|
| 4 | + * 用法: |
|---|
| 5 | + * npm run env:sit 等价于 node scripts/set-env.js sit |
|---|
| 6 | + * npm run env:prod 等价于 node scripts/set-env.js prod |
|---|
| 7 | + * |
|---|
| 8 | + * 说明: |
|---|
| 9 | + * appid 是编译期值(manifest.json 为 HBuilderX 固定输入、微信开发者工具只认 |
|---|
| 10 | + * project.config.json 的 appid),无法像接口地址那样运行时切换,所以这里做 |
|---|
| 11 | + * “一次命令写回”。改完必须重新编译一次,dist 下的 project.config.json 才会更新。 |
|---|
| 12 | + * |
|---|
| 13 | + * 唯一数据源:config/env/<env>.js 中的 UNI_APPID(DCloud 标识)、APPID(小程序 appid) |
|---|
| 14 | + */ |
|---|
| 15 | +const fs = require('fs'); |
|---|
| 16 | +const path = require('path'); |
|---|
| 17 | + |
|---|
| 18 | +const ROOT = path.resolve(__dirname, '..'); |
|---|
| 19 | +const ENV_DIR = path.join(ROOT, 'config', 'env'); |
|---|
| 20 | + |
|---|
| 21 | +const files = { |
|---|
| 22 | + manifest: path.join(ROOT, 'manifest.json'), |
|---|
| 23 | + projectConfig: path.join(ROOT, 'project.config.json') |
|---|
| 24 | +}; |
|---|
| 25 | + |
|---|
| 26 | +function fail(msg) { |
|---|
| 27 | + console.error('[set-env] ' + msg); |
|---|
| 28 | + process.exit(1); |
|---|
| 29 | +} |
|---|
| 30 | + |
|---|
| 31 | +/** 只替换第一处 "appid" : "xxx",保留原有空格/缩进风格 */ |
|---|
| 32 | +function replaceAppId(text, value) { |
|---|
| 33 | + let done = false; |
|---|
| 34 | + const result = text.replace(/"appid"(\s*:\s*)"[^"]*"/, function(match, sep) { |
|---|
| 35 | + done = true; |
|---|
| 36 | + return '"appid"' + sep + '"' + value + '"'; |
|---|
| 37 | + }); |
|---|
| 38 | + return { text: result, done: done }; |
|---|
| 39 | +} |
|---|
| 40 | + |
|---|
| 41 | +/** 替换 manifest.json 顶层 appid(第一处出现即为顶层) */ |
|---|
| 42 | +function patchManifest(text, env) { |
|---|
| 43 | + // 1) 顶层 appid(DCloud 应用标识) |
|---|
| 44 | + const top = replaceAppId(text, env.UNI_APPID); |
|---|
| 45 | + if (!top.done) fail('manifest.json 中未找到顶层 "appid" 字段'); |
|---|
| 46 | + text = top.text; |
|---|
| 47 | + |
|---|
| 48 | + // 2) mp-weixin 下的 appid(微信小程序 appid),只在该区块内替换第一处 |
|---|
| 49 | + const idx = text.indexOf('"mp-weixin"'); |
|---|
| 50 | + if (idx < 0) fail('manifest.json 中未找到 "mp-weixin" 配置块'); |
|---|
| 51 | + const scoped = replaceAppId(text.slice(idx), env.APPID); |
|---|
| 52 | + if (!scoped.done) fail('manifest.json 的 "mp-weixin" 中未找到 "appid" 字段'); |
|---|
| 53 | + text = text.slice(0, idx) + scoped.text; |
|---|
| 54 | + |
|---|
| 55 | + return text; |
|---|
| 56 | +} |
|---|
| 57 | + |
|---|
| 58 | +/** 替换 project.config.json 的 appid(保持原格式,避免整文件重排) */ |
|---|
| 59 | +function patchProjectConfig(text, env) { |
|---|
| 60 | + const res = replaceAppId(text, env.APPID); |
|---|
| 61 | + if (!res.done) fail('project.config.json 中未找到 "appid" 字段'); |
|---|
| 62 | + return res.text; |
|---|
| 63 | +} |
|---|
| 64 | + |
|---|
| 65 | +function writeIfChanged(file, next) { |
|---|
| 66 | + const prev = fs.readFileSync(file, 'utf8'); |
|---|
| 67 | + if (prev === next) { |
|---|
| 68 | + console.log(' - ' + path.relative(ROOT, file) + ' 已是目标值,无需改动'); |
|---|
| 69 | + return false; |
|---|
| 70 | + } |
|---|
| 71 | + fs.writeFileSync(file, next, 'utf8'); |
|---|
| 72 | + console.log(' √ ' + path.relative(ROOT, file) + ' 已更新'); |
|---|
| 73 | + return true; |
|---|
| 74 | +} |
|---|
| 75 | + |
|---|
| 76 | +function main() { |
|---|
| 77 | + const envName = (process.argv[2] || '').trim(); |
|---|
| 78 | + const available = fs.existsSync(ENV_DIR) |
|---|
| 79 | + ? fs.readdirSync(ENV_DIR).filter(f => f.endsWith('.js') && f !== 'index.js').map(f => f.replace(/\.js$/, '')) |
|---|
| 80 | + : []; |
|---|
| 81 | + |
|---|
| 82 | + if (!envName) { |
|---|
| 83 | + fail('请指定环境名,可选:' + available.join(' / ') + '\n 例:npm run env:sit'); |
|---|
| 84 | + } |
|---|
| 85 | + if (available.indexOf(envName) < 0) { |
|---|
| 86 | + fail('未找到 config/env/' + envName + '.js,可选:' + available.join(' / ')); |
|---|
| 87 | + } |
|---|
| 88 | + |
|---|
| 89 | + const env = require(path.join(ENV_DIR, envName + '.js')); |
|---|
| 90 | + if (!env.UNI_APPID || !env.APPID) { |
|---|
| 91 | + fail('config/env/' + envName + '.js 缺少 UNI_APPID 或 APPID'); |
|---|
| 92 | + } |
|---|
| 93 | + |
|---|
| 94 | + console.log('[set-env] 切换到 ' + envName + '(' + env.ENV_NAME + ')'); |
|---|
| 95 | + console.log(' DCloud appid : ' + env.UNI_APPID); |
|---|
| 96 | + console.log(' 小程序 appid : ' + env.APPID); |
|---|
| 97 | + console.log(' 接口地址 : ' + env.HTTP_REQUEST_URL); |
|---|
| 98 | + |
|---|
| 99 | + const manifestChanged = writeIfChanged(files.manifest, patchManifest(fs.readFileSync(files.manifest, 'utf8'), env)); |
|---|
| 100 | + const projectChanged = writeIfChanged(files.projectConfig, patchProjectConfig(fs.readFileSync(files.projectConfig, 'utf8'), env)); |
|---|
| 101 | + const changed = manifestChanged || projectChanged; |
|---|
| 102 | + |
|---|
| 103 | + console.log(changed |
|---|
| 104 | + ? '[set-env] 完成,请在 HBuilderX 中重新编译一次,并在微信开发者工具中重新打开项目' |
|---|
| 105 | + : '[set-env] 无需改动,当前已是 ' + envName + ' 环境配置'); |
|---|
| 106 | +} |
|---|
| 107 | + |
|---|
| 108 | +main(); |
|---|