-
-
Notifications
You must be signed in to change notification settings - Fork 590
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal: Add support for full ES-Node interop #539
Comments
@Andarist @lukastaegert Thoughts? |
I've got several builds where this would fail hard. Can't go into details, but I'm certainly not in favor of adding magic here. Config should be explicit imho. Beyond that, we'd welcome any help from contributors on proposing these changes. Much of this seems reasonable though I think we're all fairly short on time at the moment. |
I agree that node-resolve should not imply commonjs and json, they all mean completely different things. If you're building a browser or node es module project, you want to use node resolve but not the others. I can imagine some kind of environment "preset" would be nice. Or at least some good documentation on this. For example "node commonjs", "node es modules", "browser es module" etc. which would combine different plugins as well as set some default properties. That would be very helpful for people who don't (want to) know all the technical nuances. If I understand correctly, your suggestion is to treat The other suggestions seem reasonable, but like @shellscape they can be tackled with individual issues and PRs :) |
The reason I said
That is unremarkable - Rollup cannot even successfully bundle itself with this stack and execute correctly (womp womp) due to the I suppose a more realistic and tapered version of what I am proposing is getting Node compatibility to 100% coverage and then adding a new plugin like
Me neither - my point is that the only way to get out of After wrestling with bundles that just keep containing
It is perfectly appropriate for Rollup to assess the dependencies of a module it is bundling, and make decisions based on that information. My main goal in accomplishing this was to produce output that I can run through Closure Compiler, but I ended up having to build an entire tool to get it to work. You can see the plugin stack at: https://github.com/TeleworkInc/.gnv/blob/master/rollup.plugins.js export const distPlugins = [
shebang(),
/**
* Input is Closure Compiled to minimize strain on `node-resolve`.
*/
closureCompiler({
define: 'PRODUCTION=true',
compilation_level: 'SIMPLE',
language_in: 'ES_NEXT',
language_out: 'NO_TRANSPILE',
}),
commonjs({
transformMixedEsModules: true,
}),
json(),
disablePackages('fsevents'),
nodeResolve({
preferBuiltins: true,
}),
bundleSize(),
]; With externals at: https://github.com/TeleworkInc/.gnv/blob/master/rollup.externals.js export const distExternal = [
/**
* Builtins and manually disabled packages.
*/
...builtinModules,
...disabledModules,
/**
* Package.json dependencies.
*/
...peerDeps,
]; |
Rollup core doesn't have any concept of packages or dependencies, it just bundles es modules which refer to each other relative or absolute paths. Everything else is brought in via plugins. The Having these separate plugins is important in my opinion. Especially since bundling non-es modules is inherently broken, what works for one package will break another package. Still, having some kind of preset or multi-plugin would be nice to have especially for legacy node js. |
I think that a "preset" would be nice. Plugins should not imply each other - as in some situations they could make a lot of mess when unintended - and the dev will have a hard time disabling "implied" stuff. In my opinion a preset is definitely the way to go. But that's a concept yet to be introduced to rollup. Another note - one of the things I love about rollup is that it encourages transitioning to static imports and teaches its benefits. It encourages proper code structure without circular dependencies that depend on quirks in cjs require algorithm. |
The amount of focus on the "implied plugin" comment is a little confusing - the bulk of this proposal is not about implying the Put shortly, there are a lot of Node modules in the wild Rollup cannot compile with standard plugins. My suggestion is to fix this. It is very clear based on the responses that we do not want to change default functionality (for My apologies if I was not clear in my original phrasing but genuinely, please close this issue rather than leave additional comments regarding my comments about "implied" plugins. I tried to do my part and bring an interesting issue forward and am willing to help work to address it if anyone's interested, but if not, please just close the issue. |
I think the ticket is important but it contains a lot of points that might be better served by splitting them up into separate tickets as many of them will likely be addressed independently anyway and require independent discussion. The handling of The second point is apparently already in progress while the third point sounds like a collection of issues, each of which needs to be identified and triaged separately. |
Presets are already kind of possible via If this was possible, it'd be easier to reach browserify-levels of node compatibility: rollup --config node:node-compat --config rollup.config.js |
@ctjlewis Thank you for this proposal. I’m looking into whether to implement SvelteKit in Site.js and I’m being blocked by having issues with, for example, modules like eff-diceware-passphrase (@^1.0.0 as @^3.0.0 has issues with browserify also) which work off the bat with browserify (and Snowpack) but which I haven’t been able to get to work yet using Rollup even when using the three plugins you mention. Having a plugin like |
@aral Agreed. I ended up having to develop a workspace preset and series of configs to work around these issues, and while this is totally not ready for public use, you can take a look at https://github.com/TeleworkInc/gnv. I would be happy to work on this more if the Rollup team were interested. This test suite was super lazily written and could be redone with a more careful touch, but I'd need help, and it would need to be prioritized. Confusingly, @Rich-Harris says that Snowpack relies on Rollup under the hood, so I wonder how interop is handled in that library? |
@FredKSchott is super nice and might be able to shed light there |
Check out https://www.npmjs.com/package/esinstall, it’s Snowpacks internal package CJS->ESM installer, powered internally by rollup. |
Neat; thank you :) |
Ran across this today https://github.com/niksy/node-stdlib-browser#rollup |
Rollup Plugin Name:
node-resolve
,commonjs
,json
Rollup Plugin Version:
latest
@ allAdding support for full ES-Node interop
An important functionality for Rollup I believe is the ability to bundle ES modules which depend on Node packages, as this is a highly common development scenario. Interop with Node typically requires the inclusion of three plugins (above) which I will call the Node compatibility suite, and it presently has 86% coverage over the top ~100 NPM packages and the modules they depend on. Node interop is really the only reason I have ever needed to reach for Webpack anymore, and it would be nice to get us to the finish line on this.
Unfortunately, because a failure at any point in a dependency tree is disastrous to the developer experience, this risk compounds rapidly, and even 99% coverage is insufficient - however, I think it would be relatively easy to get 100% coverage over the top 1000 NPM packages within 30 days, as most issues seem to be caused by a few isolated issues.
Link: Node-Rollup Test Suite [PRs extremely welcome]
There are two types of errors that can occur with Node-Rollup interop:
Some build-time headaches this team is already familiar with include the notable
fsevents
issue, which I would honestly place as a principal issue, if only because it actually prevents Rollup from bundling its own API viaimport { rollup } from rollup
, which is incredibly depressing. As I understand it,chokidar
can only bundle because achokidar
-specific wrapper was added, but this is insufficient for the obvious reason that it does not actually solve the problem - a better option would be adding the ability to ignoreoptionalDependencies
, or even making them opt-in and ignore by default (what I would recommend), which is a future-proof and more general solution that will cover all packages.¹ In the test suite, this is lazily evaluated as "if both fail, pass; if both exit 0, pass" when comparing source and bundle exit codes. Nonzero exits are generalized as "equivalent" for the purposes of these tests. This check can get more aggressive once we have 100% coverage, i.e. making sure
console.log
is 1:1 and so on.Expected Behavior / Situation
It should be virtually impossible to find an NPM package which will not bundle and execute as expected.
Actual Behavior / Situation
Of the test sample (n=1303), 17 (1.3%) produce build-time errors, and 176 (13.5%) fail the runtime test, bringing total coverage to ~85.3%. Honestly, I would say this is pretty good coverage going into this issue.
Modification Proposal
Any adjustments could likely be limited to just the
node-resolve
plugin, andadding thecould be enabled with an option flag likenode-resolve
plugin to your build would just implycommonjs
andjson
nodeResolve({ legacyMode: true })
.Fix build-time failures
Add opt-in/opt-out ignore of
optionalDependencies
to handlefsevents
-like scenarios. Preferred solution is to ignoreoptionalDependencies
by default and add a flag for including them.✅ Fix hashbang directory issue Bundle fails for form require('../#/folder') due to hashbang-only directory #528 (in-progress at fix(babel): strip hash and query param in extension filter #533), which breaks for
es5-ext
package (and packages in the top 100 that depend on it, specificallyd gulp es6-iterator es6-symbol es6-weak-map gulp gulp-cli last-run semver-greatest-satisfied-range sver-compat
, see config/exclude.txt). [Update 11/13/20: This is fixed (presumably) with fix(babel): strip hash and query param in extension filter #533.]Fix other build-time errors produced by the packages in
config/exclude.txt
. There's a "return outside of function" in there and a few other issues, but I have not bothered logging the build-time errors in theresults/
dir yet as the runtime errors are much harder to test and outnumber them 10:1.Packages which cannot build are added to config/exclude.txt so that the tests will build, any package in the test sample which refuses to build is listed in there.
Fix run-time failures
The following two issues cause 50% of the run-time errors:
util.inherits
transpilations will fail in certain cases and get called with a null second argument (admittedly need help debugging this one), causing the errorTypeError [ERR_INVALID_ARG_TYPE]: The "superCtor" argument must be of type function. Received undefined
to be one of the two most common runtime errors, occurring for 64 packages that were tested for runtime errors (36% of build-time failures). See bundles/argparse.js:983:util.inherits(ArgumentGroup, action_container)
. This error seems most frequently produced by packages that rely onreadable-stream
.__filename
and__dirname
shims are needed as CJS Node modules make use of these. I considered thenode-polyfills
plugin, but it completely conflicts withnode-resolve
and makes the build process unworkable. Errors due to__filename
and__dirname
being rolled into ES output cause 25 packages to fail (14% of build-time failures). This support will need to be added in a more native manner, see [commonjs] Output contains references to __filename #523.I am happy to help as much as I can with this process, but I am a little out of my depth here and I would really appreciate support from the Rollup team in reaching 100% Node coverage.
The text was updated successfully, but these errors were encountered: