RequireJS, jquery still undefined - javascript

I know this has already been discussed, but after searching for a while I can't figure out why my small setup does not load jquery correctly with requireJS.
I'm running a small sample html page from 'file://' and try to load 2 modules with a call to require:
jquery
a custom module I wrote
If my custom module loads correctly (i can use it with its alias in the require call, jquery is always undefined)
I tried to setup paths in require.config, as well as shim (exporting '$' or 'jQuery') but it does not work.
The only way i can get jquery to correctly load, is removing all paths definition and naming the jquery file on my filesystem 'jquery.js'
Here is my config:
main.js:
require.config({
baseUrl: 'scripts',
paths: {
jquery: 'jquery-2.1.3.min' //does not work
//jquery: 'http://code.jquery.com/jquery-2.1.3.min.js' //does not work either
}
});
console.log( "main.js is loaded" ); //this is correctly ouputed to the console
test.html:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<!--
... page content ...
-->
<!-- main.js is loaded from data-main -->
<script data-main="scripts/main" src="scripts/require.js"></script>
<script type='text/javascript'>
require(
['jquery','custom'],
function($, Custom){
console.info('$:');
console.info($); //outputs undefined
console.info('Custom:');
console.info(Custom); //outputs my custom object
});
</script>
</body>
</html>
Once again, it works if I remove all paths definition for jquery, and simply name my jquery js file 'jquery.js' but this is sloppy.
Can somebody points me on the right way to go ?

