Opinions needed: AMD and RequireJs

189 views
Skip to first unread message

Jon Bomgardner

unread,
Jan 17, 2012, 7:33:18 PM1/17/12
to jx...@googlegroups.com
List,

I'm in the process of examining what it would take to support AMD (Async Module Definition) and requireJS as an AMD loader. I know that there is talk about MooTools eventually supporting it and I think it would be advantageous of us to do the same.  AMD support would allow developers to only load parts of JxLib as they need it. 

I really think this could be a good thing for the library as a whole. What do you all think?

Jon

Jon Bomgardner

unread,
Jan 17, 2012, 7:33:23 PM1/17/12
to jx...@googlegroups.com

Paul Spencer

unread,
Jan 17, 2012, 9:40:48 PM1/17/12
to jx...@googlegroups.com
Jon,

I am not very familiar with AMD or requireJS but it is on my list of things to research.  It definitely seems like it is something that would be a good idea.  Is there any risk that MooTools could adopt another approach that would be incompatible (is there another approach?  What is CommonJS?)

Cheers

Paul

--
You received this message because you are subscribed to the Google Groups "JxLib" group.
To view this discussion on the web visit https://groups.google.com/d/msg/jxlib/-/Kx-JPREzyq4J.

To post to this group, send email to jx...@googlegroups.com.
To unsubscribe from this group, send email to jxlib+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/jxlib?hl=en.

Jon Bomgardner

unread,
Jan 17, 2012, 10:38:43 PM1/17/12
to jx...@googlegroups.com
CommonJS is similar to AMD. It is what the module system in Node is based on. The requirejs website has information on both. As for the risk of MooTools adopting something different.... I don't believe so. I've been following the discussions over there on the dev list and while I believe that is the way they'll go I think it'll be pretty slow in coming.

Let me know what you think after reading through the documentation.


jon

Paul Spencer

unread,
Jan 18, 2012, 11:58:41 AM1/18/12
to jx...@googlegroups.com
I've read through the requirejs stuff, it seems very thoroughly thought out and also very useful.  If I read it correctly, we would modify all the existing JxLib source files to define them as modules with the appropriate dependencies on other JxLib modules.  I am not entirely clear how this would translate into dependency resolution in any given application - I am guessing that you could either build a combined version or define a module that requires all the widgets you need and let it include the dependencies,

define('myapp', ['JxLib/src/Source/Button/button'], function(button) {
  // do app specific stuff with 'button' module
});

I'm assuming that there would need to be a script tag that includes require.js?

In the current implementation, we would have referred to the button as Jx.Button, but in the require.js version it could be either Jx.Button or button?

Would you see us having any 'helper' functions in jxlib, for instance a jxlib.js that includes require.js and provides a more intuitive mapping of widget names to source files, so a developer could require Jx.Button (for instance)?

In order to make the dependency paths more sane, I think it would be desirable to reorganize the source tree.  Any ideas on this?

Cheers

Paul



jon

--
You received this message because you are subscribed to the Google Groups "JxLib" group.
To view this discussion on the web visit https://groups.google.com/d/msg/jxlib/-/txGeZdC7mlwJ.

Jon Bomgardner

unread,
Jan 18, 2012, 1:39:45 PM1/18/12
to jx...@googlegroups.com
Warning: This could get kinda long..
 
So, I've been thinking a lot about this and there are a couple of ways we can go but I'll answer a few of your questions first....
 
We would indeed need to define everything as modules using define specifying all dependencies. Dependencies would then resolve in a cascading fashion through the inheritance tree. This would then, as you correctly deduced, work in the manner that you saw. In your app you would require just the "top level" modules you need and they would load their own dependencies.
 
In true AMD we would avoid any global references but there's nothing stopping us from creating them. So, we could continue to reference things as Jx.Button or using the object passed in as button, like so:
 
option 1:
 
require(['JxLib/src/Source/Button/button'], function() {
  // do app specific stuff with 'button' module by referenceing as Jx.Button
});
option 2:
 
require(['JxLib/src/Source/Button/button'], function(button) {
  // do app specific stuff with 'button' module by referenceing the parameter 'button'
});
 
As for combined versions, requirejs kinda discourages that unless you use their packaging utility which suppossedly manages all of the references correctly.
 
RequireJS would need to be included somehow - whether individually or through a base file we create.
 
