We're using the lodash-contrib package, which includes a camelCase method that behaves differently than the original _.camelCase method.
Is there any way for me to restore the pointer to the original method?
In the requirejs config, we have a shim:
lodashContrib: ['lodash']
As soon as lodashContrib has loaded, it's added mixins to lodash. An example of our code:
define([
'lodashContrib'
], function() {
// our code here. At this point, _.camelCase is overridden by contrib
});
Create a file lodashCustom.js or something you can add to your requirejs configuration, and put the following inside it, then wherever you require lodashContrib you can require this instead:
define(['lodash', 'lodashContrib'], function(_, _c) {
_c.camelCase = _.camelCase;
return _c;
});
Assuming your shim implementation doesn't rely on globals, this should hopefully work fine.
Related
I have an existing project (which is run fully in the browser, no server-side component) which uses RequireJS to manage dependencies. Previously the way I'd been defining "classes" (including inheritance) was like this:
define([
'jquery',
'classes/SomeParentClass',
], function($, SomeParentClass){
function ThisClass(data){
SomeParentClass.call(this, data);
this.init = function(data){
//Do stuff
}
this.init(data);
}
ThisClass.prototype = Object.create(SomeParentClass.prototype);
ThisClass.prototype.constructor = ThisClass;
return ThisClass;
});
And then when I wanted to include it in some other class I'd use the standard RequireJS define/require syntax:
define(['classes/ThisClass'], function(ThisClass){
var fooInstance = new ThisClass(fooData);
});
I wanted to try my hand at the "class" syntax in ES6, so I set about converting one of my existing classes (I started with a "static" class for simplicity). It currently looks something like this:
define([
'jquery',
], function($){
class SomeClass {
static someStaticFn(){
//Do whatever
}
}
});
Where I'm stymied currently is how to reference SomeClass (with the new ES6 syntax) using RequireJS. Assuming that's even possible.
UPDATE
As others have pointed out below, returning the class is all RequireJS cares about. I could have sworn that I already tried that, but sure enough it worked.
In case anyone else is a dummy like me and ends up here under similar circumstances, I want to also point out that I did have some success with the requirejs-babel plugin, however only after I'd re-written my class to use ES6 export and import statements instead of RequireJS's define. After having done that, anywhere else I was including the class I had to do it like so:
define(['es6!ThisClass'], function(ThisClass){ ...
I ended up choosing to modify a class that was included in every other module, so adding all those "es6!" strings turned out to be quite a drag. Although this article on porting existing projects to ES6 mentions a way of automating the process via RequireJS config.
However, as requirejs-babel transpiles the ES6 code at runtime, I will probably not incorporate that into my project at this time. If I do decide I want to go whole hog with ES6 I'd probably use "regular" Babel or possibly TypeScript
ES6 Class is just a sugarcoat and still with same implementation underneath. You can use it the old way as creating class by function. Also be careful with browser compatibility https://kangax.github.io/compat-table/es6/.
define([
'jquery',
], function($){
return class SomeClass {
static someStaticFn(){
//Do whatever
}
}
});
I'm trying to understand how requireJs works, could somebody please explain to me, why in the following example:
http://plnkr.co/edit/HEDc8F19wICMy0zeGWpH?p=preview
More specifically here:
require(['ble'], function () {
$('#someDiv').html(Ble.A());//This works fine
var zip = new JSZip();//This fails with JSZip is not defined
console.log(zip);
});
Jquery is defined, but JSZip is not? I also tried other combinations, but only one that seems to work is when I manually specify jszip in require array like this:
require(['jszip','ble'], function (JSZip) {
$('#someDiv').html(Ble.A());
var zip = new JSZip();
console.log(zip);
});
I know that documentation states:
The shim config only sets up code relationships. To load modules that
are part of or use shim config, a normal require/define call is
needed. Setting shim by itself does not trigger code to load.
But then - is jquery some kind of "special case" and I should normally, inject my dependencies manually even if they are specified in shim config section?
ASWER:
So it turns out jQuery is indeed a special case, and normally a manual injection of dependencies is required...
If you look in the source code of jQuery you will find the following:
// Register as a named AMD module, since jQuery can be concatenated with other
// files that may use define, but not via a proper concatenation script that
// understands anonymous AMD modules. A named AMD is safest and most robust
// way to register. Lowercase jquery is used because AMD module names are
// derived from file names, and jQuery is normally delivered in a lowercase
// file name. Do this after creating the global so that if an AMD module wants
// to call noConflict to hide this version of jQuery, it will work.
// Note that for maximum portability, libraries that are not jQuery should
// declare themselves as anonymous modules, and avoid setting a global if an
// AMD loader is present. jQuery is a special case. For more information, see
// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
if ( typeof define === "function" && define.amd ) {
define( "jquery", [], function() {
return jQuery;
});
}
This means that jQuery will - when required - define itself as jquery.
require(['jszip','ble'], function (JSZip) {
In this above statement, it imports the jszip and returns a object as JSZip.
var zip = new JSZip();
Here that object is used. So with this code you did not get error.
Thus, For jszip, just require is not enough.
I am starting to use RequireJS now and I was already able to add my project dependencies but I still cannot add a jQuery anonymous function yet.
For example, with my normal_file.js I do something like:
normal_file.js:
define(['dependency1'], function(Dependency) {
var Test1 = ...;
return Test1;
});
Bu from a file that has no module, like the example below, I don't know how to encapsulate it:
lib_file.js:
(function ($) {
// Do stuff...
})(window.jQuery);
the lib_file was not made by me and I'm not sure on how it really works, but I would gess it is an anonymous auto-executed function, is that so?.
Anyway, my goal is to use both files in my main code, like below:
main.js:
requirejs.config({
baseUrl:'/static/editorial/js/',
paths: {
jquery: 'third_party/jquery-1.10.2',
react: 'third_party/react-with-addons'
}
});
var dependencies = [
'third_party/react-with-addons',
'third_party/jquery-1.10.2',
'build/utils/normal_file,
'third_party/lib_file
];
require(dependencies, function(React, $, Test1, ??) {
// do my stuff
});
How should I encapsulate that anonymous function in order to add it as a dependency to my main file?
From the RequireJS docs:
Ideally the scripts you load will be modules that are defined by
calling define(). However, you may need to use some traditional/legacy
"browser globals" scripts that do not express their dependencies via
define(). For those, you can use the shim config. To properly express
their dependencies.
Read this: http://requirejs.org/docs/api.html#config-shim
It has a really good explanation of what you have to do, and gives a nice example.
Basically, you just need to set up a shim config for lib_file.js so Require knows to load the right dependencies before giving you access to that script.
I'm using the AMD module pattern and until now, it has been relatively simple to hide what would otherwise be global objects:
define([], function(){
/*jquery here */
var tmp = $;
$ = undefined;
return tmp;
}
However, I'm curious if it's possible to do something similar with google's global objects (I guess they're really into these.. maps and pretty much any of its APIs use em).
Just doing what I've done before actually breaks the code because. It seems internally google is self referencing itself with calls to the global window.google object from scripts it loads on the fly.
I'm going to keep investigating but am curious what you all think!
Thanks.
If you're using RequireJS as your AMD loader, you can use config shims to wrap non-AMD modules, express their dependencies, perform any necessary initializations (where you could clear their global, if the script supports it) and export their global.
For Google Maps, this would look something like this (and no, you probably don't want to clear the global google variable):
require.config({
paths: {
"maps": "https://maps.googleapis.com/maps/api/js?key=API_KEY"
},
shims: {
"maps": {
exports: "google.maps"
}
}
});
Later on, you can use this as a regular AMD module:
require(["maps"], function(maps) {
var map = new maps.Map(document.getElementById("map-canvas"), ....);
...
});
I am using require.js to load my modules which generally works fine. Nevertheless, I do have two additonal questions:
1) If you have a module that is like a helper class and defines additional methods for existing prototypes (such as String.isNullOrEmpty), how would you include them? You want to avoid using the reference to the module.
2) What needs to be changed to use jQuery, too. I understand that jQuery needs to be required but do I also need to pass on $?
Thanks!
1) If you have a module that is like a helper class and defines
additional methods for existing prototypes (such as
String.isNullOrEmpty), how would you include them? You want to avoid
using the reference to the module.
If you need to extend prototypes then just don't return a value and use it as your last argument to require:
// helpers/string.js
define(function() {
String.prototype.isNullOrEmpty = function() {
//
}
});
// main.js
require(['moduleA', 'helpers/string'], function(moduleA) {
});
2) What needs to be changed to use jQuery, too. I understand that
jQuery needs to be required but do I also need to pass on $?
The only requirement for jQuery is that you configure the path correct
require.config({
paths: {
jquery: 'path/to/jquery'
}
});
require(['jquery', 'moduleB'], function($, moduleB) {
// Use $.whatever
});
In my opinion it's unnecessary to use the version of RequireJS that has jQuery built into it as this was primarily used when jQuery didn't support AMD.
Nowadays it does and keeping it separate allows you to swap another library out easily (think Zepto).
2/ For jquery it's really simple :
require(["jquery", "jquery.alpha", "jquery.beta"], function($) {
//the jquery.alpha.js and jquery.beta.js plugins have been loaded.
$(function() {
$('body').alpha().beta();
});
});
More information on require site : http://requirejs.org/docs/jquery.html#get
1/ in my devs for such extension I did it in a global file without require module code.... and I include it in my app with require... not perfect, but it's work fine
global.js
myglobalvar ="";
(...other global stuff...)
myapp.js
// Filename: app.js
define([
(...)
'metrix.globals'
], function(.....){
myApp = {
(...)