Use jspm to load script that depends on global jQuery - javascript

Yes I've read How do I shim a non CommonJS, non AMD package which depends on global jQuery & lodash?.
I'm trying to load X.js, through jspm, which is not a 'package' but an old js file I have no control over that needs a global jQuery object and needs to run like it is in a script tag.
I'm using System.import('app/X'); to load it.
I tried various shim / globals tricks to make it load but I can't quite figure it out.
How would one write the config.js to be able to import that X file so that it sees a global jQuery object? Do I have to make X a 'package' and install it to be able to shim it better?
Thanks.

If you installed jquery through jspm, all you need is to set the meta 'deps' property like this:
System.config({
meta: {
'app/X': {
deps: ['jquery']
}
}
});
System.import('app/X');
Be sure to get the X path correctly and check how jspm sets up System.config 'paths' and 'map', by default trailing .js is added automatically (with paths *.js wildcard) so you must not add it.
Maybe try to look at these links from the documentation as well https://github.com/systemjs/systemjs/blob/master/docs/module-formats.md#globals https://github.com/systemjs/systemjs/blob/master/docs/config-api.md#meta

If providing the meta 'deps' property like the following (as suggested by Mathias Rasmussen) doesn't do the trick,
System.config({
meta: {
'app/X': {
deps: ['jquery']
}
}
});
then you may have to provide a 'globals' meta property like the following:
System.config({
meta: {
'app/X': {
globals: {
'jquery': 'jquery'
}
}
}
});
In order for the above to work you will have needed to install jquery via jspm. Doing the above should also allow you to import the plugin by doing System.import('app/X'); or import 'app/X'; without having to import jquery as well. Importing the plugin alone should also bring in jquery as a dependency.

Related

How to inject a dependency on an external script

