0
# Plugin System
1
2
RequireJS provides an extensible plugin system that allows loading and processing non-JavaScript resources such as text files, CSS, HTML templates, and other custom content types. Plugins transform resources during both development and build processes.
3
4
## Plugin Interface
5
6
All RequireJS plugins must implement a standardized interface for loading and processing resources.
7
8
### Core Plugin Methods
9
10
#### load()
11
Main method for loading and processing resources.
12
13
```javascript { .api }
14
load(name, require, onload, config)
15
```
16
17
**Parameters:**
18
- `name` (String) - Resource name/path (without plugin prefix)
19
- `require` (Function) - Local require function for loading dependencies
20
- `onload` (Function) - Callback to call when resource is loaded
21
- `config` (Object) - RequireJS configuration object
22
23
**Usage Example:**
24
25
```javascript
26
define({
27
load: function(name, require, onload, config) {
28
// Load and process the resource
29
const url = require.toUrl(name + '.txt');
30
31
// Fetch the resource
32
fetch(url).then(function(response) {
33
return response.text();
34
}).then(function(text) {
35
// Process the text and return result
36
onload(text.toUpperCase());
37
}).catch(function(error) {
38
onload.error(error);
39
});
40
}
41
});
42
```
43
44
#### write() (Build Support)
45
Optional method for writing optimized resources during build process.
46
47
```javascript { .api }
48
write(pluginName, moduleName, write, config)
49
```
50
51
**Parameters:**
52
- `pluginName` (String) - Name of the plugin
53
- `moduleName` (String) - Name of the resource being processed
54
- `write` (Function) - Function to call to write optimized content
55
- `config` (Object) - Build configuration object
56
57
**Usage Example:**
58
59
```javascript
60
define({
61
// Store processed content during build
62
buildMap: {},
63
64
load: function(name, require, onload, config) {
65
// Load and process resource
66
const processedContent = processResource(name);
67
68
// Store for build if needed
69
if (config.isBuild) {
70
this.buildMap[name] = processedContent;
71
}
72
73
onload(processedContent);
74
},
75
76
write: function(pluginName, moduleName, write, config) {
77
if (this.buildMap.hasOwnProperty(moduleName)) {
78
const content = this.buildMap[moduleName];
79
// Write as optimized module
80
write.asModule(pluginName + "!" + moduleName,
81
"define(function() { return " + JSON.stringify(content) + "; });");
82
}
83
}
84
});
85
```
86
87
#### normalize() (Optional)
88
Normalize resource names for consistent handling.
89
90
```javascript { .api }
91
normalize(name, normalize)
92
```
93
94
**Parameters:**
95
- `name` (String) - Resource name to normalize
96
- `normalize` (Function) - Normalization function provided by RequireJS
97
98
**Returns:** Normalized resource name
99
100
**Usage Example:**
101
102
```javascript
103
define({
104
normalize: function(name, normalize) {
105
// Remove file extension if present
106
if (name.substr(name.length - 4) === '.txt') {
107
name = name.substr(0, name.length - 4);
108
}
109
110
// Use RequireJS normalization
111
return normalize(name);
112
}
113
});
114
```
115
116
## Plugin Usage
117
118
### Loading Resources with Plugins
119
120
Use the plugin syntax `pluginName!resourceName` to load resources:
121
122
```javascript
123
// Load text file using text plugin
124
require(['text!templates/header.html'], function(headerHtml) {
125
document.getElementById('header').innerHTML = headerHtml;
126
});
127
128
// Load multiple resources
129
require(['text!data.json', 'text!template.html'], function(jsonText, templateHtml) {
130
const data = JSON.parse(jsonText);
131
// Use data and template
132
});
133
134
// Use in module definitions
135
define(['text!config.json'], function(configText) {
136
const config = JSON.parse(configText);
137
return {
138
apiUrl: config.apiUrl,
139
version: config.version
140
};
141
});
142
```
143
144
### Plugin Configuration
145
146
Configure plugin-specific options through RequireJS configuration:
147
148
```javascript
149
requirejs.config({
150
// Plugin-specific configuration
151
text: {
152
useXhr: function() {
153
// Force XHR usage in all environments
154
return true;
155
}
156
},
157
158
// Custom plugin configuration
159
myPlugin: {
160
processingOptions: {
161
minify: true,
162
stripComments: false
163
}
164
}
165
});
166
```
167
168
## Built-in Plugin Examples
169
170
### Text Plugin Pattern
171
172
A typical implementation for loading text resources:
173
174
```javascript
175
define(['module'], function(module) {
176
'use strict';
177
178
var fetchText = function(url, callback) {
179
// Environment-specific text fetching
180
if (typeof window !== 'undefined') {
181
// Browser implementation
182
var xhr = new XMLHttpRequest();
183
xhr.open('GET', url, true);
184
xhr.onreadystatechange = function() {
185
if (xhr.readyState === 4) {
186
callback(xhr.responseText);
187
}
188
};
189
xhr.send(null);
190
} else if (typeof process !== 'undefined') {
191
// Node.js implementation
192
var fs = require.nodeRequire('fs');
193
callback(fs.readFileSync(url, 'utf8'));
194
}
195
};
196
197
var buildMap = {};
198
199
return {
200
load: function(name, req, onload, config) {
201
var url = req.toUrl(name);
202
203
fetchText(url, function(text) {
204
// Store for build optimization
205
if (config.isBuild) {
206
buildMap[name] = text;
207
}
208
209
onload(text);
210
});
211
},
212
213
write: function(pluginName, moduleName, write, config) {
214
if (buildMap.hasOwnProperty(moduleName)) {
215
var text = buildMap[moduleName];
216
write.asModule(pluginName + "!" + moduleName,
217
"define(function() { return " + JSON.stringify(text) + "; });");
218
}
219
},
220
221
version: '1.0.0'
222
};
223
});
224
```
225
226
### JSON Plugin Example
227
228
```javascript
229
define({
230
load: function(name, req, onload, config) {
231
req(['text!' + name + '.json'], function(text) {
232
try {
233
onload(JSON.parse(text));
234
} catch (e) {
235
onload.error(new Error('Invalid JSON in ' + name + ': ' + e.message));
236
}
237
});
238
}
239
});
240
```
241
242
### CSS Plugin Example
243
244
```javascript
245
define({
246
load: function(name, req, onload, config) {
247
var url = req.toUrl(name + '.css');
248
249
if (typeof window !== 'undefined') {
250
// Browser: inject CSS via link tag
251
var link = document.createElement('link');
252
link.rel = 'stylesheet';
253
link.href = url;
254
link.onload = function() { onload(true); };
255
document.head.appendChild(link);
256
} else {
257
// Node.js: just signal completion
258
onload(true);
259
}
260
}
261
});
262
```
263
264
## Advanced Plugin Features
265
266
### Conditional Resource Loading
267
268
```javascript
269
define({
270
load: function(name, req, onload, config) {
271
// Check environment or feature availability
272
if (typeof window !== 'undefined' && window.WebGL) {
273
// Load WebGL version
274
req(['text!' + name + '.webgl.glsl'], onload);
275
} else {
276
// Load fallback version
277
req(['text!' + name + '.fallback.txt'], onload);
278
}
279
}
280
});
281
```
282
283
### Resource Transformation
284
285
```javascript
286
define({
287
load: function(name, req, onload, config) {
288
req(['text!' + name + '.template'], function(template) {
289
// Transform template (e.g., precompile Handlebars)
290
const compiled = Handlebars.compile(template);
291
onload(compiled);
292
});
293
},
294
295
write: function(pluginName, moduleName, write, config) {
296
// Write precompiled template to build
297
if (buildMap.hasOwnProperty(moduleName)) {
298
const compiledTemplate = buildMap[moduleName];
299
write.asModule(pluginName + "!" + moduleName,
300
"define(['handlebars'], function(Handlebars) { return " +
301
compiledTemplate.toString() + "; });");
302
}
303
}
304
});
305
```
306
307
### Error Handling
308
309
```javascript
310
define({
311
load: function(name, req, onload, config) {
312
const url = req.toUrl(name);
313
314
fetchResource(url, function(result, error) {
315
if (error) {
316
// Signal error to RequireJS
317
onload.error(new Error('Failed to load ' + name + ': ' + error.message));
318
} else {
319
onload(result);
320
}
321
});
322
}
323
});
324
```
325
326
## Build System Integration
327
328
### Plugin Optimization
329
330
Plugins can be optimized during the build process to improve runtime performance:
331
332
```javascript
333
// Build configuration
334
{
335
// Replace plugin calls with static content
336
stubModules: ['text', 'json'],
337
338
// Optimize all plugin resources
339
optimizeAllPluginResources: true,
340
341
// Plugin-specific build settings
342
inlineText: true // Inline text! resources
343
}
344
```
345
346
### Build-Time Resource Processing
347
348
```javascript
349
define({
350
load: function(name, req, onload, config) {
351
req(['text!' + name], function(content) {
352
let processed = content;
353
354
if (config.isBuild) {
355
// Build-time processing (minification, compilation, etc.)
356
processed = minifyContent(content);
357
buildMap[name] = processed;
358
}
359
360
onload(processed);
361
});
362
},
363
364
write: function(pluginName, moduleName, write, config) {
365
if (buildMap.hasOwnProperty(moduleName)) {
366
write.asModule(pluginName + "!" + moduleName,
367
"define(function() { return " + JSON.stringify(buildMap[moduleName]) + "; });");
368
}
369
}
370
});
371
```
372
373
## Plugin Development Best Practices
374
375
### Environment Detection
376
377
```javascript
378
define({
379
load: function(name, req, onload, config) {
380
if (typeof window !== 'undefined') {
381
// Browser environment
382
loadViaBrowser(name, req, onload);
383
} else if (typeof process !== 'undefined') {
384
// Node.js environment
385
loadViaNode(name, req, onload);
386
} else {
387
// Other environments (Rhino, Nashorn, etc.)
388
loadViaGeneric(name, req, onload);
389
}
390
}
391
});
392
```
393
394
### Resource Caching
395
396
```javascript
397
define({
398
cache: {},
399
400
load: function(name, req, onload, config) {
401
if (this.cache[name]) {
402
// Return cached result
403
onload(this.cache[name]);
404
return;
405
}
406
407
// Load and cache
408
loadResource(name, req, function(result) {
409
this.cache[name] = result;
410
onload(result);
411
}.bind(this));
412
}
413
});
414
```
415
416
### Version Management
417
418
```javascript
419
define({
420
version: '2.1.0',
421
422
load: function(name, req, onload, config) {
423
// Plugin implementation
424
},
425
426
// Optional: API compatibility check
427
loadingFinished: function() {
428
console.log('Plugin v' + this.version + ' loaded successfully');
429
}
430
});
431
```
432
433
## Types
434
435
```javascript { .api }
436
interface RequirePlugin {
437
load(name: string, require: Function, onload: Function, config: Object): void;
438
normalize?(name: string, normalize: Function): string;
439
write?(pluginName: string, moduleName: string, write: Function, config: Object): void;
440
version?: string;
441
}
442
443
interface PluginOnload extends Function {
444
(result: any): void;
445
error(err: Error): void;
446
fromText(name: string, text: string): void;
447
}
448
449
interface PluginWrite extends Function {
450
(content: string): void;
451
asModule(moduleName: string, content: string): void;
452
}
453
```
454
455
The RequireJS plugin system provides a powerful foundation for extending module loading capabilities, enabling seamless integration of various resource types and custom processing logic into AMD-based applications.