Well, with those answered, here's what I'm thinking. These points might come out kinda random (and I haven't worked up any kind of POC)....
 
First, a key decision needs to be made:
 
1) Do we stick with a Jx namespace and do everything globally or do we do everything as AMD wants us to and avoid globals?
 
Once that's determined we can go forward to:
 
1) We would define everything with modules either attaching to the global Jx object or returning appropriate AMD compatible objects. If we go the AMD compatible route then we would need to re-write everything to account for that.
 
2) I envisioned writing a wrapper around the require and define functions (call them requireJx and defineJx) that would allow us to reference objects using their Jx namespace (either as Jx.Button, Jx.Field.Text or just as Button and Field.Text) and would translate that into an AMD compatible path. This would be done most likely by simply replacing the '.' character with a '/'.
 
3) We would need to decide if we're going to include requirejs in the build process and how much we include as a "base" file (perhaps just the stuff in common.js) and how to include mootools functions before they finish their AMD support.
 
4) If we go the global route then we could also setup the build to strip out the AMD support for anyone who wants a single file that they could use as they always have. This would simply be a matter of wrapping anything AMD specific in tags similar to how mootools wraps their compatibility layer. The build script is already designed to strip those out. I could then build in an option to include or remove the AMD support as people want.
 
5) We would indeed need to reorganize the source tree to make paths work properly which would, thankfully, not impact the build process for a monolithic build due to the way things implemented in that process.
 
So, at this point we need to decide which way we're going to go on the whole global object question. Once we have that I may start to work on a proof of concept in a separate branch so we can play around with things.
 
Jon
 

Paul Spencer

unread,
Jan 18, 2012, 3:33:01 PM1/18/12
to jx...@googlegroups.com
Thanks Jon.  

I think the biggest problem I perceive is the ability to drop this into existing applications without having to completely rewrite them using require.js / AMD concepts.  With that in mind, I think whatever route we go, it should be possible to do something like this:

<script src="jxlib/jxlib.js"></script>
<script>

Jx.require(['Button' /*, other widgets */], function() {
  // application initialization code that uses Jx.Button etc
  var button = new Jx.Button({});
});

</script>

and simultaneously being able to do it this way:

<script src="require.js"></script>
<script>

require(['jxlib/Button'], function(Button) {
  var myButton = new Button({});
});

</script>

So I think my answer to the central questions - globals or not? - is to go the no-global route and provide a utility script, jxlib.js, that includes the requires.js script but wraps it in our own require function and exposes the global namespace for ease of use/compatibility with existing apps.  Does that even make sense?

I didn't check out their packaging utility but would it be possible to use it in the build process to create single combined releases and/or custom versions

Cheers

Paul

--
You received this message because you are subscribed to the Google Groups "JxLib" group.
To view this discussion on the web visit https://groups.google.com/d/msg/jxlib/-/N4R-fa5lRJ0J.

Jon Bomgardner

unread,
Jan 18, 2012, 5:07:34 PM1/18/12
to jx...@googlegroups.com
Just to make sure I understand you correctly....
 
 
The script you reference 'jxlib/jxlib.js' should load require.js along with some kind of "shim" wrapper that would allow you to call Jx.require which would place everything called through it into the global Jx namespace and you could then just wrap your existing application with a call to Jx.require() with a list of all of the dependencies you need.
 
While simultaneously allowing someone to just load require.js directly and start calling dependencies based on the "normal" require methods and use the modules as non-global, non-Jx namespaced objects.
 
Correct?
 
I'm not really sure that we could do both because if we go the non-global route we would be rewritting everything in each module to not use the Jx namespace. Though I'm not entirely positive on that so let me play with it just to see if it's possible.
 
I'll create a new branch in the main jxlib repo and we can try some approaches to see what will work best.
 
Jon

Paul Spencer

unread,
Jan 18, 2012, 5:57:32 PM1/18/12
to jx...@googlegroups.com
Well I was thinking that if we did

require('Jx/Widget/Button', ['Jx/Widget'], function(Widget) {
    Widget.Button = new Class( { ... } );
    return Widget.Button;
}); 

then 

require(['Jx/Widget/Button'], function(Button) {
});

would work (AMD style) but with a wrapper function in Jx.require we could build the Jx global object as well.  Would this work?

