Questions about AMD javascript plugins in particular with the knockoutjs mapping plugin.

109 views
Skip to first unread message

Matt Smith

unread,
Feb 9, 2012, 10:20:53 AM2/9/12
to KnockoutJS
On Feb 8, 2012, at 18:52, Matthew Smith <mtsc...@gmail.com> wrote:
Ben,

I worked with you recently when I made a pull request to make Knockout
AMD compliant. I have now encountered an interesting scenario, that I
feel you may be equipped to answer. I have been using the
knockout.mapping plugin (https://github.com/SteveSanderson/
knockout.mapping) a lot, which has not yet been ported over to AMD.
How would you propose that I do so? We had elected not to have
knockout be a named module in light of that it should only be done in
rare circumstances. So, the question I have is, how do we get the
knockout module so we can apply the mappings plugin to it.

I have seen a backbone plugin (https://github.com/derickbailey/
backbone.modelbinding/blob/master/backbone.modelbinding.js) that does
this, but it doesn't quite fulfill the needs of knockout. The root
backbone project has not yet been converted to AMD. What are your
thoughts?

Thanks,
Matt

---Ben's Response ---

From: "ben hockey" <neonst...@gmail.com>
Date: Feb 8, 2012 11:13 PM
Subject: Re: Questions about AMD javascript plugins in particular with
the knockoutjs mapping plugin.
To: "Matthew Smith" <mtsc...@gmail.com>

I'm not sure what would be the cleanest way to do this...

The obvious suggestion is to get the mapping plugin converted to AMD
somehow. I see that the mapping plugin actually uses pieces of the ko
library so it is fairly tightly coupled with ko - this is less than
ideal since that would imply using ko with a fixed id. There is a new
configuration option for AMD that is likely to be agreed upon that
would overcome this problem. The config option is called map but it's
only implemented in dojo where it's called packageMap.

Anyhow, perhaps the mapping plugin could return some kind of init
function that ko needs to be passed into? If AMD is detected, return
this init function and require the consumer to call that function and
pass in ko for mapping to extend

// in a user's module somewhere.
// maybe you would make this your ko module
// and have ko-base be the original ko module
define(['ko-base', 'ko-mapping'], function (ko, mapping) {
mapping(ko); // mixes mapping plugin into ko module

// you could have as many other plugins as you want to load into
this module

return ko; // this is what everyone gets as ko
});

If the mapping plugin does not detect AMD then it should automatically
call this init function itself and pass in the global ko. This
approach allows you to avoid exposing the ko global when using AMD. If
I remember correctly you were wanting to run 2 versions of ko at the
same time so avoiding the global was important.

I have a number of ideas so if you don't like these then tell me what
you don't like about them and then we can iterate towards a better
solution.

AMD has plugins as well. This next approach leverages AMD plugins but
exposes ko as a global from within AMD.

An AMD plugin simply is an AMD module that returns an object with a
load function. We could write a plugin that loads ko plugins that have
not been converted to AMD. To use the plugin, you might use this kind
of syntax:

define(['koPlugin!knockout.mapping'], function(extendedKo){
// extendedKo is ko with mapping added to it
});

and the implementation of the plugin (off the top of my head)

define(['ko'], function (ko) {
window.ko = ko; // expose ko as global

return {
load: function(id, req, load) {
// load the non-AMD plugin
req(['koPlugin/' + id + '.js'], function () {
// pass back a reference to ko (which is now
extended)
load(ko);
});
}
};
});

You could do a variation of the plugin where it was actually the ko
module id and if used as a plugin, it would consider the id to be a
list of plugins to load.

define (['ko!knockout.mapping,knockout.foo'], function (ko) {
// ko has mapping and foo plugins applied
});

there are so many options so it's going to depend what meets your need
and what you're comfortable with. Let me know if you want more ideas
or more info about one of these ideas.

The map config option is meant to solve these kinds of issues and
ultimately would be the way to solve this. the mapping plugin can
declare a dependency on the module id 'ko' and using the config, we
can map any other module id as the one that gets returned to the
mapping plugin when it requests 'ko'. So if we have 'knockout' as our
id for knockout then we can map 'knockout' as 'ko' for the mapping
plugin via this config option. I've used this with dojo and it's a
very useful and powerful feature for being able to have modules
declare "external" dependencies (ie dependencies on modules which are
not distributed with this module)

--
ben...


------

Are there any other suggestions from the community?

Matt

Roy Jacobs

unread,
Feb 9, 2012, 10:39:18 AM2/9/12
to knock...@googlegroups.com
As the author of the mapping plugin I'm open to help with creating a package for the plugin.
I would prefer a pull request, though :)

Roy

Matt Smith

unread,
Feb 9, 2012, 11:14:30 AM2/9/12
to KnockoutJS
Roy,

I have submitted a pull request for Ben's first option, I feel that's
the best possible solution. Unless we here about something better from
the community. See Pull Request https://github.com/SteveSanderson/knockout.mapping/pull/51.

Matt
Reply all
Reply to author
Forward
0 new messages