Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[golf] core down a few bytes #470

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/curvy-cats-develop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@preact/signals-core": patch
---

Shave a few bytes off of Signals core.
9 changes: 3 additions & 6 deletions mangle.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@
},
"minify": {
"mangle": {
"reserved": [
"useSignal",
"useComputed",
"useSignalEffect"
],
"reserved": ["useSignal", "useComputed", "useSignalEffect"],
"keep_classnames": true,
"properties": {
"regex": "^_[^_]",
Expand All @@ -25,7 +21,8 @@
"compress": {
"conditionals": false,
"loops": false,
"sequences": false
"sequences": false,
"unsafe": true
}
},
"props": {
Expand Down
71 changes: 29 additions & 42 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
function cycleDetected(): never {
throw new Error("Cycle detected");
}
function mutationDetected(): never {
throw new Error("Computed cannot have side-effects");
}

const identifier = Symbol.for("preact-signals");

// Flags for Computed and Effect.
Expand Down Expand Up @@ -259,13 +252,15 @@ function Signal(this: Signal, value?: unknown) {
this._targets = undefined;
}

Signal.prototype.brand = identifier;
const signalProto = Signal.prototype;

Signal.prototype._refresh = function () {
signalProto.brand = identifier;

signalProto._refresh = function () {
return true;
};

Signal.prototype._subscribe = function (node) {
signalProto._subscribe = function (node) {
if (this._targets !== node && node._prevTarget === undefined) {
node._nextTarget = this._targets;
if (this._targets !== undefined) {
Expand All @@ -275,7 +270,7 @@ Signal.prototype._subscribe = function (node) {
}
};

Signal.prototype._unsubscribe = function (node) {
signalProto._unsubscribe = function (node) {
// Only run the unsubscribe step if the signal has any subscribers to begin with.
if (this._targets !== undefined) {
const prev = node._prevTarget;
Expand All @@ -294,7 +289,7 @@ Signal.prototype._unsubscribe = function (node) {
}
};

Signal.prototype.subscribe = function (fn) {
signalProto.subscribe = function (fn) {
const signal = this;
return effect(function (this: Effect) {
const value = signal.value;
Expand All @@ -308,23 +303,23 @@ Signal.prototype.subscribe = function (fn) {
});
};

Signal.prototype.valueOf = function () {
signalProto.valueOf = function () {
return this.value;
};

Signal.prototype.toString = function () {
return this.value + "";
signalProto.toString = function () {
return "" + this.value;
};

Signal.prototype.toJSON = function () {
signalProto.toJSON = function () {
return this.value;
};

Signal.prototype.peek = function () {
signalProto.peek = function () {
return this._value;
};

Object.defineProperty(Signal.prototype, "value", {
Object.defineProperty(signalProto, "value", {
get() {
const node = addDependency(this);
if (node !== undefined) {
Expand All @@ -334,12 +329,12 @@ Object.defineProperty(Signal.prototype, "value", {
},
set(this: Signal, value) {
if (evalContext instanceof Computed) {
mutationDetected();
throw Error("Computed side effect detected");
}

if (value !== this._value) {
if (batchIteration > 100) {
cycleDetected();
throw Error("Cycle detected");
}

this._value = value;
Expand Down Expand Up @@ -490,17 +485,17 @@ declare class Computed<T = any> extends Signal<T> {
}

function Computed(this: Computed, compute: () => unknown) {
Signal.call(this, undefined);
Signal.call(this);

this._compute = compute;
this._sources = undefined;
this._globalVersion = globalVersion - 1;
this._flags = OUTDATED;
}

Computed.prototype = new Signal() as Computed;
const computedProto = (Computed.prototype = new Signal() as Computed);

Computed.prototype._refresh = function () {
computedProto._refresh = function () {
this._flags &= ~NOTIFIED;

if (this._flags & RUNNING) {
Expand Down Expand Up @@ -553,7 +548,7 @@ Computed.prototype._refresh = function () {
return true;
};

Computed.prototype._subscribe = function (node) {
computedProto._subscribe = function (node) {
if (this._targets === undefined) {
this._flags |= OUTDATED | TRACKING;

Expand All @@ -567,13 +562,13 @@ Computed.prototype._subscribe = function (node) {
node._source._subscribe(node);
}
}
Signal.prototype._subscribe.call(this, node);
signalProto._subscribe.call(this, node);
};

Computed.prototype._unsubscribe = function (node) {
computedProto._unsubscribe = function (node) {
// Only run the unsubscribe step if the computed signal has any subscribers.
if (this._targets !== undefined) {
Signal.prototype._unsubscribe.call(this, node);
signalProto._unsubscribe.call(this, node);

// Computed signal unsubscribes from its dependencies when it loses its last subscriber.
// This makes it possible for unreferences subgraphs of computed signals to get garbage collected.
Expand All @@ -591,7 +586,7 @@ Computed.prototype._unsubscribe = function (node) {
}
};

Computed.prototype._notify = function () {
computedProto._notify = function () {
if (!(this._flags & NOTIFIED)) {
this._flags |= OUTDATED | NOTIFIED;

Expand All @@ -605,20 +600,20 @@ Computed.prototype._notify = function () {
}
};

Computed.prototype.peek = function () {
computedProto.peek = function () {
if (!this._refresh()) {
cycleDetected();
throw Error("Cycle detected");
}
if (this._flags & HAS_ERROR) {
throw this._value;
}
return this._value;
};

Object.defineProperty(Computed.prototype, "value", {
Object.defineProperty(computedProto, "value", {
get() {
if (this._flags & RUNNING) {
cycleDetected();
throw Error("Cycle detected");
}
const node = addDependency(this);
this._refresh();
Expand Down Expand Up @@ -733,7 +728,7 @@ Effect.prototype._callback = function () {

Effect.prototype._start = function () {
if (this._flags & RUNNING) {
cycleDetected();
throw Error("Cycle detected");
}
this._flags |= RUNNING;
this._flags &= ~DISPOSED;
Expand Down Expand Up @@ -775,12 +770,4 @@ function effect(compute: () => unknown | EffectCleanup): () => void {
return effect._dispose.bind(effect);
}

export {
signal,
computed,
effect,
batch,
Signal,
ReadonlySignal,
untracked,
};
export { signal, computed, effect, batch, Signal, ReadonlySignal, untracked };
4 changes: 2 additions & 2 deletions packages/core/test/signal.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ describe("effect()", () => {
c.value;
});

expect(fn).to.throw(/Computed cannot have side-effects/);
expect(fn).to.throw(/Computed side effect detected/);
});

it("should allow disposing the effect multiple times", () => {
Expand Down Expand Up @@ -950,7 +950,7 @@ describe("computed()", () => {
const a: Signal = signal(v);
const c: Signal = computed(() => a.value++);

expect(() => c.value).to.throw(/Computed cannot have side-effects/);
expect(() => c.value).to.throw(/Computed side effect detected/);
expect(a.value).to.equal(v);
});

Expand Down
Loading