简体   繁体   中英

How to give a JavaScript module conditional AMD support?

I'm building a module that I want to make available both for people that use AMD and for ones that don't. For example, I want to make it work with RequireJS:

require(['Module'], function (Module) {
  // do stuff with module
});

But I also want it to work by manually inserting all dependencies (considering they also work without AMD).

How can I test that this behavior is correct?

A working approach I found was to use the module pattern in my script file so that there are no leaked dependencies. Afterwards, I build an internal function that receives my dependencies as parameters and returns the object that represents the module I want to export.

Then, I check if there is a define function available and if it has the amd property set on it. If yes, then I register the module with define, otherwise I export it as a global.

Here's a skeleton of the code for this. We'll assume that the module is named Module and it has two dependencies, dep1 and dep2 :

(function (exports) {
  "use strict";
  var createModule = function (dep1, dep2) {
    var Module;
    // initialize the module
    return Module;
  }
  if (typeof define === 'function' && define.amd) {
    define(['dep1', 'dep2'], function (dep1, dep2) {
      return createModule(dep1, dep2);
    });
  } else {
    exports.Module = createModule(dep1, dep2);
  }
})(this);

Regarding the tests, I'm currently using yeoman for it, with mocha and PhantomJS . Here's how to make testing work with require. The approach I've taken to test both cases (with and without AMD) is to have two separate html tests. First of all, you need to add the second page in the Gruntfile:

// headless testing through PhantomJS
mocha: {
  all: ['http://localhost:3501/index.html', 'http://localhost:3501/no-amd.html']
},

In the first case, there's the normal require-based template:

<script src="lib/mocha/mocha.js"></script>
<!-- assertion framework -->
<script src="lib/chai.js"></script>

<!-- here, main includes all required source dependencies, 
    including our module under test -->
<script data-main="scripts/main" src="scripts/vendor/require.js"></script>

<script>
  mocha.setup({ui: 'bdd', ignoreLeaks: true});
  expect = chai.expect;
  should = chai.should();
  require(['../spec/module.spec'], function () {
    setTimeout(function () {
      require(['../runner/mocha']);
    }, 100);
  });
</script>

For testing non-amd, we need to explicitly include the module and all dependencies. After all is present in the page, we include the runner.

<script src="lib/mocha/mocha.js"></script>
<!-- assertion framework -->
<script src="lib/chai.js"></script>

<!-- include source files here... -->
<script src="scripts/vendor/dep1.js"></script>
<script src="scripts/vendor/dep2.js"></script>
<script src="scripts/Module.js"></script>

<script>
  mocha.setup({ui: 'bdd', ignoreLeaks: true});
  expect = chai.expect;
  should = chai.should();
</script> 
<script src="spec/romania.spec.js"></script>
<script src="runner/mocha.js"></script>

It doesn't make any sense to have two different specs, but the spec should also work with AMD and without it. The solution is similar to the one we used for the module.

(function () {
  "use strict";
  var testSuite = function (Module) {
    // break the module into pieces :)
  };
  if (typeof require === 'function') {
    require(['Module'], function (Module) {
      testSuite(Module);
    });
  } else {
    // if AMD is not available, assume globals
    testSuite(Module);
  }
})();

If you have different or more elegant ways to do this, please post them as answers here. I'd be happy to accept a better answer. :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM