FredKSchott / rollup-plugin-polyfill-node

A modern Node.js polyfill for your Rollup bundle.
Other
179 stars 57 forks source link

Conflict between Explicit Polyfill and Plugin #47

Open eric1234 opened 2 years ago

eric1234 commented 2 years ago

I am working on an application where a dependency is explicitly using the inherits polyfill. The specific code is this file which is in CJS format. But even though that package provides it's own polyfills explicitly, I also need this plugin for other dependencies that are not providing their own polyfills.

When I build my bundle I end up with an error complaining that inherits is not a function. To reduce this to a minimal reproduction lets use the following as my package.json:

{
  "name": "inherit-test",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "build": "rollup -c"
  },
  "devDependencies": {
    "@rollup/plugin-commonjs": "*",
    "@rollup/plugin-node-resolve": "*",
    "rollup": "*",
    "rollup-plugin-polyfill-node": "*"
  },
  "dependencies": {
    "inherits": "*"
  }
}

Note that I am explicitly using the inherits polyfill so don't technically need this plugin but let's imagine I will later need other dependencies that do need this plugin. Here is my actual code that I want to bundle which is just a trivial usage of the inherits function:

const inherits = require('inherits')

function Base() {}
function Sub() { Base.call(this) }
inherits(Sub, Base)

Note that this code is in CJS format just like the real file that was getting the issue. Now finally here is my rollup config:

import commonjs from '@rollup/plugin-commonjs'
import resolve from '@rollup/plugin-node-resolve'
import polyfillNode from 'rollup-plugin-polyfill-node'

export default {
  input: 'index.js',
  output: {
    format: 'iife',
    name: 'app',
    file: 'bundle.js',
  },
  plugins: [
    commonjs({
      //requireReturnsDefault: "auto",
    }),

    polyfillNode(),

    resolve({
      preferBuiltins: true,
      browser: true,
    }),
  ]
}

When I bundle it will bundle fine. But if I run the JS code I get the following error:

TypeError: inherits is not a function

This reproduces the error I am getting from the real library. You will notice above I have requireReturnsDefault option commented out. If I remove that comment and bundle then it both bundles fine and runs fine. This is great as it means I have a work-around!

But ideally I would like it to bundle and run correctly without that option. It seems this plugin should "just work" even in the presence of modules that are providing their own polyfills without needing to track down some obscure option in the commonjs plugin.

I'm not sure I completely I understand the core issue here. I think it is because the polyfill that is being explicitly specified is in CJS format while the same polyfill provided by this plugin is in ESM format. When commonjs plugin is processing the files it sees the included module is CJS format but then this plugin swaps it out for a different format meaning the glue the commonjs plugin put in place no longer works. Enabling that option enables a bit smarter glue to be put in allowing the fact that the format changed to not matter.

What is the solution? I'm not sure. It seems if a package is explicitly using it's own polyfill we shouldn't swap that out. We should use the polyfill it specifies. But I'm not sure this plugin can determine that or not.