~caneypuggies/reformedchurcheslocator/couchapp-backbone

« back to all changes in this revision

Viewing changes to _attachments/js/vendor/requirejs/docs/plugins.html

  • Committer: Tim Black
  • Date: 2013-09-16 22:50:16 UTC
  • Revision ID: tim@alwaysreformed.com-20130916225016-zk8jiba25z33ew7h
Versioned Bower vendor directory

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<div id="directory" class="section">
 
2
<h1>Plugins</h1>
 
3
 
 
4
<ul class="index mono">
 
5
    <li class="hbox"><a href="#intro">Intro</a><span class="spacer boxFlex"></span><span class="sect">&sect; 1</span></li>
 
6
    <li class="hbox"><a href="#names">Plugin Names</a><span class="spacer boxFlex"></span><span class="sect">&sect; 2</span></li>
 
7
    <li class="hbox"><a href="#api">API</a><span class="spacer boxFlex"></span><span class="sect">&sect; 3</span></li>
 
8
    <ul>
 
9
        <li class="hbox"><a href="#apiload">load</a><span class="spacer boxFlex"></span><span class="sect">&sect; 3.1</span></li>
 
10
        <li class="hbox"><a href="#apinormalize">normalize</a><span class="spacer boxFlex"></span><span class="sect">&sect; 3.2</span></li>
 
11
        <li class="hbox"><a href="#apiwrite">write</a><span class="spacer boxFlex"></span><span class="sect">&sect; 3.3</span></li>
 
12
        <li class="hbox"><a href="#apionlayerend">onLayerEnd</a><span class="spacer boxFlex"></span><span class="sect">&sect; 3.4</span></li>
 
13
        <li class="hbox"><a href="#apiwritefile">writeFile</a><span class="spacer boxFlex"></span><span class="sect">&sect; 3.5</span></li>
 
14
        <li class="hbox"><a href="#apipluginbuilder">pluginBuilder</a><span class="spacer boxFlex"></span><span class="sect">&sect; 3.6</span></li>
 
15
    </ul>
 
16
</ul>
 
17
</div>
 
18
 
 
19
<div class="section">
 
20
<h2 id="intro">
 
21
Intro
 
22
<span class="sectionMark">&sect; 1</span>
 
23
</h2>
 
24
 
 
25
<p>RequireJS allows you to write loader plugins that can load different types of resources as dependencies, and even include the dependencies in optimized builds.</p>
 
26
 
 
27
<p>Examples of existing loader plugins are the <a href="api.html#text">text!</a> and <a href="api.html#i18n">i18n!</a> plugins. The text! plugin handles loading text, and the i18n plugin handles loading a JavaScript object that is made up from objects from a few different modules. The object contains localized strings.</p>
 
28
 
 
29
<p>The RequireJS wiki has a longer <a href="https://github.com/jrburke/requirejs/wiki/Plugins">list of plugins on the RequireJS</a>.</p>
 
30
 
 
31
</div>
 
32
 
 
33
<div class="section">
 
34
<h2 id="names">
 
35
Plugin Names
 
36
<span class="sectionMark">&sect; 2</span>
 
37
</h2>
 
38
 
 
39
<p>Loader plugins are just another module, but they implement a specific API. Loader plugins can also participate in the optimizer optimizations, allowing the resources they load to be inlined in an optimized build.</p>
 
40
 
 
41
<p><b>Note</b>: the plugin and its dependencies should be able to run in non-browser environments like Node and Rhino. If they cannot, you should use an alternate <a href="#apipluginbuilder">plugin builder</a> module that can run in those environments
 
42
so that they can participate in optimization builds.</p>
 
43
 
 
44
<p>You can reference your plugin by putting its module name before a ! in the dependency. For instance, if you create a plugin with the name "foo.js", you would use it like so:</p>
 
45
 
 
46
<pre><code>
 
47
require(['foo!something/for/foo'], function (something) {
 
48
    //something is a reference to the resource
 
49
    //'something/for/foo' that was loaded by foo.js.
 
50
});
 
51
</code></pre>
 
52
 
 
53
<p>So, the plugin's module name comes before the ! separator. The part after the ! separator is called the <b>resource name</b>. The resource name may look like a normal module name. The plugin's module name can be any valid module name, so for instance, you could use a relative indicator:</p>
 
54
 
 
55
<pre><code>
 
