Clear and concise description of the problem
A typical multi-page application often have many pages that run the same code and only differ in content, e.g. blog pages in a blogger. In this kind of cases, vite currently will generate an identical entry chunk for every page:
// `assets/blog1.24e133d0.js` for `blog1.html`
import "blog.3de32cc4.js";import"vendor.d046dfe5.js"
// `assets/blog2.24e133d0.js` for `blog2.html`
import "blog.3de32cc4.js";import"vendor.d046dfe5.js"
// `assets/blog3.24e133d0.js` for `blog3.html`
import "blog.3de32cc4.js";import"vendor.d046dfe5.js"
...which is less than ideal.
Details
For the usual single-page app, one JS module will be "imported" by one html entry, for example <script src="/src/main.ts"> in index.html. Rollup sees that main.ts is only used once, so it will bundle main.ts and as many dependencies as possible into one index.[hash].js entry chunk. This is the desired behaviour.
But in the case of MPA, mutiple html files can all use the same JS module, and every html is an entry. Entries can't be merged together, so rollup will not bundle anything into the entry chunks, emitting identical files for every html that do nothing but import other modules.
Suggested solution
Since some entry chunks do nothing but import, why don't we do away with them altogether, and directly "inline" them into html as <script type=module> tags?
The above example
// assets/blog1.24e133d0.js
import "blog.3de32cc4.js";import"vendor.d046dfe5.js"
<script type="module" crossorigin src="/assets/blog1.24e133d0.js"></script>
<link rel="modulepreload" href="/assets/vendor.fc2e950e.js">
<link rel="modulepreload" href="/assets/blog.3de32cc4.js">
can be like this:
<script type="module" crossorigin src="/assets/vendor.fc2e950e.js"></script>
<script type="module" crossorigin src="/assets/blog.24e133d0.js"></script>
I've done a draft implementation of this solution: #4555.
(I'm working on the assumption that there isn't any specific reason behind the current behavior, like some hidden advantages I'm not realizing - please point out if that's not the case)
Alternative
- Not do this entirely - a lot of tiny extra JS files for any MPAs of nontrivial scale, and double that if sourcemap is enabled. A deeper critical request chain, though mitigated by
modulepreload.
- Other solutions, like trying to detect entry chunks that are identical, keeping the first one and deleting the others, like so:
// assets/blog1.24e133d0.js
import "blog.3de32cc4.js";import"vendor.d046dfe5.js"
// blog1.html
<script type="module" crossorigin src="/assets/blog1.24e133d0.js"></script>
// blog2.html 👇 share the same file
<script type="module" crossorigin src="/assets/blog1.24e133d0.js"></script>
This seems harder to implement to me though.
Additional context
The suggested solution will also be a general solution to #3127 and an alternative to #3129.
Validations
Clear and concise description of the problem
A typical multi-page application often have many pages that run the same code and only differ in content, e.g. blog pages in a blogger. In this kind of cases, vite currently will generate an identical entry chunk for every page:
...which is less than ideal.
Details
For the usual single-page app, one JS module will be "imported" by one html entry, for example
<script src="/src/main.ts">inindex.html. Rollup sees thatmain.tsis only used once, so it will bundlemain.tsand as many dependencies as possible into oneindex.[hash].jsentry chunk. This is the desired behaviour.But in the case of MPA, mutiple html files can all use the same JS module, and every html is an entry. Entries can't be merged together, so rollup will not bundle anything into the entry chunks, emitting identical files for every html that do nothing but import other modules.
Suggested solution
Since some entry chunks do nothing but import, why don't we do away with them altogether, and directly "inline" them into html as
<script type=module>tags?The above example
can be like this:
I've done a draft implementation of this solution: #4555.
(I'm working on the assumption that there isn't any specific reason behind the current behavior, like some hidden advantages I'm not realizing - please point out if that's not the case)
Alternative
modulepreload.This seems harder to implement to me though.
Additional context
The suggested solution will also be a general solution to #3127 and an alternative to #3129.
Validations