Skip to content
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: data missing from moduleInfo.meta #7477

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

aleclarson
Copy link
Member

@aleclarson aleclarson commented Mar 26, 2022

Follow-up to #6811

Fixes #6766

@aleclarson aleclarson changed the title test: add plugin test 'preserves metadata from import query string' fix: data missing from moduleInfo.meta Mar 26, 2022
if (mod) {
mod.meta = { ...mod.meta, ...resolvedMeta }
} else {
moduleGraph.ensureEntryFromResolved([
Copy link
Member Author

@aleclarson aleclarson Apr 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't a viable solution, because we want to avoid adding a ModuleNode to the module graph until it's been successfully loaded.

This comment is evidence of that desire:

// ensure module in graph after successful load
const mod = await moduleGraph.ensureEntryFromUrl(url, ssr)
ensureWatchedFile(watcher, mod.file, root)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, we could always delete the ModuleNode if it fails to load.. :)

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.

Fixes vitejs#6766
@aleclarson aleclarson force-pushed the fix/meta-getModuleInfo branch from 4f2470b to a75bf4e Compare November 16, 2022 02:33
@aleclarson aleclarson force-pushed the fix/meta-getModuleInfo branch from 9ac5e60 to f63979b Compare November 16, 2022 22:17
Copy link
Member Author

@aleclarson aleclarson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did some variable name improvements on the way. LMK what you think!

@@ -261,7 +261,8 @@ export function cssPlugin(config: ResolvedConfig): Plugin {
await fileToUrl(file, config, this),
(config.server?.origin ?? '') + devBase
),
ssr
ssr,
false
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactor: The default value of isSelfAccepting is now undefined, so we need to pass an explicit false value wherever nothing was previously passed.

@@ -508,7 +508,7 @@ export async function createServer(
ws.on('vite:invalidate', async ({ path }: InvalidatePayload) => {
const mod = moduleGraph.urlToModuleMap.get(path)
if (mod && mod.isSelfAccepting && mod.lastHMRTimestamp > 0) {
const file = getShortName(mod.file!, config.root)
const file = getShortName(mod.file, config.root)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactor: Removing nullability of ModuleNode.file as discussed with @patak-dev

@@ -149,7 +152,7 @@ export class ModuleGraph {
for (const imported of importedModules) {
const dep =
typeof imported === 'string'
? await this.ensureEntryFromUrl(imported, ssr)
? this.urlToModuleMap.get(imported)!
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anything in importedModules has a module node at this point, thanks to the importAnalysis plugin.

): Promise<ModuleNode> {
const [url, resolvedId, meta] = await this.resolveUrl(rawUrl, ssr)
let mod = this.idToModuleMap.get(resolvedId)
ensureEntryFromResolved(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A new method that allows adding a module node without calling resolveUrl again.

Comment on lines +189 to +191
const unhashedId = removeDepVersionQuery(resolvedId)
if (this.idToModuleMap.has(unhashedId)) {
resolvedId = unhashedId
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have to strip the version query here and see if a module node exists without, as we can't safely remove it from inside ensureEntryFromUrl.

const optimizedDepChunkRE = /\/chunk-[A-Z\d]{8}\.js/
const optimizedDepDynamicRE = /-[A-Z\d]{8}\.js/

export function isExplicitImportRequired(url: string): boolean {
return !isJSRequest(cleanUrl(url)) && !isCSSRequest(url)
return !isJSRequest(url) && !isCSSRequest(url)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not quite sure how safe it is to change this, but it didn't break any tests (in fact, it fixed a couple tests that were broken by this PR). For example, when a .html?vue file has &lang.js at the end, we don't want to inject ?import because that leads to duplicate entries in the module graph. Let me know if this is a problematic solution.

Comment on lines +322 to +330
const isPreBundled = resolvedId.startsWith(
getDepsCacheDirPrefix(config)
)
const isFileInsideRoot =
!isPreBundled && resolvedId.startsWith(root + '/')
const isFileOutsideRoot =
!isPreBundled &&
!isFileInsideRoot &&
fs.existsSync(cleanUrl(resolvedId))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: I hoisted these conditions to improve readability.


// normalize all imports into resolved URLs
// e.g. `import 'foo'` -> `import '/@fs/.../node_modules/foo/index.js'`
if (resolved.id.startsWith(root + '/')) {
let resolvedUrl: string
if (isPreBundled || isFileOutsideRoot) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I swapped the conditions so that isPreBundled || isFileOutsideRoot is checked before isFileInsideRoot, since it was possible (even common!) for an optimized dependency file to exist within the project root.

unwrapId(url),
ssr,
canSkipImportAnalysis(url)
const depModule = moduleGraph.ensureEntryFromResolved(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced ensureEntryFromUrl call with ensureEntryFromResolved to avoid the extra resolveUrl call

contentOnly: true
})
}
}

if (isExternalUrl(normalizedUrl) || isDataUrl(normalizedUrl)) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoiding adding external URLs and data URLs to the module graph.

[no ci]
continue
}

// the module graph expects a url without timestamp query
let hmrUrl = removeTimestampQuery(stripBase(originalUrl, base))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have to remove ?t= to avoid duplicate module graph entry, but can't overwrite originalUrl since we need that to know if the URL was changed.

@bluwy
Copy link
Member

bluwy commented Sep 19, 2023

@aleclarson There's a lot of changes unrelated to the original fix which makes it hard to review. Are you able to rebase the changes and apply the fix for #6766 specifically? Or feel free to close this too and we can continue tracking progress in that issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support for moduleInfo.meta in resolveId hook still not equivalent in vite dev and vite build
2 participants