conversejs / converse.js

Web-based XMPP/Jabber chat client written in JavaScript
http://conversejs.org
Mozilla Public License 2.0
3.07k stars 769 forks source link

Uncaught TypeError: e.noConflict is not a function #2042

Closed jackey closed 2 years ago

jackey commented 4 years ago

Describe the bug i'm planing to integrate converse.js into angular8 project. here's the index.html code.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title></title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">

  <link rel="stylesheet" type="text/css" media="screen" href="https://cdn.conversejs.org/6.0.0/dist/converse.min.css">
  <script src="https://cdn.conversejs.org/6.0.0/dist/converse.min.js" charset="utf-8"></script>

</head>
<body>
  <app-root></app-root>

  <script>

    window.loginChat = () => {
      converse.initialize({
          authentication: 'login',
          autologin: false,
          auto_away: 300,
          auto_reconnect: true,
          discover_connection_methods: true,
          bosh_service_url: 'https://conversejs.org/http-bind/', // Please use this connection manager only for testing purposes
          message_archiving: 'always',
          view_mode: 'overlayed'
      });
    };

  </script>

</body>
</html>

it's very ease and basic , so that it only call loginChat() from angular component. here's the error.

Uncaught TypeError: e.noConflict is not a function
    at Object.<anonymous> (underscore-shim.js:2)
    at Object.<anonymous> (underscore-shim.js:1)
    at r (bootstrap:63)
    at Object.<anonymous> (backbone.js:17)
    at Object.<anonymous> (backbone.js:21)
    at r (bootstrap:63)
    at Module.<anonymous> (websocket.js:547)
    at r (bootstrap:63)
    at Object.load (entry.js:60)
    at Object.initialize (entry.js:31)
entry.js:56 Uncaught RangeError: Maximum call stack size exceeded
    at Object.load (entry.js:56)
    at Object.initialize (entry.js:31)
    at Object.initialize (entry.js:31)
    at Object.initialize (entry.js:31)
    at Object.initialize (entry.js:31)
    at Object.initialize (entry.js:31)
    at Object.initialize (entry.js:31)
    at Object.initialize (entry.js:31)
    at Object.initialize (entry.js:31)
    at Object.initialize (entry.js:31)

But the interesting is it works well when call directly loginChat() in index.html ! So please help me find out way to fix it :)

devdupont commented 4 years ago

While I'm not sure if this specific error is unique to running in modern Angular, I was able to fix it by fetching JQuery before fetching converse.js. It looks like there was a suggestion in #82 to add a warning when JQuery isn't found, but I didn't receive any log info regarding this.

I will point out that the Converse quickstart doesn't mention the JQuery requirement anywhere on the page, and devs using fresh Vue, React, or Angular projects are unlikely to have a copy available.

The existing Angular example is also out of date.

For reference, the non-minified error reads: TypeError: _.noConflict is not a function. (In '_.noConflict()', '_.noConflict' is undefined)

This is also an error with 6.0.1 which is the most recent version as of this comment.

@jackey Adding this to your head should fix this. I'd also recommend pinning 6.0.1 instead of 6.0.0 <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>

devdupont commented 4 years ago

You'll also run into this error if you call converse.initialize in a <script> tag placed outside of the <body> tag even if JQuery is fetched. It only works if called within. This contradicts what is stated in the quickstart init section.

Again, not sure if these are specific to Angular, but this is what I did to make it work.

jcbrand commented 4 years ago

Converse.js doesn't have a requirement on jQuery (at least not in any version of Converse.js released in the last 2 or 3 years).

Looks more to me like underscore or lodash isn't loaded. Normally this would be included in the Converse.js bundle, so I'm not sure what they're doing to cause this error.

devdupont commented 4 years ago

We've done a lot of debugging on this issue since posting. We've been trying to get it running with Angular, and the only way we've gotten it to work is keeping Converse wholly separate from the Angular runtime. For some reason, the injected lodash library gets overridden very easily. The most elegant solution we've found is to load the lodash library itself immediately before converse.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <link type="text/css" rel="stylesheet" media="screen" href="/assets/styles/converse/converse.css" />

  <script src="/assets/scripts/lodash/lodash.js"></script>
  <script src="/assets/scripts/converse/converse.js"></script>
  <script src="/assets/scripts/converse/fastpath.js"></script>
</head>
<body>
  <app-root></app-root>
  <script src="/assets/scripts/converse/init-converse.js"></script>
</body>
</html>

Additionally, this fix doesn't work if the init converse script is embedded anywhere else but the inline body tag. The best debug I can offer to the devs is that the _ passed to _.noConflict is not a reference to lodash but an abstract module that doesn't implement any methods but _.load. The _.noConflict() call occurs in only two locations in dist/converse.js.

jcbrand commented 4 years ago

Thanks for the info @flyinactor91

We're in the process of removing usage of the _ global, instead using native methods where-ever possible, and if there are lodash methods we cannot live without, we're importing them specifically.

I'm hoping this will help in your situation and reduce conflicts with other code.

AFAIK the main thing that's holding this up is the fact that we still load some templates via lodash. We're in the process of using lit-html for those, but I don't think this will all be finished in time for the version 7 release.

jcbrand commented 2 years ago

I believe this is fixed now in Converse 8 since we don't use the _ global.

samhoseinkhani commented 2 years ago

@flyinactor91 Hi, can u share the result of your integration? I want to integrate converse with angular too.