【发布时间】:2017-09-21 13:43:47
【问题描述】:
情景:
我正在构建一个 Ionic3 应用程序,而我的 config.xml 有一些我希望能够根据我的环境更改的数据(例如,我希望我的 facebook 应用程序 ID 具有不同的开发值,分期和生产)。
我创建了一个模板config.xml(文件是config.tpl.xml)和一个before_preparecordova钩子来用正确的值替换模板中的变量并将生成的内容保存在config.xml中。
cordova 钩子使用npm 包es6-template-strings:
npm install es6-template-strings --save-dev
钩子是:
#!/usr/bin/env node
var fs = require('fs');
var path = require('path');
var compile = require('es6-template-strings/compile');
var resolveToString = require('es6-template-strings/resolve-to-string');
var ROOT_DIR = process.argv[2];
var FILES = {
SRC: "config.tpl.xml",
DEST: "config.xml"
};
var env = process.env.NODE_ENV || 'dev';
var envFile = 'src/environments/environment.' + env + '.json';
var srcFileFull = path.join(ROOT_DIR, FILES.SRC);
var destFileFull = path.join(ROOT_DIR, FILES.DEST);
var configFileFull = path.join(ROOT_DIR, envFile);
var templateData = fs.readFileSync(srcFileFull, 'utf8');
var configData = fs.readFileSync(configFileFull, 'utf8');
var config = JSON.parse(configData);
var compiled = compile(templateData);
var content = resolveToString(compiled, config);
fs.writeFileSync(destFileFull, content);
我在src/environments/ 目录中有不同环境的文件,这些文件是根据我构建cordova 时定义的NODE_ENV 值选择的。例如,如果NODE_ENV=prod(生产),那么它将使用文件environment.prod.json:
{
...
"FACEBOOK_APP_ID": "11111111",
"FACEBOOK_APP_NAME": "My Facebook App Name",
...
"PUSH_SENDER_ID": "22222222",
...
}
钩子执行时,这部分在cordova.tpl.xml:
<plugin name="cordova-plugin-facebook4" spec="~1.7.4">
<variable name="APP_ID" value="${FACEBOOK_APP_ID}" />
<variable name="APP_NAME" value="${FACEBOOK_APP_NAME}" />
</plugin>
<plugin name="phonegap-plugin-push" spec="~1.9.2">
<variable name="SENDER_ID" value="${PUSH_SENDER_ID}" />
</plugin>
变成:
<plugin name="cordova-plugin-facebook4" spec="~1.7.4">
<variable name="APP_ID" value="11111111" />
<variable name="APP_NAME" value="My Facebook App Name" />
</plugin>
<plugin name="phonegap-plugin-push" spec="~1.9.2">
<variable name="SENDER_ID" value="22222222" />
</plugin>
问题:
到目前为止一切顺利。问题是当对config.xml进行一些自动更改(比如添加插件)时,cordova.tpl.xml并没有反映出来,所以我必须记得手动进行更改。
虽然现在完成的方式仍然比以前必须添加每个环境变量要好得多(这是维护的噩梦并且容易出错),但我仍然必须在每次添加/更改/删除时更改模板一个插件(不是那么频繁,忘记了也容易发现问题,但离理想还差得很远)。
我的问题:
我想知道是否有办法避免这些手动更改,但要像现在一样继续使用环境变量。
如果可能的话,可以将config.xml 的自动更改改为config.tpl.xml(比如添加带有--save 的插件时),但我没有找到任何关于cordova 的选项这个。
或者使用config.xml作为模板并将其发送到定义了变量的另一个地方(例如www/config.xml),并在另一个位置使用config.xml来构建应用程序(不是config.xml 在根中,即模板)。我只会更改我的钩子中的src 和dest 文件(分别更改为config.xml 和www/config.xml)。但我也没有找到实现这一点的方法。
对此有什么想法吗?
(它不需要是特定于 Ionic 的解决方案。)
更新 (2017-10-13)
根据Bobby 的回答,我在安装和卸载插件时都实现了我想要的。我创建了 4 个钩子:after_plugin_add、after_plugin_rm、before_plugin_add、before_plugin_rm。
before 挂钩将模板 (config.tpl.xml) 复制到 config.xml 文件中,after 挂钩则相反。
before_plugin_add 和 before_plugin_rm 钩子如下:
#!/usr/bin/env node
var fs = require('fs');
var path = require('path');
var ROOT_DIR = process.argv[2];
var FILES = {
SRC: 'config.tpl.xml',
DEST: 'config.xml'
};
var srcFileFull = path.join(ROOT_DIR, FILES.SRC);
var destFileFull = path.join(ROOT_DIR, FILES.DEST);
var templateData = fs.readFileSync(srcFileFull, 'utf8');
fs.writeFileSync(destFileFull, templateData);
after_plugin_add 和 after_plugin_rm 挂钩几乎相同,只是交换了 FILES.SRC 和 FILES.DEST 值。
【问题讨论】:
-
谢谢!注意:这条线
var ROOT_DIR = process.argv[2];在我的情况下不起作用,因为 process.argv[2] 被解析为“准备”。在我的情况下有效的是var ROOT_DIR = '';。我正在使用 Ionic 4 和 Cordova CLI 9.0。 -
另一个问题:你是否将config.xml添加到.gitignore?从我的角度来看,不签入是有意义的。
-
@KlemensZleptnig 我将
config.yml添加到.gitignore。我不知道如何在 Ionic4 挂钩中获取根目录:/ 不过,在科尔多瓦项目中,上述内容应该可以工作。您将它们用作科尔多瓦钩子还是 ionic 在幕后处理它?我认为 Ionic4 正在添加参数。您可以尝试像console.log('1', process.argv[1])、console.log('2', process.argv[2])、console.log('3', process.argv[3])等一样记录它们。 -
但是在安装插件的过程中,
config.tpl.yml变成config.xml的文件不是交换的想法,以便将新插件添加到其中,并且在安装后恢复? ???根据这个逻辑——如果我理解正确的话——在安装过程中,config.xml中会有变量。 -
@KlemensZleptnig 这个话题有点老了,所以我忘了:P。似乎取决于您放置变量的位置(在您的情况下,它表示路径)cordova 可能会出错,所以我不知道您是否应该使用我提到的钩子。 我建议你做的事情(这是我通常做的事情),是直接在文件
config.tpl.yml中定义插件,而不是从命令行添加它们,这样准备步骤完成后,插件已安装,您不需要挂钩,也不需要将代码从config.xml复制到模板。