56
require(['./foo!something/for/foo'], function (something) {
 
57
});
 
58
</code></pre>
 
59
 
 
60
<p>Or, if it was inside a package or directory, say bar/foo.js:</p>
 
61
 
 
62
<pre><code>
 
63
require(['bar/foo!something/for/foo'], function (something) {
 
64
});
 
65
</code></pre>
 
66
 
 
67
</div>
 
68
 
 
69
<div class="section">
 
70
<h2 id="api">
 
71
API
 
72
<span class="sectionMark">&sect; 3</span>
 
73
</h2>
 
74
 
 
75
<p>RequireJS will load the plugin module first, then pass the rest of the dependency name to a load() method on the plugin. There are also some methods to help with module name normalization and for making use of the plugin as part of the <a href="optimization.html">optimizer</a>.</p>
 
76
 
 
77
<p>The complete Plugin API:</p>
 
78
 
 
79
<ul>
 
80
    <li><b><a href="#apiload">load</a></b>: A function that is called to load a resource. This is the only mandatory API method that needs to be implemented for the plugin to be useful.</li>
 
81
    <li><b><a href="#apinormalize">normalize</a></b>: A function to normalize the resource name. This is useful in providing optimal caching and optimization, but only needed if the resource name is not a module name.</li>
 
82
    <li><b><a href="#apiwrite">write</a></b>: used by the optimizer to indicate when the plugin should write out a representation of the the resource in the optimized file.</li>
 
83
    <li><b><a href="#apipluginbuilder">pluginBuilder</a></b>: A module name string for a module that should be used in the optimizer to do optimization work. That module is used instead of the plugin module when the optimizer runs.</li>
 
84
</ul>
 
85
 
 
86
<h3>
 
87
<a name="apiload">load: function (name, parentRequire, onload, config)</a>
 
88
<span class="sectionMark">&sect; 3.1</span>
 
89
</h3>
 
90
 
 
91
<p>load is a function, and it will be called with the following arguments:</p>
 
92
 
 
93
<ul>
 
94
    <li><b>name</b>: String. The name of the resource to load. This is the part after the ! separator in the name. So, if a module asks for 'foo!something/for/foo', the foo module's load function will receive 'something/for/foo' as the name.</li>
 
95
    <li><b>parentRequire</b>: Function. A local "require" function to use to load other modules. This require function has some utilities on it:
 
96
    <ul>
 
97
        <li><b>parentRequire.toUrl(moduleResource)</b>:where moduleResource is a module name plus an extension. For instance "view/templates/main.html". It will return a full path to the resource, obeying any RequireJS configuration.</li>
 
98
        <li><b>parentRequire.defined(moduleName)</b>: Returns true if the module has already been loaded and defined. Used to be called require.isDefined before RequireJS 0.25.0.</li>
 
99
        <li><b>parentRequire.specified(moduleName)</b>: Returns true if the module has already been requested or is in the process of loading and should be available at some point.</li>
 
100
    </ul></li>
 
101
    <li><b>onload</b>: Function. A function to call with the value for name. This tells the loader that the plugin is done loading the resource. <b>onload.error()</b> can be called, passing an error object to it, if the plugin detects an error condition that means the resource will fail to load correctly.</li>
 
102
    <li><b>config</b>: Object. A configuration object. This is a way for the optimizer and the web app to pass configuration information to the plugin. The i18n! plugin uses this to get the current current locale, if the web app wants to force a specific locale. The optimizer will set an <b>isBuild</b> property in the config to true if this plugin (or pluginBuilder) is being called as part of an optimizer build.</li>
 
103
</ul>
 
104
 
 
105
<p>An example plugin that does not do anything interesting, just does a normal require to load a JS module:</p>
 
106
 
 
107
<pre><code>
 
108
define({
 
109
    load: function (name, req, onload, config) {
 
110
        //req has the same API as require().
 
111
        req([name], function (value) {
 
112
            onload(value);
 
113
        });
 
114
    }
 
115
});
 
116
</code></pre>
 
117
 
 
118
<p>Some plugins may need to evaluate some JavaScript that was retrieved as text, and use that
 
119
evaluated JavaScript as the value for the resource. There is a function off the onload() argument, <strong>onload.fromText()</strong>, that can be used to evaluate the JavaScript. eval() is used by RequireJS to evaluate that JavaScript, and RequireJS will do the right work for any anonymous define() call in the evaluated text, and use that define() module as the value for the resource.</p>
 