The problem is that you load your RequireJS configuration, which is in main, through data-main. The data-main attribute merely tells RequireJS to load the module listed there but the loading is still asynchronous, so main may load after RequireJS tries to load jQuery. When this happens, RequireJS fails to find jQuery and $ is undefined. (Incidentally, I'd suggest setting enforceDefine to true in your RequireJS configuration so that you get an error message telling you when a module has not loaded. That's a better clue than having an undefined symbol.)
One solution would be to move your configuration outside of main. So you remove it from main and add it to a script element in front of the one loading RequireJS:
<script>
// RequireJS will use the value of `require` as its configuration.
require = {
baseUrl: 'scripts',
paths: {
jquery: 'jquery-2.1.3.min'
},
enforceDefine: true
};
</script>
<script src="scripts/require.js"></script>
Or you can nest require calls to force main to load before any other module:
require(['main'], function () {
require(['jquery','custom'], ...
});

Related

How to create fallback for CDN libraries without using document.write()

I want to include 3rd party libraries, such as jQuery, from CDN. I also want to create a fallback so if the CDN fails, I include my own local copy. I have followed the suggestion here:
This is how I include jQuery in my page:
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script>window.jQuery || document.write('<script src="/Scripts/jquery-3.3.1.min.js"><\/script>');</script>
At the same time Google is saying that document.write() is unreliable and should not be used:
Using document.write() can delay the display of page content by tens
of seconds and is particularly problematic for users on slow
connections. Chrome therefore blocks the execution of document.write()
in many cases, meaning you can't rely on it.
Is there any alternative method to create fallback for the CDNs?
If you don't mind loading it asynchronously you can do it like this:
function fallback() {
var element = document.createElement('script');
element.type = 'text/javascript';
element.src = 'https://code.jquery.com/jquery-3.3.1.min.js'; // or your path to your local script
document.body.appendChild(element);
}
window.jQuery || fallback();
setTimeout(function() {
console.log(window.jQuery);
}, 1000); // Add timeout since script is loaded asynchronously
I recommend using 3p packages like fallback.js or require.js given they are more scalable in case you have multiple fallbacks and they give you faster loading performance.
Example of fallback.js
HTML CODE
<html>
<head>
<!-- **The `data-main` attribute tells the library to load `main.js`** -->
<script async data-main="main" src="fallback.min.js" type="text/javascript"></script>
</head>
<body>
</body>
</html>
MAIN JS FILE
cfg({
"libs": {
"jQuery": {
"urls": [
"//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min",
"//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min"
]
},
}
});
req(function(jQuery) {
jQuery("body");
});
Example of require.js
requirejs.config({
enforceDefine: true,
paths: {
jquery: [
'https://code.jquery.com/jquery-3.4.1.min.js',
//If the CDN location fails, load from this location
'js/jquery-3.4.1.min.js'
]
}
});
require(['jquery'], function ($) {});

Require.js load CDN bootstrap and CDN popper

I wish to use require.js to load CDN hosted bootstrap and jquery.
I realise that this question has been asked before (Refer Steve Eynon's answer to Issue Loading PopperJS and Bootstrap via RequireJS, Even After Using Recommended PopperJS Version), but the posted answers do not work for me.
What I have tried so far
The host html file has content ...
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
<script data-main="js/market-place" src="js/lib/requirejs/require.min.js"></script>
</head>
<body>
html content etc.
</body>
</html>
File js/market-place.js has content ...
console.log( 'market-place.js');
requirejs(['./decision-market-common'], function(){
console.log( 'common requirement met.');
require(['bootstrap'], function( bootstrap){
console.log( 'bootstrap requirement met.');
});
});
File js/decision-market-common.js has content ...
console.log( 'decision-market-common.js');
requirejs.config({
paths: {
jquery : 'https://code.jquery.com/jquery-3.3.1.slim.min',
popper : 'https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min',
bootstrap: 'https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min'
},
shim: {
bootstrap: {
deps: ['jquery', 'globalPopper']
}
}
});
define( 'globalPopper', ['popper'], function( p){
window.Popper = p;
console.log( 'global Popper is set.');
return p;
});
Result
Using Chrome as my development browser, I get the following results, at first in the javascript console ...
market-place.js
decision-market-common.js
common requirement met.
global Popper is set.
But then I get javascript error:
Failed to load resource: net::ERR_FILE_NOT_FOUND
require.js is trying to load ./popper.js, even after it has succesfully loaded the CDN popper.js ! Why?
The answer on this question / at Issue Loading PopperJS and Bootstrap via RequireJS, Even After Using Recommended PopperJS Version didn't work for me.
My scenario was:
Using Bootstrap 4.1.3 (not possible to move to a different version)
Unable to use the bundled version, as I wanted to change the defaults within Popper (specifically, to disable GPU Acceleration to resolve some issues with blurry text in a tooltip)
Using the bundled version, I wasn't able to access the version of Popper "inside" Bootstrap to change the defaults.
Eventually, I came across the "map" option within RequireJS (https://requirejs.org/docs/api.html#config-map). I added this to my RequireJS config:
map: {
'*': {
'popper.js': 'popper'
}
}
That resulted in RequireJS resolving Popper correctly.
Not a perfect solution and I can't guarantee it will work for anyone else, but I spent a while on this, so I hope this helps someone!
And the answer is ...
use bootstrap version 4.0.0-beta. Version 4.0.0-beta works, but any version later (4.0.0 through to 4.1.3) is broken, with respect to requirejs support.
An alternative is to use the bundle version of bootstrap, and then you can use the latest version and don't need to link popper. There is no CDN of bundle bootstrap, so you would need to make a local copy. In this case, file js/decision-market-common.js looks like:
need to explicitly
console.log( 'decision-market-common.js');
requirejs.config({
paths: {
jquery : 'https://code.jquery.com/jquery-3.3.1.slim.min',
bootstrap: 'lib/bootstrap/bootstrap.bundle.min'
},
shim: {
bootstrap: {
deps: ['jquery']
}
}
});
Also, one small point: It is better to use requirejs() rather than require() (, I think?).

jquery not working well on node-webkit

I am practicing node-webkit as a nodejs beginner.
My main page is a simple html page including a main.js script
I've installed jquery using npm install jquery
index.html
<!-- index.html -->
...
<script src="js/main.js"></script>
</head>
<body>
<div id="demo">Hi! </div>
</body>
</html>
main.js
// main.js
const $ = require('jquery')
$(document).ready(function () {
$('#demo').click(function () {
$(this).text($(this).text() + 'Hi! ')
})
})
If I load jquery in my index.html like <script src="path/to/jquery.js"></script> it works well, but if I require jquery in my main.js it doesn't!
I've already tested:
main.js is properly including and working with native js methods (like document.getElementById('demo').onclick = ...)
Other node modules or libraries such as vue, lodash or natives like fs, url work well. So require function works good.
While I'm requiring jquery as above, inline <script>s doesn't work as well.
Also I realized $(document).ready(...) works! But the real problem is that $('#demo') is undefined! (I checked the console-I'm using SDK version of node-webkit)
I don't know if it's because of node-webkit or something else I'm missing?
found the solution,
I should define jquery like this:
window.$ = window.jQuery = require('jquery')
this is simply because of variable scopes in ECMAS
so if I define it like this, I can use it everywhere

Dependencies in RequireJS with Backbone, Underscore, and jQuery in 2014

I have seen a lot of questions regarding using RequireJS w/ Backbone, Underscore, and jQuery. My question is slightly different; my app works, but I don't know why.
Currently, Underscore, jQuery, and Backbone all export AMD modules, so there is no need for me to shim them and export their variables anymore. Therefore, my main.js looks like the following code snippet.
main.js
require.config({
paths: {
jquery: 'lib/jquery/jquery-1.10.2',
'jquery-ui': 'lib/jquery/jquery-ui-1.10.4.min',
underscore: 'lib/underscore/underscore.min',
backbone: 'lib/backbone/backbone.min',
'backbone.localStorage': 'lib/backbone/backbone.localStorage'
}
});
require(['jquery', 'jquery-ui', 'underscore', 'backbone', 'backbone.localStorage'], function() {
});
require.html
<!DOCTYPE html>
<html>
<head>
<title>My Sample Project</title>
<!-- data-main attribute tells require.js to load
scripts/main.js after require.js loads. -->
</head>
<body>
<h1>My Sample Project</h1>
<div id="test"> </div>
<script type="text/javascript" data-main="js/main" src="js/lib/require/require.js"></script>
<script type="text/javascript">
</script>
</body>
</html>
When I go to require.html, I can go to console and all my variables are there correctly loaded. For example, var x = Backbone.Model.extend({}); var y = new x; works just fine. However, Backbone depends on both Underscore and jQuery. Does RequireJS automatically resolve these dependencies using the modules supplied by these library, or is it only working as a fluke?
You have require right after requirejs config setup
require(['jquery', 'jquery-ui', 'underscore', 'backbone', 'backbone.localStorage'], function() {
});
They loaded in the correct order by a chance, to control that sequence you need to define dependencies of each module in a shim
Require helps a lot with this kind of work.
You can specify dependencies in a easy and correct way usim 'shim' command like this.
//Coffeescript example
paths:
backbone : 'path/backbone'
underscore : 'path/underscore'
jquery: 'path/jquery'
shim:
backbone:
deps:['underscore','jquery']
exports: 'Backbone'
This way you define that when a module called 'Backbone' was called, require will load all the dependencies written inside deps:[].
Now it will never load backbone before underscore.
I have a blog and a post about it, unfortunately it's only in portuguese, but maybe helps.
http://www.rcarvalhojs.com/backbone/2014/06/03/comecando-require-backbone.html

Convert existing web project to requirejs

I have an existing project that structure something like this, just like normal common webpage:
<script src="js/jquery.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/nanoscroller.min.js"></script>
<script src="js/bootbox.min.js"></script>
<script src="js/myscript1.js"></script>
<script src="js/tinymce.min.js"></script>
<script>
$(function(){
// my inline script
// some code which should run after myscript1.js
});
</script>
<script src="myscript2.js"></script>
Now, I try to do it with requirejs.
<script type="text/javascript">
var require = {
baseUrl: 'js',
paths: {
'jquery' : ['jquery.min'],
'bootstrap' : ['bootstrap.min'],
'nanoscroller' : ['nanoscroller.min'],
'bootbox' : ['bootbox.min'],
'myscript1' : ['myscript1'],
'tinymce' : ['tinymce.min']
},
shim: {
'bootstrap' : ['jquery'],
'nanoscroller' : ['jquery'],
'bootbox' : ['bootstrap']
}
}
</script>
<script src="require.js"></script>
<script>
require(['myscript1','tinymce'],function(){
$(function(){
// my inline script
// some code which should run after myscript1.js
});
}
</script>
<script src="myscript2.js"></script>
In myscript1.js
define(['jquery','bootstrap','nanoscroller','bootbox'],function(){
//all the myscript1 original code here
}
In myscript2.js
require(['myscript1','tinymce'],function(){
//all the myscript2 original code here
}
Well, this is just example to illustrate the structure. In my real project there are a lot more plugins and myscript.
The problem is when I run the page, sometimes everything is running and most of the time some of my script code doesn't even execute. Especially inline script. The biggest trouble is, many of the time I can't see any error in my console window. No sign of error showing up at all. No way to trace. I also try with requirejs.onError, but it doesn't seem help at all.
When it does shows up error, usually is jquery is not loaded problem. I am very curious as I have added jquery as the requirement for all of it. But, how can if the jquery is not loaded and it goes to execute the code?
Is it because my structure is wrong? Do I really need to rewrite the whole project just to get it works with requirejs? If you know how, please guide me with example of code for easier understanding.
Thank you.

Categories

Resources