Dschungelabenteuer / vite-plugin-entry-shaking

Mimic tree-shaking behaviour when importing code from an entry file in development mode.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Wildcard exports are not optimized

oriooctopus opened this issue · comments

Describe the bug A clear and concise description of what the bug is.
Exports like export * from './Unused'; are untouched by the plugin. Perhaps this is by design but I'm hoping that there can at least be an option for it.

To Reproduce Steps to reproduce the behavior:
Clone my repo, you can see the commit here:
oriooctopus@4738853

Expected behavior A clear and concise description of what you expected to happen.
I would expect "Unused" to not be in the network panel
Screenshot 2023-11-13 at 7 36 25 PM

This is a limitation stated in the readme:
https://github.com/Dschungelabenteuer/vite-plugin-entry-shaking#limitations

But I would also love this feature!

commented

TL;DR

As @sliptype mentioned, this is a known limitation, wildcard exports are "deliberately" unsupported. I'll try to explain the rationale behind this decision through a simple example.

Simple example

Let's say you have the following two files:

// `lib.ts`
export * from './bar';
export const foo = 'FOO';

// `bar.ts`
export const bar = 'BAR';
export const baz = 'BAZ';

At this point — as you would imagine — you may import any of foo, bar and baz consts from lib.ts e.g. :

// `app.ts`
import { foo, bar } from './lib';

Suppose you set lib.ts as an entry point through plugin's targets option. Whenever you start Vite's dev server, this plugin reads all of the exports from entry points and maps their names to the actual path they're imported from. This is what makes it possible to rewrite import statements to avoid loading the entire entry point.

The issue

When statically analyzing lib.ts and processing our wildcard export, there is no way of knowing what this ./bar exposes. Without any piece of information about those exposed names, we can't really rewrite our above import from app.ts: what is bar? where does it resolve to?

I mean, there is a way: we could just also run another static analysis on wildcard-exported modules, right? Well, I'm quite worried about the implications, especially performance-wise. What if our wildcard-exported module (here bar.ts) also has one or multiple wildcard exports? Yet another analysis? I'm afraid this could end up pretty wild pretty fast.

You could tell it's eventually the end-user's responsibility to make sure they don't end up in such a situation, but it's quite easy to lose track of deps and I'd like to keep a safety-first (not to say pessimistic) approach here.

However…

I'm well aware supporting these would still help some people and I get this is a bit annoying. I'll try to figure something out to make it happen in a reasonable way.

One possible trade-off between performance concerns and flexibility could be to only support wildcard exports of other entry files/targets. This would give end-users full control over wildcard-exported modules they really want tree-shaken, prevent unexpected recursions, and it could give a clearer insight on the potential performance impacts by just looking at their targets option.

I'll try to come up with something soon, happy to hear what you think about this!

@Dschungelabenteuer thank you for the clearly explained write up! Thinking about our own situation, we are similar to what you described in the bad scenario. We have an index file that imports from other index files. But, if I remember correctly it never goes more than two levels deep in total. That would fit with what you're saying about limiting recursion, but personally I'm not a big fan of limiting the recursion as 2 levels deep could easily change in the future and really is just the situation with my case. There are probably plenty of other situations that have many levels of recursion, without necessarily being a performance issue.

Perhaps the level of acceptable recursion could be controlled via a numerical prop. On that subject, it might make sense to enable/disable this feature via a boolean prop

commented

I closed this issue but forgot to ping you @sliptype @oriooctopus, this is now supported as of 0.4.0, please let me know if it doesn't address the original issue lads :-)