Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specify the webpack "mainFields" on a case by case basis

Webpack has a resolve.mainFields configuration: https://webpack.js.org/configuration/resolve/#resolvemainfields

This allows control over what package.json field should be used as an entrypoint.

I have an app that pulls in dozens of different 3rd party packages. The use case is that I want to specify what field to use depending on the name of the package. Example:

  • For package foo use the main field in node_modules/foo/package.json
  • For package bar use the module field in node_modules/bar/package.json

Certain packages I'm relying on are not bundled in a correct manner, the code that the module field is pointing to does not follow these rules: https://github.com/dherman/defense-of-dot-js/blob/master/proposal.md This causes the app to break if I wholesale change the webpack configuration to:

resolve: {
  mainFields: ['module']
}

The mainFields has to be set to main to currently get the app to work. This causes it to always pull in the CommonJS version of every dependency and miss out on treeshaking. Hoping to do something like this:

resolve: {
   foo: {
     mainFields: ['main']
   },
   bar: {
     mainFields: ['module'],
}

Package foo gets bundled into my app via its main field and package bar gets bundled in via its module field. I realize the benefits of treeshaking with the bar package, and I don't break the app with foo package (has a module field that is not proper module syntax).

like image 698
Sasha K. Avatar asked Jul 23 '19 11:07

Sasha K.


1 Answers

One way to achieve this would be instead of using resolve.mainFields you can make use of resolve.plugins option and write your own custom resolver see https://stackoverflow.com/a/29859165/6455628 because by using your custom resolver you can programmatically resolve different path for different modules

I am copy pasting the Ricardo Stuven's Answer here

Yes, it's possible. To avoid ambiguity and for easier implementation, we'll use a prefix hash symbol as marker of your convention:

require("#./components/SettingsPanel");

Then add this to your configuration file (of course, you can refactor it later):

var webpack = require('webpack');
var path = require('path');

var MyConventionResolver = {
  apply: function(resolver) {
    resolver.plugin('module', function(request, callback) {
      if (request.request[0] === '#') {
        var req = request.request.substr(1);
        var obj = {
          path: request.path,
          request: req + '/' + path.basename(req) + '.js',
          query: request.query,
          directory: request.directory
        };
        this.doResolve(['file'], obj, callback);
      }
      else {
        callback();
      }
    });
  }
};


module.exports = {
    resolve: {
      plugins: [
        MyConventionResolver
      ]
    }
    // ...
};
like image 91
Tripurari Shankar Avatar answered Oct 23 '22 00:10

Tripurari Shankar