Search code examples
webpackpackage.jsonmodule-export

Is there any way to specify the target resolution for a specific dependency in webpack?


Lets suppose our dependency has the following package.json described as:

{
  "name": "some-dependency",
  "exports": {
    ".": {
      "browser": {
        "import": "...",
        "require": "..."
      },
      "node": {
        "import": "...",
        "require": "..."
      },
    }
  }
}

How can I make webpack to resolve the node export individually only for some-dependency?. I've tried something like this:

module.exports = {

  // ...

  resolve: {

    extensions: [".jsx", ".js"],
    conditionNames: ["node", "some-dependency"],
  },
};

but it applies globally and doesn't seem to do the work right.


Solution

  • The conditionNames property is not about priority order. It is about which fields to use. The priority order is determined by exports object key order.

    Further, in your case, it is not possible to achieve this via any Webpack configuration. You will have to build your own plugin to add custom resolver logic using enhanced-resolver. For example:

    const { readFileSync } = require('fs');
    const path = require('path');
    
    // The module for which you need custom resolution
    const targetDependency = 'some-dependency';
    
    class MyCustomResolver {
      constructor(source, target) {
        this.source = source;
        this.target = target;
      }
    
      apply(resolver) {
        const target = resolver.ensureHook(this.target);
    
        resolver
          .getHook(this.source)
          .tapAsync('MyCustomResolver', (request, resolveContext, callback) => {
            // Any logic you need to create a new `request` can go here
            let newRequest = { ...request };
    
            if (request.request === targetDependency) {
              // Modify your newRequest object here.
              // Step 1: Read package.json of `some-dependency`.
              const json = JSON.parse(readFileSync(`node_module/${targetDependency}/package.json`));
    
              // Step 2: Extract required object
              const node = json.exports['.'].node;
    
              // Step 3: Modify newRequest object (Example only)
              newRequest.request = path.join(__dirname, 'node_modules', node.require);
    
              // Step 4. Modify additional param of request object if any
            }
    
            // Call the resolution function.
            resolver.doResolve(target, newRequest, null, resolveContext, callback);
          });
      }
    }
    
    module.exports = {
      resolve: {
        plugins: [
          MyCustomResolver
        ]
      }
    };