Merge pull request #1394 from spotify/freben/hmr

chore(backend-common): just tweaked the structure of useHotMemoize
This commit is contained in:
Fredrik Adelöw
2020-06-22 14:06:14 +02:00
committed by GitHub
+26 -36
View File
@@ -72,63 +72,53 @@ export function useHotCleanup(_module: NodeModule, cancelEffect: () => void) {
}
}
const CURRENT_HOT_MEMOIZE_INDEX_KEY = 'backstage.io/hmr-memoize-key';
/**
* This function allows devs to preserve
* some value between hot-reloads.
* Useful for stateful parts of the backend
* Memoizes a generated value across hot-module reloads. This is useful for
* stateful parts of the backend, e.g. to retain a database.
*
* @example
* ```ts
* const db = useHotMemoize(module, () => createDB(dbParams));
* ```
* @param _module Reference to the current module where you invoke the fn
* @param valueFactory Fn that returns the value you want to memoize
*
* @warning Don't use inside conditionals or loops,
* same rules as for hooks apply (https://reactjs.org/docs/hooks-rules.html)
*
* @param _module Reference to the current module where you invoke the fn
* @param valueFactory Fn that returns the value you want to memoize
*/
export function useHotMemoize<T>(
_module: NodeModule,
valueFactory: () => T,
): T {
const CURRENT_HOT_MEMOIZE_INDEX_KEY = 'backstage.io/hmr-memoize-key';
if (!_module.hot) {
// Just return value straight away
return valueFactory();
}
if (_module.hot && typeof _module.hot.data === 'undefined') {
// First run, init the module data
// When starting blank, reset the counter
if (!_module.hot.data?.[CURRENT_HOT_MEMOIZE_INDEX_KEY]) {
for (const ancestor of findAllAncestors(_module)) {
ancestor.hot?.addDisposeHandler(data => {
data[CURRENT_HOT_MEMOIZE_INDEX_KEY] = 1;
});
}
_module.hot.data = {
[CURRENT_HOT_MEMOIZE_INDEX_KEY]: 0,
..._module.hot.data,
[CURRENT_HOT_MEMOIZE_INDEX_KEY]: 1,
};
}
// Let's store data per module based on the order of the code invocation
const index = _module.hot.data[CURRENT_HOT_MEMOIZE_INDEX_KEY];
// Increasing the counter after each call
_module.hot.data[CURRENT_HOT_MEMOIZE_INDEX_KEY] += 1;
// Store data per module, based on the order of the code invocation
const index = _module.hot.data[CURRENT_HOT_MEMOIZE_INDEX_KEY]++;
const value = _module.hot.data[index] ?? valueFactory();
const prevValue = _module.hot.data[index];
const createDisposeHandler = (value: any) => (data: {
[key: number]: any;
[indexKey: string]: number;
}) => {
// Preserving the value through the HMR process
// Always add a handler that, upon a HMR event, reinstates the value.
_module.hot.addDisposeHandler(data => {
data[index] = value;
// Decreasing the counter after each handler
data[CURRENT_HOT_MEMOIZE_INDEX_KEY] =
// First hot update is still different, need to populate the data
typeof data[CURRENT_HOT_MEMOIZE_INDEX_KEY] === 'undefined'
? _module.hot!.data[CURRENT_HOT_MEMOIZE_INDEX_KEY] - 1
: data[CURRENT_HOT_MEMOIZE_INDEX_KEY] - 1;
};
});
if (prevValue) {
_module.hot!.addDisposeHandler(createDisposeHandler(prevValue));
return prevValue;
}
const newValue = valueFactory();
_module.hot.addDisposeHandler(createDisposeHandler(newValue));
return newValue;
return value;
}