Skip to content

Reduce count and work of signals - #1441

Draft
jacob-kofoed wants to merge 12 commits into
mainfrom
mm-signal-perf
Draft

jacob-kofoed wants to merge 12 commits into
mainfrom
mm-signal-perf

Conversation

@jacob-kofoed

Copy link
Copy Markdown
Contributor

No description provided.

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

✅ SSR Benchmark: No regressions or improvements — performance and memory are 1:1.

@github-actions

Copy link
Copy Markdown

✅ Issues Benchmark: No regressions or improvements — performance is 1:1.

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

⚡ Nordcraft Runtime Performance Benchmark

  • Noise & Equivalence Threshold: ±1.5% (Delta within CI or threshold reported as 1:1)
  • Bootstrap: 1000 iterations, seed 0
  • Base ref: 9b39b5b
  • Page Bundle Identity: Distinct build artifacts
  • Runtime Size: Base 92.1 KB vs. Head 92.8 KB (Delta: +732 B (+0.8%))
  • Runtime Size (compressed): Base 25.3 KB vs. Head 25.8 KB (Delta: +549 B (+2.1%))

✅ No regressions detected. Runtime performance is 1:1 or improved.

Scenario Base/Head time Delta Time Verdict Base/Head heap Delta Heap Verdict
mount-nordcraft 25.60 ms / 24.40 ms -4.69% (-1.20 ms) 🟢 Stable 4.13 MB / 2.49 MB -1.65 MB (-39.9%) 💾 -39.9% (-1.65 MB)
mount-pricing 6.10 ms / 5.50 ms -9.84% (-0.60 ms) 🚀 9.8% Faster 885.2 KB / 625.9 KB -259.3 KB (-29.3%) 💾 -29.3% (-259.3 KB)
reactive-clicks 10.90 ms / 10.10 ms -7.34% (-0.80 ms) 🚀 7.3% Faster 1.58 MB / 1.39 MB -198.2 KB (-12.3%) 💾 -12.3% (-198.2 KB)
list-repeat 17.00 ms / 14.50 ms -14.71% (-2.50 ms) 🚀 14.7% Faster 8.96 MB / 5.44 MB -3.52 MB (-39.3%) 💾 -39.3% (-3.52 MB)
custom-element 22.40 ms / 8.10 ms -63.84% (-14.30 ms) 🚀 63.8% Faster 13.47 MB / 1.05 MB -12.42 MB (-92.2%) 💾 -92.2% (-12.42 MB)
repeat-list-shuffle 17.80 ms / 10.40 ms -41.57% (-7.40 ms) 🚀 41.6% Faster 8.34 MB / 3.04 MB -5.30 MB (-63.5%) 💾 -63.5% (-5.30 MB)
lifecycle-churn 5.50 ms / 4.50 ms -18.18% (-1.00 ms) 🚀 18.2% Faster 1.80 MB / 1.13 MB -684.0 KB (-37.1%) 💾 -37.1% (-684.0 KB)
style-variables 19.00 ms / 16.60 ms -12.63% (-2.40 ms) 🚀 12.6% Faster 3.70 MB / 2.68 MB -1.02 MB (-27.5%) 💾 -27.5% (-1.02 MB)
context-propagation 12.20 ms / 8.50 ms -30.33% (-3.70 ms) 🚀 30.3% Faster 3.95 MB / 1.78 MB -2.18 MB (-55.0%) 💾 -55.0% (-2.18 MB)

@jacob-kofoed
jacob-kofoed force-pushed the mm-signal-perf branch 2 times, most recently from 12c6c9d to 7f75405 Compare October 27, 2026 09:58
@jacob-kofoed jacob-kofoed changed the title Better signal usage Reduce count and work of signals Oct 27, 2026
@jacob-kofoed
jacob-kofoed requested a balanced review from Copilot October 27, 2026 14:46

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved correctness regressions affect signal delivery, rendering, formula evaluation, and custom-element theme updates.

7 open issues
What changed in this PR

