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

How to use with entry point from node_modules

florianmatz opened this issue · comments

Hi,

I have a monorepo setup, where apps import components from a quite large library using barrel export files (export * from core/…, export * from form/…).

The monorepo uses workspaces so the lib behaves to the apps like a node_module.

resulting in slow loading on startup, obviously due to the problem of tree shaking you’re trying to tackle.

So, I was wondering how to use this plugin with entry points not local but from node_modules. I was not able to get it running, maybe you have some advise or even can provide another example.

commented

Hey @florianmatz! Very sorry for the delay 😅

A few things before I get to the point:

  • If I got you right, you are consuming one of your monorepo's packages as dependency of another package from the very same monorepo (lets say you have your "app" package consuming the "ui" package). If so, why would you ever need to go through the node_modules, when they're both part of the same project tree? Happy to provide an example of how I use this plugin cross-packages within monorepositories if needed, just let me know.
  • Can you confirm that by saying "slow loading on startup", you're actually talking about first access to your Vite app from the browser (because of the amount of requests being fired), and not Vite's own startup time (e.g. VITE v4.0.1 ready in 224 ms)?

That being asked, while it is technically possible to use a node_module as an entry point, I would not recommend it and rather rely on Vite's prebundling because it specifically addresses this issue (see the example they give about lodash). In other words :

  • When consuming a node_module as a facade/barrel export, the whole module should be pre-bundled by Vite so the browser should only fire one request (the whole bundled module)
  • However, when consuming any file from any package of your monorepo, it should not be pre-bundled and the browser would have to recursively fire requests for any imported files: this is specifically where this plugin is useful!

If you're still willing to use this plugin against a node_module, here's one way


This would first require you to override the ignorePatterns option because it ignores node_modules by default. Also, remember that when you set your very own ignorePatterns, it won't be merged with the default value. This is very important because it could cause most of your dependencies to be analyzed by the plugin, when it's probably irrelevant and you basically don't care about most of them.

So now, suppose you have a "mylib" dep in node_modules:

1. Overwrite ignorePatterns

// …
export default defineConfig(() => ({
  plugins: [
    EntryShakingPlugin({
      targets: [pathToMyLib] // resolves to /node_modules/mylib,
      // Keep ignoring all node_modules but handle testlib folder
      ignorePatterns: [/node_modules\/(?!mylib\/).*/],
    }),
  ],
}));

Note One thing I have tried though is using directly the name of the lib instead of manually resolving its path (e.g. targets: ['mylib'] assuming its package.json is valid). I suspect this could work out of the box because this plugin relies on Vite resolvers, but I'm not 100% sure.

This will let the plugin transform any file which imports data from your entry point, even though that entry point is located within node_modules.

2. Vite's prebundler

Now files that import anything from your entry point should be correctly transformed. However, there is another thing: since Vite pre-bundles node_module by default, you would have to either exclude your module from optimized deps, or find a way around cache busting which prevents this plugin from rewriting entry files because myFile.ts will never match myFile.ts?v=83cfeb8f. Not mutating the entry file could result in useless requests still being fired whenever you import a piece of code which is actually defined in the entry file (along with the barrel exports).

But once again, I don't see the point, a lot of pain for possibly zero benefit :/

If you meant using @mymonorepo/ui in @mymonorepo/app


Here is a working example. When starting app in dev mode, you should see that only Button and Input are requested by the browser, even though ui also exports Icon and Link.

Hi! Thanks for the detailed answer! I basically meant the latter and you're example helped me out :) - thank you very much!

commented

I'm glad I could help 🙌