Open
Conversation
added 2 commits
March 29, 2026 16:23
Add shared terser config with passes:3, hoist_vars:true for better gzip. Add freeze:false on all IIFE outputs to remove Object.freeze() wrapper.
Replace import * as with named imports {start, stop} in module arrays
across clarity.ts, data/index.ts, and all sub-module index files.
Eliminate dom[] dynamic dispatch in node.ts with domCall helper.
Removes rollup namespace objects that contained ALL module exports
when only {start, stop} was needed.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR focuses on reducing clarity-js minified bundle size by adjusting the Rollup/Terser build pipeline and refactoring runtime code patterns to be more minifier/tree-shaker friendly.
Changes:
- Optimize Rollup IIFE outputs + Terser configuration (shared options, more compress passes, disable Rollup namespace
freeze). - Replace
import * as Xnamespace imports with named imports to eliminate Rollup-generated namespace objects. - Apply minifier-friendly refactors (dedup helpers,
indexOf→includes, template literals→string concatenation, consolidatepush()calls).
Reviewed changes
Copilot reviewed 43 out of 43 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/clarity-js/src/performance/observer.ts | Switches to .includes and string coercion tweaks for smaller output. |
| packages/clarity-js/src/performance/index.ts | Uses named imports to avoid Rollup namespace objects. |
| packages/clarity-js/src/performance/encode.ts | Consolidates repeated tokens.push(...) calls. |
| packages/clarity-js/src/layout/style.ts | Refactors stylesheet method proxying and shortens internal property keys. |
| packages/clarity-js/src/layout/selector.ts | Converts template literals and indexOf patterns to smaller forms. |
| packages/clarity-js/src/layout/schema.ts | Uses .includes for JSON-LD type normalization. |
| packages/clarity-js/src/layout/node.ts | Replaces DOM namespace import with named imports; avoids dynamic property access. |
| packages/clarity-js/src/layout/mutation.ts | Deduplicates CSS rule proxy logic and uses .includes for queue checks. |
| packages/clarity-js/src/layout/index.ts | Uses named imports for module lifecycle calls. |
| packages/clarity-js/src/layout/encode.ts | Consolidates token pushes and removes small helper for minified output savings. |
| packages/clarity-js/src/layout/dom.ts | Replaces some template literal usage and indexOf comparisons with smaller constructs. |
| packages/clarity-js/src/layout/custom.ts | Renames global override storage to a shorter key and keeps define proxy behavior. |
| packages/clarity-js/src/layout/animation.ts | Deduplicates override setup and shortens internal property keys. |
| packages/clarity-js/src/interaction/index.ts | Uses named imports for start/stop/observe to remove namespace objects. |
| packages/clarity-js/src/interaction/encode.ts | Consolidates token pushes and minor string coercion changes. |
| packages/clarity-js/src/interaction/click.ts | Uses .includes for shorter membership checks. |
| packages/clarity-js/src/interaction/change.ts | Uses .includes for exclude-list membership check. |
| packages/clarity-js/src/insight/snapshot.ts | Uses .includes for tag filtering. |
| packages/clarity-js/src/insight/encode.ts | Replaces template literal string building with concatenation. |
| packages/clarity-js/src/diagnostic/internal.ts | Replaces template literals and indexOf checks with smaller constructs. |
| packages/clarity-js/src/diagnostic/index.ts | Uses named imports for module lifecycle calls. |
| packages/clarity-js/src/diagnostic/fraud.ts | Uses .includes for history membership. |
| packages/clarity-js/src/diagnostic/encode.ts | Consolidates repeated tokens.push(...) calls. |
| packages/clarity-js/src/data/variable.ts | Replaces template literals with string concatenation. |
| packages/clarity-js/src/data/upload.ts | Replaces template literals with concatenation in payload assembly and errors. |
| packages/clarity-js/src/data/signal.ts | Removes wrapper to simplify parse/dispatch logic. |
| packages/clarity-js/src/data/metric.ts | Deduplicates metric initialization via helper. |
| packages/clarity-js/src/data/metadata.ts | Replaces .toString() and template literal usage with shorter coercions/concat. |
| packages/clarity-js/src/data/index.ts | Uses named imports + inline module objects to avoid namespace objects. |
| packages/clarity-js/src/data/encode.ts | Consolidates token pushes and reduces repeated property chains. |
| packages/clarity-js/src/data/dimension.ts | Uses "" + value and .includes for shorter output. |
| packages/clarity-js/src/data/cookie.ts | Replaces template literals with concatenation in cookie assembly. |
| packages/clarity-js/src/data/consent.ts | Uses "" + consent instead of .toString(). |
| packages/clarity-js/src/data/compress.ts | Simplifies stream consumption via Response(stream).arrayBuffer(). |
| packages/clarity-js/src/data/baseline.ts | Deduplicates pointer updates and uses Object.assign for state copying. |
| packages/clarity-js/src/core/task.ts | Replaces template literal key building with concatenation. |
| packages/clarity-js/src/core/scrub.ts | Replaces template literals with concatenation; small predicate refactor. |
| packages/clarity-js/src/core/report.ts | Uses .includes for history checks. |
| packages/clarity-js/src/core/measure.ts | Replaces template literal logging with concatenation. |
| packages/clarity-js/src/core/history.ts | Deduplicates history proxy setup via helper. |
| packages/clarity-js/src/core/dynamic.ts | Replaces template literal error message with concatenation. |
| packages/clarity-js/src/clarity.ts | Uses named imports for module lifecycle + inline module objects. |
| packages/clarity-js/rollup.config.ts | Adds shared Terser options, increases compression passes, disables Rollup freeze for IIFE outputs. |
Extract helpers to deduplicate repeated code: - baseline.ts: Object.assign + updatePointer helper - mutation.ts: proxyRule helper for CSS rule proxying - style.ts: proxyStyleMethod helper + simpler arraysEqual - history.ts: proxyHistory helper for pushState/replaceState - animation.ts: simplified overrideAnimationHelper - metric.ts: init() helper for count/sum dedup - compress.ts: Response API replacing manual stream reader - signal.ts: eliminate redundant parseSignals() wrapper - Shorten internal property names: clarityOverrides→__clr
Modernize syntax patterns across 26 source files for smaller minified output: - indexOf(x)>=0 → includes(x) across ~27 occurrences - Template literals → string concatenation (avoids ES5 .concat()) - Sequential tokens.push(a); push(b) → push(a, b) - .toString() → ""+x string coercion - Inline single-use str() helper in layout/encode.ts - Local alias for b.data in data/encode.ts
Restore important comments removed during refactoring that document module ordering constraints and inter-module dependencies. Add missing trailing newlines to files modified in earlier refactor commits. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
11f1ba2 to
c7305fc
Compare
added 2 commits
March 29, 2026 17:30
bbc095f to
9a2ee5d
Compare
malaref
reviewed
Apr 7, 2026
malaref
approved these changes
Apr 7, 2026
Niyibitanga
approved these changes
Apr 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Commit 1:
build: optimize terser config and rollup output optionspasses: 3— Runs terser compression 3 times. Each pass finds new optimization opportunities from the previous pass's output (e.g., inlining single-call-site functions, then eliminating the dead variables left behind).hoist_vars: true— Consolidates 379 scatteredvardeclarations into ~164 (mostly one declaration at the IIFE top). Costs 266 raw bytes for the preamble but saves ~98 gzip bytes because gzip compresses a singlevar t,e,n,...block better than hundreds of scatteredvarkeywords.freeze: falseon all 7 IIFE outputs — Removes oneObject.freeze()wrapper around the Clarity public API namespace object that Rollup generates. Saves ~15 raw bytes.terserOptsconfig — Extracted repeatedterser({output: {comments: false}})into a shared constant applied to all IIFE builds.Options evaluated and intentionally excluded:
toplevel: true— No-op in an IIFE (everything is already inside a function scope).unsafe_comps: true— Flips comparisons (a < b→b > a). Saves raw bytes but hurts gzip by +5 bytes because reversed comparisons create less common byte patterns.pure_getters: true— Assumes all property access has no side effects. Enables variable inlining (−70 gzip). Excluded because it's a global declaration that could conflict with Zone.js proxy behavior, browser extensions wrapping DOM objects, or future code adding getters.module: true— Tells terser the code is an ES module. Removes"use strict". Excluded because the IIFE is not an ES module — removing strict mode changes runtime semantics (thisin plain function calls becomeswindowinstead ofundefined).Commit 2:
refactor: eliminate rollup namespace objects via named importsReplaces
import * as X from "..."with named imports{ start, stop }where modules are only used inmodules[]arrays for lifecycle management.When Rollup sees
import * as X, it creates a runtime namespace object containing all exports from that module — even if onlystartandstopare used. By switching toimport { start, stop }, Rollup can tree-shake the namespace and only include what's needed.data/index.tswas the biggest win: 13 sub-module namespaces (baseline,dimension,variable,limit,summary,cookie,consent,metadata,envelope,upload,ping,upgrade,extract) were converted from full namespace objects to minimal{start, stop}pairs. Thecompute()calls that previously went through the namespace were converted to direct named function imports.layout/node.tshad a special case:dom[call]used dynamic property access on thedomnamespace, which forced Rollup to keep the entire namespace as a runtime object. Replaced with adomCall()helper using explicit if/else dispatch on a boolean flag, allowing Rollup to inline everything.Commit 3:
refactor: deduplicate repeated code patterns and simplify modulesbaseline.ts— UsedObject.assignfor baseline state copy instead of 20+ individual property assignments. ExtractedupdatePointerhelper to deduplicate 3 identical pointer-update blocks.mutation.ts— ExtractedproxyRulehelper to deduplicate 4 nearly identical CSS rule proxy blocks (insertRule/deleteRuleonCSSStyleSheetandCSSMediaRule).style.ts— ExtractedproxyStyleMethodhelper forCSSStyleSheetmethod proxying. SimplifiedarraysEqualcomparison.history.ts— ExtractedproxyHistoryhelper to deduplicatepushState/replaceStateproxy setup.animation.ts— SimplifiedoverrideAnimationHelperto iterate over names array. Removed 5 unused module-level variables.metric.ts— Extractedinit()helper to deduplicate metric initialization checks acrosscount,sum, andmax.compress.ts— Replaced manualread()stream consumer loop (10 lines) withnew Response(stream).arrayBuffer()(1 line). Same browser support requirements, eliminates an entire function.signal.ts— Eliminated redundantparseSignals()wrapper function and simplified inner try/catch.clarityOverrides→__clr(20 occurrences),clarityAnimationId→__clrAId,clarityOperationCount→__clrOCnt,claritySheetId→__clrSId. These are internal properties attached to DOM elements/window, not part of any public API.Commit 4:
refactor: modernize syntax for smaller minified outputindexOf(x) >= 0→includes(x)— ~27 occurrences across 15+ files.includes()produces shorter minified output than theindexOf+ comparison pattern. The codebase already usesincludes()in existing code, so this doesn't change browser support requirements. Both use strict-equality-like comparison (SameValueZerovs===); the only difference isNaNhandling, which is irrelevant for string/tag comparisons.+concatenation — In files likeselector.ts,encode.ts,scrub.ts,dom.ts. When targeting ES5, TypeScript compiles template literals to.concat()chains which are verbose. Plain+concatenation produces shorter output.tokens.push()— Indiagnostic/encode.ts,interaction/encode.ts,layout/encode.ts,performance/encode.ts. Sequentialtokens.push(a); tokens.push(b); tokens.push(c)→tokens.push(a, b, c). Eliminates repeated method lookups..toString()→"" + x— 6 occurrences inmetadata.ts,consent.ts,observer.ts,data/encode.ts.""+xminifies to 4 characters vs.toString()which stays at 12.str()helper — Single-use wrapper function inlayout/encode.tseliminated.b.data— Indata/encode.ts, aliased deeply nestedb.datato a local variabledin the baseline encoding case, eliminating 25 repeated.data.property chains.