This PR reduces signal allocation and repeated work across runtime rendering, component initialization, and formula evaluation.

Changes:

  • Adds mapped subscriptions, lifecycle-scoped signal forks, and static-formula fast paths.
  • Streamlines DOM updates, repeated-node rendering, and subscription cleanup.
  • Reduces allocation and repeated evaluation in formula and API helpers, with focused tests.
File Description
packages/​runtime/​src/​utils/​subscribeCustomProperty.ts Adds direct custom-property binding and static-value handling.
packages/​runtime/​src/​utils/​nodes.ts Uses supported state-preserving DOM moves.
packages/​runtime/​src/​utils/​isStaticFormula.ts Adds preview-aware static-formula detection.
packages/​runtime/​src/​utils/​isStaticFormula.test.ts Tests static-formula detection.
packages/​runtime/​src/​utils/​getThemeSignal.ts Adds cookie-listener cleanup.
packages/​runtime/​src/​utils/​createFormulaCache.ts Creates entries only for cacheable formulas.
packages/​runtime/​src/​signal/​signal.ts Adds mapped subscriptions, forks, and shared update options.
packages/​runtime/​src/​signal/​signal.test.ts Tests mapped subscriptions and fork cleanup.
packages/​runtime/​src/​page.main.ts Streamlines page signals, theme initialization, and metadata updates.
packages/​runtime/​src/​events/​handleAction.ts Simplifies state updates and action cleanup.
packages/​runtime/​src/​editor/​previewAutofocus.ts Replaces intermediate signals with mapped subscriptions.
packages/​runtime/​src/​editor-preview.main.ts Uses a fork for preview-root lifecycle management.
packages/​runtime/​src/​custom-element/​ToddleComponent.ts Streamlines initialization and exposed formula signals.
packages/​runtime/​src/​context/​subscribeToContext.ts Initializes context directly and skips static subscriptions.
packages/​runtime/​src/​components/​renderComponent.ts Uses mapped attribute subscriptions.
packages/​runtime/​src/​components/​createText.ts Simplifies text subscriptions and DOM writes.
packages/​runtime/​src/​components/​createSlot.ts Uses forks for slotted-child signals.
packages/​runtime/​src/​components/​createNode.ts Optimizes conditional and repeated-node updates.
packages/​runtime/​src/​components/​createElement.ts Streamlines attributes, styles, children, and event processing.
packages/​runtime/​src/​components/​createComponent.ts Reduces initialization and attribute-update overhead.
packages/​runtime/​src/​api/​sortApis.ts Skips sorting trivial API lists.
packages/​runtime/​src/​api/​createAPIv2.ts Reuses forced-update options and simplifies state writes.
packages/​runtime/​src/​api/​createAPI.ts Replaces payload signals with mapped subscriptions.
packages/​lib/​formulas/​sort_by/​handler.ts Evaluates sorting keys once per item.
packages/​lib/​formulas/​get/​handler.ts Reuses the core path-lookup helper.
packages/​core/​src/​utils/​collections.test.ts Adds path-lookup coverage.
packages/​core/​src/​formula/​functionFormula.ts Conditionally supplies legacy context based on handler arity.

Review effort: Balanced

prev &&
Array.isArray(list) &&
list.length === prev.length &&
list.every((item, i) => item === prev[i]![1])
dataSignal.subscribeMap(
(data) => String(applyFormula(value, ctx, data, valuePath)),
(value) => {
elem.textContent = value
Comment thread packages/runtime/src/signal/signal.ts Outdated
for (const subscriber of this.subscribers) {
subscriber.notify(this.value)
}
this.subscribers.forEach(notifySubscriber, this.value)
Comment thread packages/runtime/src/signal/signal.ts Resolved
: { canCache: false, keys: [] }
let cacheInput: any
let cacheData: any
const cache: FormulaCache = {}
Comment on lines 64 to 66
dataSignal.subscriptions.push(() => {
cookieStore.removeEventListener('change', onCookieChange)
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants