2

I have a gulp task to run webpack to bundle my files. I'm trying to use jQuery with typeahead.js, but the call to require('jquery') inside the typeahead.js file seems to be loading a new jQuery object instead of using the one at the "global" scope as created by ProvidePlugin. How do I add a jQuery plugin to the jQuery instance created by ProvidePlugin?

Here is my gulp task:

gulp.task("bundlejs", function(cb) {
  pump([
    gulp.src("js/index.js"),
    webpack({
      output: { filename: BUNDLE_NAME },
      plugins: [
        new webpack.webpack.ProvidePlugin({
          $: 'jquery',
          jQuery: 'jquery',
          'window.jQuery': 'jquery'
        })
      ],
      devtool: 'source-map'
    }),
    gulp.dest(OUTPUT_JS)
  ], cb);
});

And inside an imported module:

require("imports-loader?define=>false!typeahead.js");

console.info($.fn.typeahead); // <== prints 'undefined'

Just for some additional information, the top of the typeahead bundle looks like this (full file here):

(function(root, factory) {
    if (typeof define === "function" && define.amd) {
        define("bloodhound", [ "jquery" ], function(a0) {
            return root["Bloodhound"] = factory(a0);
        });
    } else if (typeof exports === "object") {
        module.exports = factory(require("jquery")); // <== this line gets called
    } else {
        root["Bloodhound"] = factory(jQuery);
    }
})( ... );

What am I doing wrong?

Update

Per the comment stream, here is what I'm getting with my unique ID code.

Here is my /path/to/unique-id.js file:

var id = 0;

module.exports = function(o) {
  if (typeof o.__uniqueid == "undefined") {
    Object.defineProperty(o, "__uniqueid", {
      value: ++id,
      enumerable: false,
      writable: false
    });
  }
  return o.__uniqueid;
};

Using var u = require('/path/to/unique-id.js')...

In my Application.js file (the one where I use require("imports-loader?define=>false!typeahead.js"):

console.info(u($)); // <== prints 1
console.info(u(jQuery)); // <== prints 1
console.info(u(window.jQuery)); // <== prints 1
console.info(u(require('jquery'))); // <== prints 1

I modified typeahead.bundle.js to include some calls as well:

(function(root, factory) {
    if (typeof define === "function" && define.amd) {
        define("bloodhound", [ "jquery" ], function(a0) {
            return root["Bloodhound"] = factory(a0);
        });
    } else if (typeof exports === "object") {
        console.info(u(window.$)); // <== this prints 1, like I want
        console.info(u(require('jquery')); // <== this prints 2
        console.info(u(require('jquery')); // <== this prints 2
        module.exports = factory(require("jquery")); // <== original module code
    } else {
        root["Bloodhound"] = factory(jQuery);
    }
})( ... );

Update 2 (lame solution)

In the spirit of progressive problem solving and transparency, I got it to work in this kludgey way:

require("imports-loader?exports=>false,define=>false,jQuery=>window.$!typeahead.js");

I don't like this way at all, so any other answers would be appreciated.

Update 3 (another solution using another library)

I ended up switching to selectize and had to use an even lamer solution, but I thought it might help someone else going through the same problems as me:

In the module:

var selectizeRoot = {
  jQuery: require('jquery'),
  Sifter: require('sifter'),
  MicroPlugin: require('microplugin')
};

require('imports-loader?define=>false,exports=>false,this=>selectizeRoot!selectize');

This forced the jQuery used in my modules (and apparently the ProvidePlugin) into the function that adds the selectize plugin to jQuery.

Andy
  • 8,749
  • 5
  • 34
  • 59
  • How do you know that is loading a new jQuery object? Your final goal is to include jQuery from a global script tag? – Alex Michailidis Feb 21 '18 at 14:07
  • No, using webpack any reference to `$`, `jQuery`, or `window.jQuery` will be resolved by adding a `var require('jquery')` at the top of the module, as per the ProvidePlugin functionality. As for the first part of your question, I have a (working) way to determine object identity, loosely based on [this answer](https://stackoverflow.com/a/1997811/493807). – Andy Feb 21 '18 at 14:10
  • Using the exact webpack config I can see `/node_modules/jquery/dist/jquery.js` being loaded once in the webpack's output with `--display-modules`. Do you mean that webpack will give another instance of jQuery, even if it doesn't load the file again? – Alex Michailidis Feb 21 '18 at 14:15
  • It definitely seems to be doing that, yes. I'll add an update to show what I'm getting with this setup, with the unique ID code running. – Andy Feb 21 '18 at 14:17
  • You have a typo in `console.info(u(window.$))` `window.$` is not defined in the `webpack.ProvidePlugin`. – Alex Michailidis Feb 21 '18 at 14:40
  • Good catch... and yet, it works. That just makes this even weirder. :P – Andy Feb 21 '18 at 14:46
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/165567/discussion-between-alex-rokabilis-and-andy). – Alex Michailidis Feb 21 '18 at 14:48

0 Answers0