Jacob
2026-10-12 486ac751755a33139c3fcbef3c73e3136ffcf5a5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/**
 * 环境切换脚本:把 config/env/<env>.js 里的 appid 同步到编译期配置文件
 *
 * 用法:
 *   npm run env:sit     等价于 node scripts/set-env.js sit
 *   npm run env:prod    等价于 node scripts/set-env.js prod
 *
 * 说明:
 *   appid 是编译期值(HBuilderX 的编译输入就是 manifest.json),无法像接口地址那样
 *   运行时切换,所以这里做“一次命令写回”。改完必须重新编译一次,产物里的
 *   project.config.json 才会更新。
 *
 *   日常推荐:mp-weixin.appid 保持 null,只让发行脚本回写产物 appid(git 零噪音)。
 *   本脚本用于需要在 HBuilderX 里直接运行调试、或要出 App 包(顶层 appid)的场景。
 *
 *   唯一数据源:config/env/<env>.js 中的 UNI_APPID(DCloud 标识)、APPID(小程序 appid)
 */
const fs = require('fs');
const path = require('path');
 
const ROOT = path.resolve(__dirname, '..');
const ENV_DIR = path.join(ROOT, 'config', 'env');
 
// 根目录 project.config.json 不参与 mp-weixin 编译且已不入库,这里只维护 manifest.json
const files = {
   manifest: path.join(ROOT, 'manifest.json')
};
 
function fail(msg) {
   console.error('[set-env] ' + msg);
   process.exit(1);
}
 
/** 只替换第一处 "appid" : <字符串或 null>,保留原有空格/缩进风格 */
function replaceAppId(text, value) {
   let done = false;
   const result = text.replace(/"appid"(\s*:\s*)(?:"[^"]*"|null)/, function(match, sep) {
       done = true;
       return '"appid"' + sep + '"' + value + '"';
   });
   return { text: result, done: done };
}
 
/** 替换 manifest.json 顶层 appid(第一处出现即为顶层) */
function patchManifest(text, env) {
   // 1) 顶层 appid(DCloud 应用标识)
   const top = replaceAppId(text, env.UNI_APPID);
   if (!top.done) fail('manifest.json 中未找到顶层 "appid" 字段');
   text = top.text;
 
   // 2) mp-weixin 下的 appid(微信小程序 appid),只在该区块内替换第一处
   const idx = text.indexOf('"mp-weixin"');
   if (idx < 0) fail('manifest.json 中未找到 "mp-weixin" 配置块');
   const head = text.slice(0, idx);
   const body = text.slice(idx);
   const scoped = replaceAppId(body, env.APPID);
   if (scoped.done) return head + scoped.text;
 
   // 3) 字段被删掉时,按同级子项缩进补一行
   const m = body.match(/^("mp-weixin"\s*:\s*\{)(\r?\n)([ \t]*)/);
   if (!m) fail('manifest.json 的 "mp-weixin" 块格式异常,无法写入 appid');
   const nl = m[2];
   const indent = m[3];
   return head + m[1] + nl + indent + '"appid" : "' + env.APPID + '",' + nl + indent + body.slice(m[0].length);
}
 
function writeIfChanged(file, next) {
   const prev = fs.readFileSync(file, 'utf8');
   if (prev === next) {
       console.log('  - ' + path.relative(ROOT, file) + ' 已是目标值,无需改动');
       return false;
   }
   fs.writeFileSync(file, next, 'utf8');
   console.log('  √ ' + path.relative(ROOT, file) + ' 已更新');
   return true;
}
 
function main() {
   const envName = (process.argv[2] || '').trim();
   const available = fs.existsSync(ENV_DIR)
       ? fs.readdirSync(ENV_DIR).filter(f => f.endsWith('.js') && f !== 'index.js').map(f => f.replace(/\.js$/, ''))
       : [];
 
   if (!envName) {
       fail('请指定环境名,可选:' + available.join(' / ') + '\n  例:npm run env:sit');
   }
   if (available.indexOf(envName) < 0) {
       fail('未找到 config/env/' + envName + '.js,可选:' + available.join(' / '));
   }
 
   const env = require(path.join(ENV_DIR, envName + '.js'));
   if (!env.UNI_APPID || !env.APPID) {
       fail('config/env/' + envName + '.js 缺少 UNI_APPID 或 APPID');
   }
 
   console.log('[set-env] 切换到 ' + envName + '(' + env.ENV_NAME + ')');
   console.log('  DCloud appid : ' + env.UNI_APPID);
   console.log('  小程序 appid : ' + env.APPID);
   console.log('  接口地址     : ' + env.HTTP_REQUEST_URL);
 
   const changed = writeIfChanged(files.manifest, patchManifest(fs.readFileSync(files.manifest, 'utf8'), env));
 
   console.log(changed
       ? '[set-env] 完成,请在 HBuilderX 中重新编译一次,并在微信开发者工具中重新打开项目'
       : '[set-env] 无需改动,当前已是 ' + envName + ' 环境配置');
}
 
main();