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

'Could not find source file' with Vue plugin when creating new files and using VS Code's file watcher #59349

Closed
mjbvz opened this issue Jul 18, 2024 · 7 comments
Labels
External Relates to another program, environment, or user action which we cannot control.

Comments

@mjbvz
Copy link
Contributor

mjbvz commented Jul 18, 2024

πŸ”Ž Search Terms

  • Vue
  • volar
  • plugin
  • extension
  • file watcher

πŸ•— Version & Regression Information

TS 5.4.5+ using a VS Code version with vscode file watcher enabled (1.89+)

⏯ Playground Link

No response

πŸ’» Code

microsoft/vscode#214226 (comment)

  1. Install the official vue plugin for VS Code
  2. Create a new vue project (tested with https://github.com/johnsoncodehk/volar-starter)
  3. Open an existing vue file to activate the language server
  4. Now create a new .vue file and add a <script> block in it

πŸ™ Actual behavior

Intellisense doesn't work in the new block. You also see a number of request errors for this file:

 ERR <semantic> TypeScript Server Error (5.5.3)
Could not find source file: '/Users/matb/projects/sandbox/volar-starter/src/xxx.vue'.
Error: Could not find source file: '/Users/matb/projects/sandbox/volar-starter/src/xxx.vue'.
    at getValidSourceFile (/Users/matb/projects/sandbox/volar-starter/node_modules/typescript/lib/typescript.js:148819:22)
    at getEncodedSemanticClassifications3 (/Users/matb/projects/sandbox/volar-starter/node_modules/typescript/lib/typescript.js:149357:77)
    at /Users/matb/.vscode/extensions/vue.volar-2.0.26/node_modules/typescript-vue-plugin-bundle/index.js:5:3611
    at Proxy.<anonymous> (/Users/matb/.vscode/extensions/vue.volar-2.0.26/node_modules/typescript-vue-plugin-bundle/index.js:279:853)
    at IpcIOSession.getEncodedSemanticClassifications (/Users/matb/projects/sandbox/volar-starter/node_modules/typescript/lib/typescript.js:189730:41)
    at encodedSemanticClassifications-full (/Users/matb/projects/sandbox/volar-starter/node_modules/typescript/lib/typescript.js:189027:43)
    ...

πŸ™‚ Expected behavior

Script block should be treated as code

Additional information about the issue

Also doesn't happen if you set "typescript.tsserver.experimental.useVsCodeWatcher": false. However this has been on by default since the April stable release of VS Code (1.89) so it is not a new regression

@johnsoncodehk
Copy link

johnsoncodehk commented Jul 18, 2024

I did some investigation and I'm just writing it here to avoid opening a duplicate issue.

  1. Different calling timings of updateOpen and watchDirectory callbacks

    • without --canUseWatchEvents: watchDirectory is triggered before updateOpen
    • with --canUseWatchEvents: updateOpen is triggered before watchDirectory
      This will affect whether the this.openFiles.has(fileOrDirectoryPath) condition is met and the complete update branch is entered.
      A potential problem is, does the update logic assume that watchDirectory should fire before updateOpen?
  2. When calling configuredProjectForConfig.getScriptKind, Vue TS plugin is calling getScriptSnapshot to determine the script kind through the file content, causing the script to be accidentally attached to the project.
    This leads to the following judgment that the newly created file is considered to be an open attached script and has not entered a complete update.

    if (info.isAttached(project)) {
    const loadLevelToSet = Math.max(updateLevel, project.openFileWatchTriggered.get(fileOrDirectoryPath) || ProgramUpdateLevel.Update) as ProgramUpdateLevel;
    project.openFileWatchTriggered.set(fileOrDirectoryPath, loadLevelToSet);
    }

    Maybe it should be restricted to only attaching to the project when getScriptSnapshot is called at certain times.

  3. Is "don't trigger callback on open, existing files" really necessary? In theory, watchDirectory callback is only triggered when create file and delete file. In this case, we should always enter a complete update to call the plugin's getExtrenalFiles, because getExtrenalFiles will only consider FS files and not open files. Removing the early exit condition will also avoid this issue.

No need to answer me, I'm just investigating to see if there's an opportunity to fix it myself, but I don't have enough context to judge the correct fix and I will wait for the fix from TS team. πŸ™

@sheetalkamat
Copy link
Member

With vscode watchers we are getting the watch notification after the file is opened and thats exposing issue with the plugin.
The issue here is that plugin is calling getScriptSnapshot method which is supposed to be only called by language service whenever file is part of program to determine getScriptKind. This is incorrect. This should not be called anytime except when creating program and attaching files into the program as this one ensures project and LS are in sync with respect to files and scriptinfos in the program. Currently doing so fails the condition where when watch is triggered, we find that open file is already attached to the project and hence skip the update (open file does not change program root files as its consider present and avoids the over triggering updates on file save #31685). I wasnt able to get the deeper callstack into plugin to help out since its minified code and was hard to figure out whats going on but hopefully this callstack helps you:
image

PS: i was investigating this and only saw the above message after pasting my analysis. You are on track and this is issue with the plugin and needs change in plugin.

@sheetalkamat sheetalkamat added the External Relates to another program, environment, or user action which we cannot control. label Jul 18, 2024
@johnsoncodehk
Copy link

@sheetalkamat I'm not sure if there is a way to fix this problem in the Vue TS plugin. The plugin needs to get the latest file code that is not saved to the file system through getScriptSnapshot, and determine the script kind based on the file content, for example:

  • <script lang="js"> corresponds to ScriptKind.JS.
  • <script lang="ts"> corresponds to ScriptKind.TS.

If you need to debug tsserver with Vue TS plugin, the setup steps are:

This will start an environment where you can debug the Vue TS plugin and tsserver with breakpoints.

@sheetalkamat
Copy link
Member

@johnsoncodehk You dont need to call getScriptSnapshot to determine that. Instead you need to be calling project.getScriptInfo() and then call info.getScriptSnapshot() instead esp if the file is not already seen and is new.

@sheetalkamat
Copy link
Member

Also note that you would want this to fix correctly in plugin since it is really a timing thing and not a TS issue. The issue will always repro if watch notification is observed after opening the file and that can happen with or without using vscode watchers (though vscode watchers are more likely to get this because they use debouncing more than us) but its still possible. (eg #35794)

@johnsoncodehk
Copy link

@johnsoncodehk You dont need to call getScriptSnapshot to determine that. Instead you need to be calling project.getScriptInfo() and then call info.getScriptSnapshot() instead esp if the file is not already seen and is new.

Thanks for the hint, it works great.

I think closing #59354 without implementing an alternative fix is ​​not an ideal situation, getScriptSnapshot is a public API and there is no documentation (for me it just needs to be JSDoc) stating that it cannot be used casually, or there should be at least a assertion.

But anyway volarjs/volar.js#226 is sufficient for our case, please feel free to close this issue.

@typescript-bot
Copy link
Collaborator

This issue has been marked as "External" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@typescript-bot typescript-bot closed this as not planned Won't fix, can't repro, duplicate, stale Jul 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
External Relates to another program, environment, or user action which we cannot control.
Projects
None yet
4 participants