Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/base/common/hotReload.ts
5221 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { IDisposable } from './lifecycle.js';
7
8
let _isHotReloadEnabled = false;
9
10
export function enableHotReload() {
11
_isHotReloadEnabled = true;
12
}
13
14
export function isHotReloadEnabled(): boolean {
15
return _isHotReloadEnabled;
16
}
17
export function registerHotReloadHandler(handler: HotReloadHandler): IDisposable {
18
if (!isHotReloadEnabled()) {
19
return { dispose() { } };
20
} else {
21
const handlers = registerGlobalHotReloadHandler();
22
handlers.add(handler);
23
return {
24
dispose() { handlers.delete(handler); }
25
};
26
}
27
}
28
29
/**
30
* Takes the old exports of the module to reload and returns a function to apply the new exports.
31
* If `undefined` is returned, this handler is not able to handle the module.
32
*
33
* If no handler can apply the new exports, the module will not be reloaded.
34
*/
35
export type HotReloadHandler = (args: { oldExports: Record<string, unknown>; newSrc: string; config: IHotReloadConfig }) => AcceptNewExportsHandler | undefined;
36
export type AcceptNewExportsHandler = (newExports: Record<string, unknown>) => boolean;
37
export type IHotReloadConfig = HotReloadConfig;
38
39
function registerGlobalHotReloadHandler() {
40
if (!hotReloadHandlers) {
41
hotReloadHandlers = new Set();
42
}
43
44
const g = globalThis as unknown as GlobalThisAddition;
45
if (!g.$hotReload_applyNewExports) {
46
g.$hotReload_applyNewExports = args => {
47
const args2 = { config: { mode: undefined }, ...args };
48
49
const results: AcceptNewExportsHandler[] = [];
50
for (const h of hotReloadHandlers!) {
51
const result = h(args2);
52
if (result) {
53
results.push(result);
54
}
55
}
56
if (results.length > 0) {
57
return newExports => {
58
let result = false;
59
for (const r of results) {
60
if (r(newExports)) {
61
result = true;
62
}
63
}
64
return result;
65
};
66
}
67
return undefined;
68
};
69
}
70
71
return hotReloadHandlers;
72
}
73
74
let hotReloadHandlers: Set<(args: { oldExports: Record<string, unknown>; newSrc: string; config: HotReloadConfig }) => AcceptNewExportsFn | undefined> | undefined = undefined;
75
76
interface HotReloadConfig {
77
mode?: 'patch-prototype' | undefined;
78
}
79
80
interface GlobalThisAddition {
81
$hotReload_applyNewExports?(args: { oldExports: Record<string, unknown>; newSrc: string; config?: HotReloadConfig }): AcceptNewExportsFn | undefined;
82
}
83
84
type AcceptNewExportsFn = (newExports: Record<string, unknown>) => boolean;
85
86
if (isHotReloadEnabled()) {
87
// This code does not run in production.
88
registerHotReloadHandler(({ oldExports, newSrc, config }) => {
89
if (config.mode !== 'patch-prototype') {
90
return undefined;
91
}
92
93
return newExports => {
94
for (const key in newExports) {
95
const exportedItem = newExports[key];
96
console.log(`[hot-reload] Patching prototype methods of '${key}'`, { exportedItem });
97
if (typeof exportedItem === 'function' && exportedItem.prototype) {
98
const oldExportedItem = oldExports[key];
99
if (oldExportedItem) {
100
for (const prop of Object.getOwnPropertyNames(exportedItem.prototype)) {
101
const descriptor = Object.getOwnPropertyDescriptor(exportedItem.prototype, prop)!;
102
// eslint-disable-next-line local/code-no-any-casts
103
const oldDescriptor = Object.getOwnPropertyDescriptor((oldExportedItem as any).prototype, prop);
104
105
if (descriptor?.value?.toString() !== oldDescriptor?.value?.toString()) {
106
console.log(`[hot-reload] Patching prototype method '${key}.${prop}'`);
107
}
108
109
// eslint-disable-next-line local/code-no-any-casts
110
Object.defineProperty((oldExportedItem as any).prototype, prop, descriptor);
111
}
112
newExports[key] = oldExportedItem;
113
}
114
}
115
}
116
return true;
117
};
118
});
119
}
120
121