mirror of https://github.com/status-im/metro.git
Exposes HMR through the Metro API
Reviewed By: rafeca Differential Revision: D6692912 fbshipit-source-id: 6f119170c40fb99bf2cad83d00edba91bcbbe1c9
This commit is contained in:
parent
cfe3670a07
commit
1cad201448
|
@ -48,7 +48,7 @@ exports.builder = (yargs: Yargs) => {
|
|||
yargs.option('secure-key', {type: 'string'});
|
||||
yargs.option('secure-cert', {type: 'string'});
|
||||
|
||||
yargs.option('legacy-bundler', {type: 'boolean'});
|
||||
yargs.option('hmr-enabled', {alias: 'hmr', type: 'boolean'});
|
||||
|
||||
yargs.option('config', {alias: 'c', type: 'string'});
|
||||
|
||||
|
|
|
@ -16,10 +16,12 @@ const Config = require('./Config');
|
|||
const Http = require('http');
|
||||
const Https = require('https');
|
||||
const MetroBundler = require('./shared/output/bundle');
|
||||
const MetroHmrServer = require('./HmrServer');
|
||||
const MetroServer = require('./Server');
|
||||
const TerminalReporter = require('./lib/TerminalReporter');
|
||||
const TransformCaching = require('./lib/TransformCaching');
|
||||
|
||||
const attachWebsocketServer = require('./lib/attachWebsocketServer');
|
||||
const defaults = require('./defaults');
|
||||
|
||||
const {realpath} = require('fs');
|
||||
|
@ -27,6 +29,7 @@ const {readFile} = require('fs-extra');
|
|||
const {Terminal} = require('metro-core');
|
||||
|
||||
import type {ConfigT} from './Config';
|
||||
import type {Reporter} from './lib/reporting';
|
||||
import type {RequestOptions, OutputOptions} from './shared/types.flow.js';
|
||||
import type {Options as ServerOptions} from './shared/types.flow';
|
||||
import type {IncomingMessage, ServerResponse} from 'http';
|
||||
|
@ -40,6 +43,7 @@ type PublicMetroOptions = {|
|
|||
maxWorkers?: number,
|
||||
port?: ?number,
|
||||
projectRoots: Array<string>,
|
||||
reporter?: Reporter,
|
||||
// deprecated
|
||||
resetCache?: boolean,
|
||||
|};
|
||||
|
@ -71,10 +75,9 @@ async function runMetro({
|
|||
// $FlowFixMe TODO t0 https://github.com/facebook/flow/issues/183
|
||||
port = null,
|
||||
projectRoots = [],
|
||||
reporter = new TerminalReporter(new Terminal(process.stdout)),
|
||||
watch = false,
|
||||
}: PrivateMetroOptions): Promise<MetroServer> {
|
||||
const reporter = new TerminalReporter(new Terminal(process.stdout));
|
||||
|
||||
const normalizedConfig = config ? Config.normalize(config) : Config.DEFAULT;
|
||||
|
||||
const assetExts = defaults.assetExts.concat(
|
||||
|
@ -163,6 +166,7 @@ exports.createConnectMiddleware = async function(
|
|||
: Config.DEFAULT;
|
||||
|
||||
return {
|
||||
metroServer,
|
||||
middleware: normalizedConfig.enhanceMiddleware(metroServer.processRequest),
|
||||
end() {
|
||||
metroServer.end();
|
||||
|
@ -178,21 +182,25 @@ type RunServerOptions = {|
|
|||
secure?: boolean,
|
||||
secureKey?: string,
|
||||
secureCert?: string,
|
||||
hmrEnabled?: boolean,
|
||||
|};
|
||||
|
||||
exports.runServer = async (options: RunServerOptions) => {
|
||||
const port = options.port || 8080;
|
||||
const reporter =
|
||||
options.reporter || new TerminalReporter(new Terminal(process.stdout));
|
||||
|
||||
// Lazy require
|
||||
const connect = require('connect');
|
||||
|
||||
const serverApp = connect();
|
||||
|
||||
const {middleware, end} = await exports.createConnectMiddleware({
|
||||
const {metroServer, middleware, end} = await exports.createConnectMiddleware({
|
||||
config: options.config,
|
||||
maxWorkers: options.maxWorkers,
|
||||
port,
|
||||
projectRoots: options.projectRoots,
|
||||
reporter,
|
||||
resetCache: options.resetCache,
|
||||
});
|
||||
|
||||
|
@ -212,6 +220,14 @@ exports.runServer = async (options: RunServerOptions) => {
|
|||
httpServer = Http.createServer(serverApp);
|
||||
}
|
||||
|
||||
if (options.hmrEnabled) {
|
||||
attachWebsocketServer({
|
||||
httpServer,
|
||||
path: '/hot',
|
||||
websocketServer: new MetroHmrServer(metroServer, reporter),
|
||||
});
|
||||
}
|
||||
|
||||
httpServer.listen(port, options.host, () => {
|
||||
options.onReady && options.onReady(httpServer);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {Server as HttpServer} from 'http';
|
||||
import type {Server as HttpsServer} from 'https';
|
||||
|
||||
type WebsocketServiceInterface<T> = {
|
||||
+onClientConnect: (
|
||||
url: string,
|
||||
sendFn: (data: string) => mixed,
|
||||
) => Promise<T>,
|
||||
+onClientDisconnect?: (client: T) => mixed,
|
||||
+onClientError?: (client: T, e: Error) => mixed,
|
||||
+onClientMessage?: (client: T, message: string) => mixed,
|
||||
};
|
||||
|
||||
type HMROptions<TClient> = {
|
||||
httpServer: HttpServer | HttpsServer,
|
||||
websocketServer: WebsocketServiceInterface<TClient>,
|
||||
path: string,
|
||||
};
|
||||
|
||||
/**
|
||||
* Attach a websocket server to an already existing HTTP[S] server, and forward
|
||||
* the received events on the given "websocketServer" parameter. It must be an
|
||||
* object with the following fields:
|
||||
*
|
||||
* - onClientConnect
|
||||
* - onClientError
|
||||
* - onClientMessage
|
||||
* - onClientDisconnect
|
||||
*/
|
||||
|
||||
module.exports = function attachWebsocketServer<TClient: Object>({
|
||||
httpServer,
|
||||
websocketServer,
|
||||
path,
|
||||
}: HMROptions<TClient>) {
|
||||
const WebSocketServer = require('ws').Server;
|
||||
const wss = new WebSocketServer({
|
||||
server: httpServer,
|
||||
path,
|
||||
});
|
||||
|
||||
wss.on('connection', async ws => {
|
||||
let connected = true;
|
||||
const url = ws.upgradeReq.url;
|
||||
|
||||
const sendFn = (...args) => {
|
||||
if (connected) {
|
||||
ws.send(...args);
|
||||
}
|
||||
};
|
||||
|
||||
const client = await websocketServer.onClientConnect(url, sendFn);
|
||||
|
||||
ws.on('error', e => {
|
||||
websocketServer.onClientError && websocketServer.onClientError(client, e);
|
||||
});
|
||||
|
||||
ws.on('close', () => {
|
||||
websocketServer.onClientDisconnect &&
|
||||
websocketServer.onClientDisconnect(client);
|
||||
connected = false;
|
||||
});
|
||||
|
||||
ws.on('message', message => {
|
||||
websocketServer.onClientMessage &&
|
||||
websocketServer.onClientMessage(client, message);
|
||||
});
|
||||
});
|
||||
};
|
Loading…
Reference in New Issue