babel-plugin-transform-named-imports icon indicating copy to clipboard operation
babel-plugin-transform-named-imports copied to clipboard

Support Webpack's `sideEffects` property in `package.json`.

Open JHawkley opened this issue 6 years ago • 4 comments

When it comes to the problem of side-effects, Webpack has a means of marking specific files as having them through a property on the module's package.json file.

This could be used by this plugin as an indicator to use a more rigorous processing method on them or ignore them entirely.

It is a little complex, though, as you would need to check not only the current project's package.json file, but also those of any other node_modules that may have been included by the current project.

It also is a bit dependent on other node_modules properly using this Webpack feature. Perhaps allow some configuration for a strictSideEffects mode, where any module that lacks the sideEffects property is assumed to have them and ignored by this plugin.

JHawkley avatar Mar 06 '19 08:03 JHawkley

This would be interesting to support. Once we complete the transition to Webpack 4 at work, I'll put some effort into this.

Photonios avatar Aug 20 '19 09:08 Photonios

If you're doing some work with this in Webpack, I had started an attempt to convert this project into a Webpack loader. The code is currently available on GitHub if you would like to take a look.

I figured, if this plugin was this tightly coupled to Webpack, may as well just use Webpack directly and enhance its ability to resolve imports even further.

However, I am not entirely happy with its current implementation; I was kind of hoping that Babel 8 would hit soon and bring async plugins with it and greatly simplify its complexity, but it hasn't happened yet. So, I started my own async-traversal wrapper for Babel in the mean time, but it has not reached a point of maturity where it is ready to be trialed using it in the Webpack loader.

It may be that I should explore making a Webpack plugin instead of a loader.

But anyways, it's there if you would like to pick bits out of it or even contribute; it is a fork of this repo, but has been heavily transformed.

JHawkley avatar Aug 20 '19 11:08 JHawkley

One reason why I initially decided to make this a Babel plugin and not a Webpack plugin is that most Webpack projects already use Babel to transform their code. If you write this as a Webpack loader or plugin, you pay the cost of Babel having to parse the code at least twice (once by this custom loader, and once by the babel-loader itself).

https://github.com/JHawkley/resolve-imports-loader/blob/master/src/transformLoader.js#L96 runs twice on the entire code base. If you have a large code base, this becomes expensive. At least, this is what I understand from it. Please do correct me if I am wrong :)

I understand it's more convenient to have this as a Webpack loader and we could see if we can port some code the from your project here. From what I can see, you still have a stand-alone Babel plugin in https://github.com/JHawkley/resolve-imports-loader/blob/master/src/babel.js and the code looks a bit cleaner than this one. Maybe we can even find a way for the Webpack loader to use the same plugin code. Let me know if this is something you're interested in exploring.

Photonios avatar Aug 20 '19 11:08 Photonios

This is true, and I do my best to reduce it with things like the unsafeASTCaching option. I also took care to ensure that this plugin was at home in concurrent pipelines, meaning it is possible to gain some speed back through parallel execution, as well.

However, what you lose in performance, you gain back in correctness and completeness. The Babel plugin makes a couple critical assumptions that often turn out to be false in a Webpack project:

  1. All imports point to a JavaScript source file that exists somewhere on disk.
  2. The source code seen on disk will never differ from the source code actually emitted by Webpack.

So, this led to a problem where the Babel plugin would fail when trying to deal with imports that are transformed-by or the-product-of another Webpack loader.

As an example, you may have an image-loader that allows importing a JPG or PNG file as an ES6 module; it might build a small JavaScript wrapper around these resources that your project can then use to apply custom formatting based on the image's size or aspect-ratio, for example.

However, the Babel plugin has no awareness of this and would fail when it tried to open and parse a binary image file as if it was JavaScript source code, which in turn causes the entire Webpack build to fail.

There were other edge cases that I hit as well; I believe in one case a Webpack loader was creating changes between the JavaScript source on disk and the source Webpack would actually build with, so the Babel plugin ended up emitting transformations that were not actually correct for the final output.

So, this was the main motivator to turn it into a Webpack loader. Perhaps it would be possible to sniff the Webpack config file and detect these exceptions, however that seemed like a lot more work and more prone to failure compared to just asking Webpack to provide the source it's going to actually build with and transform that in isolation.

JHawkley avatar Aug 20 '19 12:08 JHawkley