-
-
Notifications
You must be signed in to change notification settings - Fork 5.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: fix rollup plugin compatibility when getModuleInfo() is used #6811
Conversation
It the general direction of the PR is agreeable, I can probably include some automatic tests that fail without this PR and pass with it. |
I've converted this into a draft as I've noticed that there's still an example where //main.js
import fn from '@foo.js?xoption=21'
document.querySelector('#app').innerHTML = `<h1>Hello Vite: ${fn()}</h1>` //vite.config.js
const virtualId = "@foo.js"
import path from 'path';
export default {
plugins: [
{
enforce: 'pre',
async resolveId(id) {
let [prequery, query] = id.split('?');
if (prequery !== virtualId) return;
const probe = query && query.match(/xoption=([^&]+)/)
const x = probe && Number(probe[1])
if (x) {
return {id: prequery, meta: {x}}
}
},
async load(id) {
if (id === virtualId) {
const x = this.getModuleInfo(id)?.meta?.x
if (!x) throw new Error('OOPS')
return `export default function () {return 21 + ${x};}`
}
}
}
]
}
|
This new helper, unused but by the locus where it was extracted from, will help a subsequent commit fix a bug. * packages/vite/src/node/server/moduleGraph.ts (ensureEntryFromResolved): New helper. (ensureEntryFromUrl): Use new helper.
This commit improves the parity of behaviour between 'vite build' and 'vite dev' when Rollup plugins retuning non-null 'meta' properties from resolveId() hooks are used. If one takes the Rollup behaviour to be any kind of reference in these cases, this is fixing a small bug in Vite, which was in a very large part already fixed by PR vitejs#5465. Here's an explanation of the faulty behaviour: The normalizeUrl() helper calls user plugins's resolveId() twice. - Once with the URL string containing a query suffix. Here it _ignores_ the meta reply. - Again, with the URL no longer containing said suffix. Here it doesn't ignore the meta reply. It is stored in the moduleGraph node. As can be seen, if the user's plugin meta reply depends on the query suffix being passed in the imported URL, that meta reply won't be registered correctly in the module graph and is not retrievable via getModuleInfo() later on. This change makes it so that the first call doesn't ignore the meta reply. This makes Vite's dev server match Rollup's plugin-calling behaviour and fixes vitejs#6766. Fix: vitejs#6766 * packages/vite/src/node/importGlob.ts (ResolvedUrl): Import it. (transformImportGlob): Use it. * packages/vite/src/node/plugins/importAnalysis.ts (ResolvedUrl): Import it. (normalizeUrl): Use it. Always return meta. (transform): Ensure moduleGraph is correctly built.
* packages/vite/src/node/server/moduleGraph.ts (ensureEntryFromResolved): Fix.
818f2b4
to
4e1f44f
Compare
I've fixed this second problem. I've also added an automated test that fails without this PR and passes with it. Rebased the PR so that the failing test comes first, then three commits which fix the failing test. Ping @patak-dev @aleclarson, please have a look at this PR. |
Can you make a Stackblitz for each of the failing plugins? You can start from https://vite.new/react |
https://stackblitz.com/edit/vitejs-vite-rgteb2?file=vite.config.js https://stackblitz.com/edit/vitejs-vite-vf7nho?file=vite.config.js |
Friendly ping. Any news here? Should I also make a Rollup "repl.it" recipe to show that this behaves nicely on Rollup? |
In the `normalizeUrl` function of the vite:import-analysis plugin, we already have the resolvedId associated with the normalized URL, as well as resolved metadata. So let's use it instead of running `resolveId` hooks again.
c7d9195
to
f0c4e1f
Compare
@@ -259,7 +260,11 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin { | |||
// its last updated timestamp to force the browser to fetch the most | |||
// up-to-date version of this module. | |||
try { | |||
const depModule = await moduleGraph.ensureEntryFromUrl(url, ssr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did I change this? This was the final spot where the resolved metadata was getting lost, so I've reverted the change you made inside the ensureEntryFromResolved
method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, it was getting lost here because the url
, passed to it was already query-trimmed. So I agree with your change here, and yes, I think it means you can revert this change in moduleGraph.ts
.
fileMappedModules.add(mod)
+ } else if (mod.id !== resolvedId) {
+ this.idToModuleMap.set(resolvedId, mod)
+ if (meta) mod.meta = { ...mod.meta, ...meta }
}
return mo
But should you? Is not that change conceptually correct in the protocol of ensureEntryFromResolved
? Depends on what one takes to be "key" inside resolvedUrl
triplet. If you say it's only the URL, you're right to revert it. If you assume its the URL/id combination, you're not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The rationale for removing that block goes like this:
The resolution of a module URL is assumed to be idempotent, which means the resolvedId
and meta
values are not expected to change between resolveId
invocations. This assumption is made clear by the ModuleNode
object having only a single id
string, rather than an array of them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The resolution of a module URL is assumed to be idempotent, which means the resolvedId and meta values are not expected to change between resolveId invocations.
Makes sense. And you now made it so that that expectation is fulfilled where it wasn't. However, they are still three arguments to the function that will sometimes ignore the latter two if they vary. This means that even with this new somewhat cleaner helper, it could perhaps be even cleaner and take only one argument. Not for this PR though, and maybe just stating what you said in a comment/docstring would probably be more than enough.
f0c4e1f
to
d284c7d
Compare
d284c7d
to
5493c29
Compare
@@ -128,7 +128,7 @@ export class ModuleGraph { | |||
for (const imported of importedModules) { | |||
const dep = | |||
typeof imported === 'string' | |||
? await this.ensureEntryFromUrl(imported, ssr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did I change this? By this point, the imported URL is resolved, so using ensureEntryFromUrl
is overkill. It pointlessly reruns the resolveId
hook chain.
We talked about this issue with the team today. Once CI issues and conflicts are resolved, we are good to merge it 👍🏼 |
patak ***@***.***> writes:
We talked about this issue with the team today. Once CI issues and
conflicts are resolved, we are good to merge it 👍🏼
To be honest, I don't understand what's causing the CI issues. Before
Alec did his changes, the CI passed. Alex then simplified the tests.
I'm not saying Alec's changes aren't good: they look fine. But I don't
understand what broke.
I'm afraid I don't have much time in the coming days to fix it, but I
can try if noone beats me to it.
João
|
Closing in favor of #7477 |
Description
Hello. This PR addresses and fixes #6766. @aleclarson requested I present it. In the issue, I show how a Rollup plugin such as this:
... exhibits different behaviour when exercised via
vite build
andvite dev
. The two small filesmain.js
andfoo.js
can help understand the context.Additional context
This change improves the parity of behaviour between
vite build
andvite dev
when Rollup plugins retuning non-nullmeta
properties fromresolveId()
hooks are used.If one takes the Rollup behavior as reference in this case (I think it's well inside of this criteria) then this is fixing a small bug in Vite.
That bug was in a very large part already fixed by PR #5465 which @aleclarson authored. Upgrading to a recent Vite version containing the PR is my prime motivation for this PR.
Here's an explanation of the faulty behaviour:
The
normalizeUrl()
helper calls user plugins'sresolveId()
twice.Once with the URL string containing a query suffix. Here it ignores the meta reply.
Again, with the URL no longer containing said suffix. Here it doesn't ignore the meta reply. It is stored in the moduleGraph node.
As can be seen, if the user's plugin meta reply depends on the query suffix being passed in the imported URL, that meta reply won't be registered correctly in the module graph and is not retrievable via getModuleInfo() later on.
This change makes it so that the first call doesn't ignore the meta reply. This makes Vite's dev server match Rollup's plugin-calling behaviour and fixes #6766.
What is the purpose of this pull request?
Before submitting the PR, please make sure you do the following
fixes #123
).