Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
c43bcb2
feat(devtools): add SEO tab documentation with detailed features and …
abedshaaban Mar 31, 2026
ffb1f35
feat(devtools): add SEO analysis features including JSON-LD, heading …
abedshaaban Mar 31, 2026
276b2ef
refactor(devtools): unify SEO severity handling across components
abedshaaban Mar 31, 2026
7432b11
feat(devtools): enhance SEO tab with canonical and robots meta tags
abedshaaban Apr 1, 2026
e52378c
feat(devtools): introduce SEO overview section with comprehensive ana…
abedshaaban Apr 1, 2026
23e0197
feat(devtools): enhance SEO tab with new styles and structured issue …
abedshaaban Apr 1, 2026
10e295e
feat(devtools): enhance SEO tab with new styles and severity handling
abedshaaban Apr 1, 2026
13e48a8
feat(devtools): update SEO tab styles and improve health score visual…
abedshaaban Apr 1, 2026
1d51b04
feat(devtools): implement accordion-style links preview in SEO tab
abedshaaban Apr 1, 2026
38a1d32
feat(devtools): enhance JSON-LD preview with new styling and validati…
abedshaaban Apr 1, 2026
ae90128
feat(devtools): enhance SEO overview with new scoring and styling fea…
abedshaaban Apr 1, 2026
48b5788
feat(devtools): add navigation and display for heading structure and …
abedshaaban Apr 1, 2026
bad6287
feat(devtools): enhance seoSubNav styles for improved responsiveness …
abedshaaban Apr 1, 2026
d898203
feat(devtools): update package.json scripts and enhance JSON-LD and l…
abedshaaban Apr 1, 2026
ea5e33c
refactor(devtools): clean up imports and improve text handling in SEO…
abedshaaban Apr 1, 2026
566271b
refactor(devtools): simplify link classification logic in links previ…
abedshaaban Apr 2, 2026
9323504
refactor(devtools): remove unused SEO overview footnote and clean up …
abedshaaban Apr 2, 2026
63e23e2
chore(devtools): update size limit for devtools package in package.json
abedshaaban Apr 2, 2026
b923405
refactor(devtools): standardize capitalization and improve formatting…
abedshaaban Apr 2, 2026
26e639e
refactor(devtools): update section titles for clarity in SEO overview
abedshaaban Apr 2, 2026
4aee218
feat(devtools): introduce new SEO tab with live previews and structur…
abedshaaban Apr 2, 2026
ec1a257
ci: apply automated fixes
autofix-ci[bot] Apr 2, 2026
dbf8ee2
refactor(devtools): update type exports for CanonicalPageIssue and Ca…
abedshaaban Apr 2, 2026
a2bb1a3
Merge branch 'main' of https://github.com/abedshaaban/tanstack-devtools
abedshaaban Apr 2, 2026
d73db33
Merge branch 'main' into main
abedshaaban Apr 2, 2026
25ec4d7
refactor(devtools): enhance SEO tab components by removing canonical …
abedshaaban Apr 4, 2026
8ff18e7
feat(devtools): add useLocationChanges hook for location change detec…
abedshaaban Apr 4, 2026
0f4f1f9
refactor(devtools): streamline imports in links-preview component
abedshaaban Apr 4, 2026
9a785e8
fix(devtools): add canonical link to basic example HTML for improved SEO
abedshaaban Apr 4, 2026
5d5de5f
Merge branch 'main' of https://github.com/abedshaaban/tanstack-devtools
abedshaaban Apr 4, 2026
2fc42a1
fix(devtools): handle empty JSON-LD script content gracefully
abedshaaban Apr 4, 2026
a197f69
fix(devtools): remove optional chaining for textContent in SEO tab co…
abedshaaban Apr 4, 2026
9e1ab03
fix(devtools): adjust max-width values in use-styles and enhance SERP…
abedshaaban Apr 5, 2026
d7df03b
feat(devtools): integrate SEO tab with new devtools-seo package and r…
abedshaaban Apr 8, 2026
24efbee
feat(devtools): refactor SEO package integration and update build con…
abedshaaban Apr 9, 2026
c0a417d
feat(devtools): clean up imports and enhance component structure in s…
abedshaaban Apr 9, 2026
6d9b016
feat(devtools): implement SEO devtools plugin with React and Solid in…
abedshaaban Apr 9, 2026
3614539
feat(devtools): add devtools DOM filter and integrate it into SEO com…
abedshaaban Apr 9, 2026
f9f82d1
feat(icons): add emblem-light SVG for SEO components
abedshaaban Apr 9, 2026
11c25b8
feat(seo): add weight property to SeoSectionSummary and update score …
abedshaaban Apr 9, 2026
4e6a3a0
feat(seo): release first SEO devtools plugin with React support and e…
abedshaaban Apr 9, 2026
cf234dd
refactor(devtools-seo): clean up SeoDevtoolsCore export and remove un…
abedshaaban Apr 9, 2026
106758f
Merge branch 'main' into feat/seo-overview
abedshaaban Apr 9, 2026
800eb0f
ci: apply automated fixes
autofix-ci[bot] Apr 9, 2026
0a3ac72
chore(deps): update @tanstack/react-devtools to version ^0.10.2
abedshaaban Apr 9, 2026
e6ba93f
Merge branch 'feat/seo-overview' of https://github.com/abedshaaban/ta…
abedshaaban Apr 9, 2026
9cc6c8d
feat(seo): enhance SEO functionality with dynamic updates and improve…
abedshaaban Apr 9, 2026
7e2d9ae
feat(tests): implement TestClientEventBus for event handling in tests
abedshaaban Apr 10, 2026
d8cb1f7
chore: clean up event-bus-client entry in pnpm-lock.yaml
abedshaaban Apr 10, 2026
2086fc1
ci: apply automated fixes
autofix-ci[bot] Apr 10, 2026
8c53b03
feat: add SEO overview, SERP preview, and social previews sections
abedshaaban Apr 10, 2026
42a5ead
feat: add SEO styles utility using goober for dynamic theming
abedshaaban Apr 10, 2026
7b833cf
refactor: reorganize imports in SeoOverviewSection for better clarity
abedshaaban Apr 10, 2026
7f6a94d
Merge branch 'feat/seo-overview' of https://github.com/abedshaaban/ta…
abedshaaban Apr 10, 2026
4bc654e
ci: apply automated fixes
autofix-ci[bot] Apr 10, 2026
fb12efb
feat: enhance SERP title overflow checks for desktop and mobile views
abedshaaban Apr 10, 2026
daa9eb5
Merge branch 'feat/seo-overview' of https://github.com/abedshaaban/ta…
abedshaaban Apr 10, 2026
3512313
ci: apply automated fixes
autofix-ci[bot] Apr 10, 2026
5a9644a
feat: optimize JSON-LD analysis with reactive signals and memoization
abedshaaban Apr 10, 2026
88a9a25
ci: apply automated fixes
autofix-ci[bot] Apr 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/puny-games-bow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/devtools-seo': patch
---