120
 
 
121
<p>Arguments for onload.fromText() (RequireJS 2.1.0 and later):</p>
 
122
 
 
123
<ul>
 
124
    <li><b>text</b>: String. The string of JavaScript to evaluate.</li>
 
125
</ul>
 
126
 
 
127
<p>An example plugin's load function that uses onload.fromText():</p>
 
128
 
 
129
<pre><code>
 
130
define({
 
131
    load: function (name, req, onload, config) {
 
132
        var url = req.toUrl(name + '.customFileExtension'),
 
133
            text;
 
134
 
 
135
        //Use a method to load the text (provide elsewhere)
 
136
        //by the plugin
 
137
        fetchText(url, function (text) {
 
138
            //Transform the text as appropriate for
 
139
            //the plugin by using a transform()
 
140
            //method provided elsewhere in the plugin.
 
141
            text = transform(text);
 
142
 
 
143
            //Have RequireJS execute the JavaScript within
 
144
            //the correct environment/context, and trigger the load
 
145
            //call for this resource.
 
146
            onload.fromText(text);
 
147
        });
 
148
    }
 
149
});
 
150
</code></pre>
 
151
 
 
152
<p>Before RequireJS 2.1.0, onload.fromText accepted a moduleName as the first
 
153
    argument: <code>onload.fromText(moduleName, text)</code>, and the loader
 
154
    plugin had to manually call <code>require([moduleName], onload)</code>
 
155
    after the onload.fromText() call.</p>
 
156
 
 
157
<p><b id="loadBuildInfo">Build considerations</b>: The optimizer traces
 
158
dependencies <b>synchronously</b> to simplify the optimization logic. This is
 
159
different from how require.js in the browser works, and it means that only
 
160
plugins that can satisfy their dependencies synchronously should participate
 
161
in the optimization steps that allow inlining of loader plugin values. Otherwise,
 
162
the plugin should just call load() immediately if <code>config.isBuild</code>
 
163
is true:</p>
 
164
 
 
165
<pre><code>
 
166
define({
 
167
    load: function (name, req, onload, config) {
 
168
        if (config.isBuild) {
 
169
            //Indicate that the optimizer should not wait
 
170
            //for this resource any more and complete optimization.
 
171
            //This resource will be resolved dynamically during
 
172
            //run time in the web browser.
 
173
            onload();
 
174
        } else {
 
175
            //Do something else that can be async.
 
176
        }
 
177
    }
 
178
});
 
179
</code></pre>
 
180
 
 
181
<p>Some plugins may do an async operation in the browser, but opt to complete
 
182
the resource load synchronously when run in Node/Rhino. This is what the text
 
183
plugin does. If you just want to run AMD modules and load plugin
 
184
dependencies using <a href="http://github.com/jrburke/amdefine">amdefine</a> in Node, those also need to complete
 
185
synchronously to match Node's synchronous module system.</p>
 
186
 
 
187
<h3>
 
188
<a name="apinormalize">normalize: function (name, normalize)</a>
 
189
<span class="sectionMark">&sect; 3.2</span>
 
190
</h3>
 
191
 
 
192
<p><b>normalize</b> is called to normalize the name used to identify a resource. Some resources could use relative paths, and need to be normalized to the full path. normalize is called with the following arguments:</p>
 
193
 
 
194
<ul>
 
195
    <li><b>name</b>: String. The resource name to normalize.</li>
 
196
    <li><b>normalize</b>: Function. A function that can be called to normalize a regular module name.</li>
 
197
</ul>
 
198
 
 
199
<p>An example: suppose there is an <b>index!</b> plugin that will load a module name given an index. This is a contrived example, just to illustrate the concept. A module may reference an index! resource like so:</p>
 
200
 
 
201
<pre><code>
 
202
define(['index!2?./a:./b:./c'], function (indexResource) {
 
203
    //indexResource will be the module that corresponds to './c'.
 
204
});
 
205
</code></pre>
 
206
 
 
207
<p>In this case, the normalized names the './a', './b', and './c' will be determined relative to the module asking for this resource. Since RequireJS does not know how to inspect the 'index!2?./a:./b:./c' to normalize the names for './a', './b', and './c', it needs to ask the plugin. This is the purpose of the normalize call.</p>
 
208
 
 
209
<p>By properly normalizing the resource name, it allows the loader to cache the value effectively, and to properly build an optimized build layer in the optimizer.</p>
 
