Using ScrollMagic.js as AMD module - javascript

How can one use the excellent ScrollMagic JS plugin as an AMD module to use with requirejs for example?
I couldn't find any reference to that online and looking at the code of ScrollMagic it doesn't seem as if it loads as an AMD module.
It does define 2 variables in the window level at the end of the module:
window.ScrollScene = ScrollScene;
window.ScrollMagic = ScrollMagic;
so it seems that a simple shim won't do because I'll need to export two variables. Is there a way to export that?
Any ideas?
Thanks!

I found something that works for me, it's little bit of a work around, but it does the trick.
in the shim configuration of requirejs I use:
shim: {
'scrollmagic': {
deps:['jquery', 'TweenMax'],
exports: 'ScrollMagic',
init: function() {
return {ScrollMagic: ScrollMagic,
ScrollScene: ScrollScene};
}
}
}
This is to comply with the fact that ScrollMagic requires jQuery as well as GSAP TweenMax libraries to be loaded.
It turns out that using the init function of the shim and then returning the two variables, does the trick.
BUT - this means that for using the ScrollMagic plugin one should use (example):
define(['scrollmagic'], function(scrollmagic) {
var magic = new scrollmagic.ScrollMagic();
var scene = new scrollmagic.ScrollScene({duration: 200});
});
Hoping that this will help somebody in the future...
== Edit ==
ScrollMagic 1.3 now supports the AMD pattern, so all this is unnecessary.

Related

Restore original lodash method overwritten by mixin?

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.

Can I use an ES6/2015 module import to set a reference in 'global' scope?

I have this situation where I am trying to import an existing library, which I'll call troublesome (using Webpack/Babel FWIW) and it has a global reference to jQuery in it which i am trying to resolve using module syntax.
I have successfully imported jquery into the 'local' scope of a module, via:
import jQuery from 'jquery'
so I tried:
import jQuery from 'jquery'
import 'troublesome'
but perhaps not surprisingly, I get something like jQuery is not a function kicked back from troublesome.js
I have tried this as well:
System.import('jquery')
.then(jQuery => {
window.jQuery = jQuery
})
import 'troublesome'
but, it turns out that System.import is part of the, so-called, 'module-loader' spec, which was pulled from the es6/2015 spec, so it isn't provided by Babel. There is a poly-fill, but Webpack wouldn't be able to manage dynamic imports accomplished via calls to System.import anyway.
but... if I call out the script files in index.html like so:
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/troublesome/troublesome.js"></script>
<script src="the-rest-of-my-js.js"></script>
the reference to jQuery is resolved in troublesome.js and things are good,
but I would prefer to avoid the script tag route as webpack doesn't manage those.
Can anyone recommend a decent strategy for dealing with scenarios like this?
update
with some guidance from #TN1ck, I was eventually able to identify one Webpack-centric solution, using the imports-loader
The configuration for this solution looks something like this:
//...
module: {
loaders: [
//...
{
test: require.resolve('troublesome'),
loader: "imports?jQuery=jquery,$=jquery"
}
]
}
Shimming modules is the way to go: http://webpack.github.io/docs/shimming-modules.html
I quote from the page:
plugin ProvidePlugin
This plugin makes a module available as variable in every module. The module is required only if you use the variable.
Example: Make $ and jQuery available in every module without writing require("jquery").
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
})
To use this with your webpack-config just add this object to an array called plugins in the config:
// the plugins we want to use
var plugins = [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
})
];
// this is your webpack-config
module.exports = {
entry: ...,
output: ...,
module: ...,
plugins: plugins
}
For es6/2015 I done the following.
import {jsdom} from 'jsdom';
import jQuery from 'jquery';
var window = jsdom(undefined, {}).defaultView;
var $ = jQuery(window);
//window.jQuery = $; //probably not needed but it's there if something wrong
//window.$ = $;//probably not needed but it's there if something wrong
Then you can use it as normal
var text = $('<div />').text('hello world!!!').text();
console.log(text);
Hope this helps.
Importing jQuery into your module does not make it available for 'troublesome'. Instead, you could create a thin wrapper module for 'troublesome' that provides jQuery and any other required "globals".
troublesome-module.js:
// Bring jQuery into scope for troublesome.
import jQuery from 'jquery';
// Import any other 'troublesome'-assumed globals.
// Paste or have build tool interpolate existing troublesome.js code here.
Then in your code you should be able to
import 'troublesome-module';
I've had a similar issue using jspm and dygraphs. The way i solved it was to use dynamic loading like you attempted using System.import but the important part was to chain-load each consecutive "part" using System.import again inside the promise onfulfillment handler (then) after setting the global namespace variable. In my scenario I actually had to have several import steps separated between then handlers.
The reason it didn't work with jspm, and probably why it didn't work for you as well is that the import ... from ... syntax is evaluated before any code, and definitely before System.import which of async.
In your case it could be as simple as:
import jQuery from 'jquery';
window.jQuery = jQuery;
System.import('troublesome').then(troublesome => {
// Do something with it...
});
Also note that the System module loader recommendation has been left out of the final ES6 specification, and a new loader spec is being drafted.
run npm install import-loader.
replace import 'troublesome' with import 'imports?jQuery=jquery,$=jquery!troublesome.
In my opinion, this is the simplest solution to your question. It is similar to the answer you wrote in your question #TN1ck, but without altering your webpack config. For more reading, see: https://github.com/webpack/imports-loader
Shimming is fine and there are various ways of resolving this, but as per my answer here, the simplest is actually just to revert to using require for the loading of the library that requires the global dependency - then just make sure your window. assignment is before that require statement, and they are both after your other imports, and your ordering should remain as intended. The issue is caused by Babel hoisting imports such that they all get executed before any other code.

Hide global window.google.maps object with AMD

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"), ....);
...
});

Faux-server dosnt work corectly with require.js

I have some Backbone Model structure in my project. Each of this model need to fetch or save and I decided to use a faux-server to mocks the server-side. In my projekt i also use a require.js and with it I have a problem.
Example:
define([
'models/billings/details',
'models/statistics/abonent',
'mocks/billings/details',
'mocks/statistics/abonent'
], function(detailsModel, statisticsAbonentModel) {
var detailsM = new detailsModel();
detailsM.fetch({async: false});
var statisticsAbonentM = new statisticsAbonentModel();
statisticsAbonentM.fetch({async: false});
});
When I define more then one mocks - only the last always run, the previous not.
When i define only one, it always run.
I try to use shim in requrie to have a one global fauxServer for each mocks but it doesnt work.:
shim:{
fauxServer: {
deps['backbone'],
exports: 'fauxServer'
}
}
I dont know where is the problem.
Here is an answer
update the lib version of faux-server to at least 0.9.3
You dont need the shim - faux-server is an AMD module
Be sure if your route function name is a unique

Load prototype enhancements with require.js

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 = {
(...)

Categories