Add the first SEO devtools plugin release with React support, live SERP and social previews, JSON-LD inspection, heading and link analysis, and an overview score. The plugin now ignores devtools-owned DOM, refreshes key sections on route changes, and uses a more balanced overall health weighting.
12 changes: 12 additions & 0 deletions examples/react/basic/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,23 @@
content="A basic example of using TanStack Devtools with React."
/>

<meta name="robots" content="index, follow" />
<link rel="canonical" href="http://localhost:3005" />
Comment on lines +36 to +37
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

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
Verify each finding against the current code and only fix it if needed.

In `@examples/react/basic/index.html` around lines 36 - 37, The canonical link in
examples/react/basic/index.html currently hard-codes "http://localhost:3005"
which will mislead crawlers; update the <link rel="canonical"> element (or
remove it) so it does not point to localhost—either replace the hard-coded URL
with the deployed example's public URL or remove the canonical tag entirely from
the fixture; ensure the change is applied to the <link rel="canonical"> element
so the example no longer signals a localhost origin.


<description
>A basic example of using TanStack Devtools with React.</description
>
</head>
<body>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "TanStack Devtools",
"url": "https://tanstack.com/devtools",
"logo": "https://tanstack.com/devtools/logo.png"
}
</script>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
Expand Down
17 changes: 8 additions & 9 deletions examples/react/basic/src/setup.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools'
import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'