210
 
 
211
<p>The <b>index!</b> plugin could be written like so:</p>
 
212
 
 
213
<pre><code>
 
214
(function () {
 
215
 
 
216
    //Helper function to parse the 'N?value:value:value'
 
217
    //format used in the resource name.
 
218
    function parse(name) {
 
219
        var parts = name.split('?'),
 
220
            index = parseInt(parts[0], 10),
 
221
            choices = parts[1].split(':'),
 
222
            choice = choices[index];
 
223
 
 
224
        return {
 
225
            index: index,
 
226
            choices: choices,
 
227
            choice: choice
 
228
        };
 
229
    }
 
230
 
 
231
    //Main module definition.
 
232
    define({
 
233
        normalize: function (name, normalize) {
 
234
            var parsed = parse(name),
 
235
                choices = parsed.choices;
 
236
 
 
237
            //Normalize each path choice.
 
238
            for (i = 0; i < choices.length; i++) {
 
239
                //Call the normalize() method passed in
 
240
                //to this function to normalize each
 
241
                //module name.
 
242
                choices[i] = normalize(choices[i]);
 
243
            }
 
244
 
 
245
            return parsed.index + '?' + choices.join(':');
 
246
        },
 
247
 
 
248
        load: function (name, req, onload, config) {
 
249
            req([parse(name).choice], function (value) {
 
250
                onload(value);
 
251
            });
 
252
        }
 
253
    });
 
254
 
 
255
}());
 
256
</code></pre>
 
257
 
 
258
<p>You do not need to implement normalize if the resource name is just a regular module name. For instance, the text! plugin does not implement normalize because the dependency names look like 'text!./some/path.html'.</p>
 
259
 
 
260
<p>If a plugin does not implement normalize, then the loader will try to normalize the resource name using the normal module name rules.</p>
 
261
 
 
262
<h3>
 
263
<a name="apiwrite">write: function (pluginName, moduleName, write)</a>
 
264
<span class="sectionMark">&sect; 3.3</span>
 
265
</h3>
 
266
 
 
267
<p><b>write</b> is only used by the optimizer, and it only needs to be implemented if the plugin can output something that would belong in an optimized layer. It is called with the following arguments:</p>
 
268
 
 
269
<ul>
 
270
    <li><b>pluginName</b>: String. The <b>normalized</b> name for the plugin. Most plugins will not be authored with a name (they will be anonymous plugins) so it is useful to know the normalized name for the plugin module for use in the optimized file.</li>
 
271
    <li><b>name</b>: String. The <b>normalized</b> resource name.</li>
 
272
    <li><b>write</b>: Function. A function to be called with a string of output to write to the optimized file. This function also contains a property function, <b>write.asModule(moduleName, text)</b>. asModule can be used to write out a module that may have an anonymous define call in there that needs name insertion or/and contains implicit require("") dependencies that need to be pulled out for the optimized file. asModule is useful for text transform plugins, like a CoffeeScript plugin.</li>
 
273
</ul>
 
274
 
 
275
<p>The text! plugin implements write, to write out a string value for the text file that it loaded. A snippet from that file:</p>
 
276
 
 
277
<pre><code>
 
278
write: function (pluginName, moduleName, write) {
 
279
    //The text plugin keeps a map of strings it fetched
 
280
    //during the build process, in a buildMap object.
 
281
    if (moduleName in buildMap) {
 
282
        //jsEscape is an internal method for the text plugin
 
283
        //that is used to make the string safe
 
284
        //for embedding in a JS string.
 
285
        var text = jsEscape(buildMap[moduleName]);
 
286
        write("define('" + pluginName + "!" + moduleName  +
 
287
              "', function () { return '" + text + "';});\n");
 
288
    }
 
289
}
 
290
</code></pre>
 
291
 
 
292
<h3>
 
293
<a name="apionlayerend">onLayerEnd: function (write, data)</a>
 
294
<span class="sectionMark">&sect; 3.4</span>
 
295
</h3>
 
296
 
 
297
<p><b>onLayerEnd</b> is only used by the optimizer, and is only supported in 2.1.0 or later of the optimizer. It is called after the modules for the layer have been written to the layer. It is useful to use if you need some code that should go at the end of the layer, or if the plugin needs to reset some internal state.</p>
 
