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

feat: add client events to import.meta.hot.on #3638

Merged
merged 14 commits into from
Jun 25, 2021

Conversation

fwouts
Copy link
Contributor

@fwouts fwouts commented Jun 2, 2021

Description

This adds an exported function setCustomErrorHandler to the @vite/client package.

Example usage:

import { setCustomErrorHandler } from "@vite/client";

setCustomErrorHandler((err: ViteError) => {
  showNotification(err.message + '\n' + err.stack);
});

This is useful when neither Vite's HMR overlay or the fallback console.error implementation are sufficient. For example, in the context of reactpreview.com, Vite is running in an iframe which needs to send the full error to the parent frame, where it's rendered appropriately (with custom styling).

Additional context

N/A


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.
  • Read the Pull Request Guidelines and follow the Commit Convention.
  • 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).
  • Ideally, include relevant tests that fail without this PR but pass with it.

@Shinigami92 Shinigami92 added the p2-nice-to-have Not breaking anything but nice to have (priority) label Jun 2, 2021
@Shinigami92
Copy link
Member

Shinigami92 commented Jun 2, 2021

idea: IMO we could try to find a better more expressive name 🤔
So it's kinda a hook if I understand correctly, so maybe something like listenViteError, addEventListener('vite:error', () => { ... }) or so?!

@fwouts
Copy link
Contributor Author

fwouts commented Jun 2, 2021

idea: IMO we could try to find a better more expressive name 🤔
So it's kinda a hook if I understand correctly, so maybe something like listenViteError, addEventListener('vite:error', () => { ... }) or so?!

Pretty much! I like that approach.

If we were to do this, then I guess we'd also want to enable listening to other events such as successful connection to the Websocket, HMR reloads, and so on. This would actually be useful for me as well, as I'm currently having to monkey-patch console.log to be notified of those.

I'll update this PR later today!

@fwouts fwouts changed the title feat: add setCustomErrorHandler to @vite/client feat: add addHMRListener and removeHMRListener to @vite/client Jun 2, 2021
@fwouts
Copy link
Contributor Author

fwouts commented Jun 2, 2021

@Shinigami92 I did something a bit simpler and added a general HMRListener. It's not as granular as adding event listeners for specific event types, but I reckon it's just as functional (you can always filter on the receiving side). It works for my use case too. Thoughts?

@Shinigami92
Copy link
Member

Sorry to inform you, but I will not have much time the next few days 🙁
@patak-js Could you take over this?

IMO: yeah could be okay this way how it's currently implemented, but using EventEmitter could be nicer and stronger in the future 🤔 🤷 I don't know 🤔

@fwouts
Copy link
Contributor Author

fwouts commented Jun 4, 2021

I've integrated @Shinigami92's suggestion from fwouts#1 and added some types + basic tests.

One thing I realised is that, because the import needs to be import { viteEventTarget } from '/@vite/client', types aren't detected properly. Would you have suggestions on how to solve this? Is there a better import statement that would also work?

@fwouts fwouts changed the title feat: add addHMRListener and removeHMRListener to @vite/client feat: add ViteEventTarget to @vite/client Jun 4, 2021
@Shinigami92
Copy link
Member

I provided just some minor improvements

Initially I thought we need to pass payload as a value, so the detail is future proof, but actually we always pass through the received payload, it also have the err already and we don't modify it 👍

I also updated the tests to confirm that the correct detail was passed

But we may need to define tests for error and connected 🤔

@fwouts It's now up to you to define the first set of which events we currently need 🙂


Beside that, I think you need to rebase the branch after you merged my second suggestions 😅
Cause it seems there are some failing unrelated tests 🤔

@Shinigami92
Copy link
Member

And sorry when I'm not responsive today anymore, real life is catching up 😄

@fwouts
Copy link
Contributor Author

fwouts commented Jun 5, 2021

Thank you! And don't worry you've been extremely responsive, much appreciated.

FYI now that #3677 is approved, this PR isn't blocking me anymore, so no rush at all 🙂

