What is RequireJS doing?

What is RequireJS doing?

by Justin Hunt -
Number of replies: 15
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Plugin developers

I am having trouble getting a javascript library that worked up until 2.8, work on 2.9.

It is a whiteboard called literallycanvas that has some dependencies (react.js / jquery / fastclick).

It fails to load and I get a huge long error in the console that I am pretty sure comes from RequireJS.

But its not actually an AMD module or called from one, yet.  Other libraries called in the same way, that use JQuery, don't error out. In this case the error messages from RequireJS are the only ones and they are pretty hard work. I don't know what to make of them. So I am not even sure if the problem with RequireJS.

The first one looks like this. This shows up all the time, on other pages too.

Error: Load timeout for modules: core/first
http://requirejs.org/docs/errors.html#timeout

This error is specific to the literallycanvas whiteboard. I truncated it to the first few lines ...

Error: Mismatched anonymous define() module: function (){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
/**


Is RequireJS loading all the javascript now, even the javascript that is not in AMD modules? Would packaging everything up into AMD modules be a way to solve this?

Average of ratings: -
In reply to Justin Hunt

Re: What is RequireJS doing?

by Damyon Wiese -
Picture of Core developers Picture of Moodle HQ Picture of Plugin developers Picture of Testers
RequireJS is only loading the AMD modules - nothing outside of an "amd" folder will be loaded.

But - if you have a javascript error earlier in the page, than the requirejs calls it could be affected.

Also - the above error does look more like you have some faulty AMD code somewhere so you should double check you haven't left any files in and "amd" folders.

You could disable "cachejs" to see the non-minified version of the JS in your browser, and you will probably get a better error message.
Average of ratings: Useful (1)
In reply to Justin Hunt

Re: What is RequireJS doing?

by Justin Hunt -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Plugin developers
I still have no fix for this, just a bit more information. I apologize in advance because this is a bit of brain dump. Really I have spent way too much time on this, and I just hope this just shortcuts the trouble shooting for somebody else. If anybody has some good advice though, that would be great. 


The problem is that requirejs doesn't like it if any other JS calls an an anonymous define. 

An anonymous define looks like this. ( the bit that says "define(e)" )

if ( typeof define === "function" && define.amd ){
    // AMD support
    define(e);
  }


In fact most of the time you see a bit of code like this, its designed to be used with requirejs or another amd loader. Don't get confused already, the idea is that requirejs (or the loader) will manage all that anonymous stuff for you and avoid conflicts with similarly named things in javascript.  As long as you load it with requirejs. 

So thats why requirejs is not loading my javascript, and yet its error'ing like crazy on me. Because LiterallyCanvas has the anonymous define thing you see above. So to get around this, I need to load up LiterallyCanvas with requirejs. 

To load it all used to look like this:

$PAGE->requires->js("/filter/poodll/js/literallycanvas.js/js/react-0.10.0.js");
$PAGE->requires->js("/filter/poodll/js/literallycanvas.js/js/fastclick.js");
$PAGE->requires->js("/filter/poodll/js/literallycanvas.js/js/ie_customevent.js");
$PAGE->requires->js("/filter/poodll/js/literallycanvas.js/js/literallycanvas.min.js");


I tried to load it all the AMD way via the info on the javascript modules page and actually it just ignored it all. So I think I was not even close. I added an amd folder and a src folder, and inside it put the literallycanvas.js folder. That looks a bit like this:

/literallycanvas.js/image/picture.jpg
/literallycanvas.js/css/style.css
/literallycanvas.js/js/literallycanvas.js
/literallycanvas.js/js/literallycanvas.min.js
/literallycanvas.js/js/react.js (dependency)
/literallycanvas.js/js/fastclick.js (dependency)

(And it requires jquery.)

Then I tried various combinations of this:

$PAGE->requires->js_amd_inline('require(["jquery","filter_poodll/literallycanvas.js/js/literallycanvas"],null);');

And this:

$PAGE->requires->js_call_amd("filter_poodll/literallycanvas.js/js/literallycanvas",'init',array());

But I don't think these were even called. And I don't know what to do about all the dependencies really. I am sure it wouldn't work as I have done it there, but I think we did not even get there.

 And there is no init function that I want to call from here, so though I used js_call_amd , I really wish there was a  "js_load_amd." I still do all the init'ing in YUI for the entire plugin. The YUI module has a lot of logic in it that sets everything up. So I just want the literallycanvas loaded really. 

Before all of this there is another error, that I think is compounding all that I am doing it. It looks like this:

I tried to chase this error down the rabbit hole, but got nowhere.

I did look to see what other plugins were doing with AMD but discovered that its basically not being used at all in core, and as far as I could see in plugin land only by the two theme warriors Mary Evans and Gareth Barnard. But they don't seem to be loading 3rd party libraries. So I don't have a good reference to look at . 

This has been a bad time sink. So, I am just going to turn off literally canvas for PoodLL for now. But I noticed similar issues on jquery plugins loaded from VideoEasy and Generico, so I really need a bit of a solution for this. 

In reply to Justin Hunt

Re: What is RequireJS doing?

by Gareth Barnard -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Plugin developers

Hi Jason,

I sometimes get that error (even though the code is fine) after a 'Purge all caches' when reloading on my slow Net-book.

External library wise, I have been doing stuff and made it work!  I put the minimised version from the developer (where the code already supports AMD) directly into the 'build' folder: https://github.com/gjb2048/moodle-theme_shoehorn/blob/master/amd/build/chartist.min.js - I could not make the src compile.  Then that can be referenced in custom AMD JS: https://github.com/gjb2048/moodle-theme_shoehorn/blob/master/amd/src/shoehorn_chart.js#L2 and used with an initialisation function: https://github.com/gjb2048/moodle-theme_shoehorn/blob/master/amd/src/shoehorn_chart.js#L9 and https://github.com/gjb2048/moodle-theme_shoehorn/blob/master/layout/tiles/additionaljs.php#L46-L88.

I hope this helps, cheers,

Gareth

In reply to Gareth Barnard

Re: What is RequireJS doing?

by Justin Hunt -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Plugin developers

Thanks Gareth. That was a big help. I got almost all the way, and I think it will be ok for most 3rd party libraries. But in the case of LiterallyCanvas perhaps its special. LC has its own dependency, React.js. And though requirejs loads react.js fine, LiterallyCanvas does not seem to like it that way and tries to use a "shim" and complains that React.JS can't be found.

I even hacked  React.js so it was not loaded by requirejs, and that kept LC happy, but then LC got upset about jquery issues. 

I will leave it for now, but perhaps I will contact the LC developers.   

In reply to Justin Hunt

Re: What is RequireJS doing?

by Gareth Barnard -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Plugin developers

No problem Jason.  Perhaps this is a scope issue in that you could load React.js as a dependancy yourself in the same code you load LC?

In reply to Gareth Barnard

Re: What is RequireJS doing?

by Justin Hunt -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Plugin developers

I think thats exactly what it is. Trying to do the init and other stuff from the old module.js was the problem. After researching it, I learned that the scope of the dependencies that are passed in is limited to the functions defined in the AMD module. Loading the dependencies and modules in AMD and then using them from module.js is not going to work. I suppose you could find a way, but really its a fools errand.  

So its bye bye module.js and hello AMD. I was able to get things mostly working in Generico this afternoon after I realised this. 

In reply to Justin Hunt

Re: What is RequireJS doing?

by Sonja Sperber -

Hi folks,



as we have similar pros, I’d like to put my 

questions here.


we use:

Release: moodle 2.9

Theme bcu 

Video Plugin : Video Easy


We have one course with a 47 segments. The course includes

a number materials such as videos for instance.


If we open the course in the Browser the page loads

endlessly and the javascript links to update each single

segment are not active.


When I break up the loading process, I get different error

messages which I think are related to AMD:  


1.) 

Uncaught Error: Load timeout for modules: core/first

http://requirejs.org/docs/errors.html#timeoutC @ require.min.js:12D @ 

require.min.js:24(anonymous function) @ require.min.js:24

require.min.js:12 Uncaught Error: Script error for: core/first

http://requirejs.org/docs/errors.html#scripterror


2.)

Uncaught Error: Script error for: core/first

http://requirejs.org/docs/errors.html#scripterrorC @ require.min.js:12i.onScriptError @ require.min.js:27

Navigated to http://ourdomain.com/course/view.php?id=12&notifyeditingon=1

require.min.js:12 Uncaught Error: Script error for: jqueryprivate

http://requirejs.org/docs/errors.html#scripterrorC @ require.min.js:12i.onScriptError @ require.min.js:27


3.)

Uncaught TypeError: Cannot read property 'init_add_tree' of undefined(anonymous function) @ view.php?id=12:426e._notify @ yui_combo.php?rollup/3.17.2/yui-moodlesimple-min.js&rollup/1450172222/mcore-min.js:9T @ yui_combo.php?rollup/3.17.2/yui-moodlesimple-min.js&rollup/1450172222/mcore-min.js:9e.Loader._finish @ yui_combo.php?rollup/3.17.2/yui-moodlesimple-min.js&rollup/1450172222/mcore-min.js:16e.Loader._onFailure @ yui_combo.php?rollup/3.17.2/yui-moodlesimple-min.js&rollup/1450172222/mcore-min.js:16p @ yui_combo.php?rollup/3.17.2/yui-moodlesimple-min.js&rollup/1450172222/mcore-min.js:17s.js.length.e.Get.js.onFailure @ yui_combo.php?rollup/3.17.2/yui-moodlesimple-min.js&rollup/1450172222/mcore-min.js:17s._finish @ yui_combo.php?rollup/3.17.2/yui-moodlesimple-min.js&rollup/1450172222/mcore-min.js:12s._next @ yui_combo.php?rollup/3.17.2/yui-moodlesimple-min.js&rollup/1450172222/mcore-min.js:12s._progress @ yui_combo.php?rollup/3.17.2/yui-moodlesimple-min.js&rollup/1450172222/mcore-min.js:13c @ yui_combo.php?rollup/3.17.2/yui-moodlesimple-min.js&rollup/1450172222/mcore-min.js:12




The info in links such as "http://requirejs.org/docs/errors.html#scripterror"

are rather general and not too much helpful. Can you get me started

how to trace the error source?


Thanks in advance for your help!


Cheers,

Sonja


In reply to Sonja Sperber

Re: What is RequireJS doing?

by Mary Evans -

It sounds to me like a conflict going on With your plugins.

I would do as Gareth suggested in the themes forum discussion, that is to try removing the Video Easy plugin.

Also, you did not mention the theme you are using. It could be that as well.

cheers

Mary

In reply to Mary Evans

Re: What is RequireJS doing?

by Sonja Sperber -

Hi all,


thanks to you all for your fast answers ... that could be helpful!


As I mentioned we use the BCU theme:

https://moodle.org/plugins/theme_bcu


Best,

Sonja


In reply to Sonja Sperber

Re: What is RequireJS doing?

by Sonja Sperber -

Hi...

... think I have to trample on your nerves one more time...


I reduced it  to a minimum. So work with the "clean theme" shipped by default

with moodle (Our Version 2.9).



Non-the-les the Javascript module „jquery.jscrollpane.min.js" does not get loaded.

I guess because it is not an AMD module..


According to the console log in the browser:


jquery.jscrollpane.min.js:8 Uncaught ReferenceError: jQuery is not defined


the source „jquery.jscrollpane.min.js“ begins with:



............................... BEGIN JS CODE ...................

// comments

(function (factory) {

  if ( typeof define === 'function' && define.amd ) {

      // AMD. Register as an anonymous module.

      define(['jquery'], factory);

  } else if (typeof exports === 'object') {

      // Node/CommonJS style for Browserify

      module.exports = factory(require('jquery'));

  } else {

      // Browser globals

      factory(jQuery);

  }

}(function($){


        $.fn.jScrollPane = function(settings)

        {

                // JScrollPane "class" - public methods are available through $('selector').data('jsp')

                function JScrollPane(elem, s)

                {

….

............................... END JS CODE ...................


So wanted to create my own first AMD module also in order to be able to

turn my current „jquery.jscrollpane.min.js“ into an AMD- module.

Maybe there are more convenient ways to let the page load without errors ?

Please let me know ...


So I read the moodle - docs - page


https://docs.moodle.org/dev/Javascript_Modules


I inserted the helloworld.js (out of the moodle doc) under <moodlefolder>"blocks/navigation/amd/src“ and

inside helloworld.js changed block_overview for block_navigation.

So when I include helloworld.js via the php file

blocks/navigation/block_navigation.php with


$this->page->requires->js_call_amd('block_navigation/helloworld‘)


the page


throws the following error messages in the browser:


Notice: Trying to get property of non-object in /var/www/html/moodle/blocks/navigation/block_navigation.php on line 60

Fatal error: Call to a member function js_call_amd() on null in /var/www/html/moodle/blocks/navigation/block_navigation.php on line 60


So there must be a basic mistake ..

Can You get me started here to write AMD js -Files and to include

them within moodle. My aim is to get „jquery.jscrollpane.min.js"

running in order to let people open page flawlessly.


Any Hint, starting help is very welcome!

(by  the way I also installed grunt and created a helloworld.min.js, if that helps...)


Sorry for asking so cluelessly ..

and thanks a lot for your help!


Cheers,


Sonja



In reply to Sonja Sperber

Re: What is RequireJS doing?

by Justin Hunt -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Plugin developers

Sonja

Sorry I missed this. I banged my head on the same issues quite a lot before I finally got it. First of all please read this blog post. It explains about jquery and AMD in VideoEasy/Generico.

http://poodll.com/to-amd-or-not-to-amd/

From what you posted about the scrollpane, it looks like it does support AMD. Because it has these lines in it

 if ( typeof define === 'function' && define.amd ) {
      // AMD. Register as an anonymous module.
      define(['jquery'], factory);
Mary suggested removing the VideoEasy filter. Certainly turning it off is useful to see if it is interfering with what you are doing. You probably don't need to remove it though. By itself it won't conflict with anything, but some configuration of template settings might lead to problems . Actually I think you could probably do this in VideoEasy or Generico. But since your question is about making an AMD module, lets talk about that.

If you already have a javascript library that supports AMD, put the the xxx.min.js in your theme or plugin's "amd/build" folder. Then from your own AMD module include that as a depencency, Here is a little diagram I made to show how a module's definition should look :

amd_stuff

In this case jquery should be referred to as $ and core/log as log, when you use them in in your own javascript code within the module. If you had placed your jquery.jscrollpane.min.js in the build directory as mentioned earlier, then you would include it in the list of dependencies as '[componentname]/jquery.jscrollpane' . (If this was in a theme called "monster" then the component name would be theme_monster.)

You also need to add a reference to the dependency, after $ and log. I guess you would use "jScrollPane" And that is how you would refer to it in your own code. You also need to tell Moodle to load your AMD module. And so you need to have a function in there that Moodle will call when it loads your function. It really only needs to do something like :

$('.scroll-pane').jScrollPane();


So your function might simply be:

init: function(){
   $('.scroll-pane').jScrollPane();
}

And then somewhere in your theme (in PHP), you would tell Moodle to load the AMD module and call your function. If your theme was called "theme_monster" and your custom AMD module was called "scrollalot" then the function call would be: 

$PAGE->requires->js_call_amd('theme_monster/scrollalot','init',array());

NB the 'init' is the name of the function that we defined a little earlier.

Hope that helps.

Average of ratings: Useful (1)
In reply to Justin Hunt

Re: What is RequireJS doing?

by Sonja Sperber -


Hi Justin,


thanks a lot for your infos! I’m really grateful for 

that and will help me to create my own  AMD modules.


Especially poodll.com/to-amd-or-not-to-amd/ 

let me load the jscrollpane flawlessly…


Generico is definitely a plugin to install.


Before I removed also VideoEasy. 


However I still get an error message in the browser where 

I need your help:



………………………………begin error code…………………………………………….

moodle-block_navigation: Initialising navigation block tree


http://ourserver.com/lib/requirejs.php/1450376735/core/first.js Failed to load resource: the server responded with a status of 500 (Internal Server Error)


require.js:12 Uncaught Error: Script error for "core/first"

http://requirejs.org/docs/errors.html#scripterror



Uncaught TypeError: Cannot read property 'init' of undefined

(anonymous function) @ view.php?id=53:300

proto._notify @ yui_combo.php?rollup/3.17.2/yui-moodlesimple.js&rollup/1450376735/mcore-debug.js:1089

handleLoader @ yui_combo.php?rollup/3.17.2/yui-moodlesimple.js&rollup/1450376735/mcore-debug.js:1234

Y.Loader._finish @ yui_combo.php?rollup/3.17.2/yui-moodlesimple.js&rollup/1450376735/mcore-debug.js:8152

Y.Loader._onFailure @ yui_combo.php?rollup/3.17.2/yui-moodlesimple.js&rollup/1450376735/mcore-debug.js:8246

complete @ yui_combo.php?rollup/3.17.2/yui-moodlesimple.js&rollup/1450376735/mcore-debug.js:8440

Y.Get.js.onFailure @ yui_combo.php?rollup/3.17.2/yui-moodlesimple.js&rollup/1450376735/mcore-debug.js:8507

Transaction._finish @ yui_combo.php?rollup/3.17.2/yui-moodlesimple.js&rollup/1450376735/mcore-debug.js:4941

Transaction._next @ yui_combo.php?rollup/3.17.2/yui-moodlesimple.js&rollup/1450376735/mcore-debug.js:5141

Transaction._progress @ yui_combo.php?rollup/3.17.2/yui-moodlesimple.js&rollup/1450376735/mcore-debug.js:5249on

Error @ yui_combo.php?rollup/3.17.2/yui-moodlesimple.js&rollup/1450376735/mcore-debug.js:5033



………………………………end error code…………………………………………….


How can I debug the error ? 

What is to don in the „AMD“ system  ( require- folder?)


Cheers,


Sonja


In reply to Sonja Sperber

Re: What is RequireJS doing?

by Justin Hunt -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Plugin developers

It is very hard to debug these things in my experience.  First make sure you purge your cache so that the error is not something already fixed. In fact it helps to turn off all javascript caching. Do that at: Site Administration - > appearance -> Ajax and Javascript

500 errors are errors occurring in PHP. There might be something in your server error logs with more information about where that is occurring. 

The error about the missing init function, likely relates to whatever it was to be init'ed not being created in the first place. So you need to find out what that was. In your own code are any of your JS functions called "init"?

Do you have any Generico templates that might be failing? Try disabling Generico and see if that makes any difference.

In reply to Sonja Sperber

Re: What is RequireJS doing?

by Damyon Wiese -
Picture of Core developers Picture of Moodle HQ Picture of Plugin developers Picture of Testers
The call to first.js is actually the call that will load all of the AMD modules on your moodle site in a single request. I don't know why it is returning a 500 error - but I would start by checking the permissions on all the files in any amd/ folder under moodle.