Modules and webpack

One of the things I wanted to do is allow my React application to “dynamically” load code from another website for an internal application. The idea being other teams can work on their code and the main application will load the latest deployed version if the user navigates to something that uses it – basically we’re talking about writing plugins.

Note: This is not a great idea for any code you cannot 100% control as you’ll obviously have no idea whether it’s malicious, so if you’re thinking of doing something similar make sure you know what code is being downloaded etc.

Where’s my Module gone

To begin with I wrote an “importer” class in a separate application which successfully loaded code – using axios to download it, Typescript to transpile it (if needed) and the standard Module to compile (module._compile) it, then I slotted the code into a Module and away you go. All worked great until it got deployed within the React application and all of a sudden _compile (and other methods) were missing from Module.

The thing is, webpack basically uses it’s own module system.

webpack modules

The post I wrote on getting up and running with webpack was inspired by the module dilemma as I needed to better understand what webpack was doing under the hood.

If we create and build a webpack project we’ll end up with main.js, here’s a snippet from it for the __webpack_require__ function

function __webpack_require__(moduleId) {
   if(installedModules[moduleId]) {
      return installedModules[moduleId].exports;
   }

   var module = installedModules[moduleId] = {
      i: moduleId,
      l: false,
      exports: {}
   };

   modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
   module.l = true;
   return module.exports;
}

Note: I’ve removed all the comments just to reduce it to the minimal code.

So within the functions web pack generates for our code/exports etc. we’ll see __webpack_require__ used a fair bit, i.e. to load import/require code (import/require is replaced with __webpack_require__) and looking at the function itself we can see that __webpack_require__ uses it’s own module system, i.e. it caches modules in installedModules (which becomes __webpack_require__.c). We can also see that if the module is not cached a new one is created which looks very different from a NodeModule.

Finally, after the module is created a call is made to the new module, which in this case is one of the functions that’s passed to the __webpack_require__ within main.js which basically returns a function to our code which then becomes the “exports” code returned by the __webpack_require__ function.