feat: hmr logic for the backend

This commit is contained in:
Ivan Shmidt
2020-06-11 02:51:06 +02:00
parent 0331d33a37
commit a1a60ad9d1
16 changed files with 131 additions and 28 deletions
+51
View File
@@ -0,0 +1,51 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export function useHotEffect(
_module: NodeModule,
effectFactory: () => () => void,
) {
const cancelEffect = effectFactory();
if (_module.hot) {
_module.hot.addDisposeHandler(() => {
cancelEffect();
});
}
}
export function useHotMemoize<T>(
_module: NodeModule,
valueFactory: () => T,
): T {
if (!_module.hot) {
return valueFactory();
}
const index = (useHotMemoize as any).index ?? 0;
(useHotMemoize as any).index += 1;
const prevValue = _module.hot?.data?.[index];
if (prevValue) {
_module.hot!.addDisposeHandler(data => {
data[index] = prevValue;
});
return prevValue;
}
const newValue = valueFactory();
if (_module.hot) {
_module.hot.addDisposeHandler(data => {
data[index] = newValue;
});
}
return newValue;
}
+1
View File
@@ -18,3 +18,4 @@ export * from './errors';
export * from './logging';
export * from './middleware';
export * from './service';
export * from './hot';
@@ -19,6 +19,7 @@ import cors from 'cors';
import express, { Router } from 'express';
import helmet from 'helmet';
import { Server } from 'http';
import stoppable from 'stoppable';
import { Logger } from 'winston';
import { getRootLogger } from '../logging';
import {
@@ -27,6 +28,7 @@ import {
requestLoggingHandler,
} from '../middleware';
import { ServiceBuilder } from './types';
import { useHotEffect } from '../hot';
const DEFAULT_PORT = 7000;
@@ -35,9 +37,14 @@ export class ServiceBuilderImpl implements ServiceBuilder {
private logger: Logger | undefined;
private corsOptions: cors.CorsOptions | undefined;
private routers: [string, Router][];
constructor() {
/**
* Reference to the module where builder is created
* Needed for the HMR
*/
private module: NodeModule;
constructor(module: NodeModule) {
this.routers = [];
this.module = module;
}
setPort(port: number): ServiceBuilder {
@@ -82,9 +89,20 @@ export class ServiceBuilderImpl implements ServiceBuilder {
logger.error(`Failed to start up on port ${port}, ${e}`);
reject(e);
});
const server = app.listen(port, () => {
logger.info(`Listening on port ${port}`);
const server = stoppable(
app.listen(port, () => {
logger.info(`Listening on port ${port}`);
}),
0,
);
useHotEffect(this.module, () => {
return () =>
server.stop((e: any) => {
if (e) console.error(e);
});
});
resolve(server);
});
}
@@ -19,6 +19,6 @@ import { ServiceBuilderImpl } from './ServiceBuilderImpl';
/**
* Creates a new service builder.
*/
export function createServiceBuilder() {
return new ServiceBuilderImpl();
export function createServiceBuilder(_module: NodeModule) {
return new ServiceBuilderImpl(_module);
}