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: virtual messages HMR for vite #437

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

Conversation

BobbieGoede
Copy link
Member

I'm slowly learning more about HMR and have been working on something similar for nuxt-i18n nuxt-modules/i18n#3363

This is a starting point for HMR without reloading the page, so translations can be changed while app state is preserved.

This PR is incomplete:

  • It assumes the Vue instance is found on an element with #app
  • This overwrites locale messages with those exported by @intlify/unplugin-vue-i18n/messages, if users are merging other messages with those exported by the virtual bundle (e.g. merging objects during creation of the i18n instance) these will be lost on change.
  • Untested using webpack, I'm assuming it does not work the same there without additional changes.

Copy link
Member

@kazupon kazupon left a comment

Choose a reason for hiding this comment

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

Good job!
Look good too me for your draft PR.
Let's keep going!

@BobbieGoede BobbieGoede force-pushed the feat/virtual-messages-hmr branch from bd59a96 to 145a5ce Compare February 20, 2025 15:50
@kazupon kazupon added the Type: Feature Includes new features label Feb 21, 2025
@BobbieGoede BobbieGoede changed the title [DRAFT] feat: virtual messages HMR feat: virtual messages HMR for vite Feb 21, 2025
@BobbieGoede BobbieGoede marked this pull request as ready for review February 21, 2025 12:02
@BobbieGoede
Copy link
Member Author

BobbieGoede commented Feb 21, 2025

I couldn't figure out how to add support for this for webpack, so it's vite only now.

Since this functionality will overwrite all (global) messages with those from the merged virtual bundle, and since the way I retrieve the vue-i18n instance probably won't work in all projects (using #app to find vue instance), this functionality is disabled by default.

It can be enabled by passing the hmr: true option.

@BobbieGoede BobbieGoede requested a review from kazupon February 21, 2025 12:06
@kazupon
Copy link
Member

kazupon commented Feb 21, 2025

I couldn't figure out how to add support for this for webpack, so it's vite only now.

I agree, that's enough for now.

vue-i18n instance probably won't work in all projects (using #app to find vue instance), this functionality is disabled by default.

It might be a good idea to add an option to unplugin-vue-i18n that specifies the app root.
This would be a manual, allowing you to support HMR.

@BobbieGoede
Copy link
Member Author

@kazupon
I have added and option to configure the selector used appRootContainer, it defaults to '#app'.

I have also changed the HMR code so that it falls back to reloading the page if the app root instance is not found while also logging an error on the dev server.

@BobbieGoede
Copy link
Member Author

The feature is now enabled by default, since it falls back to the original behavior if it fails it should work well for most projects.

My only concern is for projects that merge the messages object at creation:

import messages from '@intlify/unplugin-vue-i18n/messages'

const i18n = createI18n({
  messages: {
    en: {
       ...messages.en,
       keyLostOnHMR: 'foo',
    },
  },
})

As any additional keys there would be lost on HMR, though I'm not sure if this is a common pattern 🤔 In such cases HMR would have to be disabled.

@kazupon
Copy link
Member

kazupon commented Feb 22, 2025

As any additional keys there would be lost on HMR, though I'm not sure if this is a common pattern 🤔 In such cases HMR would have to be disabled.

When developing, it may be a good idea to have the vue-i18n side expose an interface dedicated to HMR and work with unplugin-vue-i18n.

In the case of Vue, it seems that globalThis is exposed as a dedicated interface to support HMR for components.

https://github.com/vuejs/core/blob/604d08760ee5b01772bc33cefd89ebdca9bb1b82/packages/runtime-core/src/hmr.ts#L28-L39

I think that you can handle all messages using a similar approach for the messages (resources) of vue-i18n.

@BobbieGoede
Copy link
Member Author

When developing, it may be a good idea to have the vue-i18n side expose an interface dedicated to HMR and work with unplugin-vue-i18n.

In the case of Vue, it seems that globalThis is exposed as a dedicated interface to support HMR for components.
I think that you can handle all messages using a similar approach for the messages (resources) of vue-i18n.

I'll look into adding something like it to vue-i18n, at the very least it would make it easier to get the vue-i18n instance without needing to access the app root.

I'm not sure if this would make it possible to prevent losing the additional message keys as described in my previous comment 🤔 At least I don't see a way without additional changes.

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

Successfully merging this pull request may close these issues.

2 participants