-
-
Notifications
You must be signed in to change notification settings - Fork 66
Feat SEO Section (Overview, Heading Structure, Links & JSON LD Preview) #416
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
base: main
Are you sure you want to change the base?
Changes from all commits
c43bcb2
ffb1f35
276b2ef
7432b11
e52378c
23e0197
10e295e
13e48a8
1d51b04
38a1d32
ae90128
48b5788
bad6287
d898203
ea5e33c
566271b
9323504
63e23e2
b923405
26e639e
4aee218
ec1a257
dbf8ee2
a2bb1a3
d73db33
25ec4d7
8ff18e7
0f4f1f9
9a785e8
5d5de5f
2fc42a1
a197f69
9e1ab03
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@tanstack/devtools': patch | ||
| --- | ||
|
|
||
| Introduce a new SEO tab in devtools: live head-driven social and SERP previews, structured data (JSON-LD), heading and link analysis, plus an overview that scores and links into each section. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| import { onCleanup, onMount } from 'solid-js' | ||
|
|
||
| const LOCATION_CHANGE_EVENT = 'tanstack-devtools:locationchange' | ||
|
|
||
| type LocationChangeListener = () => void | ||
|
|
||
| const listeners = new Set<LocationChangeListener>() | ||
|
|
||
| let lastHref = '' | ||
| let teardownLocationObservation: (() => void) | undefined | ||
|
|
||
| function emitLocationChangeIfNeeded() { | ||
| const nextHref = window.location.href | ||
| if (nextHref === lastHref) return | ||
| lastHref = nextHref | ||
| listeners.forEach((listener) => listener()) | ||
| } | ||
|
|
||
| function dispatchLocationChangeEvent() { | ||
| window.dispatchEvent(new Event(LOCATION_CHANGE_EVENT)) | ||
| } | ||
|
|
||
| function observeLocationChanges() { | ||
| if (teardownLocationObservation) return | ||
|
|
||
| lastHref = window.location.href | ||
|
|
||
| const originalPushState = window.history.pushState | ||
| const originalReplaceState = window.history.replaceState | ||
|
|
||
| const handleLocationSignal = () => { | ||
| emitLocationChangeIfNeeded() | ||
| } | ||
|
|
||
| window.history.pushState = function (...args) { | ||
| originalPushState.apply(this, args) | ||
| dispatchLocationChangeEvent() | ||
| } | ||
|
|
||
| window.history.replaceState = function (...args) { | ||
| originalReplaceState.apply(this, args) | ||
| dispatchLocationChangeEvent() | ||
| } | ||
|
|
||
| window.addEventListener('popstate', handleLocationSignal) | ||
| window.addEventListener('hashchange', handleLocationSignal) | ||
| window.addEventListener(LOCATION_CHANGE_EVENT, handleLocationSignal) | ||
|
|
||
| teardownLocationObservation = () => { | ||
| window.history.pushState = originalPushState | ||
| window.history.replaceState = originalReplaceState | ||
| window.removeEventListener('popstate', handleLocationSignal) | ||
| window.removeEventListener('hashchange', handleLocationSignal) | ||
| window.removeEventListener(LOCATION_CHANGE_EVENT, handleLocationSignal) | ||
| teardownLocationObservation = undefined | ||
| } | ||
|
Comment on lines
+28
to
+56
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Only restore history methods if this hook still owns them. Lines 50-51 unconditionally put back the originals. If something else wraps 🛠️ Suggested fix- window.history.pushState = function (...args) {
+ const pushStateWrapper: History['pushState'] = function (...args) {
originalPushState.apply(this, args)
dispatchLocationChangeEvent()
}
+ window.history.pushState = pushStateWrapper
- window.history.replaceState = function (...args) {
+ const replaceStateWrapper: History['replaceState'] = function (...args) {
originalReplaceState.apply(this, args)
dispatchLocationChangeEvent()
}
+ window.history.replaceState = replaceStateWrapper
...
teardownLocationObservation = () => {
- window.history.pushState = originalPushState
- window.history.replaceState = originalReplaceState
+ if (window.history.pushState === pushStateWrapper) {
+ window.history.pushState = originalPushState
+ }
+ if (window.history.replaceState === replaceStateWrapper) {
+ window.history.replaceState = originalReplaceState
+ }
window.removeEventListener('popstate', handleLocationSignal)
window.removeEventListener('hashchange', handleLocationSignal)
window.removeEventListener(LOCATION_CHANGE_EVENT, handleLocationSignal)🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| export function useLocationChanges(onChange: () => void) { | ||
| onMount(() => { | ||
| observeLocationChanges() | ||
| listeners.add(onChange) | ||
|
|
||
| onCleanup(() => { | ||
| listeners.delete(onChange) | ||
| if (listeners.size === 0) teardownLocationObservation?.() | ||
| }) | ||
| }) | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't ship a localhost canonical URL.
Line 37 hard-codes
http://localhost:3005, so the published example will canonicalize to the wrong origin outside local dev. That gives crawlers — and this new SEO tab — a false signal. Use the deployed example URL here, or drop the canonical tag from this fixture.🤖 Prompt for AI Agents