Consider treeshaking module for serving files in dev mode
See original GitHub issueClear and concise description of the problem
Hello! Lately as our codebase has grown bigger and bigger over the last months we’ve been experiencing slow page reloading using Vite. That is not surprising given that our module size went off the chart, but it really is becoming a real pain point for us. I hear that we are not alone in this case, reading through some related issues: https://github.com/vitejs/vite/discussions/8232 and I totally agree with what @patak-dev says here: https://github.com/vitejs/vite/issues/7608#issuecomment-1087877492
The thing is, HMR has some reliability issues in our large codebase (where sometimes patching generates some issues) and these issues are very hard to debug, and creating a minimal reproduction is a huge amount of energy (for potentially no results) I failed to follow up on that ticket as well: https://github.com/vitejs/vite/issues/3719
With all that said, we are guilty of doing something that really does not help: we often import shared code with an index file because it is handy:
// /shared/index.ts
export { a } from './a'
export { b } from './b'
export { c } from './c'
// Component.vue
import { a, b } from '/shared'
// instead of
import a from '/shared/a'
import b from '/shared/b'
Of course, I already hear people say: ‘Duh! just don’t do this and import every single module individually you lazy dumbass’ I would answer: easier said than done when your codebase is a big monorepo and you share hundreds of compositions/components/libraries/helpers… We obviously see that this is way forward if we want to address our pain points with slow reloads.
END OF CONTEXT----
Suggested solution
Like I said above, we have clear directions for improving the perf of our app in development but this whole issue got me thinking about the module loading strategy of Vite’s dev server, and I wanted to start a discussion about considering to support treeshaking for module delivering because I think it could potentially help others.
Let’s take the example above:
// /shared/index.ts
export { a } from './a'
export { b } from './b'
export { c } from './c'
// Component.vue
import { a, b } from '/shared'
// instead of
import a from '/shared/a'
import b from '/shared/b'
Currently Vite delivers /shared/index.ts
as is and the browser will load c
module even though we’re not using it. If c
has some other dependencies, browser will load them as well, etc… You end up loading a whole module dep branch that we’re not even using.
In my wildest dreams, Vite could transform Component.vue
as such:
// Component.vue
import { a, b } from '/shared?dep=a,b'
// /shared/index.ts?dep=a,b
export { a } from './a'
export { b } from './b'
// c module is ruled out
I have created a small stackblitz to highlight the current Vite behaviour: https://stackblitz.com/edit/vitejs-vite-cjqcd4?file=src/App.vue
Did you guys ever consider it ? Am I out of my mind ?
Basically my thought is: if Vite was “smart” enough to treeshake module for creating the dep tree, we would not have the need to refactor at all, and potentially it could speed up the app loading for a lot of users.
I most likely have a naive conception of how the whole thing works and I don’t how much is feasible on that front but I wanted to kickstart discussion nonetheless. There are probably a lot of different requirements regarding side-effects etc… and I understand it is potentially a huge Pandora’s box…
Alternative
No response
Additional context
No response
Validations
- Follow our Code of Conduct
- Read the Contributing Guidelines.
- Read the docs.
- Check that there isn’t already an issue that request the same feature to avoid creating a duplicate.
Issue Analytics
- State:
- Created a year ago
- Reactions:22
- Comments:7
Top GitHub Comments
I’ve came across a similar issue with my team while working on our company’s software overhaul.
Just for the record, we’re using Storybook to document all kinds of things, from components to data strategies. We’ve came up with a lot of custom components to make our documentation even more interactive and impactful. All these components are made available and imported through an index file.
Now, whenever we’d import any component from that entry file - in development mode - it would initiate browser requests to load all files imported by this entry file. This makes some pages really slow to (re)load since they would load a whole bunch of files even though it only actively consumes a very specific piece of code.
Given the lack of actual solution on Vite side, I’ve ended up writing a simple Vite plugin which mimics tree-shaking when importing code from entry files. This appears to work pretty well with our codebase as the number or browser requests drastically decreased (since we’ve adopted it). I thought it could maybe help some of you guys out there, so i’ve tried to make it a public package. This is still very experimental and I can’t tell for sure this will suit your needs, but I would love to see it being field-tested and get any feedback.
vite-plugin-entry-shaking
My team hit this issue as well in our migration from Webpack to Vite. It wasn’t obvious initially as we were starting with small chunks of code pertaining to only 1 React app, but as we added more React apps and corresponding entrypoints (we have a multi-page app setup) the issue surfaced, causing a page not to load in local development mode.
We were scratching our heads for a bit trying to figure it out because the error was coming from a module way down in the dependency tree for another module tied to a route that we weren’t viewing/loading. We looked through the network requests and started swapping out import statements, which resolved the issue.
I wasn’t able to find anything in the docs about using
index.js
files with multiple module exports, but I think it would be helpful to at least have this documented somewhere.