mirror of
https://github.com/outline/outline.git
synced 2026-08-03 13:27:25 +03:00
fix: Mangled class names cause x is not a function in prod (#13184)
* fix: Mangled class names cause 'is not a function' in prod * feedback, switch to WeakMap
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
import { AfterChange, LifecycleManager } from "./Lifecycle";
|
||||
|
||||
describe("LifecycleManager", () => {
|
||||
it("executes registered hooks", () => {
|
||||
const hook = vi.fn();
|
||||
|
||||
class Model {
|
||||
static onChange = hook;
|
||||
}
|
||||
AfterChange(Model, "onChange");
|
||||
|
||||
LifecycleManager.executeHooks(Model, "afterChange", "arg");
|
||||
expect(hook).toHaveBeenCalledWith("arg");
|
||||
});
|
||||
|
||||
it("does not leak hooks between classes that share a name", () => {
|
||||
const hook = vi.fn();
|
||||
|
||||
// Minified builds can mangle two unrelated classes to the same name.
|
||||
const One = class Model {
|
||||
static onChange = hook;
|
||||
};
|
||||
const Two = class Model {};
|
||||
|
||||
AfterChange(One, "onChange");
|
||||
|
||||
expect(() =>
|
||||
LifecycleManager.executeHooks(Two, "afterChange", "arg")
|
||||
).not.toThrow();
|
||||
expect(hook).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -1,12 +1,14 @@
|
||||
type ModelClass = { readonly name: string };
|
||||
type ModelClass = Function;
|
||||
type Hook = (...args: unknown[]) => unknown;
|
||||
|
||||
export class LifecycleManager {
|
||||
private static hooks = new Map<string, Map<string, string[]>>();
|
||||
// Keyed by the class itself – minified builds mangle class names and two
|
||||
// classes in separate chunks can end up sharing one.
|
||||
private static hooks = new WeakMap<ModelClass, Map<string, string[]>>();
|
||||
|
||||
public static getHooks(target: ModelClass, lifecycle: string): string[] {
|
||||
const key = `lifecycle:${lifecycle}`;
|
||||
const modelHooks = this.hooks.get(target.name);
|
||||
const modelHooks = this.hooks.get(target);
|
||||
return modelHooks?.get(key) ?? [];
|
||||
}
|
||||
|
||||
@@ -28,11 +30,11 @@ export class LifecycleManager {
|
||||
lifecycle: string
|
||||
): void {
|
||||
const key = `lifecycle:${lifecycle}`;
|
||||
let modelHooks = this.hooks.get(target.name);
|
||||
let modelHooks = this.hooks.get(target);
|
||||
|
||||
if (!modelHooks) {
|
||||
modelHooks = new Map();
|
||||
this.hooks.set(target.name, modelHooks);
|
||||
this.hooks.set(target, modelHooks);
|
||||
}
|
||||
|
||||
let lifecycleHooks = modelHooks.get(key);
|
||||
|
||||
Reference in New Issue
Block a user