Bug Tracker

Opened 7 years ago

Closed 7 years ago

Last modified 6 years ago

#13504 closed bug (notabug)

noConflict() does not undef from AMD

Reported by: itay@… Owned by:
Priority: undecided Milestone: None
Component: unfiled Version: git
Keywords: Cc:
Blocked by: Blocking:

Description

When somebody calls jQuery.noConflict([true]), it does not undefine the registered module from define.

For example, if I have something like:

<script src="jquery.js"></script>
<script>
  var my$ = $.noConflict(true);
</script>

and then some other script tries to do:

<script src="other-jquery.js"></script>
<script>
  require(["jquery"], function($) { ... });
</script>

It will get the old jQuery. Furthermore, if you try and define a path with the name of 'jquery' in require.js, it will always resolve to the first one jQuery. noConflict should also undefine itself from require.

Change History (3)

comment:1 Changed 7 years ago by timmywil

Resolution: notabug
Status: newclosed

noConflict should have nothing to do with AMD. Nor should you ever need to undefine a module. AMD loaders have their own processes for loading different versions of jQuery. Burke wrote a little loader plugin for requirejs on the fly for this problem. https://github.com/jrburke/requirejs/issues/221

comment:2 Changed 6 years ago by dslatten

noConflict should have nothing to do with AMD.

Ideally, perhaps. But in practice, jQuery butchers the global namespace, even when loaded via AMD. noConflict is the recommended solution, remember?

Nor should you ever need to undefine a module.

Ideally, perhaps. But in practice, jQuery butchers the AMD scope by defining itself as the named module, jquery. This greatly increases the chances of collisions in scenarios where 2 AMD modules (loaded on the same page, without knowledge of the other's existence) depend on different versions of jQuery. I don't know if the AMD spec defines how to handle module ID collisions, but it looks like the RequireJS implementation accepts the first module definition and ignores any subsequent attempts to redefine it. It also provides a means of undefining a module, but that's substantially different from noConflict's behavior (which returns the conflicting variables to their previous owner).

Another problem that could arise from jQuery naming itself jquery is that a developer could publish an AMD module that uses a customized copy of jQuery. The developer probably wouldn't think to customize the module ID. As a result, an AMD script can essentially hijack the jquery module ID before the real jquery.js has a chance to claim it. Any AMD modules that depend on jquery would transparently be given the customized version. This might even be exploited for malicious purposes...?

The real issue here, in my opinion, is that jQuery defines itself as jquery, and this makes it difficult for developers to create robust, jQuery-dependent AMD apps/widgets that will be embedded in uncontrolled environments. Undefining (or rolling back) jquery via noConflict is one possible solution, but I think a better solution is to make this an anonymous define call. I know jrburke had some reasoning for hard-coding the jquery module ID, but perhaps that decision deserves another look.

If the jQuery AMD module is anonymous, developers have the option of assigning it a unique module ID and using it privately (e.g., in their widget), without worrying about breaking jquery-dependent modules that might already exist on the host page.

comment:3 Changed 6 years ago by jrburke

I posted a response to dslatten's anonymous module registration question here: https://github.com/jquery/jquery/pull/557#issuecomment-19155140

and suggest either keeping that discussion there, or broken out separately as a different, standalone ticket from deciding how to deal with a global jQuery variable if AMD is in use (see above comment for details).

Note: See TracTickets for help on using tickets.