Automatically watches the metro configuration file

Reviewed By: BYK

Differential Revision: D6408358

fbshipit-source-id: d167534c9c51c3c079148d982ef4ab44c8be0d75
This commit is contained in:
Maël Nison 2017-11-28 04:17:21 -08:00 committed by Facebook Github Bot
parent b282031517
commit 5cc0939454
4 changed files with 92 additions and 34 deletions

View File

@ -19,12 +19,20 @@ import type {ConfigT} from './Config';
const METRO_CONFIG_FILENAME = 'metro.config.js';
exports.findMetroConfig = async function(
filename: ?string,
): Promise<$Shape<ConfigT>> {
exports.watchFile = async function(
filename: string,
callback: () => *,
): Promise<void> {
fs.watchFile(filename, () => {
callback();
});
await callback();
};
exports.findMetroConfig = async function(filename: ?string): Promise<?string> {
if (filename) {
// $FlowFixMe: We want this require to be dynamic
return require(path.resolve(process.cwd(), filename));
return path.resolve(process.cwd(), filename);
} else {
let previous;
let current = process.cwd();
@ -33,14 +41,25 @@ exports.findMetroConfig = async function(
const filename = path.join(current, METRO_CONFIG_FILENAME);
if (fs.existsSync(filename)) {
// $FlowFixMe: We want this require to be dynamic
return require(filename);
return filename;
}
previous = current;
current = path.dirname(current);
} while (previous !== current);
return null;
}
};
exports.fetchMetroConfig = async function(
filename: ?string,
): Promise<$Shape<ConfigT>> {
const location = await exports.findMetroConfig(filename);
if (location) {
// $FlowFixMe: We want this require to be dynamic
return require(location);
} else {
return {};
}
};

View File

@ -16,7 +16,7 @@ const MetroApi = require('..');
const os = require('os');
const {findMetroConfig, makeAsyncCommand} = require('../cli-utils');
const {fetchMetroConfig, makeAsyncCommand} = require('../cli-utils');
import typeof Yargs from 'yargs';
@ -52,6 +52,6 @@ exports.builder = (yargs: Yargs) => {
// eslint-disable-next-line no-unclear-flowtypes
exports.handler = makeAsyncCommand(async (argv: any) => {
argv.config = await findMetroConfig(argv.config);
await MetroApi.runBuild(argv);
const config = await fetchMetroConfig(argv.config);
await MetroApi.runBuild({...argv, config});
});

View File

@ -16,7 +16,13 @@ const MetroApi = require('..');
const os = require('os');
const {findMetroConfig, makeAsyncCommand} = require('../cli-utils');
const {
findMetroConfig,
fetchMetroConfig,
watchFile,
makeAsyncCommand,
} = require('../cli-utils');
const {promisify} = require('util');
import typeof Yargs from 'yargs';
@ -49,15 +55,44 @@ exports.builder = (yargs: Yargs) => {
// eslint-disable-next-line no-unclear-flowtypes
exports.handler = makeAsyncCommand(async (argv: any) => {
argv.config = await findMetroConfig(argv.config);
let server = null;
let restarting = false;
await MetroApi.runServer({
...argv,
onReady(server) {
console.log(
`The HTTP server is ready to accept requests on ${server.address()
.address}:${server.address().port}`,
);
},
});
async function restart() {
if (restarting) {
return;
} else {
restarting = true;
}
if (server) {
console.log('Configuration changed... restarting the server...');
await promisify(server.close).call(server);
}
const config = await fetchMetroConfig(argv.config);
server = await MetroApi.runServer({
...argv,
config,
onReady,
});
restarting = false;
}
function onReady(server) {
console.log(
`The HTTP server is ready to accept requests on ${server.address()
.address}:${server.address().port}`,
);
}
const metroConfigLocation = await findMetroConfig(argv.config);
if (metroConfigLocation) {
await watchFile(metroConfigLocation, restart);
} else {
await restart();
}
});

View File

@ -145,8 +145,13 @@ exports.createConnectMiddleware = async function(
watch: true,
});
return (req: IncomingMessage, res: ServerResponse) => {
return metroServer.processRequest(req, res);
return {
middleware(req: IncomingMessage, res: ServerResponse) {
return metroServer.processRequest(req, res);
},
end() {
metroServer.end();
},
};
};
@ -163,13 +168,13 @@ type RunServerOptions = {|
exports.runServer = async (options: RunServerOptions) => {
const serverApp = connect();
const metroMiddleware = exports.createConnectMiddleware({
const {middleware, end} = await exports.createConnectMiddleware({
config: options.config,
maxWorkers: options.maxWorkers,
projectRoots: options.projectRoots,
});
serverApp.use(metroMiddleware);
serverApp.use(middleware);
let httpServer;
@ -185,7 +190,6 @@ exports.runServer = async (options: RunServerOptions) => {
httpServer = Http.createServer(serverApp);
}
// $FlowFixMe: The port parameter IS optional
httpServer.listen(options.port, options.host, () => {
options.onReady && options.onReady(httpServer);
});
@ -195,15 +199,15 @@ exports.runServer = async (options: RunServerOptions) => {
// timeout of 120 seconds to respond to a request.
httpServer.timeout = 0;
return new Promise((resolve, reject) => {
httpServer.on('error', error => {
reject(error);
});
httpServer.on('close', () => {
resolve();
});
httpServer.on('error', error => {
end();
});
httpServer.on('close', () => {
end();
});
return httpServer;
};
type RunBuildOptions = {|