Jx.require = function(deps) {
  require(deps, function() {
    // expose deps through global Jx namespace?
  });
}

I'm just not sure how to go about the 'exposing' part ... :D

Cheers

Paul

 
Jon

--
You received this message because you are subscribed to the Google Groups "JxLib" group.
To view this discussion on the web visit https://groups.google.com/d/msg/jxlib/-/EPLXGH3EAf8J.

Jon Bomgardner

unread,
Jan 18, 2012, 6:36:57 PM1/18/12
to jx...@googlegroups.com
Do you think writing each module like this would work:
 
First, define the Jx global object in the base file as we'll need it to include Jx.require(). Then, for example, the Jx.Button module would be defined as follows.
 
 
define([deps],function(deps){
 
    //expose via JX
    Jx.Button = new Class(... as usual but using deps, not Jx namespace ... );
 
    //then return the Class definition for use by require
    return Jx.Button;
 
});
 
Then in your app you could do:
 
Jx.require(['Jx.Button',...],function(button,...){
    //use button here
});
 
or just use it as normal as it's already defined....
 
new Jx.Button();
 
That way, the global Jx object would be defined. We could also design then to be written like so:
 
define([deps],function(deps){
 
    //create the class
    var button = new Class(... as usual but using deps, not Jx namespace ... );
 
    //<NoAMD>
    Jx.Button = button;
   //</NoAMD>
 
    //<AMD>
    return Jx.Button;
    //<AMD>
 
});
 
We then build an option into the build process (perhaps --use-amd  or --no-amd) that would force the build to strip the appropriate tags and contents out of the build.   This way, as long as someone has the right build they could use either the true AMD or the global Jx as they like. Everyone would then use something like:
 
Jx.require(['Jx.Button', 'Field.Text', ... other deps...], function(<include deps here if using strict AMD>){
    //Then in here you can either use Jx namespace or parameters passed in depending on your build.
});
 
The Jx.require function can check the passed in dependencies, change as needed, and pass everything to requirejs and on return from requirejs call the passed in callback with the arguments returned from require (if needed).
 
What do you think?

Paul Spencer

unread,
Jan 18, 2012, 7:11:12 PM1/18/12
to jx...@googlegroups.com
Perfect!  A further refinement might be:

if (window['Jx']) { window.Jx.Button = button; }
return button;

then no preprocessing is required?

Paul

--
You received this message because you are subscribed to the Google Groups "JxLib" group.
To view this discussion on the web visit https://groups.google.com/d/msg/jxlib/-/az1nscF496gJ.

aek

unread,
Jan 19, 2012, 12:56:19 AM1/19/12
to JxLib
Personaly I don't like this kind of functionality, I think that is an
imposed way of work pushing away developers from the library. I use
dojo.require, try with qooxdoo way of do stuff, I saw yui new way of
doing the same, now even ExtJS 4 has a require function. Personally I
don't see the point for JxLib.
Let me explain:

Dojo has 3 main projects with a lot of files that you wouldn't need
always, In my experience with dojo I end having a part of the main
page to declare as many dojo.require I need for the rest of the
application since I always load views using ajax and the response is
always an json object defining the view inside a function. I saw the
dojo point.

YUI 3 now has something similar, Y.use function that create an
instance of YUI with the required modules to be used inside a supplied
function. So you can create differents YUI instances. I don't see the
point here since YUI is not as big as Dojo and in my opinion need to
focus a little more on get functionalities and widgets created to make
a more robust and competitive library since YUI 2.x it's more suitable
than YUI 3.x

ExtJS is big and has a toon of heavyweigth widgets, finally has
something to speed up the page load to use only what is needed for
ExtJS 4.x.

Qooxdoo has his own way to do this and a particular way of use the
library itself that involve an compilation fase. I don't like the way
it's designed to work as a developer even when the results are
awesome. But the loader is non intrusive for the developer, intrusive
is the way to get the loader to work using a compilation fase that is
not native from javascript.

