0
# Dedupe Mixin
1
2
Dedupe Mixin provides a utility function for automatically deduplicating JavaScript class mixins to prevent duplicate application of the same mixin in an inheritance chain. It uses a WeakMap to track which mixins have been applied to which classes, ensuring that each mixin is only applied once even when multiple inheritance paths attempt to apply the same mixin.
3
4
## Package Information
5
6
- **Package Name**: @open-wc/dedupe-mixin
7
- **Package Type**: npm
8
- **Language**: JavaScript (ES modules)
9
- **Installation**: `npm install @open-wc/dedupe-mixin`
10
11
## Core Imports
12
13
```javascript
14
import { dedupeMixin } from '@open-wc/dedupe-mixin';
15
```
16
17
For CommonJS (if bundled/transpiled):
18
19
```javascript
20
const { dedupeMixin } = require('@open-wc/dedupe-mixin');
21
```
22
23
## Basic Usage
24
25
```javascript
26
import { dedupeMixin } from '@open-wc/dedupe-mixin';
27
28
// Create a mixin function
29
const LoggingMixin = (superClass) => class extends superClass {
30
log(message) {
31
console.log(`[${this.constructor.name}] ${message}`);
32
}
33
};
34
35
// Wrap with dedupeMixin to prevent duplicate application
36
const DedupedLoggingMixin = dedupeMixin(LoggingMixin);
37
38
// Create a base class
39
class BaseElement extends HTMLElement {
40
constructor() {
41
super();
42
this.attachShadow({ mode: 'open' });
43
}
44
}
45
46
// Apply the mixin once
47
class ComponentA extends DedupedLoggingMixin(BaseElement) {
48
connectedCallback() {
49
this.log('ComponentA connected');
50
}
51
}
52
53
// Apply the mixin again - it will be deduplicated
54
class ComponentB extends DedupedLoggingMixin(ComponentA) {
55
connectedCallback() {
56
super.connectedCallback();
57
this.log('ComponentB connected');
58
}
59
}
60
61
// Only one LoggingMixin is applied in the inheritance chain
62
const component = new ComponentB();
63
```
64
65
## Capabilities
66
67
### Mixin Deduplication
68
69
Wraps a mixin function to ensure it is only applied once in any inheritance chain.
70
71
```javascript { .api }
72
/**
73
* Apply each mixin in the chain to make sure they are not applied more than once to the final class.
74
* @param {function} mixin - Mixin to be applied
75
* @returns {function} Mixed class factory with mixin applied only once
76
*/
77
function dedupeMixin(mixin);
78
```
79
80
The `dedupeMixin` function:
81
- Takes a mixin function as input
82
- Returns a new function that applies the mixin only if it hasn't been applied before
83
- Uses a WeakMap internally to track applied mixins without memory leaks
84
- Works across complex inheritance hierarchies
85
- Prevents duplicate behavior, performance issues, and unexpected side effects
86
87
**Usage Examples:**
88
89
```javascript
90
import { dedupeMixin } from '@open-wc/dedupe-mixin';
91
92
// Define a mixin
93
const TimestampMixin = (superClass) => class extends superClass {
94
getTimestamp() {
95
return new Date().toISOString();
96
}
97
};
98
99
// Create deduped version
100
const DedupedTimestampMixin = dedupeMixin(TimestampMixin);
101
102
// Multiple applications - only applies once
103
class Base {}
104
class A extends DedupedTimestampMixin(Base) {}
105
class B extends DedupedTimestampMixin(A) {} // Mixin not applied again
106
107
const instance = new B();
108
console.log(instance.getTimestamp()); // Works correctly
109
```
110
111
```javascript
112
// Complex inheritance with multiple mixins
113
const MixinA = dedupeMixin((superClass) => class extends superClass {
114
featureA() { return 'A'; }
115
});
116
117
const MixinB = dedupeMixin((superClass) => class extends superClass {
118
featureB() { return 'B'; }
119
});
120
121
const MixinC = dedupeMixin((superClass) => class extends superClass {
122
featureC() { return 'C'; }
123
});
124
125
// Compose mixins - each only applied once despite multiple paths
126
const ComposedMixin = (superClass) => MixinA(MixinB(MixinC(superClass)));
127
const AnotherMixin = (superClass) => MixinC(MixinA(MixinB(superClass)));
128
129
class Final extends AnotherMixin(ComposedMixin(Base)) {}
130
// Each mixin (A, B, C) is only applied once despite multiple inheritance paths
131
```
132
133
## Types
134
135
```typescript { .api }
136
/**
137
* Generic constructor type for class constructors
138
*/
139
type Constructor<T> = new (...args: any[]) => T;
140
141
/**
142
* Dedupe mixin function with TypeScript support
143
* @param mixin - A mixin function that extends a constructor
144
* @returns The same mixin function with deduplication behavior
145
*/
146
declare function dedupeMixin<T extends (s: Constructor<any>) => any>(mixin: T): T;
147
```
148
149
The TypeScript definitions provide:
150
- Full type safety with generic type preservation
151
- Proper inference of mixin return types
152
- Constructor type utility for defining mixin signatures
153
- Maintains the original mixin function signature while adding deduplication