298
 
 
299
<p>One example: a plugin that needs to write out some utility functions at the beginning of a layer, as part of the first <a href="#apiwrite">write</a> call, and the plugin needs to know when to reset the internal state to know when to write out the utilities for the next layer. If the plugin implements onLayerEnd, it can get notified when to reset its internal state.</p>
 
300
 
 
301
<p>onLayerEnd is called with the following arguments:</p>
 
302
 
 
303
<ul>
 
304
    <li><b>write</b>: Function. A function to be called with a string of output to write to the optimized layer. <b>Modules should not be written out</b> in this call. They will not be normalized correctly for coexistence with other define() calls already in the file. It is useful only for writing out non-define() code.</li>
 
305
    <li><b>data</b>: Object. Information about the layer. Only has two properties:
 
306
    <ul>
 
307
     <li><b>name</b>: the module name of the layer. May be undefined.</li>
 
308
     <li><b>path</b>: the file path of the layer. May be undefined, particularly if the output is just to a string that is consumed by another script.</li>
 
309
     </li>
 
310
</ul>
 
311
 
 
312
 
 
313
<h3>
 
314
<a name="apiwritefile">writeFile: function (pluginName, name, write)</a>
 
315
<span class="sectionMark">&sect; 3.5</span>
 
316
</h3>
 
317
 
 
318
<p><b>writeFile</b> is only used by the optimizer, and it only needs to be implemented if the plugin needs to write out an alternate version of a dependency that is handled by the plugin. It is a bit expensive to scan all modules in a project to look for all plugin dependencies, so this writeFile method will only be called if <b>optimizeAllPluginResources: true</b> is in the build profile for the RequireJS optimizer. writeFile is called with the following arguments:</p>
 
319
 
 
320
<ul>
 
321
    <li><b>pluginName</b>: String. The <b>normalized</b> name for the plugin. Most plugins will not be authored with a name (they will be anonymous plugins) so it is useful to know the normalized name for the plugin module for use in the optimized file.</li>
 
322
    <li><b>name</b>: String. The <b>normalized</b> resource name.</li>
 
323
    <li><b>parentRequire</b>: Function. A local "require" function. The main use of this in writeFile is for calling parentRequire.toUrl() to generate file paths that are inside the build directory.</li>
 
324
    <li><b>write</b>: Function. A function to be called with two arguments:
 
325
        <ul>
 
326
            <li><b>fileName</b>: String. The name of the file to write. You can use parentRequire.toUrl() with a relative path to generate a file name that will be inside the build output directory.</li>
 
327
            <li><b>text</b>: String. The contents of the file. Must be UTF-8 encoded.</li>
 
328
        </ul>
 
329
        This function also contains a property function, <b>write.asModule(moduleName, fileName, text)</b>. asModule can be used to write out a module that may have an anonymous define call in there that needs name insertion or/and contains implicit require("") dependencies that need to be pulled out for the optimized file.</li>
 
330
</ul>
 
331
 
 
332
<p>See the <a href="https://github.com/jrburke/requirejs/blob/master/text.js">text! plugin</a> for an example of writeFile.</p>
 
333
 
 
334
<h3>
 
335
<a name="apipluginbuilder">pluginBuilder</a>
 
336
<span class="sectionMark">&sect; 3.6</span>
 
337
</h3>
 
338
 
 
339
<p><b>pluginBuilder</b> can be a string that points to another module to use instead of the current plugin when the plugin is used as part of an optimizer build.</p>
 
340
 
 
341
<p>A plugin could have very specific logic that depends on a certain environment, like the browser. However, when run inside the optimizer, the environment is very different, and the plugin may have a <b>write</b> plugin API implementation that it does not want to deliver as part of the normal plugin that is loaded in the browser. In those cases, specifying a pluginBuilder is useful.</p>
 
342
 
 
343
<p>Some notes about using a pluginBuilder:</p>
 
344
 
 
345
<ul>
 
346
    <li>Do not use named modules for the plugin or the pluginBuilder. The pluginBuilder text contents are used instead of the contents of the plugin file, but that will only work if the files do not call define() with a name.</li>
 
347
    <li>Plugins and pluginBuilders that run as part of the build process have a very limited environment. Right now the optimizer runs on top of Rhino, but it may in the future run also on Node. Be careful of the environment assumptions if you want the plugin to run as part of the optimizer.</li>
 
348
</ul>
 
349
 
 
350
</div>