javascriptvitelaravel-mixjvectormap

how to import jvectormap-next using 'import' (not 'require')


I'm providing details below about my specific issue with jvectormap, but I believe this really breaks down to a question of how to import a module that's exporting a factory (not a class or var).

PLEASE NOTE: I cannot use require but have to use import!! (We are migrating from Mix to Vite).

The old code that works with require (can't use any longer):

require('jvectormap-next')($);
$.fn.vectorMap('addMap', 'us-merc', require('jvectormap-content/us-merc'));

The code that should work (I definitely could be doing something wrong)??

import jvnext from 'jvectormap-next';
jvnext($);
import US_Merc from 'jvectormap-content/us-merc';  
$.fn.vectorMap('addMap', 'us-merc', US_Merc);

This always gives an error of $.fn.vectorMap does not exist.

Module's Export Code Inside the jvectormap-next module are two export pathways:

The first occurrence (line 191):

(function (factory) {
  if (typeof exports === 'object') {
    // Node/CommonJS style for Browserify
    module.exports = factory;                               <--- EXECUTION ALWAYS RUNS HERE
  } else if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['jquery'], factory);
  } else {
    // Browser globals
    factory(jQuery);
  }
}(function ($) {
  ...
  // This is the function that defines $.fn.vectorMap -- ultimately, how do you call this??
});

The second occurrence (line 249):

(function (factory) {
    if ( typeof define === 'function' && define.amd ) {
        // AMD. Register as an anonymous module.
        define(['jquery'], factory);             
    } else if (typeof exports === 'object') {
        // Node/CommonJS style for Browserify
        module.exports = factory;                         <--- EXECUTION ALWAYS RUNS HERE
    } else {
        // Browser globals
        factory(jQuery);
    }
}(function ($) {
  ...
  //This function DOES NOT define $.fn.vectorMap, but the execution DOES run in here
});

As you can see, execution steps into both of the function(factory) methods. But when I make the jvnext($); call above, the code ONLY steps into the SECOND function($), and it never enters the first section which is where the jquery method is defined.

Can someone help me understand how to properly convert this from require to import?


Solution

  • Since nobody responded, I'm going to answer this question for anyone else who is interested. (At least, this is how I solved it).

    There core issue is that there are two module.exports = and the second export overwrites the first one

    If you dig into the code for jvectormap-next, it includes a library in the source code, and that library has its own module.exports = code. When the code is inlined during the build process, the lib is brought in after the original module export.

    There is also a difference in how the code runs when it's brought in using require vs import:

      if ( typeof define === 'function' && define.amd ) {
            // AMD. Register as an anonymous module.
            define(['jquery'], factory);             
        } else if (typeof exports === 'object') {
            // Node/CommonJS style for Browserify
            module.exports = factory;     <--- Runs when 'import' is used
      } else {
        // Browser globals
        factory(jQuery);     <--- Runs when 'require' is used
      }
    

    So using require actually executes both of the function($){...} calls. A call to import, however, simply exports those functions and does not execute them.

    My Solution
    I created a fork of the jvectormap-next library and made two small changes:

    //First export
     if (typeof exports === 'object') {
        // Node/CommonJS style for Browserify
        module.exports.jvectormap = factory;
      }
    
    ///Second export (from the lib)
     if (typeof exports === 'object') {
        // Node/CommonJS style for Browserify
        module.exports.lib = factory;
      }
    

    Now when you bring in the code, it looks like this:

    import jvectormap from 'my-jvectormap-fork';  //Bring from git repo or whatever
    import $ from 'jquery';
    
    jvectormap.jvectormap($); //Initialize the first factory method
    jvectormap.lib($); //Initialize the second factory method
    
    //Good to go