import { TanStackDevtools } from '@tanstack/react-devtools'
import {
Link,
Outlet,
Expand All @@ -9,7 +7,8 @@ import {
createRoute,
createRouter,
} from '@tanstack/react-router'
import { TanStackDevtools } from '@tanstack/react-devtools'
import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'
import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools'
import { PackageJsonPanel } from './package-json-panel'

const rootRoute = createRootRoute({
Expand All @@ -28,6 +27,7 @@ const rootRoute = createRootRoute({
</>
),
})

const indexRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/',
Expand All @@ -39,22 +39,26 @@ const indexRoute = createRoute({
)
},
})

function About() {
return (
<div className="p-2">
<h3>Hello from About!</h3>
</div>
)
}

const aboutRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/about',
component: About,
})

const routeTree = rootRoute.addChildren([indexRoute, aboutRoute])
const router = createRouter({
routeTree,
})

export default function DevtoolsExample() {
return (
<>
Expand All @@ -79,11 +83,6 @@ export default function DevtoolsExample() {
name: 'Package.json',
render: () => <PackageJsonPanel />,
},

/* {
name: "The actual app",
render: <iframe style={{ width: '100%', height: '100%' }} src="http://localhost:3005" />,
} */
]}
/>
<RouterProvider router={router} />
Expand Down
47 changes: 47 additions & 0 deletions examples/react/seo/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/emblem-light.svg" />
<link rel="shortcut icon" href="/emblem-light.svg" />
<link rel="apple-touch-icon" href="/emblem-light.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />

<title>SEO Devtools Example - TanStack Devtools</title>
<meta
name="description"
content="A React example for the TanStack SEO devtools plugin."
/>
<meta property="og:title" content="SEO Devtools Example" />
<meta
property="og:description"
content="Inspect page metadata, headings, links, and structured data."
/>
<meta property="og:url" content="https://example.com/seo" />
<meta
property="og:image"
content="https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=800"
/>
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="SEO Devtools Example" />
<meta
name="twitter:description"
content="Inspect page metadata, headings, links, and structured data."
/>
<link rel="canonical" href="https://example.com/seo" />
</head>
<body>
<script id="seo-json-ld" type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebSite",
"name": "TanStack Devtools SEO Example",
"url": "https://example.com/seo"
}
</script>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>
37 changes: 37 additions & 0 deletions examples/react/seo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "@tanstack/react-devtools-seo-example",
"private": true,
"type": "module",
"scripts": {
"dev": "vite --port=3006",
"build": "vite build",
"preview": "vite preview",
"test:types": "tsc"
},
"dependencies": {
"@tanstack/devtools-seo": "workspace:^",
"@tanstack/react-devtools": "^0.10.2",
"@tanstack/react-router": "^1.132.0",
"react": "^19.2.0",
"react-dom": "^19.2.0"
},
"devDependencies": {
"@tanstack/devtools-vite": "0.6.0",
"@types/react": "^19.2.0",
"@types/react-dom": "^19.2.0",
"@vitejs/plugin-react": "^6.0.1",
"vite": "^8.0.0"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
13 changes: 13 additions & 0 deletions examples/react/seo/public/emblem-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
56 changes: 56 additions & 0 deletions examples/react/seo/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {
Link,
Outlet,
RouterProvider,
createRootRoute,
createRoute,
createRouter,
} from '@tanstack/react-router'

function AppShell() {
return (
<div>
<nav
style={{
display: 'flex',
gap: 12,
padding: '16px 24px 0',
}}
>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Outlet />
</div>
)
}

const rootRoute = createRootRoute({
component: AppShell,
})

const indexRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/',
component: () => {
return <h1>Home</h1>
},
})

const aboutRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/about',
component: () => {
return <h1>About</h1>
},
})

const routeTree = rootRoute.addChildren([indexRoute, aboutRoute])

const router = createRouter({
routeTree,
})

