如何以编程方式启动/停止 Metro Bundler
Posted
技术标签:
【中文标题】如何以编程方式启动/停止 Metro Bundler【英文标题】:How to programmatically start/stop Metro Bundler 【发布时间】:2019-03-16 21:43:34 【问题描述】:我正在尝试为 React-Native 项目设置持续集成,但在端到端测试中遇到了一些问题,尤其是在 Metro 捆绑器周围。
在这种情况下使用 react-native 脚本似乎不可靠:
ios 构建会在新终端中自发生成一个捆绑程序,并在构建完成后继续运行。 android 构建依赖于必须事先手动启动的正在运行的实例。 除了发出信号(Ctrl+C 或 kill)之外,无法通过其他方式停止捆绑程序。 没有与构建同步以确保捆绑程序在应用启动时准备好进行处理。我想编写一个自定义脚本,它可以启动 Metro,在服务器准备好后运行测试,最后停止服务器以清理环境。
【问题讨论】:
经过大量实验后,我认为 Metro 必须作为单独的进程运行,否则将无法响应客户端请求。所以挑战是派生一个新进程,解析控制台输出并保持执行直到 Metro 准备好。 【参考方案1】:metro bundler 必须作为单独的进程运行才能处理请求。这样做的方法是使用Child Process : Spawn 并保持返回的对象正确清理。
这是一个基本脚本,它同时启动 Metro 和 Gradle,并根据日志输出等到两者都准备好。
'use strict';
const cp = require('child_process');
const fs = require('fs');
const readline = require('readline');
// List of sub processes kept for proper cleanup
const children = ;
async function asyncPoint(ms, callback = () => )
return await new Promise(resolve => setTimeout(() =>
resolve(callback());
, ms));
async function fork(name, cmd, args, readyRegex, timeout = )
return new Promise((resolve) =>
const close = () =>
delete children[name];
resolve(false);
;
if(timeout)
setTimeout(() => close, timeout);
const child = cp.spawn(
cmd,
args,
silent: false,
stdio: [null, 'pipe', 'pipe'],
,
);
child.on('close', close);
child.on('exit', close);
child.on('error', close);
const output = fs.createWriteStream(`./volatile-build-$name.log`);
const lineCb = (line) =>
console.log(`[$name] $line`);
output.write(line+'\n');
if (readyRegex && line.match(readyRegex))
resolve(true);
;
readline.createInterface(
input: child.stdout,
).on('line', lineCb);
readline.createInterface(
input: child.stderr,
).on('line', lineCb);
children[name] = child;
);
async function sighandle()
console.log('\nClosing...');
Object.values(children).forEach(child => child.kill('SIGTERM'));
await asyncPoint(1000);
process.exit(0);
function setSigHandler()
process.on('SIGINT', sighandle);
process.on('SIGTERM', sighandle);
async function main()
setSigHandler();
// Metro Bundler
const metroSync = fork(
'metro',
process.argv0,
[ // args
'./node_modules/react-native/local-cli/cli.js',
'start',
],
// options
readyRegex: /Loading dependency graph, done./,
timeout: 60000,
);
// Build APK
const buildSync = fork(
'gradle',
'./android/gradlew',
[ // args
`--project-dir=$__dirname/android`,
'assembleDebug',
],
// options
readyRegex: /BUILD SUCCESSFUL/,
timeout: 300000,
);
if (await metroSync && await buildSync)
// TODO: Run tests here
sighandle();
main();
【讨论】:
以上是关于如何以编程方式启动/停止 Metro Bundler的主要内容,如果未能解决你的问题,请参考以下文章
在 MahApps Metro DataGridCheckBoxColumn 中,我如何以编程方式返回复选框值? (并修复额外的行)
如何在 Java 中以编程方式启动和停止 Amazon EC2 实例