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: resolvedUrls is null in plugin's configureServer after server restart #15450

Merged
merged 2 commits into from
Jan 10, 2024

Conversation

XiSenao
Copy link
Collaborator

@XiSenao XiSenao commented Dec 28, 2023

Description

fixes #15438
refs #14890

Additional context

#14890 PR fixed the issue of indirectly referencing the dev server instance (e.g. referencing it In the delayed execution function), which was not effective when directly referencing the dev server instance after restarting the server (e.g. partial middlewares and configureServer hook in the plugin). vite will expose the dev server instance to the configureServer hook in the plugin, which also means that the dev server instance may be used by other hooks in the plugin. Therefore, I think it is necessary to maintain consistency of the dev server instance after server restart. as for the middlewares, I don't think any additional processing is necessary at the moment, as it may result in performance loss and inconsistent behavior before and after configuration. This fix adds a layer of proxy to the dev server reference in the configureServer hook of the plugin.


What is the purpose of this pull request?

  • Bug fix
  • New Feature
  • Documentation update
  • Other

Before submitting the PR, please make sure you do the following

  • Read the Contributing Guidelines, especially the Pull Request Guidelines.
  • Check that there isn't already a PR that solves the problem the same way to avoid creating a duplicate.
  • Provide a description in this PR that addresses what the PR is solving, or reference the issue that it solves (e.g. fixes #123).
  • Update the corresponding documentation if needed.
  • Ideally, include relevant tests that fail without this PR but pass with it.

Copy link

stackblitz bot commented Dec 28, 2023

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@XiSenao XiSenao changed the title fix: resolvedUrls is null in plugin's configureServer fix: resolvedUrls is null in plugin's configureServer hook after server restart Dec 28, 2023
@XiSenao XiSenao changed the title fix: resolvedUrls is null in plugin's configureServer hook after server restart fix: resolvedUrls is null in plugin's configureServer after server restart Dec 28, 2023
@XiSenao
Copy link
Collaborator Author

XiSenao commented Jan 3, 2024

After restarting the server, does Vite not need to expose the new dev server instance to user plugins? @bluwy @sapphi-red

@bluwy
Copy link
Member

bluwy commented Jan 8, 2024

Thanks for investigating this! The indirections in server handling today took me quite some time to understand 😄 So from what I understand, the configureServer hook is referencing the old server on init, so after _setInternalServer, it's still not referencing the new server, causing the problem.

The proxy seems like the only way best way to handle this. Though at this point, maybe it's easier to have createServer() simply return a Proxy, which proxies to whichever latest server internally. And that should simplify a lot of our old/new server handling. I think I'll let @patak-dev chime in on this before deciding the best way forward.

After restarting the server, does Vite not need to expose the new dev server instance to user plugins?

It should expose the new one. It's a bug that it doesn't since #14890

@bluwy bluwy added the p3-minor-bug An edge case that only affects very specific usage (priority) label Jan 8, 2024
Copy link
Member

@patak-dev patak-dev left a comment

Choose a reason for hiding this comment

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

Thanks for the PR! Ya... this is getting trickier and trickier. I vote to merge this PR for the next minor and test it during the beta period we are just starting. And then evaluate @bluwy's idea of making createServer return a proxy for the next major. It would also be easier to explain and document how the server magical instance behaves.

@patak-dev patak-dev added this to the 5.1 milestone Jan 8, 2024
@XiSenao
Copy link
Collaborator Author

XiSenao commented Jan 8, 2024

The indirections in server handling today took me quite some time to understand 😄

oh, I am very sorry that my description has caused you trouble in understanding the meaning. In order to avoid further misunderstandings, I would like to provide a more detailed explanation of this issue.

During the server restart phase, a new dev Server will be created through the _createServer function.

let newServer = null
try {
// delay ws server listen
newServer = await _createServer(inlineConfig, { ws: false })
} catch (err: any) {

The configureServer hook will be executed within the _createServer function
for (const hook of config.getSortedPluginHooks('configureServer')) {
postHooks.push(await hook(server))
}

and at this point, the dev server instance passed to the configureServer hook can be considered as an new initialized dev server instance.
let server: ViteDevServer = {

After creating a new dev server, existing dev server instances will be reused using the Object.assign method.
// Assign new server props to existing server instance
const middlewares = server.middlewares
newServer._configServerPort = server._configServerPort
newServer._currentServerPort = server._currentServerPort
Object.assign(server, newServer)

Due to reusing the existing dev server instance, the subsequent updates to the properties are on the existing dev server instance rather than a new dev server instance.
In the #14890 PR, the _setInternalServer method is used to rebind the dev server instance inside the _createServer function, which is a good idea.
_setInternalServer(_server: ViteDevServer) {
// Rebind internal the server variable so functions reference the user
// server instance after a restart
server = _server
},

However, the configureServer hook cannot access the re-bound dev Server instance in the _setInternalServer function due to closure reasons, leading to the problem in #15438.
postHooks.push(await hook(server))

This is also what I mentioned in the description "which was not effective when directly referencing the dev server instance after restarting the server". Directly referencing the dev Server instance cannot access the server in the _setInternalServer function due to closure reasons, and that is the current problem.

The indirect reference to the dev server instance mentioned in the description refers to a situation similar to the following.

transformRequest(url, options) {
return transformRequest(url, server, options)
},

When referencing the dev server instance in the function, the function will be triggered at some point in the future. At this point, the dev server instance instance obtained is the one re-bound in the _setInternalServer method, which is the correct behavior.

Though at this point, maybe it's easier to have createServer() simply return a Proxy, which proxies to whichever latest server internally.

It may be a lack of thinking on my part, I don't know why making createServer return a proxy can change the dev server reference in the configureServer hook.

@bluwy
Copy link
Member

bluwy commented Jan 9, 2024

oh, I am very sorry that my description has caused you trouble in understanding the meaning. In order to avoid further misunderstandings, I would like to provide a more detailed explanation of this issue.

To be clear, I'm not criticising your code or explanations! 😅 I think they're good, but the code with have today (written by many people) made the whole flow hard to grasp, so that took me a while.

It may be a lack of thinking on my part, I don't know why making createServer return a proxy can change the dev server reference in the configureServer hook.

I mean that if createServer returns a proxy that only proxies API to the newer dev server. Then we can let _createServer be a lot simpler since it only needs to deal with its own let server: ViteDevServer = {... instance by itself. It doesn't need to know that it's server reference could mean a new dev server or anything. That's handled within createServer and restartServer only. Or in other words, we no longer need _setInternalServer and Object.assign. (Though this is just an idea)

Copy link
Member

@sapphi-red sapphi-red left a comment

Choose a reason for hiding this comment

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

Thanks for the PR!
I also vote to merge this PR for 5.1. If we don't get any reports about the incompatibility using Proxy, then I think we can try @bluwy's idea with more confidence.

@patak-dev patak-dev merged commit 653a48c into vitejs:main Jan 10, 2024
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
p3-minor-bug An edge case that only affects very specific usage (priority)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

resolvedUrls is null in plugin's configureServer
4 participants