umdjs / umd Goto Github PK
View Code? Open in Web Editor NEWUMD (Universal Module Definition) patterns for JavaScript modules that work everywhere.
License: MIT License
UMD (Universal Module Definition) patterns for JavaScript modules that work everywhere.
License: MIT License
Hi
I wasn't sure where else to post this. I've been working on a library that implements a UMD pattern to allow modular loading of dependencies through a package syntax. You can find the project here: https://github.com/wellcaffeinated/PhysicsJS
The extension modules plug into the core so loading can happen with RequireJS like this:
require({
packages: [
{
name: 'physicsjs',
location: 'path/to/physicsjs',
main: 'physicsjs-0.5.1.min'
}
]
}, [
'physicsjs', // core
'physicsjs/bodies/circle' // extensions...
], function( Physics ){
// use library with the circle body mixin defined
});
The extensions that mixin to the core need to declare the core (and possibly other extensions) as dependencies. So the current UMD suggestions weren't quite working for me.
I finally found something that works, and compiles nicely with the r.js optimization tool.
Here is the syntax:
(function( root, define, fn ){
define = (typeof define === 'function' && define.amd) ? define : function( name, deps, fn ){
if ( !fn ){
fn = deps;
deps = name;
}
// Node.js
if ( typeof exports === 'object' ){
deps = deps.map( require );
module.exports = fn( deps );
} else {
// global object
// map
for ( var i = 0, l = deps.length; i < l; ++i ){
deps[ i ] = root[ deps[i] ];
}
// could also have root.NAME = fn.apply( root, deps );
fn.apply( root, deps );
}
};
define([ 'dep' ], fn);
})(this, this.define, function( dep1, dep2, ... ){
// code plugs into the first dependency
});
Thought it would be useful. Feedback is appreciated!
The file umd3-draft.js
simply contains an unfinished draft, I am not sure what it is needed for. If it is useful, could an explanation be included in the README.md file? Otherwise, could it be deleted? Thanks.
As noted at es6-module-loader wiki:
System.register can be considered as a new module format...
How about extending the UMD pattern to also use System.register
?
Something like:
if (System && typeof System.register === "function") {
System.register(['b'], factory);
} else if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['exports', 'b'], factory);
} else if (typeof exports === 'object') {
// CommonJS
factory(exports, require('b'));
} else {
// Browser globals
factory((root.commonJsStrict = {}), root.b);
}
A similar discussion also takes place at mozilla/localForage#158.
jQuery-plugin should provide a paradigm that shares instances of jQuery. It currently doesn't. If I want to share one instance of jQuery and have multiple different CommonJS-packaged extensions to it, we should be able to make that work.
This problem is pervasive. It affects at least two projects I'm working on now: DataTables and Notify.js. My suggestion is to have the jQuery plugin look like this..
require('jQuery-plugin-foo')(window, [$]);
where
require('jQuery-plugin-foo')(window, $); // extends $
require('jQuery-plugin-foo')(window); // creates a jQuery object from the provided window.
If an instance of jQuery is provided the plugin gets that instance rather than creating its own in the UMD code. As for adding window
, why not? It's explicit, but we can always satisfy this signature easily. Further, where window is not native (like under Node) it permits the user to provide something like jsdom. Ideas?
The Grunt example linked in the readme isn't very clear for me. I can only assume that if it wasn't properly UMD, then loads of the underlying tests would fail, which isn't ideal really.
It would be great if there were solid tests (in this / a separate project) for testing if everything is exported correctly, etc. Having tests properly documented, maintained and used would only increase confidence. Then there could be build system specific plugins / projects which just wrap / use these tests (perfect for CI).
What do you think? I'd love to contribute but I wouldn't be 100% sure what exactly sure be tested and what all the edge cases are.
Thank you for this project! I suggest plugin developers (e.g. https://github.com/malsup/ ) to use this biolerplate.
What is the AMD way of having a private (and public) variable in a jQuery plugin that every function can read/write?
commonjsStrict.js line 22: https://github.com/umdjs/umd/blob/master/commonjsStrict.js#L22
Wouldn't assigning exports to module.exports in here further generalize the module definition by allowing the module to directly assign a function or instantiated object to the exports
variable in the module definition?
factory((exports = module.exports), require('b'));
As far as I can tell, there shouldn't be a downside to this, though I cannot determine whether the exports
special object from AMD can be treated the same.
We have two templates
This is really stupid. We're making the learning curve complex because of one concern..
} else if (typeof module === 'object' && module.exports) {
// Node/CommonJS
module.exports = factory(require('jquery'));
}
That's one branch in an else statement? Is that all there is too it? Who cares.. Browserify is huge and growing explosively. The time it takes to,
isn't worth saving a branch on an if statement. Not to mention, we're making assumptions about how people are using UMD. The whole purpose of UMD is that it should just work if it at all possible.
tldr; _DELETE jqueryPluginCommonjs.js, and move the conditional into jqueryPlugin.js_
Otherwise HTML like so:
<div id="exports"></div>
... can trip up the detection and trigger an exception by attempting to access module.exports
, since elements with ids are automatically made globally available by their id value.
if(typeof exports === 'object' && '' + exports === '[object Object]')
should fix this issue.
I just added UMD support to Vaccine. I thought you may be interested in seeing the different approach to handling the many options for UMD. (I don't have all the options in there currently, though.)
Instead of having separate discrete files, like is done in this repository, the UMD boilerplate is configured based off options like "support CommonJS", "export with return
", etc. When a user checks one of the options, the file adjusts. This makes it easier for the user to get what they want. It also makes it easier to add other options.
In case a user picks a combination of options that doesn't work together, it highlights the problem options and provides a link to fix it.
I just started working on the site three days ago, so there may be some issues that I haven't caught. That said, there are already some neat features, like showing minified (and approximate gzipped) sizes and "diffing" between two different versions.
I hope you find this approach interesting. Let me know your feedback.
hi everybody,
I'm trying to use the "jqueryPluginCommonjs.js" for the first time and I'm using browserify to create the bundle for the browser.
I wrapped a simple jquery plugin that I made (and tested) before, but I can't figure out why it works only if I specify the "browser" property within the package.json of my app:
"browser": {
"fvalidation": "./node_modules/fvalidation/index.js"
},
"dependencies": {
"fvalidation": "^0.1.1"
}
If I don't specify the browser field i get the error:
TypeError: $(...).fvalidation is not a function at HTMLDocument.
The module is here: https://github.com/Giulico/fValidation
And in my app.js file I'm doning something like this
var fvalidation = require('fvalidation');
$(document).ready(function() {
$('#myForm').fvalidation({
onSubmit: function() { console.log('done!'); }
});
});
Iβm wondering if you might help me to understand what am I wrong.
Thank you in advance
Giulio
With CommonJS being used not only in node.js but also in browser environments, such as browserify and webmake, the discouragement [1] of jqueryPluginCommonjs.js should be removed (concerns Readme.md and jqueryPluginCommonjs.js itself).
[1] "However, jQuery is unlikely to run in most CommonJS environments, so only use this version if you know you are targeting a CommonJS environment that can load jQuery appropriately."
// It is unlikely jQuery will run in a CommonJS
// environment. See jqueryPlugin.js if you do
// not want to add the extra CommonJS detection.
UMD isn't currently compatible with JavaScript modules because import
and export
declarations would cause a syntax errors in engines that don't yet support modules. This makes UMD now less universal than it could be.
#125 makes UMD bundles loadable via import
statements, but the bundle will still write to globals (or use define
or exports
if available), so there are no useful symbols to import.
I think we can make importing UMD from JS modules better with a small shim that's imported instead and provides real exports.
There are two possible versions of the shim:
The shim first sets up a global object to capture the UMD exports, then loads the UMD, then resets the global:
my-module-setup.js:
// Each UMD-JS-module shim needs it's _own_ setup module, even though the contents are the same, so that it evaluates before each UMD loads
window.exports = {}
my-module.js:
// We need a separate import to run code before the UMD module evaluates
import './my-module-setup.js';
// load the UMD module, which will populate window.exports
import './my-module.umd.js';
//export the UMD exports
export default let exports = window.exports;
// cleanup
window.exports = undefined;
The custom shim works the same, but uses individual exports. This would likely be generated:
my-module.js:
// We need a separate import to run code before the UMD module evaluates
import './my-module-setup.js';
// load the UMD module, which will populate window.exports
import './my-module.umd.js';
//export the UMD exports
export const a = window.exports.a;
export const b = window.exports.b;
// cleanup
window.exports = undefined;
Custom shims would not support mutable bindings, ie you can't reassign an export from within the defining module.
I don't know if I can post this question here. Feel free to reject it, please.
What if my universal module need underscore OR lodash? May I be explicit about that in my module definition?
Thanks,
Adriano
The variant returnExports.js
says:
// If you want something that will work in other stricter CommonJS environments,
// or if you need to create a circular dependency, see commonJsStrict.js
But it doesn't really explain what the strictness is about. What is violating CommonJS in the stricter sense, and which still seems to work in node, in this example?
https://github.com/umdjs/umd/blob/master/templates/amdWebGlobal.js
What about case when i have amd, but for any architecture reasons i dont use it, but i still want just to include library and get global variable.
More correctly will be:
define(['b'], function (b) {
return factory(b);
});
root.amdWebGlobal = require('b');
because global variables are for "inline" usages, not for amd approach.
"backward compatibility" of libraries should not be affected by my architecture.
why by adding third party amd it should breaks existing usages of any library?
this is definitely wrong approach.
It's unclear what the license is for these code snippets. My very limited understanding of copyright law suggests that source code without a license implies a copyright by the author and does not allow sharing / modifications / distribution / etc.
I would love to use these patterns, but am hesitant to do so until I understand the IP implications. It would be great if the example source files had a license header, if there was a LICENSE
file, README.md
was updated, or similar.
My first attempt at a UMD implementation: MultiEvent provided a lot of issues that I imagine might affect others who'd like to support UMD.
Any chance on creating a section in the readme for example implementations? Seeing working examples would be a big help.
Starting with backbone and underscore.
What say ye?
In a Jest test I'm writing I need to initialize jsdom (just for that specific test).
The problem is that doing:
// init jsdom here
import library from 'umdLibrary';
The umdLibrary
that requires window
will blow up because window
is not yet defined when imported, but it's needed when used.
How can this be solved?
Support for the Google Closure module system is easy to add also.
Example: https://developers.google.com/closure/library/docs/tutorial
Just add this style at the top of the file:
if (typeof goog != 'undefined' && typeof goog.provide == 'function') {
goog.provide('MyModule');
goog.require('MyDependency1');
goog.require('MyDependency2');
// ...
}
The tool then used to build the full dependency tree is found here:
https://developers.google.com/closure/library/docs/depswriter
Regards
/ Fredrik Blomqvist
Hi,
Given it would be fairly simple to extract the core out of grunt-umd and make it a library of its own I started thinking perhaps the project would belong below umdjs
.
It would look like this:
The primary advantage of having the tools below the same namespace would be discoverability. In addition it would add some credibility to the build tools and allow more people (umdjs team) to maintain them.
Does this sound reasonable to you? I understand if you are busy and prefer to keep tooling outside of umdjs
but there are certain benefits as outlined above.
i've got es5-shim with UMD, and synchronous inline script which uses this shim (it must be synchronous due to block html parsing) but require.js resolve es5shim dependency asynchronous, and inline script rise an error, because inline-script run before require(['es5-shim']) is done.
So UMD in case of such libraries, should always immediately run factory and exports for AMD its value;
also there is one more example why it should always immediately run factory, #78
Please help me how to provide window
to this plugin.
It is clear to me that parameters should be reordered
from function (window, $, undefined)
to function ($, window, undefined)
But how to give window to it in AMD mode?
/*global jQuery: true */
/*!
--------------------------------
Infinite Scroll
--------------------------------
*/
(function (window, $, undefined) {
"use strict";
$.infinitescroll = function infscr(options, callback, element) {
this.element = $(element);
// Flag the object in the event of a failed creation
if (!this._create(options, callback)) {
this.failed = true;
}
};
})(window, jQuery);
I had this issue before with IE.
Take a look at this code:
var x = 10;
function a(){ return x; try{}catch(x){} };
alert(a()); // 10 in V8, undefined in IE
In IE (not sure until which version), if a variable is declared anywhere in the scope (inside any block, even a false if), it is available everywhere in that scope, even before its declaration.
Therefore this code overwrites define in environments like IE:
if (typeof module === 'object' && typeof define !== 'function') {
var define = function (factory) {
module.exports = factory(require, exports, module);
};
}
This jQuery plugin's file is called: jquery.scrollTo.min.js
How should I define its name?
define('jquery.scrollTo.min', ['jquery'], factory);
I would like to name it "jquery-scrollto" without path definition:
define('jquery-scrollto', ['jquery'], factory);
Please help me on this.
Who would have permissions to activate this project in Travis CI?
https://travis-ci.org/umdjs/umd
Now that we have npm test with linting since #57.
Missing a space for proper github format.
I have a project that's built to use node, requirejs and regular web scripts. It uses XMLHttpRequest to make calls to the server, but that's not available by default in node. It needs to be required first.
I found a few solutions, but all of them feels hacky. Is there any way of doing this easily? Shouldn't UMD have this 'feature' built in?
Any help would be greatly appreciated.
Cheers.
When using UMD in a script that is evaluated as a JavaScript module (tested in Chrome Canary and Safari stable), the reference to the global object (presumably window
) is incorrectly detected.
Please refer to this test case for a demonstration of the problem: http://jsbin.com/yuvulec/1/edit?html
JavaScript modules are always evaluated as JavaScript strict mode code [1]. In strict mode, an undefined
or null
this
is no longer coerced to the global object [2].
The following output in the console:
Everything is great!
Uncaught TypeError: Cannot read property 'b' of undefined
I think it's no use, but please advise.
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
$.fn.jqueryPlugin = function () {};
// it is OK?
return $.fn.jqueryPlugin;
}));
Not sure if I'm looking at the right CommonJS spec (the commonjs.org-site is a bit confusing), but in the current jQuery plugin template (jqueryPlugin.js, line 7) module.exports
is used instead of the CommonJS standard exports
.
You can compare this with commonjsStrict, line 23, which does check and use the exports
-object β not module.exports
.
I think jqueryPlugin.js
should be changed to use the exports
-object.
Note: Both files were checked at commit 95563fd (latest master as of 23rd Dec 2016)
Hi everyone
How can I solve this problem when I use AMD?
(function (factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else {
factory(window.Zepto || window.jQuery);
}
}(function ($) {
$.fn.Plugin = function () {};
}));
Some thing like this:
define(['zepto' || 'jquery'], factory)
π»
The UMD template from here https://github.com/umdjs/umd/blob/master/templates/returnExportsGlobal.js is not consumed properly in webpack 2.
See my S/O question here: https://stackoverflow.com/questions/45929231/how-to-consume-an-umd-module-with-webpack
I suggested an improvement to the UMD template. What do you think?
If I wanted my module to have multiple require
s using the method outlined in returnExports.js
, how would that look?
This line is almost entirely useless..
module.exports = factory(require('jquery'));
This is because require('jquery') returns a factory itself if it doesn't have a window object. So, if you're using node, you're feeding a factory into a factory, and confusingly calling the factory $
.
We can do this..
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof module === 'object' && module.exports) {
// Node/CommonJS
module.exports = factory(null, require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
}(function ($, jQueryFactory) {
if ( $ ) {
$.fn.jqueryPluginCommonJs = function () {};
}
}));
Or, we can do something like this...
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof module === 'object' && module.exports) {
// Node/CommonJS
if ( window === undefined ) { throw new Error("jQuery requires a window") }
module.exports = factory( require('jquery')(window) );
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
$.fn.jqueryPluginCommonJs = function () {};
}));
Or, we can try to instantiate one with jsdom
or the like. Just saying this follows the UMD paradigm doesn't skirt the issue that jQuery requires a window. We should handle cases where there is no Window Object if we're going to call this a fair boilerplate for jQuery.
Its not immediately obvious how I need to modify the scripts in order to use them for my own module. Maybe using more informative variable names would improve the intuitiveness.
myModuleName
, dependencyOne
, dependencyTwo
It seems a lot of people find these inclusions ugly out of principle. It really makes no sense to me.
But perhaps some simple rejigging could help people see them more nicely?
For example, removing the unnecessary '{' in the definitions. Perhaps even simplify the comments.
Then instead of:
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['b'], factory);
} else {
// Browser globals
root.amdWeb = factory(root.b);
}
}(this, function (b) {
//use b in some fashion.
// Just return a value to define the module export.
// This example returns an object, but the module
// can return a function as the exported value.
return {};
}));
We can have:
(function (root, factory) {
// AMD
if (typeof define === 'function' && define.amd)
define(['b'], factory);
// Browser global
else
root.amdWeb = factory(root.b);
}(this, function (b) {
//use b and return the exported object / function
return {};
}));
I know there's good reasons for allowing multiple globals etc. Also there are probably many arguments against removing unnecessary braces. But I still find it nicer to look at, and I'm just trying to see why people are getting caught up with this!
I'd love for http://docpad.org/plugin/umd to be added to the listings here, but I'm not sure which listing it should go under?
I am using the nodeAdapter
for AMD modules, however it breaks AMD because it overrides the define
function, as var define
is hoisted outside of the if
statement.
I'm a bit confused how anyone has actually got this to workβ¦
I have a project that splits functionality into multiple submodules to manage complexity.
Are there patterns for UMD (in my case, global/require/node support) when multiple files are involved?
More specifically, my project creates a namespace for the library with submodules placed within that namespace, e.g. MyModule
is the module namespace with MyModule.SubModule1
and MyModule.SubModule2
as submodules.
My specific goal is to be able to concatenate/minify the files into one file to be distributed.
Any ideas? Thanks!
A plugin of mine β mark.js
β needs the name mark.js
in CommonJS environments, and markjs
in RequireJS environments due to the fact that otherwise RequireJS will try to load a file mark.js
directly instead of the plugin specified in the dependency path (Example of a working path naming).
Due to the fact that Webpack and others support both β AMD and CommonJS β it would be safer to name the CommonJS statement before the AMD statement. Because otherwise it would take the AMD statement which would be markjs
in my above named examplen, and markjs
isn't valid for CommonJS environments (because the node module name is mark.js
).
I guess this is a common approach for JavaScript modules where the name is ending with .js
.
I want to write my Handlebar helpers to work with RequireJS AMD, Node JS and Web.
It takes Handlebars as a dependency. I could not find any umd script to support this.
How to do it?
This may not be within the scope of this repository, but I am wondering if there is a recommendation for the best way to wrap pre-existing code as a umd, without having to be concerned with modifying the code itself, other than to wrap it, that would work equally well with typical browser scripts as well as node.js modules, and result in wrapped source that is a umd.
So in this case not so much an approach for someone writing a new module to take, as the approach for a build script, package manager, etc. to take that would like to be able to do something like apply existing code to a mustache template of the form
// top portion of umd definition here {{ source }} // bottom portion of umd definition here
such that the wrapped source is a well-defined umd that could withstand minifiers that rename variables and properties and realizing that scripts, when node.js modules, could easily take one of two forms:
exports.foo= 'bar'; exports.baz = function() { return 'buz' };
module.exports = function(foo) { foo.bar = 'buz'; };
What would be best-practice (or even a suggested boilerplate) for this?
Scenario
define()
is definedSolution
I think the solution is pretty simple - simply check for module.exports
before checking for define
. Browserify - unlike RequireJS - doesn't need to pollute the global namespace so the likelihood of module
and exports
being globally defined is low.
Thoughts?
This issue is to discuss the current patterns in the repo as well as how we would like to address the variations on the todo list. I recall that Thomas had some particular comments here about how best the library/noConflict versions should best be handled, but let's carry on the conversation here so that it's not left in gists and lost later :)
Hello all,
I am attempting to transpile a file (it comes with it's own transpiled version but i wanted to be able to work with the es6 version and transpile it myself):
https://github.com/cbcrc/knockout-dragula/blob/master/knockout-dragula.js
I have set up gulp like so:
gulp.task('transpile', function() {
return gulp.src('Dependencies/lib/knockout-dragula/knockout-dragula.js')
.pipe(plumber())
.pipe(babel({
presets: ['es2015'],
plugins: ["transform-es2015-modules-umd"]
}))
.pipe(gulp.dest('Scripts/generated'));
});
The file that it is generating looks starts like this:
(function (global, factory) {
if (typeof define === "function" && define.amd) {
define(['exports', 'knockout', 'dragula'], factory);
} else if (typeof exports !== "undefined") {
factory(exports, require('knockout'), require('dragula'));
} else {
var mod = {
exports: {}
};
factory(mod.exports, global.knockout, global.dragula);
global.knockoutDragula = mod.exports;
}
})(this, function (exports, _knockout, _dragula) {
The problem i am encountering and i am not sure if it is ignorance on my part but _knockout
is coming through undefined.
I looked at the transpiled file that they supply and this looks like this at the start:
https://github.com/cbcrc/knockout-dragula/blob/master/dist/knockout-dragula.js
(function (global, factory) {
if (typeof define === 'function' && define.amd) {
define(['exports', 'module', 'knockout', 'dragula'], factory);
} else if (typeof exports !== 'undefined' && typeof module !== 'undefined') {
factory(exports, module, require('knockout'), require('dragula'));
} else {
var mod = {
exports: {}
};
factory(mod.exports, mod, global.ko, global.dragula);
global.knockoutDragula = mod.exports;
}
})(this, function (exports, module, _knockout, _dragula) {
After some debugging the breaking difference seems to be this:
factory(mod.exports,
global.knockout , global.dragula);//broken
vs.
factory(mod.exports, mod,
global.ko, global.dragula); //works
If i change my version to global.ko
it works.
Am i doing something wrong, do i need to do something extra so that it knows to look for knockout inside global.ko
and not global.knockout
?
Many thanks.
4imble
I tried following the jquery plugin example with the jQuery plugin for valums/file-uploader (see akre54/file-uploader@6972e0e) but got a "Uncaught Error: Mismatched anonymous define() module:" error, where the rest of the code block printed to the console.
Can you give me some pointers on what I might be doing wrong? requirejs version is 2.1.2. Thanks!
RequireJS allows some syntatic sugar so that instead of passing an array of dependencies, then declaring names for those dependencies in the factory in (hopefully) the correct order, you just class require
, and then can use more familiar (to CommonJS people) require()
calls:
define(function(require){
var $ = require('jquery')
var utilities = require('../app/utilities')
// insert magic words here that make browser do things
})
To do this in a UMD friendly way, I think you'd do something like this:
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define(factory)
} else {
// Browser
root.returnExports = factory()
}
}(this, function (require) {
if (typeof require === 'function' && define.amd){
var $ = require('jquery')
}
// insert more magic words here
return {}
}));
I don't know how prevalent this type is, but I find it much easier to write and read. Maybe this example could be covered?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.