aearly/grunt-urequire

UMD Template and rootExports

pvoisin opened this issue · 9 comments

Hi!

I have two AMD modules, A & B, which I'm trying to convert using UMD template so that they either available as AMD, CommonJS & available in global using rootExports.

So, for example, I'm including that fragment in the configuration:

rootExports: ["A"],
noRootExports: false // which isn't supposed to be required based on what I've read

But I'm getting the following:

(function (factory) {
  if (typeof exports === 'object') {
    var nr = new (require('urequire').NodeRequirer) ('A', module, __dirname, '.');
    module.exports = factory(nr.require, exports, module);
} else if (typeof define === 'function' && define.amd) {
    define(factory);
  }
}).call(this, function (require, exports, module) {

I thought I should have gotten an additional else block like:

else {
  global.A = factory();
}

There should be something I'm getting wrong. Any idea?

It seems you 've used rootExports in the config, which isn't right.

You 'll either use rootExports as

({urequire: { rootExports: 'A' } });

on top of moduleA_Path/A.js file (as a sort of in-line directive)

OR

you use dependencies.exports.root key in the config:

dependencies: exports: root: 'moduleA_Path/A': 'A'

With the latter you have noConflict() always on, with the first you can control it (default is off).

An you're right, noRootExports: false is the default and redundant.

Thanks for your answer. I'm having hard times catching it... :-)

Here's what I get from the following configuration. I see some changes in the generated code but it still doesn't export to global scope when I load the files in a browser. Does that ring any bell to you?

urequire: {
    UMD: {
        debugLevel:90,
        verbose: true,
        path: "source",
        main: "XML",
        dstPath: "distribution",
        dependencies: {
            exports: {
                root: {"XML": "XML", "XPath": "XPath"}
            }
        }
    }
}
// Generated by uRequire v0.6.11 - template: 'UMD' 
(function (window, global) {

var __isAMD = !!(typeof define === 'function' && define.amd),
    __isNode = (typeof exports === 'object'),
    __isWeb = !__isNode;
(function (factory) {
  var rootExport = function (root, __umodule__) {
  var __old__xml0 = root['XML'];
root['XML'] = __umodule__;

__umodule__.noConflict = function () {
  root['XML'] = __old__xml0;
return __umodule__;
};
return __umodule__;
};if (typeof exports === 'object') {
    var nr = new (require('urequire').NodeRequirer) ('XML', module, __dirname, '.');
    module.exports = rootExport(global, factory(nr.require, exports, module));
} else if (typeof define === 'function' && define.amd) {
    define(function (require, exports, module) {
  return rootExport(window, factory(require, exports, module));
});
  }
}).call(this, function (require, exports, module) {


var XML = {};

  return XML;


})
}).call(this, (typeof exports === 'object' ? global : window), (typeof exports === 'object' ? global : window))

Hmm very weird - one possibility I can think of is that you are loading the UMD module/file directly, i.e

  <script src="XML.js"></script>

instead of using an AMD loader (like RequireJS) to load your "XML" dependency, eg

  <script src="bower_components/requirejs/require.js" data-main="XML"></script>

I tested the latter and it worked fine, the XML {} is exposed with a noConlict() baked in.

Maybe I should add a check aka after if (typeof define === 'function' && define.amd) { add an else clause:

        } else {
          throw new Error("UMD runs only on AMD or CommonJS environments");
        }

You can add this check manually to test this case.

If you want a standalone file that works as AMD/CommonJS but also as plain <script src='...'> you can use the combined template which has a tiny AMD loader (almond) embedded.

Thanks again! Indeed, I'm loading it like a standalone script. I thought UMD designed to support either AMD, CommonJS and global exports, like it is written here:

>'UMD' template is based on a familiar standardized UMD template with optional global exports inspired by returnExportsGlobal.js.

So according to what I read it could be so but it absoluetly requires that what loads the scripts is AMD or CommonJS-based?

P.S.: I'm having trouble to connect to urequire.org now - I hope it is a local problem.

Well, practically it would be easy to execute a single UMD file & export it when running as plain <script src='...'>, along these lines:

        if (typeof define === 'function' && define.amd) {
          ....
        } else { // plain <script src='...'> execution
          var require = function(){ throw new Error("Can't require outside AMD or CommonJS environments")};
          var exports = {};
          var module = {exports: exports};
          rootExport(window, factory(require, exports, module));
        }

but it will only work for single files that dont have have other dependencies, i.e dont require() something else. The reason is that you either:

  • need a loader to do the work, aka RequireJS (which is inherently NON blocking / asynchronous due to browser env)

OR

  • pre-bundle all files in one package (with internal mini-loader), just as combined template or other bundlers like browserify do.

I assumed that since the whole point of modules & uRequire is to promote splitting of you complex project into many interdependent files and disavow the one-large-javascript-file plague, these extra 4 lines of code would be a waste of space. Of course it could be a config option like build.noLoaderUMD: false to control the output. Still I think having one file with no deps is an anti-pattern and should be avoided.

If you really need this feature, perhaps you could help by forking uRequire and amend ModuleGeneratorTemplates and declare the option in the config blending and then hit me with a PR :-) Help appreciated and reciprocated 👍

Great, thanks for your help/answer again. That's really appreciated!

I do agree with all that and I finally got a way through the tool now.

Be sure I'll participate for some addition if something valuable arises!

You're welcome :-)

PS: urequire.org expired to day and the registar is asking me for $100 bucks to restore it...grhhh!

Great, many thanks! I'll have a look for sure.