Minimal reproduction: https://github.com/zposten/rollup-babel-helpers-runtime-bug
The rollup babel plugin README explains here and here that by performing the following steps, I should be able to avoid having the babel helper functions injected into my bundle, and instead should be able to import those functions from the @babel/runtime NPM package, thus ensuring that my library does not add duplicate code to my user's application:
@babel/plugin-transform-runtimeuseESModules option of that plugin to true@babel/runtime to dependencies in package.jsonbabelHelpers option of the babel plugin to 'runtime'output.format to es or cjsesm format instead of es, but the big list of options does not list esm as a valid formatDespite performing all those steps, the Rollup output bundle still contains the babel helper functions. This is in contrast to the output of running babel directly, which does produce the expected results.
So after doing a bit of digging, it looks like this issue is a result of combining the node-resolve plugin with babel and transform-runtime. The resolve plugin pulls in the @babel/runtime module and will include it in the bundle unless specified and treated as an external module (i.e. set external: ['@babel/runtime'] in rollup config). However, in this case, rollup does an exact string match and since the imports come from nested paths (e.g. @babel/runtime/helpers/esm/classCallCheck) rollup does not treat these modules as external and bundles them in.
A quick solution is to use a regex and specify external: [/@babel\/runtime/] in your rollup config and rollup will treat all of the babel helpers as external. I pulled down your reproduction repo and tweaked this and it seems to work properly now.
Either that or one could use the resolveOnly option in the node-resolve plugin which allows you to specify a regex and only resolve modules that match and you could exclude @babel/runtime there: resolve({ resolveOnly: [/^(?!.*@babel\/runtime).*/] }).
Either way, perhaps we should add to the docs that using a regex here is necessary for rollup to properly treat these helpers as external?
You can try this to to ignore all dependencies
external: id => !id.startsWith('.') && !path.isAbsolute(id)
or just this
external: id => id.includes('@babel/runtime')
Either way, perhaps we should add to the docs that using a regex here is necessary for rollup to properly treat these helpers as external?
That would be great. Would you like to prepare a PR for this?
You can try this to to ignore all dependencies
external: id => !id.startsWith('.') && !path.isAbsolute(id)
This! Not only does this solve this particular bug, but I have been looking for a way to mark every NPM dependency as external. I can't think of an instance where it would ever make sense to include any dependency in the built code of a library.
You can try this to to ignore all dependencies
external: id => !id.startsWith('.') && !path.isAbsolute(id)This! Not only does this solve this particular bug, but I have been looking for a way to mark every NPM dependency as external. I can't think of an instance where it would ever make sense to include any dependency in the built code of a library.
For CommonJS and ESM outputs, you would almost never want to bundle the dependencies in as part of your bundle because you can rely on the library consumer to pull in your dependencies (via npm or some package manager) and bundle them in during their build process. However, for example, if you've got some UMD bundle hosted via CDN, you probably want your consumers to have everything they need to use your library inside that one single bundle file.
For CommonJS and ESM outputs, you would almost never want to bundle the dependencies in as part of your bundle because you can rely on the library consumer to pull in your dependencies (via npm or some package manager) and bundle them in during their build process. However, for example, if you've got some UMD bundle hosted via CDN, you probably want your consumers to have everything they need to use your library inside that one single bundle file.
Thank you for your reply, that makes sense. This is getting pretty far outside the scope of this bug, but do you think it would make sense for that to be rollup's external default for CommonJS and ESM outputs?
Thank you for your reply, that makes sense. This is getting pretty far outside the scope of this bug, but do you think it would make sense for that to be rollup's
externaldefault for CommonJS and ESM outputs?
Well, actually that is rollup's default behavior. It's the node-resolve plugin that by default pulls in all of your dependencies. See here for more info about this: https://rollupjs.org/guide/en/#warning-treating-module-as-external-dependency.