rollup/rollup-plugin-babel

proposal-private-methods skips @rollup/plugin-commonjs when injecting `import` statement

micaelmbagira opened this issue · 6 comments

I am bundling a project with the following rollup config

module.exports = [
  {
    input: './src/index.js',
    output: [
      { file: pkg.main, format: 'cjs' },
    ],
    plugins: [
      babel(),
      commonjs(),
    ],
  },
];

However the commonjs plugin (which resolves require statements) is not working -- basically require('./foo') is not being replaced by the actual source.

I found that it's because I am using '@babel/plugin-proposal-private-methods' which injects these two lines (I had to tap in rollup/plugin-commonjs to find that out).
For instance if I remove in my source code, all the usage of private methods/properties (even if I leave the plugin configuration in .babelrc), it works.

import { classPrivateFieldGet as _classPrivateFieldGet } from "\0rollupPluginBabelHelpers.js";
import { classPrivateFieldSet as _classPrivateFieldSet } from "\0rollupPluginBabelHelpers.js";

Because of that, rollup considers the compiled module as an esModule and thus does not start resolving the other require.

Tbh I am not sure whose responsibility it is.

If needed, here is my babel config:

module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        modules: false,
        targets: {
          node: '10',
        },
      },
    ],
  ],
  plugins: [
    '@babel/plugin-proposal-class-properties',
    '@babel/plugin-proposal-private-methods',
  ],
};

It's because rollup detects those files as modules (because of the injected import statements), and thus doesn't replace require` that in modules is not the CommonJS function.

You can tell Babel that you are not using modules using the soureType option:

{
  sourceType: "script",
  presets: [
    [
      '@babel/preset-env',
      {
        modules: false,
        targets: {
          node: '10',
        },
      },
    ],
  ],
  plugins: [
    '@babel/plugin-proposal-class-properties',
    '@babel/plugin-proposal-private-methods',
  ],
}

Note that if this problem is only for code in node_modules and you are using ES modules in your source code, you can configure it like this:

{
  sourceType: "module",
  presets: [
    [
      '@babel/preset-env',
      {
        modules: false,
        targets: {
          node: '10',
        },
      },
    ],
  ],
  plugins: [
    '@babel/plugin-proposal-class-properties',
    '@babel/plugin-proposal-private-methods',
  ],
  overrides: [
    { test: /node_modules/, sourceType: "script" }
  ]
}

@nicolo-ribaudo indeed this causes a problem only for the code produced by babel

import { classPrivateFieldGet as _classPrivateFieldGet } from "\0rollupPluginBabelHelpers.js";

In any case, sourceType: "script", does not work and throws this error

'import' and 'export' may appear only with 'sourceType: "module"' (2:0)
Consider renaming the file to '.mjs', or setting sourceType:module or sourceType:unambiguous in your Babel config for this file.
1 | class Foo extends Bar {};
2 | export default Foo;

which I actually don't understand since my code is not using import/export.

When using

overrides: [
    { test: /node_modules/, sourceType: "script" }
  ]

the compilation goes through but the initial problem is still there and thus the require statements are still not transformed.

Ok, try setting sourceType to unambiguous. It doesn't work in some edge cases, but if you find them you can special-case the files where it's throwing (or keeping "require") using overrides.

@nicolo-ribaudo unambiguous worked here. Let's see if it causes any problems later. It seems a bit odd that we need this step even though the problematic code is generated by babel 😅but it's fine for now.

Well, Rollup expects native ES modules. The rollup-plugin-commonjs package internally transforms CommonJS to ESM before giving it to rollup. Then it's kinda expected that Babel (with rollup-plugin-babel) generates ESM imports 😅

@nicolo-ribaudo fair enough, I think I will just use import/export syntax, it seems like a better fit than setting the sourceType for this use case.