Open thomasdavis opened 13 years ago
Just a bump :) What are your thoughts on the patterns that are currently in the repo?.
It would be great if we could take these further to cover greater concerns:
There's an opportunity here to explore solutions that haven't been looked at in great detail just yet.
Edit: For anyone that wishes to contribute to this discussion our current focus is on defining a) a reliable UMD and b) a version of a) which is optimized for use in libraries like jQuery. There's an interesting discussion thread below and another started recently by James here https://gist.github.com/1262861
Ok here is just some random thoughts of mine. One of my main concerns is developing a global module open source system method of writing maintainable Javascript. Easy to understand, easy to fork, works in house and in the online community.
There is a difference between a plugin and a "widget". Of course a "widget" is simply a glorified plugin I still think it is worthy of noting. So I would like to see the widget factory implementations and the plugins separated or something like that. I guess a clear distinction between what should be a plugin and what should be a widget also. Anything to do with UI components should be a widget and everything else a plugin e.g. something that corrects the height of your page etc Any plugin/widget should more often then not keep state on the UI components it is manipulating I believe this would be a great practise and allows you to more easily stop memory leaks and allows greater functionality.
Now when dealing with a widget factory, a widget author now cannot easily release his script as a stand alone script and requires the user also bundle the widget factory e.g. jqueryUI needs core/widget to run any of the widgets. Is it possible that we create widgets in such a way they when run without a factory they still perform with certain functionality? Or can we write a solid widget factory library that is small and be pasted in to the top of your widgets?
Now onto the widgets themselves, I quite like AMD. https://github.com/amdjs/amdjs-api/wiki/AMD Regardless of any performance enhancements it allows, it also allows for modular development. Several AMD loaders are in development and the most known to myself is Require.js. Require.js removes everything from the global namespace which is a step forward for plugin development, with exception to jQuery(but I want to fix this). AMD is heavily based off Common.js specification which is great and brings me to the next point.
Wouldn't it be nice now if these widgets/plugins can be loaded via Require.js, Normal Script tags, Node.js and anywhere else the Common.js format is allowed. I by chance found an article describing this exact point and can't find any others lol
http://www.sitepen.com/blog/2010/09/30/run-anywhere-javascript-modules-boilerplate-code/
Another issue with plugin patterns is how do we split them up when they grow and which of the current patterns allow for us to do this in a readable manner. For example DataTables is a jquery plugin that is huge and needs to be split up.
How can they merge without polluting the global namespace? We could use a loader but that makes the script dependent so the run anywhere pattern has to be taken into consideration.
Inside the plugin/widgets patterns themselves what policies are in place for best development practises. A plugin can contain DOM Manipulation, Event Handling, Business Logic Processing and Initialization etc. How are we separating this logic? Naming Conventions? Structure of the code?
I believe it to be possible. =D
I think you bring up some very interesting points, a few of which I cover in my modular large-scale JS application architecture article: http://addyosmani.com/largescalejavascript/ :)
I see two separate pieces of work here:
1) Defining or fixing known definitions of AMD compatible modules to make them more compatible with jQuery plugins/plugin development. @rpflorence actually just posted this today which is related https://gist.github.com/1198466
2) Providing examples of broader concerns with respect to plugin development (multi-file plugin namespacing/merging etc). I liked your example of the jQuery DataTables plugin as it has quite an interesting architecture and might serve as a good starting point for us to explore multi-file architectures. I'll comment back with more once I've had a chance to review their code :)
Reviewing DataTables, they actually appear to have opted for an architecture that isn't split across multiple files, instead keeping everything in one place - this is just insane..
https://github.com/DataTables/DataTables/blob/master/media/js/jquery.dataTables.js.
I'd actually been hoping they approached their development more like the way they allow DataTable plugins to function. ie. you pass an instance of a DataTable object to the plugin and it extends it with additional behaviour. Here's an example: http://datatables.net/release-datatables/extras/AutoFill/media/js/AutoFill.js
Going to speak to Rick Waldron and Ben Alman to see if they have any further ideas that could contribute to this discussion.
So, I spoke to Rick and Ben.
Right now it's looking like the jQueryUI codebase might serve as the best real-world example of an architecture that logically extends itself across multiple files in a clean way..and works. If you take a look at it, they're essentially defining every component (autocomplete, scrollable etc) as an extension to an existing namespace (a little like modular development). For example, see here for the explode effect (a non-UI component):
https://github.com/jquery/jquery-ui/blob/master/ui/jquery.effects.explode.js
This is extremely simple, however it's not a bad example of how logic for particular functionality can be separated across multiple files. Possibly more important to look at is the effects core: https://github.com/jquery/jquery-ui/blob/master/ui/jquery.effects.core.js
I would be interested in us coming up either a) a basic example of a jQueryUI boilerplate template that acts as a core and has one or two widgets that extend it further. eg. core.ui.js, module1.ui.js, module2.ui.js.
Alternatively, one could try to define something outside the confines of jQueryUI and Ben pointed me in the direction of his hashchange + BBQ plugin which apparently achieves this quite well. I'll take a look at it.
What are your thoughts on all this? :)
I read your article and loved every line of it.
The gist by @rpflorence is a work of art and definitely what I had in mind.
At this stage is it safe to assume we are building jQuery dependent standards? I myself am fine with that and alternatives can be rebuilt using different utility belts.
One feature I feel the gist leaves out is the ability to build a module that is a widget or a plugin. So .explode is a plugin and would run well but if wanted to implement .progressbar we would hit a brick wall. So I actually agree that jQuery UI has done well with the file layout and the actual jquery ui widget factory itself is quite extensive and useful. I would propose that the gist also includes a conditional to allow $.widget to be called and the returned public api{} could be a jquery ui widget definition.
In regards to logically extending a plugin across a file system, require.js does this really well already using the r.js compressor. The only drawback is that it's not a universal module.
Using the logic of jQuery UI, for non AMD loaded modules we could extend a namespace. Splitting the "name" of the module apart by "." we could extend modules.
Some rough probably wrong un-optimized pseudo code.
lol don't have the greatest amount of time so that solution is horrid. But it allows for modules to be packaged without a loader. Another cool feature would to be to make it work regardless of the include order. So it would have to be able to extend objects which may be to much boiler plate code.
So just to clarify,
the modules should be able to be pluginable either through AMD(easy) or when simply concatenated together through extension of the core object.
Thanks :)
I considered plugging in to the widget factory and things like dojo.declare
and new Class
for MooTools but the script would quickly get out of hand. The true reason for not supporting this stuff in my gist is that not everything is an element widget--consider pub/sub that hangs from $.publish
and $.subscribe
.
Great discussion.
Personally, I use RequireJS with an altered version of jQuery for AMD, and then just write all my widgets as AMD modules. I've also been thinking pretty hard about how to manage all of this stuff for different environments.
An option is to make the boilerplate a micro library and include things such as dojo.declare, newClass $.widget(. But I do prefer it being standalone.
Or if the boilerplate exist in it's own repository, shell scripts could co-exist that produce build versions or update your code base etc
Do you have any examples of AMD widget implementations on github?
So using AMD spec the extending boilerplate plugins works by using packages/dependencies.
Another solution for when the plugins are being loaded directly into the global namespace is to have the module themselves expose a .extend/.plugin method in the public api.
(function (name, definition){
var theModule = definition(),
hasDefine = typeof define === 'function',
hasExports = typeof module !== 'undefined' && module.exports;
if (hasDefine){ // AMD Module
define(theModule);
} else if (hasExports) { // Node.js Module
module.exports = theModule;
} else { // Assign to common namespaces or simply the global object (window)
(this.jQuery || this.ender || this.$ || this)[name] = theModule;
}
})('core', function () {
var module = this;
module.plugins = [];
// define your module here and return the public API
return {
plugin: function(plugin){
module.plugins.push(plugin);
},
plugins: module.plugins
};
});
Great to see the discussion continue!.
I would say yes, for this project I think that it would make the most sense for us to focus on jQuery dependant standards, however, if possible it would be useful if we could in some ways keep an open mind about making the more flexible enough to be adapted by other frameworks in the future.
@thomasdavis your above example looked like a promising start. As per above there is of course nothing to stop us from exploring an optimized version for dojo or other codebases at a later date. I like the idea of the modules exposing an extend/plugin method, but I wonder if there are any caveats to having it this way.
This is another interesting resource for us to look at: http://tagneto.blogspot.com/2011/01/jquery-ui-as-amd-modules-for-use-in.html. James Burke appears to have previously done some work on AMD-wrapped modules for jQueryUI to be used with RequireJS (albeit via a conversion script) and perhaps there are ideas here we can benefit from reviewing. I'm also going to see if I can speak to anyone on the jQueryUI team to find out if they've previously explored anything around AMD-modules and their library.
@rpflorence, you mention that you write all of your widgets as AMD modules - would you happen to have some code/examples around that you could share? It would be interesting to take a look at how different people have approached this subject.
Here's a simple guy from my current project that manages an array of checked inputs.
define([
'lib/vendor/jquery',
'lib/util/object',
'lib/util/array'
], function (jQuery, object, array){
return {
create: function (selector){
var instance = object.create(this);
return instance.init.apply(instance, arguments);
},
init: function (element){
this.element = jQuery(element);
this.active = [];
this.attach();
},
attach: function (){
this.element.delegate('input', 'click', jQuery.proxy(this.clickHandler, this));
},
clickHandler: function (event){
var target = jQuery(event.currentTarget);
this.check(target);
},
check: function (element){
var name = element.attr('name'),
isOn = element.prop('checked');
array[isOn ? 'include' : 'erase'](this.active, name);
}
}
});
And the usage would be something like:
require(['src/widget/checkedInputs'], function (checkedInputs){
var instance = checkedInputs.create('#something');
});
@rpflorence ahh so that widget is not being passed to any widget factory though?
Just a quick update:
Thomas and I had a discussion regarding the direction of the project earlier today and we think a useful end goal would be a UMD- compatible plugin pattern capable of working with either the jQueryUI widget factory or another widgeting solution (Ben Alman's SimpleWidget comes to mind) - this would of course work with AMD-compatible loaders like requirejs etc.
Ideally we would aim to define something that offers a solution for modular plugin development free of any widget solutions (not everything is a plugin), but let's see what initial progress we can make on defining a base we can work from.
Thomas had expressed some concerns about directly using $.widget inside the UMD (which I share), to which I proposed the idea of passing the widget 'factory/solution' in as an additional context which we could then extend with the plugin. I think this is interesting because there's a level of flexibility that it may offer. These ideas do however require some further refining.
I like this a lot, in a way it has similarities to xa.js : http://xajs.chalmershouse.co.uk/
@skippychalmers I noticed your comment on the other ticket and just wanted to respond. I think that the architecture you were describing sounded a lot like the prototypal inheritance pattern for plugin development that Alex Sexton proposed - effectively, you maintain an external configuration object (obj literal) containing your properties and methods than have a method which actually converts this object into a plugin, leaving you free to alter the final plugin structure without worrying about the configuration itself. Does that sound right or was your proposal quite different? :)
@addyosmani is there any concrete resources on OBL vs function based plugin architectural? and if not we should write one up.
@addyosmani Yes, this is pretty much it. It means you don't need to copy and paste a file and fill in the blanks but you can have an object dispense plugin objects ready for you to extend and customise. A lot of the menial organisational tasks can be automated. The only problem is overhead, which if the "framework" can be kept to a minimal file size and feature set, will be negligible in size.
@skippychambers @thomasdavis I believe I've seen a few different people attempt to approach the subject from a 'heres this neat way I'm defining plugins using objects', but outside of Sexton's article on the topic I don't believe there's anything else that concrete on the topic. Would certainly be interesting to look at in more detail.
Outside of our work on a UMD/AMD compatible widget/plugin pattern definition, I would be interested to hear/see any alternatives to the prototypal inheritance pattern example currently in the repo at the moment. If there's a cleaner way either of you might approach it, please feel free to suggest.
I'm about 65% through doing a writeup on the repo at the moment which will hopefully encourage a few more developers to take a look at it (and perhaps improve the quality of what is already there if I/we have missed anything) :)
Sounds good, I'll see what I can do :)
Another OOP plugin post, this time by @rpflorence http://ryanflorence.com/authoring-jquery-plugins-with-object-oriented-javascript/ Thoughts?
I actually just read this earlier today, definitely a lot of great points and a great paving for the future. What I feel it lacks is an intuitive nature or "beauty".
Will post my weekend of research and thoughts later today.
Excellent. Looking forward to it! :)
Hi guys, I took a look at that link you posted @addyosmani, and have to agree with @thomasdavis. I also especially don't like replacing the prototype object like that.
A mix between a constructor pattern and prototype pattern has always worked really well for me. On a slightly different note, I have to pick a small bone with sexton and say that, IMO if you are using the jQuery library (or rather, sizzler.js) to search through the DOM, find your element, then convert it to a jQuery DOM element, and then load up the jQuery data libraries and functions and then pass in a string and return the actual domain object (its not strictly a domain object, but can't think of another word just now) related to the DOM object, and then call a method on it which then goes back and updates the DOM.... you're doing it wrong.
Even though it might sometimes be useful, I never directly associate a dom element via the data plugin to any domain objects. Any interactions like that should be managed via the objects themselves, not via the DOM.
Not that the relationship shouldn't be there, to help a developer out in edge case scenarios, but I'm just saying IMO I don't think it should be encouraged. :)
(lots of thoughts to comment on this. will as soon as I'm back from work) :)
Cheers for getting involved with the discussion @skippychalmers. Always good to have a few more heads contributing!.
Thanks @addyosmani, I'm glad to be of even a little assistance. I know I'm mostly focusing on the basic jQuery plugin pattern, but I feel it has the most to offer the casual developer. Putting all these different styles together is absolutely fantastic (thanks). I would however, suggest that we perfect & fully document some demos for a 'best-practice' selection. It's never really fair to weigh down on one approach over others, but I know there are a lot of desperate and short-attention-span developers out there who just want to "do it right".... I know... there is no "right" answer, but there can be a "not-that-wrong" answer, that'll suit them fine. Maybe the place for that is not here, and this should be covered in a blog post, but still worth me mentioning.
At the end of the day, consistency is king as you all know. These basic and advanced plugins work quite well. However, when coding in an OOP style, it becomes nice to have "classes", or as I've stupidly named them in the past "constructs" (I think I was playing Halo? and it stuck....). I've used the jQuery basic plugin pattern to do a few wee things for work lately, one of which is here: https://github.com/skippychalmers/CI_Validation.js . Excuse the mess, it was done in a hurry. You'll see how I've made a "Field" subclass, and how useful that has been to me. (Excuse the tabs instead of spaces too... sorry! It's how work rolls).
I know none of this is news to you guys, but the average developer can struggle to decide how to structure things like classes and manage the relationships between them etc, (eg, how do you reference the parent class?). It'd be really nice to document some more patterns that incorporated this kind of multi-level plugin.
Within http://github.com/skippychalmers/xa.js, I've made a distinction between the "App" and the "classes". A class can have child-classes (or subclasses... extending off it, if the sugar to do that is in place), and every class references it's parent class, whilst all classes have a direct reference to the "App". This seems to make sense to me just now, but I've read about many other ways of doing it. What do you think guys? Can we develop the boilerplate further to allow for classes in some form or other?
Cheers James
Thanks James. I agree that we should fully document all of the patterns. To date I've been improving the inline comments as best as possible - there's also going to be a Script Junkie post about this project coming later in the week, but there is still a lot of work that can still be done.
How I see things progressing is organising the patterns into folders based on category to support further additions. This can be done in many ways, but I want to ensure we don't go down the 'this is the one single pattern you should use' direction. I think offering ideal examples of a few different modular approaches (including a strong OOP one) would greatly help developers and feel free to propose a boilerplate for this that you feel is ideal here - we're more than open to discussing them and welcoming others to offer input :)
Something Thomas and I have been working on/ thinking about is an AMD/UMD compatible module definition and we'll probably continue with that in parallel to any discussions about other patterns that are being worked on. Lots to do :)
Sent from my iPad
On 14 Sep 2011, at 21:23, James Chalmersreply@reply.github.com wrote:
Thanks @addyosmani, I'm glad to be of even a little assistance. I know I'm mostly focusing on the basic jQuery plugin pattern, but I feel it has the most to offer the casual developer. Putting all these different styles together is absolutely fantastic (thanks). I would however, suggest that we perfect & fully document some demos for a 'best-practice' selection. It's never really fair to weigh down on one approach over others, but I know there are a lot of desperate and short-attention-span developers out there who just want to "do it right".... I know... there is no "right" answer, but there can be a "not-that-wrong" answer, that'll suit them fine. Maybe the place for that is not here, and this should be covered in a blog post, but still worth me mentioning.
At the end of the day, consistency is king as you all know. These basic and advanced plugins work quite well. However, when coding in an OOP style, it becomes nice to have "subclasses", or as I've stupidly named them in the past "constructs" (I think I was playing Halo?). I've used the jQuery basic plugin pattern to do a few wee things for work lately, one of which is here: https://github.com/skippychalmers/CI_Validation.js . Excuse the mess, it was done in a hurry. You'll see how I've made a "Field" subclass, and how useful that has been to me. (Excuse the tabs instead of spaces too... sorry! It's how work rolls).
I know none of this is news to you guys, but the average developer can struggle to decide how to structure things like subclasses and manage the relationships between them etc, (eg, how do you reference the parent class?). It'd be really nice to document some more patterns that incorporated this kind of multi-level plugin.
Within http://github.com/skippychalmers/xa.js, I've made a distinction between the "App" and the "classes". A class can have subclasses, and every class references it's parent class, whilst all classes have a direct reference to the "App". This seems to make sense to me just now, but I've read about many other ways of doing it. What do you think guys? Can we develop the boilerplate further to allow for subclasses in some form or other?
Cheers James
Reply to this email directly or view it on GitHub: https://github.com/addyosmani/jquery-plugin-patterns/issues/1#issuecomment-2097659
I completely agree Addy, thanks for hearing me out. I'll see what I can do about an OOP boilerplate suggestion for you to consider.
It seems we've forgotten to actually pass in the document to the patterns...
Some further work on another AMD plugin pattern based on a chat Thomas and I had earlier: https://gist.github.com/1241672.
Would you ever consider a really light framework / wrapper to automate parts of this pattern? Nothing that would grow arms and legs....
I probably wouldn't use a framework to automate parts of the pattern, but perhaps a build script or a build tool of some sort which either generates the boilerplate code required prior to development or wrapped modules as necessary post-creation at build-time. We may look into this idea further once we've nailed down how the pattern should ideally be represented :)
Kit Cambridge published his version of the UMD earlier today: https://gist.github.com/1251221 Very interesting. Seems to be a little more comprehensive than the version we were looking at earlier. Thoughts?
@addyosmani, I see what you mean. Yes probably for the best, think I am on the same page as you now. I like the work you guys are doing with these UMD / AMD patterns.
For the AMD folks, I am thinking of advocating this style of boilerplate. If you see problems with it, please feel free to let me know.
It is meant to be a bit more general, not specifically plugin-focused for jquery pieces, but I can put in a version of it that shows what to do, or point to a format of your choice. I think it is important to allow grabbing dependencies, like jQuery, via a require('') call though.
Hey @jrburke. I like the boilerplate you've suggested. I see that John's been involved with some further discussion on that gist, so I'll review where you guys have got to and make any comments there/here in case there's anything useful I can add :)
Thus far I like @jrburke implementation the best. Dependencies will always be an issue though.
Looking forward to hearing further suggestions. If anyone has further progress they'd like us to discuss this weekend, feel free to drop a note about it in here. Usually floating around google chat, github or IRC :)
Addy Osmani Sent with Sparrow (http://www.sparrowmailapp.com/?sig)
On Thursday, 15 September 2011 at 08:36, James Chalmers wrote:
I completely agree Addy, thanks for hearing me out. I'll see what I can do about an OOP boilerplate suggestion for you to consider.
Reply to this email directly or view it on GitHub: https://github.com/addyosmani/jquery-plugin-patterns/issues/1#issuecomment-2101901
I've been experimenting with a few different styles incorporating a more OOP approach... I think some of my attempts are kicking about as plugins on my github page. I've blogged a wee bit about it all in a highly-confused fashion too on chalmershouse.co.uk. If you strip back all the issues, the only question I'm really asking here is how you could load classes within other classes and also maintain some sort of relationship between them.
Loading 'widgets' or 'plugins' within another widget or plugin is fine and makes perfect sense. The work you are doing with UMD / AMD patterns also encourages a lot of structural consistency between widgets too, which helps. The problem is more to do with separating out small tasks and less abstracted functionality in an OOP fashion within a 'plugin' or 'widget'.
A solution is slowly forming in my head somewhere. I don't want anything too smart and filled with "magic", I like to keep developers close to the nuts and bolts of their code so I'm trying to keep this very simple. The solution may be found in writing up a simple set of rules for "sub"-object interaction... maybe even a common facade sort of thing.
Meanwhile, I've been keeping an eye on the UMD / AMD work that you're all doing and I've got to say I'm chuffed with how it's getting on :)
That's cool, @skippychalmers.
I'm going to talk to Thomas, James and John about possibly formalizing the distributed work on the UMD pattern - at the moment we have a lot of fragmented efforts across different gists and repos, but maybe this could benefit from a central effort. Right now I think there are only a limited number of people looking at this and a clean, usable UMD has the potential to positively affect how people write modules. I'll post back once we know more.
Dear UMD enthusiasts
Announcing uRequire: After having a few rough times trying to run/test AMD modules on nodejs and following JR Burke's advice that I should turn to UMD, I decided to write up a converter that reads AMD modules and converts them to UMD so they can run on both web and nodejs.
The result so far is very promising, it has certainly surpassed my expectations - although its still an early alpha/proof of concept. It can read not only AMD but also nodejs modules and its doing dependency checks and path translation on both @ build & @ runtime on node.
You can read more about it and grab the (coffeescript) source here https://github.com/anodynos/uRequire or just run it with npm install urequire -g
Your comment, feedback & PRs are welcome
twitter: @agelospik
What do you think about, is it better to create more comments in the patterns or to create a wiki page for each? I want to create an "more" further explanation for the pattern
's but still stuck at this question...
Edit: And by the way, my english is cruel as a duck in a toilet, so maybe someone of you has to revise them before merge ;-)
To be honest, I prefer expanding on the comments unless we think it's going to get extremely verbose.
@anodynos Thanks! Will check out uRequire.
@addyosmani Ok, I agree with you. However I'm afraid that the patterns will bloated, with lots of comments, maybe too much?! And, I think it's quite annoying to remove all the comments before you can start "really"... as well i think, sometimes it is more helpful to read unheeded blank lines around a bit of code instead of reading a bit of code between lots of comments.
Possibly it is good to provide a clean version for each pattern (as in +@zenorocha's jquery boilerplate) -> what will end up in a bloating repository ;-)
So we have to go maybe with the initial proposal: wiki pages?
Any suggestions to this?
Comments in the code it's not enough for beginners.
What I'm doing on jQuery Boilerplate repository right now is creating these two guides:
Would be great if you could take a look and help me writing that.
Is done! I've added some more explanatory comments about the 'lightweight plugin wrapper' and added the ability to return values from methods: Extending jQuery Boilerplate
So, picking this thread up again I think that we should definitely do a better job of explaining the patterns. If someone would like to take this on, I'm more than happy for you to use any content you want from the jQuery plugin patterns section of Learning JavaScript design patterns
That would be great!
I just created a wiki page with the content of your book. We could reference each pattern to a wiki page (or to your book section), that way they can read more about it.
https://github.com/jquery-boilerplate/patterns/wiki/jQuery-Plugin-Patterns-Guide
I didn't finish because I want to hear what do you think about it.
I'd be happy for us to keep the wiki page up to date and transfer over the contents to the book chapter at intervals during the year. That way any member of the community could help us keep the wiki page up to date (easier than editing HTML in a different repo) and we could have project/org specific notes in there too.
Just chiming in here, going to post some thoughts later today.