ScottHamper / Cookies

JavaScript Client-Side Cookie Manipulation Library
The Unlicense
1.77k stars 170 forks source link

Added noConflict() so multiple versions can be included in the same context safely #15

Closed jstayton closed 10 years ago

jstayton commented 10 years ago

Hey Scott,

I've added a noConflict method so that multiple versions/instances of Cookies can be included in the same context safely. I'm currently using it in a third-party JavaScript library that developers can include on their site. I don't want the Cookies version I'm using to conflict with a version already being included by the developer. Other major libraries like Underscore and jQuery include a noConflict method if you'd like to compare implementations.

I've only made changes to the source and added tests. I haven't minified, updated the README, or anything else.

Let me know if you have any questions or comments. Thanks!

ScottHamper commented 10 years ago

Hey Justin,

I'm a little conflicted about merging this pull request (hurr hurr). On one hand, I'm thrilled that you're using Cookies.js as a dependency for your own library, and I'd like to support that! But, I'm wondering if adding a noConflict method to the library is really the best way to handle this. Is there a reason you're preferring to embed a version of Cookies.js directly into your library over just listing it as a dependency, especially now that there's bower support and the dependency could be auto-resolved? (Thanks again for that!)

I think jQuery's shifting API combined with its huge plugin community really demands that there be a mechanism to allow multiple versions of it to be loaded on a page at a time. With Cookies.js, I can't help but feel that there is less justification for providing similar functionality (at least at this point in time). Cookies.js has had a stable API for a reasonably long time now (I think since version 0.2.0, so we're talking around June 2012), and I don't anticipate introducing any breaking changes to it in the future.

What are your thoughts?

jstayton commented 10 years ago

Hey Scott,

I understand your concern. Let me explain my use of Cookies a bit more.

There is a reason why I need to embed Cookies in my own library: it has to be included from a centralized, CDN-hosted URL. A similar example is Facebook Login for Web. It's not a library a developer includes in their own codebase, or installs with Bower. So, if a developer includes my library, but is using an older/newer version of Cookies for their own code, there's not much they can do.

noConflict to the rescue. My library can call noConflict and revert the global window.Cookies to its previous value (the version included by the developer), while my library can store and use version I embedded internally. It comes in really handy for third-party JavaScript.

ScottHamper commented 10 years ago

Hey Justin,

Ok, I understand what you're trying to do now. I'd like to get your thoughts on an alternative, though. What if instead of supplying a noConflict, I simply updated the immediately invoked function expression similar to a change you made in your pull request. E.g.,

(function(context, undefined) {
    // .....
    context.Cookies = Cookies; // this used to just be `window.Cookies = Cookies;`
})(window);

This way, when you'd like to embed the library into your own, you'd just need to replace the window parameter with whatever container you'd like to use.

This seems like it would be the simplest/lightest-weight change to fit your needs. If you wanted to update the embedded Cookies.js version in the future, you would only have to copy/paste and then change that one keyword. Since updating versions is something that would be done only occasionally, this seems like it might be a reasonable way to go.

What do you think?

ScottHamper commented 10 years ago

Although, thinking about that more, it may not really be ideal since it requires context to be a root object, and not a direct reference to Cookies.

var thirdParty = {};
var Cookies;

(function (context, undefined) {
    var Cookies = ...
    // ...
    context.Cookies = Cookies;
})(thirdParty);

Cookies = thirdParty.Cookies;

I don't know. Let me know what you think - I wanna get something working for you, I'm just not sure I'm convinced that noConflict is the most ideal way yet.

jstayton commented 10 years ago

Hey Scott,

I appreciate your help and interest in coming to a solution.

I'm not so sure about your proposed solution. While a build system like Grunt could automate the update and changing of the variable, I just don't think it's obvious or intuitive for developers. If they need to use Cookies in third-party JavaScript, they're going to look for noConflict. That's the agreed upon name and way to do this.

I also don't think you're going to find a much more lightweight solution.

jstayton commented 10 years ago

Hey Scott,

I've simplified the code even more, removing this/context in favor of using window directly.

ScottHamper commented 10 years ago

Hey Justin,

Sorry for the long delay - I haven't forgotten about you, I've just been pretty busy! I've been thinking about this issue more, and looked into how Sizzle was written since it's specifically intended to be embedded within other JS libraries. It has a very similar export process to Cookies.js's export, which got me thinking - I'd like to do some playing around with this when I have some time, but I believe Require.js offers an optimization tool that may be able build a script with dependencies resolved and included in the final output, which might allow for embedding Cookies.js in another script without having to extend the API.

I think that noConflict makes a lot of sense for jQuery and underscore, as those libraries use a generic symbol for their namespace and there are other well known libraries that also use these symbols. I think this is the primary use case for noConflict - to avoid namespace conflicts between two totally different libraries - and where it would be considered a best practice. I'm not convinced that a noConflict method is truly an agreed upon best practice to allow a library to be easily embed-able in others - dependency resolution seems to be more commonly handled by module systems.

jstayton commented 10 years ago

Hey Scott,

Fair enough. I will look into alternate ways of handling this, including your suggestion. Thanks again for your help!