I'll look at the PR within the next day.

@Shinigami92
Copy link
Member

Hey @fwouts, in the team we discussed that there is already a import.meta.hot.on

We should rebuild this PR to use it and make it possible to use e.g.

import.meta.hot.on('vite:connected', (...) => { ... })

@fwouts
Copy link
Contributor Author

fwouts commented Jun 12, 2021

Hey @fwouts, in the team we discussed that there is already a import.meta.hot.on

We should rebuild this PR to use it and make it possible to use e.g.

import.meta.hot.on('vite:connected', (...) => { ... })

Sounds good! Makes me feel better about not having time for this PR last week :)

This event cannot be relied upon because there is a race condition between the WebSocket connection, established as soon as client.js is run, and whatever subsequent code actually invokes import.meta.hot.on()
@fwouts
Copy link
Contributor Author

fwouts commented Jun 13, 2021

@Shinigami92 This is now updated to use import.meta.hot.on. One thing I noticed is that there's a race condition between the WebSocket established in client.js and wherever you call import.meta.hot.on (since that has to come from a separate module loaded subsequently), so I decided to remove the vite:connected event for now.

Shinigami92
Shinigami92 previously approved these changes Jun 13, 2021
@Shinigami92 Shinigami92 changed the title feat: add ViteEventTarget to @vite/client feat: add client events to import.meta.hot.on Jun 13, 2021
@Shinigami92
Copy link
Member

Do you want also to extend the docs? So maybe we can list which (known) events can be listened
But on the other hand, due to we have strong types here, it's not that necessary to be explicitly
documented in the docs 🤔

@fwouts
Copy link
Contributor Author

fwouts commented Jun 17, 2021

Good suggestion. I've added documentation, I figure it's not obvious unless mentioned :)

Shinigami92
Shinigami92 previously approved these changes Jun 17, 2021
Comment on lines +71 to +72
type CustomEventName<T extends string> = (T extends `vite:${T}` ? never : T) &
(`vite:${T}` extends T ? never : T)
Copy link
Member

Choose a reason for hiding this comment

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

Mh 🤔 if custom events from plugins can also be send, should we enforce the type to start with vite: always?

@patak-js What do you think?

Otherwise I now approve this PR from my side

Copy link
Member

Choose a reason for hiding this comment

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

I don't know if I understand the question, we should enforce vite: for our events, and custom events are free to use their own naming convention.

Copy link
Member

Choose a reason for hiding this comment

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

I don't know if I understand the question, we should enforce vite: for our events, and custom events are free to use their own naming convention.

@patak-dev
Copy link
Member

Looks good! My only doubt is about naming and timing of notifications. Right now the notification happens before the vite takes care of the event.
Would we want at some point to notify after the event? In Vue, we use beforeUpdate and updated as the naming for lifecycle hooks

Should 'vite:update' be splitted into vite:beforeUpdate and vite:updated? Same for rest (except for error)
If we don't want this now, should the name already be changed to beforeUpdate to be more explicit and allow these post events in the future?

@fwouts
Copy link
Contributor Author

fwouts commented Jun 17, 2021

Great suggestion @patak-js. I've updated the event names and doc.

I tried implementing vite:updated for post-update but that wasn't as simple as I expected, since you need to wait for all modules to have been fetched and executed. There's also the question of what to do if any of them fails to load. Probably worth exploring in a separate PR!

@patak-dev patak-dev requested a review from antfu June 18, 2021 08:20
@antfu
Copy link
Member

antfu commented Jun 24, 2021

I will add this to the list and ask for Evan for the final review.

@antfu antfu merged commit de1ddd4 into vitejs:main Jun 25, 2021
aleclarson pushed a commit to aleclarson/vite that referenced this pull request Nov 8, 2021
Co-authored-by: Shinigami92 <[email protected]>
Co-authored-by: Christopher Quadflieg <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
p2-nice-to-have Not breaking anything but nice to have (priority)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants