ReviewOS

stacks/stx

The shipped client runtime logs on every signal.set: 41 unconditional console.log calls in dist/signals.js

#2107
Closed glennmichael123 opened this 8 days ago · {{ comments.length }} {{ comments.length === 1 ? 'comment' : 'comments' }}
8 days ago

dist/signals.js — the client runtime every stx page loads — ships with unconditional console.log calls. None are behind a debug flag.

grep -c "console.log(" node_modules/@stacksjs/stx/dist/signals.js
# 41

A sample:

console.log('[stx] signals runtime loading');
console.log('[stx] entering IIFE');
console.log('[stx] signal.set:', value, '->', newValue, 'effects:', effects.size);
console.log('[stx] :if dispatch on', el.tagName, ifAttr + '="' + ... );
console.log('[stx] bindIfChain entry:', head.tagName, 'branches:', ...);
console.log('[stx] bindIfChain SKIPPED (head already bound):', ...);

Checked on @stacksjs/stx 0.2.176. I looked for a guard around each one — a debug config read, a window.__stx_debug, anything — and found none: every [stx]-prefixed log in the file is unconditional.

Why it matters

signal.set logs on every state change. That is the hot path. A page with a few reactive inputs produces a log per keystroke; a :for over a list that updates produces one per mutation. The cost is not only noise — console.log of live object references keeps them reachable for devtools and is slow enough to show up when it runs per-keystroke.

It buries the app's own output. Any app debugging its own code now reads its logs through a stream of framework internals, and anything logged by the page is a needle in that. This is the part that actually cost us time — we lost a while scrolling past [stx] lines before realising they were not ours.

It is visible to end users. Anyone opening devtools on a production stx site sees the framework narrating its own binding decisions, including element tag names and attribute values.

Expected

Either strip these at build time, or gate them on an explicit opt-in — debug: true in stx.config.ts already exists as a concept and would be the natural switch. The messages are genuinely useful when you need them; bindIfChain SKIPPED (head already bound) is exactly what you would want while diagnosing a double-bind. They just should not be on by default.

A build-time strip is probably better than a runtime flag: it keeps the code readable and costs nothing at runtime.

Workaround

None that is good. An app can monkey-patch console.log to filter [stx], which is worse than the problem.

8 days ago

Verified against latest main c539a63 (STX 0.2.643 source), then built the packages and tested their actual archives in an isolated installed consumer. The reported production behavior does not reproduce on this version.

The distinction: dist/signals.js is the server-side runtime generator, not the browser asset served verbatim. Development runtime strings retain logging intentionally. generateSignalsRuntime() strips console.log before minification, including the fallback when minification fails. debug defaults to false. Default inline/cached, serve and production-build assets are quiet; debug: true explicitly opts into trace logs. console.warn and console.error remain intact.

Regression coverage pushed in 8ff3baa:

  • packages/stx/test/signals/runtime-log-stripping.test.ts executes the runtime and verifies 20 signal updates notify subscribers without any console.log; the debug variant is a positive control that does log.
  • packages/stx/test/build/build-assets.test.ts checks default build/serve/cached assets and explicit debug selection.
  • scripts/installed-package-smoke.ts verifies runtime output from packed/installed artifacts, not checkout source or a grep of generator strings.

Validation: 1,672 passed / 0 failed across 208 signals/build test files; full package build, installed-package smoke, typecheck, changed-file lint and formatting passed. New remote CI is pending.

Closing as already resolved on the verified 0.2.643 source/build. This commit adds tests only; it does not claim a new runtime fix or a new npm release. The original report names 0.2.176. If traces remain on a current installation with debug disabled, please provide the actual served runtime URL/content and resolved package version so we can distinguish stale assets or dependency resolution from a new regression.

Sign in to comment on this issue.