`$page.url.hash` is not updated.
Describe the bug
When the URL hash value is changed using the address bar, the $page store is not updated.
Reproduction
Checked on Chrome, Firefox, and Safari. Reference 'System Info' for version numbers.
<script>
import { page } from '$app/stores';
$: console.log($page.url.hash);
</script>
<svelte:window
on:hashchange={() => {
console.log($page.url.hash, 'store');
console.log(window.location.hash, 'location')
}}
/>
<a href="#1">#1</a>
- Load the page
- Click the anchor element.
- Replace
#1with#2in the address bar. - Check the console.
<!-- Anchor is clicked. Hash is now #1 -->
#1
#1 store
#1 location
<!-- URL is updated. Hash is now #2 -->
#1 store
#2 location
Logs
No response
System Info
System:
OS: macOS 13.2.1
CPU: (8) arm64 Apple M1
Memory: 78.86 MB / 8.00 GB
Shell: 5.8.1 - /bin/zsh
Binaries:
Node: 18.14.1 - ~/.nvm/versions/node/v18.14.1/bin/node
npm: 9.3.1 - ~/.nvm/versions/node/v18.14.1/bin/npm
Browsers:
Chrome: 110.0.5481.177
Firefox: 110.0
Safari: 16.3
npmPackages:
@sveltejs/adapter-auto: ^2.0.0 => 2.0.0
@sveltejs/kit: ^1.5.0 => 1.11.0
svelte: ^3.54.0 => 3.55.1
vite: ^4.0.0 => 4.1.4
Severity
annoyance
Additional Information
No response
@Rich-Harris Just to brainstorm: one of the ways to deal with this is to update instances of the stores of page and url whenever the event hashchanges is emitted?
https://github.com/sveltejs/kit/blob/f1beb92474dafa628fda2d1b3ae26d8e9d49ff2a/packages/kit/src/runtime/client/client.js#L1693-L1704
This is where the magic should happen? 🤔
Accessing the stores via:
https://github.com/sveltejs/kit/blob/f1beb92474dafa628fda2d1b3ae26d8e9d49ff2a/packages/kit/src/runtime/client/singletons.js#L16-L21
I've seen the other pr's related to the hashchange event like #3177 but can't see through the problem yet 👀
Here's what I've been trying: the hashchange event emits an special event called HashChangeEvent which contails newURL and oldURL properties. Whenever we detect a change in the hash, we compare if there has been a change (maybe this is redundant).
But whenever i try to update the store.page inside the svelte:hashchange acts kinda weird. Like there is some kinda race or something.
Lets say we update the page with the new hash on the hashchange event:
addEventListener('hashchange', (event) => {
const new_url = new URL(event.newURL);
const old_url = new URL(event.oldURL);
// if the hashchange happened as a result of clicking on a link,
// code here...
// If the hash is the only thing that changed via user input, update the hash on the store
if (new_url.hash != old_url.hash) {
stores.page.set({ ...page, url: { ...page.url, hash: new_url.hash } });
stores.page.notify();
return;
}
And this is the code for +page.svelte
<script>
import { page } from '$app/stores';
$: console.log('Store', $page.url.hash);
</script>
<svelte:window
on:hashchange={() => {
console.log($page.url.hash, 'store');
console.log(window.location.hash, 'location');
}}
/>
If we replace #1 with #2 in the address bar, the expected output is 2. This is the scenario:
- ❗ The
console.logof $page.url.hash will print:1 - ✅
console.logofwindow.location.hashwill print:2 - ✅ the reactive
$page.url.hashoutside of thehashchangeevent will print the correct output:2.
It's like hashchange event is not aware of the store changes? just after the first update of the store it will recognize it.
Hello!
Would a change such as this be acceptable?
// This is within an else block for if (hash_navigating)
// In the occasion of the hash being updated directly through
// the browser's address bar, the page store needs to be
// updated
const url = new URL(location.href, document.baseURI);
current.url = url;
stores.page.set({ ...page, url });
stores.page.notify();
It seems to work with shallow, manual tests, but I am not sure about other implications. Furthermore, I've been unable to write a Playwright test to change the address bar and check the value's change in a div whose content is $page.url.
exclamation The
console.logof $page.url.hash will print:1
I think this may be the same bug I have run into in #10013
UPDATE: Doesn't appear so