fix(browser): Improve extension lifecycle for tree shaking#3164
fix(browser): Improve extension lifecycle for tree shaking#3164dustinbyrne merged 5 commits intomainfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| if (ext.webVitalsAutocapture) { | ||
| initTasks.push(() => { | ||
| this.webVitalsAutocapture = new ext.webVitalsAutocapture!(this) as WebVitalsAutocapture | ||
| }) | ||
| this.extensions.push((this.webVitalsAutocapture = new ext.webVitalsAutocapture(this))) | ||
| } | ||
|
|
||
| if (ext.exceptionObserver) { | ||
| initTasks.push(() => { | ||
| this.exceptionObserver = new ext.exceptionObserver!(this) as ExceptionObserver | ||
| this.exceptionObserver.startIfEnabledOrStop() | ||
| }) | ||
| this.extensions.push((this.exceptionObserver = new ext.exceptionObserver(this))) | ||
| } | ||
|
|
||
| if (ext.deadClicksAutocapture) { | ||
| this.extensions.push( | ||
| (this.deadClicksAutocapture = new ext.deadClicksAutocapture(this, isDeadClicksEnabledForAutocapture)) | ||
| ) | ||
| } |
There was a problem hiding this comment.
WebVitalsAutocapture, ExceptionObserver, and DeadClicksAutocapture don't have initialize() methods and call their startup logic in constructors. This means they initialize immediately (synchronously) when constructed here, unlike other extensions which have deferred initialization via initialize() being called in initTasks (lines 761-766).
This creates inconsistent initialization timing across extensions and changes behavior compared to the old code where their construction was deferred via initTasks. Consider adding initialize() methods to these three classes (moving startup logic out of constructors) to ensure all extensions follow the unified lifecycle pattern.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
There was a problem hiding this comment.
This is fine; I don't see any reason to need to change this. Calls to initialize() are guarded anyway, it won't call it if it doesn't have an initialize function.
|
Size Change: -2.75 kB (-0.04%) Total Size: 6.71 MB
ℹ️ View Unchanged
|
|
pr has a conflict otherwise all good |
Introduce an Extension interface with optional initialize() and onRemoteConfig() lifecycle hooks. Existing conditionally-constructed extensions now implement this interface and are tracked in an extensions[] array, enabling unified lifecycle dispatch.
918b72e to
570817b
Compare
Problem
Extensions in posthog-js are tree-shakable via
__extensionClasses, but the lifecycle is ad-hoc. Each extension has its own startup pattern (startIfEnabled(),startIfEnabledOrStop(),init(),loadIfEnabled(), etc.), and_onRemoteConfigdispatches to each one with individual hardcoded calls. This means posthog-core has to know about every extension individually, and adding or removing one requires touching multiple places. A unified interface lets us treat all extensions equally and call them in a loop.This is PR 1/3
Changes
Introduces an
Extensioninterface with standardized lifecycle hooks (initialize()andonRemoteConfig()) and anextensions: Extension[]array on the PostHog class.Extensioninterface (extensions/types.ts): Definesinitialize?()andonRemoteConfig?(config)hooks, plus anExtensionConstructor<T>type replacing the oldExtension<T>alias in types.ts._initExtensionspushes constructed extensions to the array and callsinitialize()._onRemoteConfigiterates the array instead of calling each extension individually (surveys, logs, conversations, and exceptions still use hardcoded calls since they aren't tree-shakable yet)._replaceExtensionhelper: Used when session recording is recreated during cookieless opt-in — removes old instance from array and initializes the new one.implement Extensionwith aninitialize()method wrapping their existing startup logic.ENTRYenv var to filter entrypoints during build.No behavioral changes. This is a structural refactor of code that already worked via
__extensionClasses.Bundle size
Release info Sub-libraries affected
Libraries affected
Checklist
If releasing new changes
pnpm changesetto generate a changeset file