| # amdefine |
| |
| A module that can be used to implement AMD's define() in Node. This allows you |
| to code to the AMD API and have the module work in node programs without |
| requiring those other programs to use AMD. |
| |
| ## Usage |
| |
| **1)** Update your package.json to indicate amdefine as a dependency: |
| |
| ```javascript |
| "dependencies": { |
| "amdefine": ">=0.1.0" |
| } |
| ``` |
| |
| Then run `npm install` to get amdefine into your project. |
| |
| **2)** At the top of each module that uses define(), place this code: |
| |
| ```javascript |
| if (typeof define !== 'function') { var define = require('amdefine')(module) } |
| ``` |
| |
| **Only use these snippets** when loading amdefine. If you preserve the basic structure, |
| with the braces, it will be stripped out when using the [RequireJS optimizer](#optimizer). |
| |
| You can add spaces, line breaks and even require amdefine with a local path, but |
| keep the rest of the structure to get the stripping behavior. |
| |
| As you may know, because `if` statements in JavaScript don't have their own scope, the var |
| declaration in the above snippet is made whether the `if` expression is truthy or not. If |
| RequireJS is loaded then the declaration is superfluous because `define` is already already |
| declared in the same scope in RequireJS. Fortunately JavaScript handles multiple `var` |
| declarations of the same variable in the same scope gracefully. |
| |
| If you want to deliver amdefine.js with your code rather than specifying it as a dependency |
| with npm, then just download the latest release and refer to it using a relative path: |
| |
| [Latest Version](https://github.com/jrburke/amdefine/raw/latest/amdefine.js) |
| |
| ### amdefine/intercept |
| |
| Consider this very experimental. |
| |
| Instead of pasting the piece of text for the amdefine setup of a `define` |
| variable in each module you create or consume, you can use `amdefine/intercept` |
| instead. It will automatically insert the above snippet in each .js file loaded |
| by Node. |
| |
| **Warning**: you should only use this if you are creating an application that |
| is consuming AMD style defined()'d modules that are distributed via npm and want |
| to run that code in Node. |
| |
| For library code where you are not sure if it will be used by others in Node or |
| in the browser, then explicitly depending on amdefine and placing the code |
| snippet above is suggested path, instead of using `amdefine/intercept`. The |
| intercept module affects all .js files loaded in the Node app, and it is |
| inconsiderate to modify global state like that unless you are also controlling |
| the top level app. |
| |
| #### Why distribute AMD-style modules via npm? |
| |
| npm has a lot of weaknesses for front-end use (installed layout is not great, |
| should have better support for the `baseUrl + moduleID + '.js' style of loading, |
| single file JS installs), but some people want a JS package manager and are |
| willing to live with those constraints. If that is you, but still want to author |
| in AMD style modules to get dynamic require([]), better direct source usage and |
| powerful loader plugin support in the browser, then this tool can help. |
| |
| #### amdefine/intercept usage |
| |
| Just require it in your top level app module (for example index.js, server.js): |
| |
| ```javascript |
| require('amdefine/intercept'); |
| ``` |
| |
| The module does not return a value, so no need to assign the result to a local |
| variable. |
| |
| Then just require() code as you normally would with Node's require(). Any .js |
| loaded after the intercept require will have the amdefine check injected in |
| the .js source as it is loaded. It does not modify the source on disk, just |
| prepends some content to the text of the module as it is loaded by Node. |
| |
| #### How amdefine/intercept works |
| |
| It overrides the `Module._extensions['.js']` in Node to automatically prepend |
| the amdefine snippet above. So, it will affect any .js file loaded by your |
| app. |
| |
| ## define() usage |
| |
| It is best if you use the anonymous forms of define() in your module: |
| |
| ```javascript |
| define(function (require) { |
| var dependency = require('dependency'); |
| }); |
| ``` |
| |
| or |
| |
| ```javascript |
| define(['dependency'], function (dependency) { |
| |
| }); |
| ``` |
| |
| ## RequireJS optimizer integration. <a name="optimizer"></name> |
| |
| Version 1.0.3 of the [RequireJS optimizer](http://requirejs.org/docs/optimization.html) |
| will have support for stripping the `if (typeof define !== 'function')` check |
| mentioned above, so you can include this snippet for code that runs in the |
| browser, but avoid taking the cost of the if() statement once the code is |
| optimized for deployment. |
| |
| ## Node 0.4 Support |
| |
| If you want to support Node 0.4, then add `require` as the second parameter to amdefine: |
| |
| ```javascript |
| //Only if you want Node 0.4. If using 0.5 or later, use the above snippet. |
| if (typeof define !== 'function') { var define = require('amdefine')(module, require) } |
| ``` |
| |
| ## Limitations |
| |
| ### Synchronous vs Asynchronous |
| |
| amdefine creates a define() function that is callable by your code. It will |
| execute and trace dependencies and call the factory function *synchronously*, |
| to keep the behavior in line with Node's synchronous dependency tracing. |
| |
| The exception: calling AMD's callback-style require() from inside a factory |
| function. The require callback is called on process.nextTick(): |
| |
| ```javascript |
| define(function (require) { |
| require(['a'], function(a) { |
| //'a' is loaded synchronously, but |
| //this callback is called on process.nextTick(). |
| }); |
| }); |
| ``` |
| |
| ### Loader Plugins |
| |
| Loader plugins are supported as long as they call their load() callbacks |
| synchronously. So ones that do network requests will not work. However plugins |
| like [text](http://requirejs.org/docs/api.html#text) can load text files locally. |
| |
| The plugin API's `load.fromText()` is **not supported** in amdefine, so this means |
| transpiler plugins like the [CoffeeScript loader plugin](https://github.com/jrburke/require-cs) |
| will not work. This may be fixable, but it is a bit complex, and I do not have |
| enough node-fu to figure it out yet. See the source for amdefine.js if you want |
| to get an idea of the issues involved. |
| |
| ## Tests |
| |
| To run the tests, cd to **tests** and run: |
| |
| ``` |
| node all.js |
| node all-intercept.js |
| ``` |
| |
| ## License |
| |
| New BSD and MIT. Check the LICENSE file for all the details. |