fix(useDate): arm the useLocale sync through the plugin install path - #845
Open
sridhar-3009 wants to merge 1 commit into
Open
fix(useDate): arm the useLocale sync through the plugin install path#845sridhar-3009 wants to merge 1 commit into
sridhar-3009 wants to merge 1 commit into
Conversation
createDatePlugin constructed its date context eagerly, at createDatePlugin() call time - before app.use() runs and before any component exists. At that point instanceExists() is false, so the useLocale lookup and the reactive locale-sync watchEffect never armed; only a one-shot, non-reactive sync ran once. The documented "integration with useLocale for automatic locale sync" never actually worked through the plugin path. createDate now checks hasInjectionContext() instead of instanceExists() - inject() (which useLocale relies on) works both inside a component's setup() and inside a plugin's app.runWithContext() callback. createDatePlugin now constructs its context lazily, inside provide(), so it runs within that runWithContext() call instead of outside any Vue context - this also means installing the same plugin definition on multiple app instances gives each app its own locale/firstDayOfWeek context. Also documents (use-date FAQ) that the adapter instance itself should still be constructed fresh per request under SSR rather than shared at module scope, since per-install context isolation doesn't extend to an adapter object passed to every install. Adds SSR firstDayOfWeek coverage (Monday/Sunday/Saturday locales, explicit override, two adapters not sharing state) and a hydration test verifying the plugin path produces matching server/client output with zero mismatches.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #798
Issue 1:
useLocalesync never arms through the plugin pathcreateDatePluginbuilds its date context eagerly, atcreateDatePlugin()call time:That runs before
app.use()ever executes, so there's no active component and no active injection context.createDate()gates both theuseLocale()lookup and the reactivewatchEffectsync behindinstanceExists(), which checksgetCurrentInstance()- alwaysfalseat that point. So the documented "integration withuseLocalefor automatic locale sync" never functioned through the plugin path; only the one-shot, non-reactiveelsebranch ran, once, at plugin-factory time.Fix:
instanceExists()→hasInjectionContext().inject()(whichuseLocalerelies on) works both inside a component'ssetup()and inside a plugin'sapp.runWithContext()callback -instanceExists()only covers the former.createDatePluginnow also constructs its context lazily, insideprovide(), so construction actually happens within thatrunWithContext()call instead of outside any Vue context. As a side benefit, this also means installing the same plugin definition on multipleappinstances gives each app its ownlocale/firstDayOfWeekcontext, instead of one context object being shared and reused by every install.onScopeDisposegets Vue 3.5'sfailSilentlysecond argument, since there's no active effect scope at plugin-install time (unlike inside a component) and the watcher is meant to live for the app's lifetime anyway.Issue 2: adapter sharing under SSR
The lazy-context fix above isolates the
locale/firstDayOfWeekcontext per app install, but it can't isolate the adapter itself - that's a single object reference the caller passes viaoptions.adapter, reused by everyprovide()call for a given plugin instance. If an app follows the idiomatic-looking pattern of constructing the plugin once at module scope (export const datePlugin = createDatePlugin({ adapter: new V0DateAdapter() })) and reusing it across every SSR request, every request's locale sync still writes into that one shared adapter, and (per #796) that now affects calendar layout, not just formatting.This isn't fixable purely in
createDate/createDatePluginwithout a breaking API change (e.g. accepting an adapter factory), so per the issue's suggested scope, I added a FAQ entry to the use-date docs page spelling out the correct per-request pattern and why the module-scope one is unsafe.Test plan
devfirst: a new test mountingcreateLocalePlugin+createDatePlugintogether (the documented usage pattern, notcreateDate()called directly in a component) failed - locale stayeden-USafter switchinguseLocaletode. Passes with the fix.firstDayOfWeekcoverage the issue flagged as missing: Monday (de-DE), Sunday (en-US), Saturday (ar-EG), and an explicitfirstDayOfWeekoverride, all underIN_BROWSER=falselocale/firstDayOfWeekleaks into the other (the "two adapters not sharing state" case from the issue)index.hydration.test.ts(new) using the existinghydrate()test-utility for a realrenderToString→ client-hydrate comparison:createDatePlugin+createLocalePlugininstall, zero hydration mismatches, matching locale/firstDayOfWeekoutput between server and clientpnpm vitest run --project v0:unit→ 4708 passed, 1 skippedpnpm --filter=@vuetify/v0 typecheckandpnpm eslintclean on changed filespnpm run build:docssucceeds (docs page change)@vuetify/v0)