Singleton Pattern Packages
Singleton Pattern Packages
Singleton pattern packages expect only one instance to exist within an application. Packages like React, styled-components, and emotion rely on shared state or context that breaks when multiple instances exist. Design systems must handle these packages carefully to avoid causing duplicate installations in consumer projects.
What Are Singleton Pattern Packages
Singleton pattern packages are libraries designed to have exactly one instance per application. They typically use global state, context mechanisms, or module-level variables that assume uniqueness. When multiple instances exist, these mechanisms fail.
React is the most common example. React’s hooks, context, and reconciler depend on a single React instance. Two React instances cause hooks to throw errors, context to not propagate between components using different instances, and reconciliation to fail.
How Singleton Pattern Packages Work
Understanding why singletons break with multiple instances helps prevent issues. Several technical patterns create singleton dependencies.
Module-level state expects uniqueness. Code like let currentInstance = null assumes only one module instance exists. Multiple instances each have their own currentInstance, causing state divergence.
Context relies on object identity. React’s context uses object identity to match providers and consumers. Components using different React instances have different context objects that do not match.
Internal registries assume global scope. Hooks registration in React, theme contexts in styled-components, and cache instances in data libraries all assume single instances. Multiple instances create isolated registries that cannot interact.
Key Considerations
- Always use peer dependencies for singleton packages
- Externalize singletons in build output
- Test for singleton violations in consumer conditions
- Document singleton requirements clearly
- Consider which packages in the design system are singletons
Common Questions
How should design systems handle singleton dependencies?
Design systems must prevent bundling singletons to avoid causing duplicates. Several practices ensure proper singleton handling.
Peer dependencies declare singleton requirements. Rather than regular dependencies, singletons should be peer dependencies. This makes consumers provide the package, ensuring only their version exists.
Build externalization prevents bundling. Build tools should be configured to externalize peer dependencies. Webpack’s externals, Rollup’s external, and similar configurations ensure singletons are not included in the design system bundle.
Peer dependency ranges should be broad. Supporting multiple versions (^17.0.0 || ^18.0.0) lets consumers use their preferred version. Narrow ranges might force consumers to install versions conflicting with other dependencies.
Testing should simulate consumer environments. Running tests with the design system built and installed as a dependency (rather than as source code) reveals singleton issues before release.
What symptoms indicate singleton violations?
Singleton violations cause various symptoms depending on the package involved. Recognizing these patterns helps diagnose issues quickly.
React singleton violations produce specific errors. “Invalid hook call” errors, “Cannot read property ‘ReactCurrentOwner’ of undefined,” and context not propagating often indicate multiple React instances.
Styled-components symptoms include styles not applying, ServerStyleSheet issues, and theme context failing. Multiple instances create separate style registries that do not coordinate.
General symptoms include context not working across component boundaries, global state not sharing, and features working in development but failing in production builds.
Debugging involves checking for multiple installations using npm ls, verifying build output does not include singletons, and comparing package versions in different parts of the application.
Summary
Singleton pattern packages require exactly one instance per application. Design systems must use peer dependencies and externalize singletons in builds to avoid causing duplicates. Symptoms of singleton violations include context failures, hook errors, and state isolation. Proper handling prevents these issues in consumer projects.
Buoy scans your codebase for design system inconsistencies before they ship
Detect Design Drift Free