softonic / axios-retry

Axios plugin that intercepts failed requests and retries them whenever possible
Other
1.9k stars 167 forks source link

Export type change in 3.2.1+ after bundling (formerly: TypeError: axiosRetry is not a function) #206

Open dominics opened 2 years ago

dominics commented 2 years ago

Hello! I saw #181 and I think I'm experiencing something similar when trying to bundle a dependency (analytics-node) that happens to require axios-retry. The library in question loads axios-retry with require(), BUT Webpack seems to bundle the ESM export instead, causing the original issue - but only post-3.2.0 (i.e. a breaking change since then)

#181 didn't have good reproduction instructions, so I've made sure to isolate the problem in a repo: https://github.com/dominics/axios-retry-bundle-repro - an excerpt from the README is:

(That's the only difference). Each has a Webpack install, with a very simple configuration:

module.exports = {
    entry: "./index.js",
    output: {
        filename: "bundle.js",
        libraryTarget: "commonjs",
    },
};

There's a yarn test script in each directory. It makes a webpack bundle of this script and runs it:

var axiosRetry = require('axios-retry')
console.log(axiosRetry)

To reproduce the issue, I recommend running:

cd 3.2.0 && yarn install && yarn test && cd ..
cd 3.2.1 && yarn install && yarn test && cd ..

Results after bundling

3.2.0 returns the following function:

[Function: O] {
  isNetworkError: [Function: i],
  isSafeRequestError: [Function: a],
  isIdempotentRequestError: [Function: c],
  isNetworkOrIdempotentRequestError: [Function: R],
  exponentialDelay: [Function: l],
  isRetryableError: [Function: f]
}

However when we try to bundle 3.2.1, we get a breaking change, and get a module object instead (newer versions such as 3.2.4 and 3.3.1 return the same):

Object [Module] {
  isNetworkError: [Getter],
  isRetryableError: [Getter],
  isSafeRequestError: [Getter],
  isIdempotentRequestError: [Getter],
  isNetworkOrIdempotentRequestError: [Getter],
  exponentialDelay: [Getter],
  default: [Getter]
}

Summary

It seems that, if you're using a common bundler with default settings, you'll likely experience #181 as a breaking change on a patch release, and this problem seems to remain in 3.3.1 - I would guess the likely issue is how the bundler is handling the package.json changes that were made in 3.2.1 - probably Webpack 4 is grabbing at the wrong import (e.g. maybe because the ESM module is listed in package.json as the module field? yet Webpack 4 doesn't understand to use the ESM module struct's default property? something like that)

This could be entirely a problem with how the bundler is choosing which export to bundle, and it might even be unfair to expect libraries to think of how they're bundled as part of their public interface. It may be fair to say "use a different bundler then!". But practically, 3.2.1+ will break at runtime for people who are trying to bundle their dependencies, when 3.2.0 was working for them, so I still felt it was worth it to isolate that issue.

Hope the reproduction helps! I'm not sure what the fix is, or whether the situation is even fixable.

dominics commented 2 years ago

Updated the repro repo to have versions 3.2.1 and 3.3.1 as well as the original 3.2.0 and 3.2.4 that were relevant to #181

mindhells commented 2 years ago

Interesting, this is what I found out so far:

There's probably something that can be tuned up in the webpack config for webpack 4 to make it work, not sure we can do anything (a part from removing the "module" property) Any ideas?

mindhells commented 2 years ago

And BTW, @dominics thanks a lot for taking the time to create the example.

dominics commented 2 years ago

There's probably something that can be tuned up in the webpack config for webpack 4 to make it work

Yup, I I think this is: adding a resolve.alias config option from { axios-retry: "axios-retry/index.js" } so that Webpack doesn't need to look at the package.json

removing the "module" property

I suspect that might be a breaking change for anyone now relying on it?

I can't think of much that can be done - the main lesson I'm taking from this is my bundler is too old!