import-js / eslint-plugin-import

ESLint plugin with rules that help validate proper imports.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Option to exempt side-effect imports from 'import/no-duplicates'

matthias-ccri opened this issue · comments

Our use case is that we have internal npm packages that (unfortunately) have module side-effects. These may also export values. We also have good packages that are side-effect-free, but it's hard to know which is which.

So we may have imports like this:

import '@org/foo-plugin'; // side effect
import { util } from '@org/bar-plugin'; // side effect plus value import
import { initGoodPlugin } from '@org/good-plugin'; // side-effect-free

I think it would be best to have explicit side-effect imports, and sometimes this means duplicating imports. Here's why.

Here is the scenario:

  1. Initially, there is a side-effect import: import '@org/bar-plugin';. It's obvious that this is a side-effect import.
  2. Then some time later, a value is needed, so the side-effect import changes to a value-import: import { util } from '@org/bar-plugin';. It's no longer obvious that this import exists to trigger a side effect.
  3. Then some time after that, the value becomes no longer needed, so because of our "no unused imports rule", the import becomes import { } from '@org/bar-plugin';, and the developer will likely remove the import, thinking "it's no longer needed".

So in this scenario, the side-effect was accidentally lost.

One way to avoid this would be to have two imports:

import { util } from '@org/bar-plugin';
import '@org/bar-plugin'; // trigger side-effects

And if you suggest that we should just avoid having side-effectful packages, I'd say yes I agree, and let me tell you about the employment opportunities at my company I work for so you can help us out ;)

But for now, having the dedicated side-effect import is a good workaround. But it requires us to eslint-ignore not once but twice. (cries on keyboard)

TLDR:
Would it make sense for this rule to have an ignoreSideEffectImports option?

I am confused about why it wouldn't be easier to just split up the side effects and the exports into different entry points on those internal packages, since you can just go change all the callsites.

I can't imagine that added complexity for 21 million people a week is justified to avoid slightly fewer people doing some work in your company :-/

That would be the better solution, and I hope to do that one day. But this issue with side effects might be good to address in general. Sure it's better to not have them, but side-effectful packages can exist, and I assume my company is not the only ones stuck using them. So the scenario that I laid out could be encountered by anyone who uses a side-effectful package.

I don't presume to know if this request merits implementation, but I thought it was worth bringing up. I understand if this is deemed out of scope because side effects are an antipattern.

I'm fine with side effects :-) just not with side-effecting files also exporting things.

Probably a more reliable approach would be to use the nonstandard sideEffects field - which can, apparently, indicate specific entry points that have side effects vs not - and that way it'd be more general-purpose.

In

import { util } from '@org/bar-plugin';
import '@org/bar-plugin'; // trigger side-effects

doesn't the first line trigger the side-effects? And the 2nd line is a no-op because each module is only evaluated once. If so, I think the following makes more sense:

import '@org/bar-plugin'; // trigger side-effects
import { util } from '@org/bar-plugin'; // import named export 'util'

Yes, it does, and you’re right - however the fix needs to be made in the package itself to split up the side effects from the exported values.

Yes that's right, and I agree with @ljharb. Side effects are an antipattern, and any efforts to improve the antipattern would be better spent removing the antipattern. That's what I think I'll do in my current codebase. Vote to close this issue?

Sounds good.