JxLib is build on the top of mootools and use the mootools style of
class definition, it's growing and I don't see any another library
here in mootools with the power and well design that I saw in JxLib,
but still the comunity is very little here (I don't know why). This
way of use for JxLib since it's build using mootools and mootools
class system may throw away users and contributors for the library
since mootools don't supports RequireJS yet and who knows if it will
support it. Actually users can use RequireJS with JxLib to load only
the needed js files and it's not offitially supported by the library.
JavaScript toolkits are used mainly by web developers to create the
frontend for server side webapps developed in ??? plattform, take a
momment to think that maybe your toolkit it's used to automatically
create the UI based on XML, YML, Object, JSON or any other descriptor
format think of Ruby on Rails, Grails, ArcheType(My created
architecture/framework for Java and PHP) and others around that wants
to have an direct integration without another proccess involved in the
middle.

As I said there is a non-intrusive loader in Qooxdoo that load the
files when it's needed but he obtain the path through the compilation
proccess. We can do something like this using a convention over
configuration, How this can be done? If:
Every class in JxLib is defined in a separated file
The file name is the same of the classname
The file name it's located in a folder relative to the package name of
the class
The class namespace is registered in JxLib to have the default loader
function

The file can be loaded replacing the loader function with the JxLib
class itself by the loader function and the developer doesn't need to
worry about the need to declare the file to be loaded by requirejs or
a wrapper around it. I think this behavior can be implemented I don't
know if this fit in the mootools class system for dependecy resolution
when they want to extend or implement from a class in a class
definition. This are a couple of ideas that I have around this.
I don't desagree with the idea of having a classloader in JxLib but
I'm not agree when the solution will make the proccess of working with
the library more complex for users and developers and involve such
lots of changes.

Paul Spencer

unread,
Jan 19, 2012, 8:31:43 AM1/19/12
to jx...@googlegroups.com
Hi Axel,  thanks for chiming in :)  I appreciate your experience with other toolkits, I have not had the opportunity to experiment much with anything other than ExtJS (and only that via Sencha Touch).  I think that we can learn something from the fact that other major UI toolkits provide a 'require'-like syntax for dependency management :)

I am not sure that I fully understand the argument against providing the ability to support asynchronous module loading in JxLib, however.  While I am willing to be convinced otherwise, I do think that it is a good idea to have a run-time dependency resolution system that allows you to specify exactly what you want to use in your application and have it loaded on demand. 

I think your main objection is that it will make the library harder to use?  If so, I agree that usability must not suffer if we implement this.  I think, based on the previous discussion, that Jon is also on board with this and we are working to define an architecture that would be flexible enough to work in a variety of ways, the simplest being that you could just load a 'compiled' version of jxlib that would contain the code exported to the global namespace as it works now.  This may require using the requireJS optimizer.  The benefit of doing this work, from my point of view, is the simplicity with which a stripped down version can be loaded on-demand in an application - but to gain this benefit, an application would require some changes.

Looking forward to more discussion on this!

Cheers

Paul


--
You received this message because you are subscribed to the Google Groups "JxLib" group.

Jon Bomgardner

unread,
Jan 19, 2012, 1:59:33 PM1/19/12
to jx...@googlegroups.com
Right, wish I had thought of that. We could then have the base file define Jx or not depending on whether the user want to work in global mode...
 
I'm going to look at the requirejs packaging script to see how we might be able to leverage it to build custom builds and to allow anyone who wants to use "global mode" to build a single file.
 
I'll let you know what I find.
 
Thanks,
Jon

Jon Bomgardner

unread,
Feb 26, 2012, 6:14:53 PM2/26/12
to jx...@googlegroups.com
For all of those who are interested, please take a few minutes to check out the new amd-branch branch of the jxlib github repo. I've gotten a large amount of the work necessary for amd support done in there. just check it out and build as usual using ./build.sh and you'll get everything you need. Currently, the examples pages are working in "global" mode so you can just drop the jxlib.js file fro this build into a current application and for the most part it should just work. 

This branch does have 1 set of breaking changes though to be aware of and that is that Jx.Store.Protocol.xxxx is now Jx.Data.Protocol.xxxx and the same for Parsers (Jx.Store.Parser.xxxx -> Jx.Data.Parser.xxx). I felt that the "Data" namespace was more fitting for these pieces as they can be used with more than just Jx.Stores.

There is currently a single example (test.html) in the require directory under the examples you can look at to get a sense of how it will be working. I'll be getting more examples converted in the near future and have a few ideas for making the examples a bit more useful and interactive.

Thanks,
Jon

Thanks,
Jon
Reply all
Reply to author
Forward
0 new messages