I'm using a cloud service called Parse in a JavaScript closure injected with require.js:
define([/*some dependencies*/],
function(/*some dependencies*/) {
...
// using Parse. For example:
var TestObject = Parse.Object.extend("TestObject");
...
}
The tutorial for using Parse in Javascript instructs to include their script in the HTML header:
<script src="//www.parsecdn.com/js/parse-1.4.2.min.js"></script>
I don't want the HTML page to depend on Parse and I don't want to clutter the HTML with external scripts. Instead, I would like to require parse-1.4.2.min.js directly from the script. What's the proper way of doing so? How do I define this dependency and make it work?
Similar to jQuery, Parse adds itself to the global scope on load. If no other scripts depend on it, it can simply be included as a dependency in a module or require call.
require([
'https://www.parsecdn.com/js/parse-1.4.2.min.js',
], function () {
console.log(Parse);
}
If you are using any other non-AMD scripts that depend on Parse (or any other library) you will need to use a config/shim. It tells requireJS what order it should load the scripts, based on their dependencies.
E.g. when using a jQuery plugin, you wouldn't want it to load and execute before jQuery itself.
A config/paths setup also helps organise your project by allowing script locations to be defined in a single location and then included by reference.
See the requireJS docs for more info.
The following config/require successfully loads Parse and a fictional plugin:
require.config({
// define paths to be loaded, allows locations to be maintained in one place
paths: {
parse: 'https://www.parsecdn.com/js/parse-1.4.2.min',
plugin: 'example-non-amd-parse-plugin.js'
},
// define any non-amd libraries and their dependancies
shim: {
parse: {
exports: 'Parse'
},
plugin: {
exports: 'plugin',
deps: ['parse']
}
}
});
require(['parse'], function(Parse){
console.log(Parse);
});
// note Parse is not required
require(['plugin'], function(plugin){
// Parse is available as it is depended on by plugin and on the global scope
console.log(Parse, plugin);
});
So after all I just wrote this and it seems to work. Don't know what the problem was in the first place...
define(["https://www.parsecdn.com/js/parse-1.4.2.min.js"],
function () {

Using webpack to process an AMD library with external dependencies

I have a library written in AMD style that can be used with RequireJS. jquery and jquery-ui are assumed to be provided by the user of the library. Say it looks like this:
// main-lib.js
define(['jquery', './aux-lib.js'], function ($) { ..(1).. });
// aux-lib.js
define(['jquery', 'jquery-ui'], function ($) { ..(2).. });
I'm trying to figure out how webpack works. For example, say I want to bundle these files into a single AMD style library file that still assumes jquery and jquery-ui from the outside:
// out.js
define(['jquery', 'jquery-ui'], function ($) { ..(1)..(2).. } );
How is this accomplished?
When I run webpack with main-lib.js as entry-point, it will complain that it can't find jquery and jquery-ui. If I configure the correct paths with resolve.alias, it bundles jquery and jquery-ui into out.js, which is not what I want. I tried using output.externals to no avail.
This was a pretty simple, stupid mistake on my part. The relevant field is not output.externals, but simply externals. See here. The other two relevant fields introduced there are inside output, but externals is not.
PS: externals can also be an array. Here is my current configuration:
{
entry: './main-lib.js',
output: {
path: './',
filename: 'out.js',
libraryTarget: 'amd'
},
externals: ['jquery', 'jquery-ui']
}
It's working quite nicely.

How to use require.js with complicated source tree, or import something else from CommonJS'es main.js?

My JS code is Backbone.js based, so I think it is a good idea to separate "classes" with this logic as shown on picture (though I'm not sure where to place templates - in this packages or in global templates folder, and do not mind main.js - it is not related to CommonJS packages) :
Now since there is fairly lot of them - I've decided to use require.js to deal with this bunch of <script src=... tags but got stuck with app.js config file (which is the only one that I include like this -
<script data-main="/static/js/app.js" src="/static/js/libmin/require.js"></script>
What do I mean with stuck - of course I can iterate all this js files in require statement using names like PlayerApp/PlayerAppController.js, or using paths directive (not sure if it will make the code look not that ugly), but it would be cool if I can use something like python's from package import *, and of course there is no such thing in require.js.
The most similar thing is packages directive, but seems like it allows you to import only main.js from each package, so then the question is - what is the most correct way to load other files of concrete package from CommonJS's main.js? I have even found a way to determine current .js file's name and path - like this, and given that I can make up other files names in current package(if I will keep naming them with the same pattern), but still do not know how to import them from main.js
Edit:
There might be an opinion that it is not very clear what exactly am I asking, so let me get this straight: how on Earth do I import a huge amount of javascript files with that project structure in the most nice way?
You are mis-understanding the purpose of a module loader. require.js is not there to make it easy for you to import all of your packages into the current namespace (i. e. the browser). It is there to make it easy to import everything you need to run app.js (based on your data-main attribute). Don't try to import * - instead, just import thingYouNeed.
Configuration
What you will want to do is set up your require.config() call with all the necessary paths for libraries like Backbone that don't support AMD and then update your code to explicitly declare its dependencies:
require.config({
// Not *needed* - will be derived from data-main otherwise
baseUrl: '/static/js/app',
paths: {
// A map of module names to paths (without the .js)
backbone: '../libmin/backbone',
underscore: '../libmin/underscore',
jquery: '../libmin/jquery.min',
jqueryui.core: '../libmin/jquery.ui.core'
// etc.
}
shim: {
// A map of module names to configs
backbone: {
deps: ['jquery', 'underscore'],
exports: 'Backbone'
},
underscore: {
exports: '_'
},
jquery: {
exports: 'jQuery'
},
// Since jQuery UI does not export
// its own name we can just provide
// a deps array without the object
'jqueryui.core': ['jquery']
}
});
Dependencies
You will want to update your code to actually use modules and declare your dependencies:
// PlayerAppModel.js
define(['backbone'], function(Backbone) {
return Backbone.Model.extend({modelStuff: 'here'});
});
// PlayerAppView.js
define(['backbone'], function(Backbone) {
return Backbone.View.extend({viewStuff: 'here'});
});
// PlayerAppController.js
define(['./PlayerAppModel', './PlayerAppView'],
function(Model, View) {
// Do things with model and view here
// return a Controller function of some kind
return function Controller() {
// Handle some route or other
};
});
Now, when you require(['PlayerApp/PlayerAppController'], function(Controller) {}) requirejs will automatically load jQuery, underscore, and Backbone for you. If you never actually use mustache.js then it will never be loaded (and when you optimize your code using the r.js compiler, the extra code will be ignored there as well).

Adding RequireJS module that uses jquery on a page that already has jquery as a global

I have an add-on to an application (call it appX) that allows users to create their own customizations using javascript, css and appX's webservices api.
Usually customizations are small and do not involve a lot of external libraries/plugins but when they do have external libs the typical users' library of choice is jQuery.
In the next version of appX they are using jQuery natively which I know is going to break some of the customizations.
So I have a need to modularize this situation. I have some other problems that are coming up and RequireJS seems like a good solution to these issues. I just need to figure out how to apply RequireJS properly for this situation
In my POC I'm loading require.js as follows:
<!--A bunch of other script including jQuery (but not require) are loaded already -->
<script type="text/javascript" src="/custom/js/require.js"></script>
<script type="text/javascript" src="/custom/js/dostuff.js"></script>
We'll call the jQuery loaded with appX jqueryx and the one I want to load jqueryp (p for private)
jQuery utilizes AMD and by default uses this definition internally:
define( "jquery", [], function () { return jQuery; } );
But in this case RequireJS is loaded AFTER jQuery (jqueryx) so there will be no default 'jquery' definition correct?
Some more background before I show you my problem... the file structure is like this:
appx
/js:
jqueryx.js
other.js
appx
/custom/js:
jqueryp.js
dostuff.js
Looking at the RequireJS api it seems that I should be doing something like this:
require.config({
baseUrl : 'custom/js',
paths : { 'jquery' : 'jqueryp'},
map: {
'*': { 'jquery': 'jquery-private' },
'jquery-private': { 'jquery': 'jquery' }
}
});
define(['jquery'], function (jq) {
return jq.noConflict( true );
});
require(['jquery'], function(jq){
console.log(jq.fn.jquery);
});
But when I do this I get an error:
Mismatched anonymous define() module: function (jq)...
I've played around with switching references to jquery, jquery-private as it's kind of confusing but with no progress.
How should I be applying RequireJS to this situation?
Almost a year late but better than no answer at all...
The following part should be moved into a "jquery-private.js" file:
define(['jquery'], function (jq) {
return jq.noConflict( true );
});
You can't define a module in your main entry point. Even if you could, the module has no name so how would you reference it?

require.js loads dependencies incorrectly

So this is the setup, my base file is main.js which defines the scripts that are needed on all pages of the site I'm building. It looks like this:
define([
'/javascript/requirePlugins/require-order.js!http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js',
'/javascript/requirePlugins/require-order.js!/javascript/jquery-global-plugins.js',
'/javascript/requirePlugins/require-order.js!/javascript/globals.js'
], function () {
loadFonts();
}
);
It loads jQuery, some plugins and the globals script file. On one page I'm trying to load a jQuery plugin, but the plugin tries to load before jQuery is loaded. It looks like this:
require(['/javascript/requirePlugins/require-order.js!/main','/javascript/requirePlugins/require-order.js!/javascript/3rdparty/lemon-slider-0.2.js'], function () {
$j('#carousel<%= ClientID %>').lemmonSlider({loop:false});
});
The function doesn't appear to be following the order requested. I'm not sure I can even nest ordered functions like this. I've also tried just applying jQuery as a dependency, but this also fails:
require(['/javascript/requirePlugins/require-order.js!/jquery','/javascript/requirePlugins/require-order.js!/javascript/3rdparty/lemon-slider-0.2.js'], function () {
$j('#carousel<%= ClientID %>').lemmonSlider({loop:false});
});
Any suggestions to where I'm doing this wrong is appreciated, thanks
order plugin is removed and you may try shim config to load plugins in order
requirejs.config({
paths: {
'jquery': 'https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min',
'bootstrap': '../bootstrap/js/bootstrap.min',
'select2': 'vendor/select2',
'jshashtable': 'vendor/jshashtable-2.1',
'jquery.numberformatter': 'vendor/jquery.numberformatter-1.2.3.min',
'jq-datepicker': 'vendor/bootstrap-datepicker',
'jq-datepicker.da': 'vendor/bootstrap-datepicker.da'
},
// Use shim for plugins that does not support ADM
shim: {
'bootstrap': ['jquery'],
'select2': ['jquery'],
'jq-datepicker': ['jquery'],
'jshashtable': ['jquery'],
'jquery.numberformatter': ['jquery', 'jshashtable']
},
enforceDefine: true
});
EDIT:
require-jquery is also no more maintaining.
The order plugin is useful if you just have a few top-level scripts you wanted loaded in order and those scripts do not use the module API supported by requirejs. It does not work out so well if you mix it/use it to load modules that do use the define() module API.
In particular, order just makes sure the script gets loaded first. However, the define() API specifies other scripts to load, and the order plugin does not know to wait for those scripts to load.
For this particular problem, I suggest using require-jquery.js as sinsedrix suggested. That, or wrap the scripts you use in define() calls. volo can help you do this with its amdify command:
volo.js amdify path/to/lemon-slider-0.2.js depends=jquery
Also, I would set the baseUrl and use "module naming" for the dependencies instead of full paths. This will allow the optimizer to work correctly. You can also map 'order' to the requirePlugins path, which helps cut down some of the line noise. I would also create a 'jquery' paths entry so that if you do wrap the other plugins in define calls, it will map back to the jquery loaded in your main.js file. So, in the top level script for your page:
requirejs.config({
baseUrl: '/javascript/',
paths: {
order: 'requirePlugins/require-order',
jquery: 'http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min'
}
});
Then your main.js can be written like so:
define([
'order!jquery',
'order!jquery-global-plugins',
'order!globals'
], function () {
loadFonts();
}
);
Note that here, the order usage is fine, as long as those dependencies do not call define() themselves.
But if you are wrapping the scripts you use in define calls, then you can get rid of the order! usage above. Keep the jquery paths config though.
Maybe you should try tu use the require-jquery : http://requirejs.org/docs/jquery.html
Then you won't have to worry about when jquery is loaded.

Categories

Resources