0
# Utility Classes
1
2
Additional utilities for source compatibility and specialized use cases, including source-like object conversion and size-only sources.
3
4
## Capabilities
5
6
### CompatSource
7
8
Converts source-like objects into real Source instances, enabling compatibility with objects that implement the source interface but aren't actual Source instances.
9
10
```typescript { .api }
11
/**
12
* Converts source-like objects to real Sources
13
* @param sourceLike - Object implementing source-like interface
14
*/
15
class CompatSource extends Source {
16
constructor(sourceLike: SourceLike);
17
18
/**
19
* Static factory method that returns Source unmodified if already a Source,
20
* otherwise wraps in CompatSource
21
* @param sourceLike - Source or source-like object
22
* @returns Real Source instance
23
*/
24
static from(sourceLike: SourceLike): Source;
25
}
26
```
27
28
**Usage Examples:**
29
30
```javascript
31
const { CompatSource } = require("webpack-sources");
32
33
// Source-like object (not a real Source)
34
const sourceLike = {
35
source() {
36
return "console.log('from source-like');";
37
},
38
size() {
39
return 29;
40
},
41
map() {
42
return null;
43
}
44
};
45
46
// Convert to real Source
47
const compatSource = new CompatSource(sourceLike);
48
console.log(compatSource.source()); // "console.log('from source-like');"
49
console.log(compatSource instanceof Source); // true
50
51
// Static factory method - preferred approach
52
const source1 = CompatSource.from(sourceLike); // Wraps in CompatSource
53
const source2 = CompatSource.from(compatSource); // Returns as-is (already Source)
54
55
console.log(source1 !== sourceLike); // true - wrapped
56
console.log(source2 === compatSource); // true - not re-wrapped
57
58
// Use with objects that have partial source interface
59
const minimalSourceLike = {
60
source: () => "minimal content"
61
// size, map, etc. will use defaults
62
};
63
64
const minimal = CompatSource.from(minimalSourceLike);
65
console.log(minimal.size()); // Calculated from source content
66
console.log(minimal.map()); // null (default)
67
```
68
69
### SizeOnlySource
70
71
Source that only provides size information without actual content. Useful for tracking sizes without storing large content in memory.
72
73
```typescript { .api }
74
/**
75
* Source that only provides size information
76
* @param size - Size in bytes
77
*/
78
class SizeOnlySource extends Source {
79
constructor(size: number);
80
}
81
```
82
83
**Usage Examples:**
84
85
```javascript
86
const { SizeOnlySource } = require("webpack-sources");
87
88
// Create size-only source
89
const sizeOnly = new SizeOnlySource(1024);
90
91
console.log(sizeOnly.size()); // 1024
92
93
// Other methods throw errors - no actual content available
94
try {
95
sizeOnly.source(); // Throws: "Content and Map of this Source is not available (only size() is supported)"
96
} catch (e) {
97
console.log("Cannot get source:", e.message);
98
}
99
100
try {
101
sizeOnly.buffer(); // Throws same error
102
} catch (e) {
103
console.log("Cannot get buffer:", e.message);
104
}
105
106
try {
107
sizeOnly.map(); // Throws same error
108
} catch (e) {
109
console.log("Cannot get map:", e.message);
110
}
111
112
// Useful for size calculations without content
113
const totalSize = sources.reduce((sum, source) => {
114
return sum + source.size();
115
}, 0);
116
117
// Memory-efficient size tracking
118
const fileSizes = files.map(file =>
119
new SizeOnlySource(file.stats.size)
120
);
121
```
122
123
### Source-Like Interface
124
125
Interface definition for objects that can be converted to Sources via CompatSource.
126
127
```typescript { .api }
128
/**
129
* Interface for objects that can be converted to Sources
130
*/
131
interface SourceLike {
132
/** Required: Returns source content */
133
source(): string | Buffer;
134
135
/** Optional: Returns content as Buffer (auto-generated if missing) */
136
buffer?(): Buffer;
137
138
/** Optional: Returns size in bytes (calculated if missing) */
139
size?(): number;
140
141
/** Optional: Returns source map (defaults to null) */
142
map?(options?: MapOptions): RawSourceMap | null;
143
144
/** Optional: Returns both source and map (auto-generated if missing) */
145
sourceAndMap?(options?: MapOptions): SourceAndMap;
146
147
/** Optional: Updates hash (defaults to abstract error if missing) */
148
updateHash?(hash: HashLike): void;
149
}
150
```
151
152
**Complete Implementation Example:**
153
154
```javascript
155
const { CompatSource } = require("webpack-sources");
156
157
// Full source-like implementation
158
class CustomSourceLike {
159
constructor(content, filename) {
160
this.content = content;
161
this.filename = filename;
162
}
163
164
source() {
165
return this.content;
166
}
167
168
buffer() {
169
return Buffer.from(this.content, 'utf8');
170
}
171
172
size() {
173
return this.content.length;
174
}
175
176
map(options) {
177
// Custom source map generation
178
return {
179
version: 3,
180
sources: [this.filename],
181
names: [],
182
mappings: "AAAA",
183
file: this.filename
184
};
185
}
186
187
sourceAndMap(options) {
188
return {
189
source: this.source(),
190
map: this.map(options)
191
};
192
}
193
194
updateHash(hash) {
195
hash.update("CustomSourceLike");
196
hash.update(this.content);
197
}
198
}
199
200
const custom = new CustomSourceLike("console.log('test');", "test.js");
201
const source = CompatSource.from(custom);
202
203
console.log(source.source()); // "console.log('test');"
204
console.log(source.map().sources); // ["test.js"]
205
```
206
207
### Utility Usage Patterns
208
209
**Working with Unknown Sources:**
210
211
```javascript
212
const { CompatSource, Source } = require("webpack-sources");
213
214
function processAnySource(input) {
215
// Ensure we have a real Source instance
216
const source = CompatSource.from(input);
217
218
// Now we can safely use all Source methods
219
console.log("Size:", source.size());
220
console.log("Content:", source.source());
221
222
return source;
223
}
224
225
// Works with real Sources
226
processAnySource(new RawSource("test"));
227
228
// Works with source-like objects
229
processAnySource({
230
source: () => "custom content",
231
size: () => 14
232
});
233
```
234
235
**Size Tracking Without Content:**
236
237
```javascript
238
const { SizeOnlySource, ConcatSource } = require("webpack-sources");
239
240
class BuildTracker {
241
constructor() {
242
this.chunks = [];
243
}
244
245
addChunk(name, size) {
246
// Track size without storing content
247
this.chunks.push({
248
name,
249
source: new SizeOnlySource(size)
250
});
251
}
252
253
getTotalSize() {
254
return this.chunks.reduce((sum, chunk) => {
255
return sum + chunk.source.size();
256
}, 0);
257
}
258
259
getSummary() {
260
return this.chunks.map(chunk => ({
261
name: chunk.name,
262
size: chunk.source.size()
263
}));
264
}
265
}
266
267
const tracker = new BuildTracker();
268
tracker.addChunk("main.js", 45000);
269
tracker.addChunk("vendor.js", 120000);
270
271
console.log("Total size:", tracker.getTotalSize()); // 165000
272
console.log("Summary:", tracker.getSummary());
273
```
274
275
**Compatibility Layer:**
276
277
```javascript
278
const { CompatSource } = require("webpack-sources");
279
280
// Legacy system that returns source-like objects
281
function legacySourceProvider(filename) {
282
return {
283
source: () => fs.readFileSync(filename, 'utf8'),
284
// Missing other methods - CompatSource will provide defaults
285
};
286
}
287
288
// Modern system that needs real Sources
289
function modernProcessor(source) {
290
// Ensure compatibility
291
const realSource = CompatSource.from(source);
292
293
// Use full Source API
294
const content = realSource.source();
295
const buffer = realSource.buffer();
296
const size = realSource.size();
297
298
// Process...
299
}
300
301
// Bridge legacy and modern systems
302
const legacySource = legacySourceProvider("input.js");
303
modernProcessor(legacySource); // Works seamlessly
304
```