export default function App() {
return <RouterProvider router={router} />
}
12 changes: 12 additions & 0 deletions examples/react/seo/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { createRoot } from 'react-dom/client'
import { seoDevtoolsPlugin } from '@tanstack/devtools-seo/react'
import { TanStackDevtools } from '@tanstack/react-devtools'

import App from './App'

createRoot(document.getElementById('root')!).render(
<>
<App />
<TanStackDevtools plugins={[seoDevtoolsPlugin()]} />
</>,
)
19 changes: 19 additions & 0 deletions examples/react/seo/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "ESNext",
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "Bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src", "vite.config.ts"]
}
7 changes: 7 additions & 0 deletions examples/react/seo/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'
import { devtools } from '@tanstack/devtools-vite'

export default defineConfig({
plugins: [devtools(), react()],
})
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@
"test:eslint": "nx affected --target=test:eslint --exclude=examples/**",
"test:knip": "knip",
"test:lib": "nx affected --targets=test:lib --exclude=examples/**",
"test:lib:dev": "pnpm test:lib && nx watch --all -- pnpm test:lib",
"test:lib:dev": "pnpm test:lib && node -e \"require('node:fs').rmSync('.nx/workspace-data/d/disabled',{force:true})\" && NX_DAEMON=true nx daemon --start && NX_DAEMON=true nx watch --all -- pnpm test:lib",
"test:pr": "nx affected --targets=test:eslint,test:sherif,test:knip,test:lib,test:types,test:build,build",
"test:sherif": "sherif",
"test:types": "nx affected --targets=test:types --exclude=examples/**",
"watch": "pnpm run build:all && nx watch --all -- pnpm run build:all"
"watch": "pnpm run build:all && node -e \"require('node:fs').rmSync('.nx/workspace-data/d/disabled',{force:true})\" && NX_DAEMON=true nx daemon --start && NX_DAEMON=true nx watch --all -- pnpm run build:all"
},
"nx": {
"includedScripts": [
Expand Down
78 changes: 78 additions & 0 deletions packages/devtools-seo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
{
"name": "@tanstack/devtools-seo",
"version": "0.1.0",
"description": "SEO overview panel for TanStack Devtools",
"author": "TanStack",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/TanStack/devtools.git",
"directory": "packages/devtools-seo"
},
"homepage": "https://tanstack.com/devtools",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
},
"keywords": [
"devtools",
"seo",
"solid-js"
],
"type": "module",
"types": "dist/esm/index.d.ts",
"module": "dist/esm/index.js",
"exports": {
".": {
"import": {
"types": "./dist/esm/index.d.ts",
"default": "./dist/esm/index.js"
}
},
"./react": {
"import": {
"types": "./dist/esm/react/index.d.ts",
"default": "./dist/esm/react/index.js"
}
},
"./package.json": "./package.json"
},
"sideEffects": false,
"engines": {
"node": ">=18"
},
"files": [
"dist/",
"src"
],
"scripts": {
"clean": "premove ./build ./dist",
"lint:fix": "eslint ./src --fix",
"test:eslint": "eslint ./src",
"test:types": "tsc",
"test:build": "publint --strict",
"build": "vite build"
},
"dependencies": {
"@tanstack/devtools-ui": "workspace:*",
"@tanstack/devtools-utils": "workspace:*",
"goober": "^2.1.16",
"solid-js": "^1.9.9"
},
"peerDependencies": {
"react": ">=16.8",
"solid-js": ">=1.9.7"
},
"peerDependenciesMeta": {
"react": {
"optional": true
}
},
"devDependencies": {
"@tanstack/vite-config": "0.4.3",
"@types/react": "^19.2.0",
"react": "^19.2.0",
"vite": "^8.0.0",
"vite-plugin-solid": "^2.11.11"
}
}
7 changes: 7 additions & 0 deletions packages/devtools-seo/src/core.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/** @jsxImportSource solid-js */

import { constructCoreClass } from '@tanstack/devtools-utils/solid'

const [SeoDevtoolsCore] = constructCoreClass(() => import('./solid-panel'))

export { SeoDevtoolsCore }
Loading
Loading