Suppose I need to use a library which is accessed via a global variable e.g. jQuery, lodash, d3, etc. Let’s assume that the library does not export modules of any flavor.
What is the best way to import such a library?
Option 1: Just use the global
This seems counterproductive – modules are a superior method of sharing code. Nonetheless, it is apparently an option some pursue.
Example usage with lodash, which uses the _
global variable, in an adapter:
// adapters/my-custom-adapter.js
findQuery: function(store, type, query) {
return this.findAll(store, type).then(function(data) {
return _.filter(data, _.matches(query))
});
}
- Pros
- No effort, just import the library in your Brocfile
- Cons
- Undermines the benefits of modules
Option 2: Create a vendor/shims.js file
Another option is to wrap the global in a module so it can be imported in the standard fashion.
Example usage:
// vendor/shims.js
define('lodash', [], function() {
'use strict';
return {default: _};
});
// adapters/my-custom-adapter.js
import _ from 'lodash';
findQuery: function(store, type, query) {
return this.findAll(store, type).then(function(data) {
return _.filter(data, _.matches(query))
});
}
- Pros
- You can import in a familiar way
- I have seen this approach before
- Cons
- You must use AMD module syntax (i.e. the transpiler target module syntax). Using AMD seems bad because then the transpiler abstraction leaks. Shouldn’t we always use ES6 module declarations?
Sidebar Anyone know why the transpiler doesn’t support the module
declaration (which I think is part of the ES6 spec)?
module 'lodash' {
export default: _;
}
So I guess option 2b is modify the transpiler to support module
.
Option 3: Create a vendor/lodash.js, use ES6 modules
Similar to option 2, but each vendored lib gets its own file.
Example usage:
// vendor/lodash.js
export default _;
// adapters/my-custom-adapter.js
import _ from 'vendor/lodash';
findQuery: function(store, type, query) {
return this.findAll(store, type).then(function(data) {
return _.filter(data, _.matches(query))
});
}
- Pros
- Uses ES6 modules
- Cons
- Clunkier import path and more ceremony for adding new libs
Option 4: Modify the loader to use globals
It looks like there is some precedent in ES6 polyfills for loading globals when all else fails. That is, when a module has not been registered, there is a final check to see if the required module name is defined globally. I’m curious if this is considered a bad idea.
Example usage:
// adapters/my-custom-adapter.js
import _ from '_';
findQuery: function(store, type, query) {
return this.findAll(store, type).then(function(data) {
return _.filter(data, _.matches(query))
});
}
Am I missing potential solutions? Which solution is preferable?
Thanks!