vite
vite copied to clipboard
Omit `__vitePreload` if dependency array is empty
Description
Vite provides modulePreload.resolveDependencies
to give fine-grained control over module preloading. However, when I exclude module dependencies, it still imports the preloader. This is a feature request not to render the preloader at all if the dependency list is empty.
This has the additional benefit that if no preloading happens, I don't have to pay the price for the preloading script.
I need this for a Vite plugin generating content scripts for browser extensions. Content scripts are non-modules and thus don't allow the import func from 'file'
syntax. Additionally, since files are local, the waterfall without preloading is negligible.
Suggested solution
Given:
modulePreload: {
resolveDependencies: (url, deps, { importer }) => {
return [];
}
}
Instead of:
import { __vitePreload } from "./preload-helper.js";
__vitePreload(() => import("path/to/file.js")), true ? [] : void 0); // note empty preload list
output:
import("path/to/file.js"));
Alternative
I considered creating a plugin, but Vite runs built-in "enforce": "post"
plugins last after user "post"
plugins...so I can't override the import within the transform
hook.
Additional context
This is essentially a follow up of https://github.com/vitejs/vite/issues/5991 and https://github.com/vitejs/vite/pull/9938. This is a common pattern (https://github.com/vitejs/vite/issues/8023#issuecomment-1118234452) in browser extensions.
Validations
- [X] Follow our Code of Conduct
- [X] Read the Contributing Guidelines.
- [X] Read the docs.
- [X] Check that there isn't already an issue that request the same feature to avoid creating a duplicate.
β π― for this. Incredibly frustrating to set modulePreload: false
and then find that every dynamic import is still wrapped with __vitePreload()
calls. It is doubly frustrating when you realize itβs basically dead code added to your bundle by the build tool that is supposed to be helping you optimize things. To make it worse, if you have dynamic imports and CSS dependencies, those get injected as pseudo-preloads, of some sort, which is essentially Vite not honoring the modulePreload: false
option at all, really.
any updates regarding this issue? It's frustrating to have this polyfill in web extensions.
Vite currently can't omit the __vitePreload
because the dependency array can only be retrieved during the generateBundle
phase (after Rollup has chunked everything). So Vite can only preemptively guess that a dynamic import might need preloading and inject it before Rollup chunks things.
While Vite could maybe walk back and remove the __vitePreload
text altogether (using some form of regex), that also has caveats too like extra work needed to re-ensure sourcemaps are correct. I think leaving it alone is still fine as __vitePreload
only has a small overhead for empty deps.
If the idea is to have no preloading at all then modulePreload: false
would be the option. However as noted above, we can't completely avoid preloading if CSS deps is involved, otherwise your application styles will be broken. To prevent that, I think disabling build.cssCodeSplit
should work.
So altogether, I'm not sure if there's anything else we can do here.
Currently to use vite on WebExtension, the public dir can be useful. the way is importing vite-processed source in public dir source. and register the public dir source to the content_script. because the source in public dir be just copied to dist and don't bundled by vite.
Yes, the overhead of the empty array is negligible. The key issue though as mentioned in the original post is that there are some environments where specific files 1) need dynamic imports 2) cannot be modules. (e.g. browser extension content-scripts).
I can hack around to remove the __vitePreload
using a regex and magic-string during BUILD in later rollup hooks. The challenge is that in DEV mode transform
is the last hook before Vite sends files to the browser and it runs its code to add the __vitePreload
in a post hook that runs after my plugin. There's simply no opportunity to undo that __vitePreload
in a user Vite plugin in DEV mode because of plugin ordering.
~How do you feel about "enforce": "post-post"
for user plugins? π~
PS: In writing this it occurred to me that I might be able remove the __vitePreload
by adding a service-worker that overwrites the module, though I'm not sure about the viability of that. Either way, I understand that it's challenging given the constraints of your integration with Rollup, but it still feels like something that could/should somehow be resolved in Vite rather than hacked around in user land.
some environments where specific files 1) need dynamic imports 2) cannot be modules.
I don't quite understand this. Dynamic imports only work for modules, if it can't be modules, it's conflicting the idea.
The challenge is that in DEV mode
transform
is the last hook before Vite sends files to the browser and it runs its code to add the__vitePreload
in a post hook that runs after my plugin.
You can have a transform hook like this:
{
transform: {
order: 'post'
handler() {}
}
}
The order
(supported by Rollup) re-arranges the hooks after enforce
re-arranges the plugins.
it still feels like something that could/should somehow be resolved in Vite rather than hacked around in user land.
I think this depends on Vite's target audience focus, which is mainly browser apps, SSR, backend integrations, etc. Developing web extensions isn't part of the original goal so requiring workarounds seems fair to me.
In medium-sized applications on low-end devices, Vite's code preload kills performance during the initial load. Every extra Promise
is a performance killer, as are calls to document.querySelector
. I'm not entirely sure how to create a reproduction since there are many interrelated modules involved.
Yes, the overhead of the empty array is negligible. The key issue though as mentioned in the original post is that there are some environments where specific files 1) need dynamic imports 2) cannot be modules. (e.g. browser extension content-scripts).
I can hack around to remove the
__vitePreload
using a regex and magic-string during BUILD in later rollup hooks. The challenge is that in DEV modetransform
is the last hook before Vite sends files to the browser and it runs its code to add the__vitePreload
in a post hook that runs after my plugin. There's simply no opportunity to undo that__vitePreload
in a user Vite plugin in DEV mode because of plugin ordering.~How do you feel about
"enforce": "post-post"
for user plugins? π~PS: In writing this it occurred to me that I might be able remove the
__vitePreload
by adding a service-worker that overwrites the module, though I'm not sure about the viability of that. Either way, I understand that it's challenging given the constraints of your integration with Rollup, but it still feels like something that could/should somehow be resolved in Vite rather than hacked around in user land.
i want know the work around please i am using astro BTW
The answer is right in the comment you highlighted. Write a Vite plugin that finds the __vitePreload
and removes it.
Bluwy also gives you the hint that you can work around Vite's plugin ordering by passing an object handler with order
instead of a handle function directly as a hook. See https://rollupjs.org/plugin-development/#transform
{
transform: {
order: 'post'
handler(code, id) {
// Check if `id` is my special file that shouldn't have ` __vitePreload`.
// If Vite has already added the preload by the time we're here to remove it
}
}
}
PS: If need to preserve source maps you can use magic-string
.
PPS: The workaround might not be worth the effort for a regular application. It's best if you're operating in a constrained environment like Chrome extensions that absolutely MUST not have the preload. YMMV.
Preloading seems to automatically change my js loading order, I need to disable this behavior. If anyone looks at this question, I will provide examples and scenarios https://github.com/module-federation/vite/issues/40