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

Extension Activation on web is not fired for each local folder opened #146868

Closed
alefragnani opened this issue Apr 6, 2022 · 19 comments
Closed
Assignees
Labels
info-needed Issue requires more information from poster

Comments

@alefragnani
Copy link

Does this issue occur when all extensions are disabled?: Yes/No

  • VS Code Version: web
  • OS Version: MacOS Big Sur / MSEdge and Safari

Steps to Reproduce:

Maybe. I'm missing something, but it seems the extension activation in web extensions works a bit different compared to desktop.

I mean, in desktop, the regular activate function is fired every time a workspace is opened, respecting of course what you defined in activationEvents. which in my case, is * yet. In web (http://vscode.dev to be more precise), it seems the extension is activated only once when you navigate to http://vscode.dev. And no matter how many local folders you open, the activate function is not called anymore.

I'm using the side load approach to test my extension in web, and noticed this behavior because I use workspaceFolders while in the activation event to manage some data used on my extension. In web, this is returning undefined, even after I opened some local folder.

I didn't find any documentation nor any issue that points to this behavior, so I wonder I’m doing something wrong.

On the other hand, I could see the onDidChangeWorkspaceFolders being fired when you open a different folder, but based on API Docs, this event should be fired only when you add/remove some folder from a workspace.

Also, I’m not sure another issue is being caused by the side load approach (just like debugging extensions does) but the activationEvents is not being respected on web. I changed my extension to workspaceContains:somefile and it was activated even on an empty workspace.

Thank you

@alexdima
Copy link
Member

alexdima commented Apr 7, 2022

I mean, in desktop, the regular activate function is fired every time a workspace is opened, respecting of course what you defined in activationEvents. which in my case, is * yet. In web (http://vscode.dev/ to be more precise), it seems the extension is activated only once when you navigate to http://vscode.dev. And no matter how many local folders you open, the activate function is not called anymore.

activate() for an extension is called at most once per nodejs extension host process or per web worker extension host. You can prove this by always logging process.pid from the activate() method. On the desktop, we have a bunch of complex rules around folders and workspaces and they drive the lifecycle of the extension host process:

  • each folder gets its own fresh nodejs extension host process. If a different folder is opened, the workbench reloads and the previous nodejs extension host process gets terminated and a new one gets created.
  • workspaces can exist with 0, 1, or N folders. A workspace with 1 folder is treated differently than a folder. If a different workspace is opened, the workbench reloads and the previous nodejs extension host process gets terminated and a new one gets created.
    • there is a twist: because of a very early extension API called workspace.rootPath which hard codes the assumption that there is at most one folder opened in vscode, whenever the first folder in a workspace changes, we restart the nodejs extension host process. This was done because many extensions were using that property and they had assumptions that it never changes. @bpasero Are we any closer to removing this behavior?

I am not 100% familiar with what the workspace model is on the web and what occurs when opening a local folder. @bpasero @joaomoreno @sandy081 Does the workbench restart the web worker extension host when that happens?

I'm using the side load approach to test my extension in web, and noticed this behavior because I use workspaceFolders while in the activation event to manage some data used on my extension. In web, this is returning undefined, even after I opened some local folder.

Again I'm not 100% sure what the workbench does here @bpasero @joaomoreno @sandy081 ?

On the other hand, I could see the onDidChangeWorkspaceFolders being fired when you open a different folder, but based on API Docs, this event should be fired only when you add/remove some folder from a workspace.

Again I don't know. @sandy081 ?

Also, I’m not sure another issue is being caused by the side load approach (just like debugging extensions does) but the activationEvents is not being respected on web. I changed my extension to workspaceContains:somefile and it was activated even on an empty workspace.

What are the exact steps to reproduce this? Maybe there is some race condition that is causing all these issues where you are observing an empty workspace while in fact the workspace has a local folder. 🤷

@alexdima alexdima assigned joaomoreno and sandy081 and unassigned joyceerhl Apr 7, 2022
@alefragnani
Copy link
Author

Hi @alexdima ,

First of all, thank you for the detailed explanation. I was aware VS Code internals should be complex, but never looked at the details.

  • each folder gets its own fresh nodejs extension host process. If a different folder is opened, the workbench reloads and the previous nodejs extension host process gets terminated and a new one gets created.

I guess this point summarize my understanding of VS Code desktop. And that's exactly the behavior I think differs from the web. It seems the workbench is not reloading on the web, and as a result, the activate() function is not called for new folders.

What are the exact steps to reproduce this? Maybe there is some race condition that is causing all these issues where you are observing an empty workspace while in fact the workspace has a local folder.

A simple web extension would reproduce the issue

  1. Create a new web extension using yo code
  2. Change activationEvents to be *
  3. Add a Timestamp to the console.log call in extension.ts, provided by yo code
  4. Debug the extension, using the Run Web Extension task
  5. You will notice the activate() function being called once, no matter if Extension Development Host has a folder or not
  6. At the Extension Development Host window, open 2 different folders
  7. You will notice that activate() function being called 2x. One for each folder you opened
  8. Finish the debug
  9. Use the Side Load approach to test the extension in https://vscode.dev
  10. Run npx serve --cors -l 5000 in one terminal
  11. Run npx localtunnel -p 5000 on another terminal
  12. Copy the url provided by the localtunnel command
  13. Open a new tab in the browser and paste the url
  14. Click Click to Continue to open the localtunnel
  15. Open https://vscode.dev in a new tab in the browser
  16. Open DevTools and go to Console tab
  17. Open the Command Palette and choose Developer: Instal Web Extension...
  18. Paste the url from the localtunnel and wait for the extension to be installed
  19. You will see that activate() message log once
  20. Open 2 different local folders in https://vscode.dev
  21. You will NOT see that activate() message anymore, which means the extension wasn't activate for each folder you opened. This behavior differs from the desktop.

Thank you

@bpasero
Copy link
Member

bpasero commented Apr 8, 2022

@alexdima as for restarting extension host when the first folder changes, please chime in to #69335 which discusses that and the consequences. I think that issue is currently not seeing any progress.

Specifically there are calls to restart the extension host that are probably also going to restart the web worker (you would have to tell):

extensionService.restartExtensionHost();

That is when:

  • entering a workspace (because that changes the workspace ID and thus storage location for extensions)
  • changing the first folder (because that changes workspace.rootPath)

In web, this is returning undefined, even after I opened some local folder.

@alefragnani can you isolate this in a small sample to look at?

@bpasero
Copy link
Member

bpasero commented Apr 8, 2022

Forgot to mention: when you open vscode.dev we immediately bring you into a multi root workspace that is empty. The reason is that MR workspaces are the only ones that allow to add and remove folders without reload and that is required for accessing local files. The MR workspace is a bit special in that it uses an in-memory fs provider, but that should not have any impact here.

@joaomoreno joaomoreno removed their assignment Apr 8, 2022
@sandy081 sandy081 removed their assignment Apr 8, 2022
@alefragnani
Copy link
Author

when you open vscode.dev we immediately bring you into a multi root workspace that is empty. The reason is that MR workspaces are the only ones that allow to add and remove folders without reload and that is required for accessing local files

If it brings you an empty workspace, that's may be the reason why web and desktop is working different.

@bpasero The sample extension I've created yesterday to isolate the steps is here https://github.com/alefragnani/vscode-test-web-workspace

@bpasero
Copy link
Member

bpasero commented Apr 8, 2022

To clarify: we only force an empty MR workspace onto you for when you open vscode.dev / insiders.vscode.dev. Once you go to a remote, that changes.

In other words, in web, without a server, the empty window experience is that empty MR workspace where you can open local folders in if the browser supports that. And when you do, immediately the first folder will change and thus most likely restart the extension host.

On desktop, when you open a folder, the window reloads into that folder.

So yeah, there is a difference.

@alefragnani
Copy link
Author

alefragnani commented Apr 8, 2022

immediately the first folder will change and thus most likely restart the extension host.

Well, if the extension host was restarted every time you change the first folder, the behavior would be similar to Desktop.

I understand the reasons that motivated such differences, and when I noticed the onDidChangeWorkspaceFolders event were being fired, it was quite clear to me the multi-root approach were being used. But, as I didn't find any documentation/warning about it, neither updates on the API docs, I didn't want to start a refactoring on my extensions without proper directions.

I suggest to update the Update existing extensions to web extensions guide, to warn other extension authors about such differences.

In fact, based on recent discussions we had on that unofficial Slack channel, FAQ and Know Issues sections would be of great value for newcomers.

Thank you

@bpasero
Copy link
Member

bpasero commented Apr 8, 2022

It is documented, no?

vscode/src/vscode-dts/vscode.d.ts

Lines 11328 to 11331 in b261d64

* **Note:** this event will not fire if the first workspace folder is added, removed or changed,
* because in that case the currently executing extensions (including the one that listens to this
* event) will be terminated and restarted so that the (deprecated) `rootPath` property is updated
* to point to the first workspace folder.

@alefragnani
Copy link
Author

I'm referring to this activation difference between Desktop and Web.

Not only on this API, but also on that guide I mentioned.

@bpasero
Copy link
Member

bpasero commented Apr 8, 2022

Oh ok, to clarify: I was not talking about how activation works, I was only commenting that vscode.dev is a bit special that you are immediately put into an empty MR workspace. But a user could easily do the same on desktop when launching from the command line, so an extension has to be aware.

@alefragnani
Copy link
Author

About that, maybe I'm mistaken, but I have memories when multi-root workspaces was first released that the add/remove folders were firing the extension host restart. That's why my extension didn't have to deal with the onDidChangeWorkspaceFolder event up until now, and I could keep using the activate() function to load the all available workspaceFolders.

But yeah, testing yesterday on Desktop, I've noticed the extension needs to be updated to properly support the onDidChangeWorkspaceFolder event.

@bpasero
Copy link
Member

bpasero commented Apr 8, 2022

Maybe https://github.com/microsoft/vscode/wiki/Adopting-Multi-Root-Workspace-APIs is still helpful. It is dated by now but the API never changed.

@alefragnani
Copy link
Author

Yeah...as I said, maybe I'm mistaken. In this case, I probably am 😆

@alexdima
Copy link
Member

alexdima commented Dec 8, 2022

@alefragnani Sorry for being so slow, this issue fell through the cracks.

I'm trying the steps from here and have a few questions:

  • At steps 6 & 7, you mention that you open two different folders. What do you mean exactly? (there are many ways to open two folders, by creating a new window and then opening another folder, by using the open folder action twice in a sequence, by adding a second folder to a workspace, etc.)
  • At steps 20 & 21, there is the same ambiguity. How do you open two different folders on the web?

@alexdima alexdima added the info-needed Issue requires more information from poster label Dec 8, 2022
@alefragnani
Copy link
Author

Hi @alexdima , no problem, and sorry for the delay to answer you as well 🤝

About the steps, in both cases (steps 6 & 7 and 20 & 21), I used File / Open Folder command, opening two different local folders from my machine..

I just repro the steps and the behavior seems to the same, so you should be able to reproduce it as well.

Thank you

@alexdima
Copy link
Member

@alefragnani Thank you for your answer. I tried selecting two different local folders using the File / Open folder command:

image

When I try this, and press Open, on step 7 I see that the extension activates only once:

image

@alefragnani
Copy link
Author

alefragnani commented Dec 29, 2022

@alexdima , sorry for the ambiguity in the steps.

When I did say "opening two different local folders from my machine" I wasn't meaning a multi-select approach but instead, one folder at a time, so the second selection replaces the first.

You could read the steps as:

...
6. At the Extension Development Host window, open some random folder
6.1. You will notice that activate() function being called.
6.2 At the Extension Development Host window, open another random folder
6.3. You will notice that activate() function being called again.
7. You will notice that activate() function being called 2x. One for each folder you opened
8. Finish the debug
...

The same scenario for steps 20 & 21

Thank you

@vscodenpa
Copy link

Hey @alexdima, this issue might need further attention.

@alefragnani, you can help us out by closing this issue if the problem no longer exists, or adding more information.

@alexdima
Copy link
Member

I went through the steps again. Basically this issue is about:

  • on Desktop, each time File > Open Folder is invoked, the entire renderer reloads and the previous extension host process gets killed and a new one gets created. This means that the extension gets to deactivate() and activate() again every time the folder changes.
  • on Web, when File > Open Folder is invoked, the page doesn't reload and the extension host is kept and the extension activates only once. Extensions should react to folder changes via the event onDidChangeWorkspaceFolders

@bpasero has confirmed that this is because on the web the workbench always runs in multi-root workspace mode:

Forgot to mention: when you open vscode.dev we immediately bring you into a multi root workspace that is empty. The reason is that MR workspaces are the only ones that allow to add and remove folders without reload and that is required for accessing local files. The MR workspace is a bit special in that it uses an in-memory fs provider, but that should not have any impact here.

So IMHO everything works as designed, I don't think there is anything actionable here.

@alexdima alexdima closed this as not planned Won't fix, can't repro, duplicate, stale Mar 21, 2023
@github-actions github-actions bot locked and limited conversation to collaborators May 5, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
info-needed Issue requires more information from poster
Projects
None yet
Development

No branches or pull requests

9 participants