@rankcli/agent-runtime 0.0.14 → 0.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +77 -393
- package/dist/index.d.ts +77 -393
- package/dist/index.js +417 -6443
- package/dist/index.mjs +296 -6313
- package/package.json +6 -1
- package/scripts/build-deno.ts +0 -134
- package/src/analyzers/core-web-vitals-analyzer.test.ts +0 -236
- package/src/analyzers/core-web-vitals-analyzer.ts +0 -557
- package/src/analyzers/geo-analyzer.test.ts +0 -310
- package/src/analyzers/geo-analyzer.ts +0 -814
- package/src/analyzers/image-optimization-analyzer.test.ts +0 -145
- package/src/analyzers/image-optimization-analyzer.ts +0 -348
- package/src/analyzers/index.ts +0 -233
- package/src/analyzers/internal-linking-analyzer.test.ts +0 -141
- package/src/analyzers/internal-linking-analyzer.ts +0 -419
- package/src/analyzers/mobile-seo-analyzer.test.ts +0 -140
- package/src/analyzers/mobile-seo-analyzer.ts +0 -455
- package/src/analyzers/security-headers-analyzer.test.ts +0 -115
- package/src/analyzers/security-headers-analyzer.ts +0 -318
- package/src/analyzers/structured-data-analyzer.test.ts +0 -210
- package/src/analyzers/structured-data-analyzer.ts +0 -590
- package/src/audit/ai/analyzer.ts +0 -347
- package/src/audit/ai/index.ts +0 -29
- package/src/audit/ai/prompts/content-analysis.ts +0 -271
- package/src/audit/ai/types.ts +0 -179
- package/src/audit/checks/additional-checks.ts +0 -439
- package/src/audit/checks/ai-citation-worthiness.ts +0 -399
- package/src/audit/checks/ai-content-structure.ts +0 -325
- package/src/audit/checks/ai-readiness.ts +0 -339
- package/src/audit/checks/anchor-text.ts +0 -179
- package/src/audit/checks/answer-conciseness.ts +0 -322
- package/src/audit/checks/asset-minification.ts +0 -270
- package/src/audit/checks/bing-optimization.ts +0 -206
- package/src/audit/checks/brand-mention-optimization.ts +0 -349
- package/src/audit/checks/caching-headers.ts +0 -305
- package/src/audit/checks/canonical-advanced.ts +0 -150
- package/src/audit/checks/canonical-domain.ts +0 -196
- package/src/audit/checks/citation-quality.ts +0 -358
- package/src/audit/checks/client-rendering.ts +0 -542
- package/src/audit/checks/color-contrast.ts +0 -342
- package/src/audit/checks/content-freshness.ts +0 -170
- package/src/audit/checks/content-science.ts +0 -589
- package/src/audit/checks/conversion-elements.ts +0 -526
- package/src/audit/checks/crawlability.ts +0 -220
- package/src/audit/checks/directory-listing.ts +0 -172
- package/src/audit/checks/dom-analysis.ts +0 -191
- package/src/audit/checks/dom-size.ts +0 -246
- package/src/audit/checks/duplicate-content.ts +0 -194
- package/src/audit/checks/eeat-signals.ts +0 -990
- package/src/audit/checks/entity-seo.ts +0 -396
- package/src/audit/checks/featured-snippet.ts +0 -473
- package/src/audit/checks/freshness-signals.ts +0 -443
- package/src/audit/checks/funnel-intent.ts +0 -463
- package/src/audit/checks/hreflang.ts +0 -174
- package/src/audit/checks/html-compliance.ts +0 -302
- package/src/audit/checks/image-dimensions.ts +0 -167
- package/src/audit/checks/images.ts +0 -160
- package/src/audit/checks/indexnow.ts +0 -275
- package/src/audit/checks/interactive-tools.ts +0 -475
- package/src/audit/checks/internal-link-graph.ts +0 -436
- package/src/audit/checks/keyword-analysis.ts +0 -239
- package/src/audit/checks/keyword-cannibalization.ts +0 -385
- package/src/audit/checks/keyword-placement.ts +0 -471
- package/src/audit/checks/links.ts +0 -273
- package/src/audit/checks/llms-txt.ts +0 -224
- package/src/audit/checks/local-seo.ts +0 -296
- package/src/audit/checks/mobile.ts +0 -167
- package/src/audit/checks/modern-images.ts +0 -226
- package/src/audit/checks/navboost-signals.ts +0 -395
- package/src/audit/checks/on-page.ts +0 -209
- package/src/audit/checks/page-resources.ts +0 -285
- package/src/audit/checks/pagination.ts +0 -180
- package/src/audit/checks/performance.ts +0 -153
- package/src/audit/checks/platform-presence.ts +0 -580
- package/src/audit/checks/redirect-analysis.ts +0 -153
- package/src/audit/checks/redirect-chain.ts +0 -389
- package/src/audit/checks/resource-hints.ts +0 -420
- package/src/audit/checks/responsive-css.ts +0 -247
- package/src/audit/checks/responsive-images.ts +0 -396
- package/src/audit/checks/review-ecosystem.ts +0 -415
- package/src/audit/checks/robots-validation.ts +0 -373
- package/src/audit/checks/security-headers.ts +0 -188
- package/src/audit/checks/security.ts +0 -144
- package/src/audit/checks/serp-preview.ts +0 -251
- package/src/audit/checks/site-maturity.ts +0 -453
- package/src/audit/checks/social-meta.test.ts +0 -275
- package/src/audit/checks/social-meta.ts +0 -134
- package/src/audit/checks/soft-404.ts +0 -151
- package/src/audit/checks/structured-data.ts +0 -238
- package/src/audit/checks/tech-detection.ts +0 -496
- package/src/audit/checks/topical-clusters.ts +0 -435
- package/src/audit/checks/tracker-bloat.ts +0 -462
- package/src/audit/checks/tracking-verification.test.ts +0 -371
- package/src/audit/checks/tracking-verification.ts +0 -636
- package/src/audit/checks/url-safety.ts +0 -682
- package/src/audit/deno-entry.ts +0 -66
- package/src/audit/discovery/index.ts +0 -15
- package/src/audit/discovery/link-crawler.ts +0 -233
- package/src/audit/discovery/repo-routes.ts +0 -347
- package/src/audit/engine.ts +0 -627
- package/src/audit/fixes/index.ts +0 -209
- package/src/audit/fixes/social-meta-fixes.test.ts +0 -329
- package/src/audit/fixes/social-meta-fixes.ts +0 -463
- package/src/audit/index.ts +0 -74
- package/src/audit/runner.test.ts +0 -299
- package/src/audit/runner.ts +0 -130
- package/src/audit/types.ts +0 -1963
- package/src/content/featured-snippet.ts +0 -367
- package/src/content/generator.test.ts +0 -534
- package/src/content/generator.ts +0 -501
- package/src/content/headline.ts +0 -317
- package/src/content/index.ts +0 -62
- package/src/content/intent.ts +0 -258
- package/src/content/keyword-density.ts +0 -349
- package/src/content/readability.ts +0 -262
- package/src/executor.ts +0 -336
- package/src/fixer/framework-fixes.test.ts +0 -489
- package/src/fixer/framework-fixes.ts +0 -5287
- package/src/fixer/index.ts +0 -6
- package/src/fixer/schemas.ts +0 -971
- package/src/fixer.ts +0 -642
- package/src/frameworks/detector.test.ts +0 -248
- package/src/frameworks/detector.ts +0 -899
- package/src/frameworks/index.ts +0 -68
- package/src/frameworks/recipes/angular.yaml +0 -171
- package/src/frameworks/recipes/astro.yaml +0 -206
- package/src/frameworks/recipes/django.yaml +0 -180
- package/src/frameworks/recipes/laravel.yaml +0 -137
- package/src/frameworks/recipes/nextjs.yaml +0 -268
- package/src/frameworks/recipes/nuxt.yaml +0 -175
- package/src/frameworks/recipes/rails.yaml +0 -188
- package/src/frameworks/recipes/react.yaml +0 -202
- package/src/frameworks/recipes/sveltekit.yaml +0 -154
- package/src/frameworks/recipes/vue.yaml +0 -137
- package/src/frameworks/recipes/wordpress.yaml +0 -209
- package/src/frameworks/suggestion-engine.ts +0 -357
- package/src/geo/geo-content.test.ts +0 -305
- package/src/geo/geo-content.ts +0 -266
- package/src/geo/geo-history.test.ts +0 -473
- package/src/geo/geo-history.ts +0 -433
- package/src/geo/geo-tracker.test.ts +0 -359
- package/src/geo/geo-tracker.ts +0 -411
- package/src/geo/index.ts +0 -11
- package/src/geo/llm-citation-checker.ts +0 -188
- package/src/git/commit-helper.test.ts +0 -261
- package/src/git/commit-helper.ts +0 -329
- package/src/git/index.ts +0 -12
- package/src/git/pr-helper.test.ts +0 -284
- package/src/git/pr-helper.ts +0 -307
- package/src/index.ts +0 -76
- package/src/keywords/ai-keyword-engine.ts +0 -1062
- package/src/keywords/ai-summarizer.ts +0 -387
- package/src/keywords/ci-mode.ts +0 -555
- package/src/keywords/engine.ts +0 -359
- package/src/keywords/index.ts +0 -151
- package/src/keywords/llm-judge.ts +0 -357
- package/src/keywords/nlp-analysis.ts +0 -706
- package/src/keywords/prioritizer.ts +0 -295
- package/src/keywords/site-crawler.ts +0 -342
- package/src/keywords/sources/autocomplete.ts +0 -139
- package/src/keywords/sources/competitive-search.ts +0 -450
- package/src/keywords/sources/competitor-analysis.ts +0 -374
- package/src/keywords/sources/dataforseo.ts +0 -206
- package/src/keywords/sources/free-sources.ts +0 -294
- package/src/keywords/sources/gsc.ts +0 -123
- package/src/keywords/topic-grouping.ts +0 -327
- package/src/keywords/types.ts +0 -144
- package/src/keywords/wizard.ts +0 -457
- package/src/loader.ts +0 -40
- package/src/ranking/index.ts +0 -5
- package/src/ranking/serp-client.ts +0 -348
- package/src/ranking/tracker.ts +0 -380
- package/src/ranking/types.ts +0 -123
- package/src/reports/index.ts +0 -7
- package/src/reports/report-generator.test.ts +0 -293
- package/src/reports/report-generator.ts +0 -713
- package/src/scheduler/alerts.test.ts +0 -458
- package/src/scheduler/alerts.ts +0 -328
- package/src/scheduler/index.ts +0 -8
- package/src/scheduler/scheduled-audit.test.ts +0 -377
- package/src/scheduler/scheduled-audit.ts +0 -149
- package/src/test/integration-test.ts +0 -325
- package/src/tools/analyzer.ts +0 -373
- package/src/tools/crawl.ts +0 -293
- package/src/tools/files.ts +0 -301
- package/src/tools/h1-fixer.ts +0 -249
- package/src/tools/index.ts +0 -67
- package/src/tracking/github-action.ts +0 -326
- package/src/tracking/google-analytics.ts +0 -265
- package/src/tracking/index.ts +0 -45
- package/src/tracking/report-generator.ts +0 -386
- package/src/tracking/search-console.ts +0 -335
- package/src/types.ts +0 -148
- package/src/utils/http.ts +0 -302
- package/src/wasm-adapter.ts +0 -297
- package/src/wasm-entry.ts +0 -14
- package/tsconfig.json +0 -17
- package/tsup.wasm.config.ts +0 -26
- package/vitest.config.ts +0 -15
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
# Ruby on Rails SEO Recipe
|
|
2
|
-
# Rails is server-rendered by default, excellent for SEO
|
|
3
|
-
|
|
4
|
-
framework: rails
|
|
5
|
-
display_name: Ruby on Rails
|
|
6
|
-
category: server-rendered
|
|
7
|
-
ssr_default: true
|
|
8
|
-
|
|
9
|
-
seo_strengths:
|
|
10
|
-
- "Server-rendered HTML by default"
|
|
11
|
-
- "Turbo for fast navigation without SPA"
|
|
12
|
-
- "Strong conventions reduce mistakes"
|
|
13
|
-
- "Mature gem ecosystem"
|
|
14
|
-
|
|
15
|
-
checks:
|
|
16
|
-
- code: RAILS_NO_META_TAGS_GEM
|
|
17
|
-
severity: warning
|
|
18
|
-
title: "Not using meta-tags gem"
|
|
19
|
-
description: "The meta-tags gem provides a clean API for SEO tags."
|
|
20
|
-
howToFix: |
|
|
21
|
-
Add meta-tags to Gemfile:
|
|
22
|
-
|
|
23
|
-
```ruby
|
|
24
|
-
gem 'meta-tags'
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Run `bundle install`, then:
|
|
28
|
-
|
|
29
|
-
```ruby
|
|
30
|
-
# app/views/layouts/application.html.erb
|
|
31
|
-
<head>
|
|
32
|
-
<%= display_meta_tags site: 'Your Site' %>
|
|
33
|
-
</head>
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
```ruby
|
|
37
|
-
# In controllers or views
|
|
38
|
-
set_meta_tags title: 'Page Title',
|
|
39
|
-
description: 'Page description',
|
|
40
|
-
keywords: 'seo, rails'
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
- code: RAILS_NO_SITEMAP_GEM
|
|
44
|
-
severity: warning
|
|
45
|
-
title: "Not using sitemap_generator gem"
|
|
46
|
-
description: "sitemap_generator creates SEO-friendly sitemaps automatically."
|
|
47
|
-
howToFix: |
|
|
48
|
-
Add to Gemfile:
|
|
49
|
-
|
|
50
|
-
```ruby
|
|
51
|
-
gem 'sitemap_generator'
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Generate config:
|
|
55
|
-
```bash
|
|
56
|
-
rails sitemap:install
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
Configure config/sitemap.rb:
|
|
60
|
-
```ruby
|
|
61
|
-
SitemapGenerator::Sitemap.default_host = "https://yoursite.com"
|
|
62
|
-
|
|
63
|
-
SitemapGenerator::Sitemap.create do
|
|
64
|
-
add '/about', changefreq: 'monthly'
|
|
65
|
-
Product.find_each do |product|
|
|
66
|
-
add product_path(product), lastmod: product.updated_at
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Generate: `rails sitemap:refresh`
|
|
72
|
-
|
|
73
|
-
- code: RAILS_NO_CANONICAL
|
|
74
|
-
severity: warning
|
|
75
|
-
title: "Missing canonical URLs"
|
|
76
|
-
description: "Rails apps with multiple URLs for same content need canonicals."
|
|
77
|
-
howToFix: |
|
|
78
|
-
Add canonical tag in layout:
|
|
79
|
-
|
|
80
|
-
```erb
|
|
81
|
-
<!-- Using meta-tags gem -->
|
|
82
|
-
<%= display_meta_tags canonical: request.original_url %>
|
|
83
|
-
|
|
84
|
-
<!-- Or manually -->
|
|
85
|
-
<link rel="canonical" href="<%= request.original_url.split('?').first %>" />
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
- code: RAILS_TURBO_BREAKS_CRAWLERS
|
|
89
|
-
severity: notice
|
|
90
|
-
title: "Turbo may affect JavaScript-dependent crawlers"
|
|
91
|
-
description: "Turbo Drive updates pages via JavaScript, which some crawlers may miss."
|
|
92
|
-
howToFix: |
|
|
93
|
-
For SEO-critical pages, ensure content is in initial HTML.
|
|
94
|
-
|
|
95
|
-
For dynamic content, add data-turbo="false":
|
|
96
|
-
```erb
|
|
97
|
-
<%= link_to 'Critical Page', critical_path, data: { turbo: false } %>
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
Or disable for specific pages:
|
|
101
|
-
```erb
|
|
102
|
-
<meta name="turbo-visit-control" content="reload">
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
- code: RAILS_NO_JSON_LD
|
|
106
|
-
severity: notice
|
|
107
|
-
title: "No structured data detected"
|
|
108
|
-
description: "Add JSON-LD for rich snippets."
|
|
109
|
-
howToFix: |
|
|
110
|
-
Create a helper:
|
|
111
|
-
|
|
112
|
-
```ruby
|
|
113
|
-
# app/helpers/seo_helper.rb
|
|
114
|
-
module SeoHelper
|
|
115
|
-
def json_ld(data)
|
|
116
|
-
content_tag :script, data.to_json.html_safe,
|
|
117
|
-
type: 'application/ld+json'
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
Use in views:
|
|
123
|
-
```erb
|
|
124
|
-
<%= json_ld({
|
|
125
|
-
"@context" => "https://schema.org",
|
|
126
|
-
"@type" => "Product",
|
|
127
|
-
"name" => @product.name,
|
|
128
|
-
"description" => @product.description
|
|
129
|
-
}) %>
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
- code: RAILS_SLOW_QUERIES
|
|
133
|
-
severity: warning
|
|
134
|
-
title: "N+1 queries may slow pages"
|
|
135
|
-
description: "Slow pages hurt SEO. Use includes/eager_load."
|
|
136
|
-
howToFix: |
|
|
137
|
-
Use bullet gem to detect N+1:
|
|
138
|
-
|
|
139
|
-
```ruby
|
|
140
|
-
# Gemfile
|
|
141
|
-
gem 'bullet', group: 'development'
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
Fix with includes:
|
|
145
|
-
```ruby
|
|
146
|
-
# Before (N+1)
|
|
147
|
-
@posts = Post.all
|
|
148
|
-
@posts.each { |p| p.author.name }
|
|
149
|
-
|
|
150
|
-
# After (2 queries)
|
|
151
|
-
@posts = Post.includes(:author).all
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
- code: RAILS_NO_CACHING
|
|
155
|
-
severity: notice
|
|
156
|
-
title: "Page caching not configured"
|
|
157
|
-
description: "Rails caching can dramatically improve response times."
|
|
158
|
-
howToFix: |
|
|
159
|
-
Enable caching in production:
|
|
160
|
-
|
|
161
|
-
```ruby
|
|
162
|
-
# config/environments/production.rb
|
|
163
|
-
config.action_controller.perform_caching = true
|
|
164
|
-
config.cache_store = :redis_cache_store, { url: ENV['REDIS_URL'] }
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
Use fragment caching:
|
|
168
|
-
```erb
|
|
169
|
-
<% cache @product do %>
|
|
170
|
-
<%= render @product %>
|
|
171
|
-
<% end %>
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
performance_tips:
|
|
175
|
-
- "Use Russian doll caching for nested views"
|
|
176
|
-
- "Enable asset fingerprinting and CDN"
|
|
177
|
-
- "Use Turbo for SPA-like experience"
|
|
178
|
-
- "Profile with rack-mini-profiler"
|
|
179
|
-
- "Use Postgres for full-text search instead of LIKE"
|
|
180
|
-
|
|
181
|
-
recommended_gems:
|
|
182
|
-
seo:
|
|
183
|
-
- "meta-tags - SEO tag management"
|
|
184
|
-
- "sitemap_generator - XML sitemaps"
|
|
185
|
-
performance:
|
|
186
|
-
- "bullet - N+1 detection"
|
|
187
|
-
- "rack-mini-profiler - Performance profiling"
|
|
188
|
-
- "bootsnap - Faster boot times"
|
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
# React SEO Recipe
|
|
2
|
-
# Client-side rendering frameworks are notoriously problematic for SEO
|
|
3
|
-
|
|
4
|
-
framework: react
|
|
5
|
-
display_name: React
|
|
6
|
-
category: spa
|
|
7
|
-
ssr_default: false
|
|
8
|
-
|
|
9
|
-
seo_challenges:
|
|
10
|
-
- "Client-side rendering means empty HTML for crawlers"
|
|
11
|
-
- "Dynamic content invisible to search engines"
|
|
12
|
-
- "Slow First Contentful Paint"
|
|
13
|
-
- "No server-side meta tag generation"
|
|
14
|
-
- "JavaScript-dependent routing breaks crawlability"
|
|
15
|
-
|
|
16
|
-
checks:
|
|
17
|
-
# Critical - these will severely hurt SEO
|
|
18
|
-
- code: REACT_CSR_DETECTED
|
|
19
|
-
severity: error
|
|
20
|
-
title: "Client-side rendered React app detected"
|
|
21
|
-
description: "React apps without SSR send empty HTML to crawlers. Search engines may not index your content."
|
|
22
|
-
impact: "Critical - your content is likely invisible to Google"
|
|
23
|
-
howToFix: |
|
|
24
|
-
Option 1: Migrate to Next.js for automatic SSR/SSG
|
|
25
|
-
Option 2: Add prerendering with react-snap or prerender.io
|
|
26
|
-
Option 3: Use react-helmet-async with a prerender service
|
|
27
|
-
detection:
|
|
28
|
-
html_patterns:
|
|
29
|
-
- '<div id="root"></div>'
|
|
30
|
-
- '<div id="app"></div>'
|
|
31
|
-
missing_content: true # Body has minimal text content
|
|
32
|
-
|
|
33
|
-
- code: REACT_NO_SSR_META
|
|
34
|
-
severity: error
|
|
35
|
-
title: "Meta tags not server-rendered"
|
|
36
|
-
description: "Title and meta description are set client-side and won't be seen by crawlers."
|
|
37
|
-
impact: "Search results will show wrong or missing title/description"
|
|
38
|
-
howToFix: |
|
|
39
|
-
For Vite/CRA: Use a prerender plugin or migrate to Next.js
|
|
40
|
-
|
|
41
|
-
Quick fix with vite-plugin-ssr:
|
|
42
|
-
```tsx
|
|
43
|
-
// pages/+Head.tsx
|
|
44
|
-
export function Head() {
|
|
45
|
-
return <>
|
|
46
|
-
<title>Your Title</title>
|
|
47
|
-
<meta name="description" content="Your description" />
|
|
48
|
-
</>
|
|
49
|
-
}
|
|
50
|
-
```
|
|
51
|
-
detection:
|
|
52
|
-
title_in_js: true
|
|
53
|
-
title_not_in_html: true
|
|
54
|
-
|
|
55
|
-
- code: REACT_HYDRATION_MISMATCH
|
|
56
|
-
severity: warning
|
|
57
|
-
title: "Hydration mismatch detected"
|
|
58
|
-
description: "Server HTML differs from client render, causing flicker and potential SEO issues."
|
|
59
|
-
impact: "Can cause content to briefly disappear, confusing crawlers"
|
|
60
|
-
howToFix: |
|
|
61
|
-
Common causes:
|
|
62
|
-
1. Using Date.now() or Math.random() in render
|
|
63
|
-
2. Browser-only APIs like window.localStorage
|
|
64
|
-
3. Different data on server vs client
|
|
65
|
-
|
|
66
|
-
Fix: Use useEffect for browser-only code:
|
|
67
|
-
```tsx
|
|
68
|
-
const [mounted, setMounted] = useState(false);
|
|
69
|
-
useEffect(() => setMounted(true), []);
|
|
70
|
-
if (!mounted) return null; // or skeleton
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
# Warnings - important but not critical
|
|
74
|
-
- code: REACT_HELMET_NOT_ASYNC
|
|
75
|
-
severity: warning
|
|
76
|
-
title: "Using react-helmet instead of react-helmet-async"
|
|
77
|
-
description: "react-helmet has memory leaks and doesn't work properly with SSR."
|
|
78
|
-
howToFix: |
|
|
79
|
-
Replace react-helmet with react-helmet-async:
|
|
80
|
-
```bash
|
|
81
|
-
npm uninstall react-helmet
|
|
82
|
-
npm install react-helmet-async
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
Update imports:
|
|
86
|
-
```tsx
|
|
87
|
-
// Before
|
|
88
|
-
import { Helmet } from 'react-helmet';
|
|
89
|
-
|
|
90
|
-
// After
|
|
91
|
-
import { Helmet, HelmetProvider } from 'react-helmet-async';
|
|
92
|
-
|
|
93
|
-
// Wrap app in provider
|
|
94
|
-
<HelmetProvider>
|
|
95
|
-
<App />
|
|
96
|
-
</HelmetProvider>
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
- code: REACT_ROUTER_NO_SSR
|
|
100
|
-
severity: warning
|
|
101
|
-
title: "React Router without server-side support"
|
|
102
|
-
description: "Client-side routing breaks when crawlers access URLs directly."
|
|
103
|
-
howToFix: |
|
|
104
|
-
Ensure your server returns the same HTML for all routes.
|
|
105
|
-
|
|
106
|
-
For static hosting (Netlify, Vercel):
|
|
107
|
-
Add a redirect rule to serve index.html for all routes.
|
|
108
|
-
|
|
109
|
-
netlify.toml:
|
|
110
|
-
```toml
|
|
111
|
-
[[redirects]]
|
|
112
|
-
from = "/*"
|
|
113
|
-
to = "/index.html"
|
|
114
|
-
status = 200
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
- code: REACT_NO_PRERENDER
|
|
118
|
-
severity: warning
|
|
119
|
-
title: "No prerendering configured"
|
|
120
|
-
description: "Static pages could be prerendered for better SEO and performance."
|
|
121
|
-
howToFix: |
|
|
122
|
-
Add react-snap for build-time prerendering:
|
|
123
|
-
```bash
|
|
124
|
-
npm install react-snap
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
package.json:
|
|
128
|
-
```json
|
|
129
|
-
{
|
|
130
|
-
"scripts": {
|
|
131
|
-
"postbuild": "react-snap"
|
|
132
|
-
},
|
|
133
|
-
"reactSnap": {
|
|
134
|
-
"source": "build"
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
# Performance-related
|
|
140
|
-
- code: REACT_BUNDLE_TOO_LARGE
|
|
141
|
-
severity: warning
|
|
142
|
-
title: "React bundle too large"
|
|
143
|
-
description: "Large JavaScript bundles delay interactivity and hurt Core Web Vitals."
|
|
144
|
-
howToFix: |
|
|
145
|
-
1. Use React.lazy() for code splitting:
|
|
146
|
-
```tsx
|
|
147
|
-
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
|
|
148
|
-
|
|
149
|
-
<Suspense fallback={<Loading />}>
|
|
150
|
-
<HeavyComponent />
|
|
151
|
-
</Suspense>
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
2. Analyze bundle with source-map-explorer:
|
|
155
|
-
```bash
|
|
156
|
-
npm install source-map-explorer
|
|
157
|
-
npx source-map-explorer build/static/js/*.js
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
- code: REACT_NO_SUSPENSE
|
|
161
|
-
severity: notice
|
|
162
|
-
title: "Not using Suspense for data fetching"
|
|
163
|
-
description: "Without Suspense, content pops in causing layout shifts (CLS)."
|
|
164
|
-
howToFix: |
|
|
165
|
-
Use Suspense with a data fetching library:
|
|
166
|
-
```tsx
|
|
167
|
-
<Suspense fallback={<Skeleton />}>
|
|
168
|
-
<DataComponent />
|
|
169
|
-
</Suspense>
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
performance_tips:
|
|
173
|
-
- "Use React.memo() for expensive components"
|
|
174
|
-
- "Lazy load routes with React.lazy()"
|
|
175
|
-
- "Use useMemo/useCallback to prevent unnecessary rerenders"
|
|
176
|
-
- "Consider using Preact for smaller bundle size"
|
|
177
|
-
- "Use production builds (NODE_ENV=production)"
|
|
178
|
-
|
|
179
|
-
migration_paths:
|
|
180
|
-
nextjs:
|
|
181
|
-
effort: medium
|
|
182
|
-
benefits:
|
|
183
|
-
- "Automatic SSR/SSG"
|
|
184
|
-
- "Built-in Image optimization"
|
|
185
|
-
- "File-based routing"
|
|
186
|
-
- "API routes"
|
|
187
|
-
guide: "https://nextjs.org/docs/migrating/from-create-react-app"
|
|
188
|
-
|
|
189
|
-
remix:
|
|
190
|
-
effort: medium
|
|
191
|
-
benefits:
|
|
192
|
-
- "Nested routing with data loading"
|
|
193
|
-
- "Progressive enhancement"
|
|
194
|
-
- "Better error boundaries"
|
|
195
|
-
guide: "https://remix.run/docs/en/main/guides/migrating-react-router-app"
|
|
196
|
-
|
|
197
|
-
vite-ssr:
|
|
198
|
-
effort: low
|
|
199
|
-
benefits:
|
|
200
|
-
- "Keep existing code"
|
|
201
|
-
- "Add SSR incrementally"
|
|
202
|
-
guide: "https://vite-plugin-ssr.com/"
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
# SvelteKit SEO Recipe
|
|
2
|
-
# SvelteKit has excellent SSR and SSG support with minimal overhead
|
|
3
|
-
|
|
4
|
-
framework: sveltekit
|
|
5
|
-
display_name: SvelteKit
|
|
6
|
-
category: meta-framework
|
|
7
|
-
base_framework: svelte
|
|
8
|
-
ssr_default: true
|
|
9
|
-
|
|
10
|
-
seo_strengths:
|
|
11
|
-
- "SSR by default"
|
|
12
|
-
- "Excellent performance (small runtime)"
|
|
13
|
-
- "Built-in prerendering"
|
|
14
|
-
- "File-based routing"
|
|
15
|
-
- "Form actions for progressive enhancement"
|
|
16
|
-
|
|
17
|
-
checks:
|
|
18
|
-
- code: SVELTEKIT_NO_LOAD_FUNCTION
|
|
19
|
-
severity: warning
|
|
20
|
-
title: "Page without load function"
|
|
21
|
-
description: "Data fetching in +page.svelte bypasses SSR. Use +page.server.ts or +page.ts."
|
|
22
|
-
howToFix: |
|
|
23
|
-
Move data fetching to a load function:
|
|
24
|
-
|
|
25
|
-
```ts
|
|
26
|
-
// src/routes/products/+page.server.ts
|
|
27
|
-
export async function load({ fetch }) {
|
|
28
|
-
const products = await fetch('/api/products').then(r => r.json());
|
|
29
|
-
return { products };
|
|
30
|
-
}
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
```svelte
|
|
34
|
-
<!-- src/routes/products/+page.svelte -->
|
|
35
|
-
<script>
|
|
36
|
-
export let data;
|
|
37
|
-
</script>
|
|
38
|
-
|
|
39
|
-
{#each data.products as product}
|
|
40
|
-
<div>{product.name}</div>
|
|
41
|
-
{/each}
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
- code: SVELTEKIT_NO_LAYOUT_HEAD
|
|
45
|
-
severity: warning
|
|
46
|
-
title: "Missing svelte:head in layout"
|
|
47
|
-
description: "Common meta tags should be in a layout for consistency."
|
|
48
|
-
howToFix: |
|
|
49
|
-
Add svelte:head to your layout:
|
|
50
|
-
|
|
51
|
-
```svelte
|
|
52
|
-
<!-- src/routes/+layout.svelte -->
|
|
53
|
-
<script>
|
|
54
|
-
import { page } from '$app/stores';
|
|
55
|
-
</script>
|
|
56
|
-
|
|
57
|
-
<svelte:head>
|
|
58
|
-
<title>{$page.data.title ?? 'Your Site'}</title>
|
|
59
|
-
<meta name="description" content={$page.data.description ?? 'Default description'} />
|
|
60
|
-
<link rel="canonical" href={$page.url.href} />
|
|
61
|
-
</svelte:head>
|
|
62
|
-
|
|
63
|
-
<slot />
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
- code: SVELTEKIT_NO_PRERENDER
|
|
67
|
-
severity: notice
|
|
68
|
-
title: "Static pages not prerendered"
|
|
69
|
-
description: "Static pages should be prerendered for best performance."
|
|
70
|
-
howToFix: |
|
|
71
|
-
Add prerender to static pages:
|
|
72
|
-
|
|
73
|
-
```ts
|
|
74
|
-
// src/routes/about/+page.ts
|
|
75
|
-
export const prerender = true;
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
Or set default in svelte.config.js:
|
|
79
|
-
```js
|
|
80
|
-
kit: {
|
|
81
|
-
prerender: {
|
|
82
|
-
default: true
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
- code: SVELTEKIT_NO_TRAILING_SLASH
|
|
88
|
-
severity: notice
|
|
89
|
-
title: "Inconsistent trailing slash handling"
|
|
90
|
-
description: "Configure trailing slash to avoid duplicate content."
|
|
91
|
-
howToFix: |
|
|
92
|
-
Set in svelte.config.js:
|
|
93
|
-
|
|
94
|
-
```js
|
|
95
|
-
kit: {
|
|
96
|
-
trailingSlash: 'never' // or 'always'
|
|
97
|
-
}
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
- code: SVELTEKIT_ENHANCED_IMAGE
|
|
101
|
-
severity: notice
|
|
102
|
-
title: "Not using enhanced images"
|
|
103
|
-
description: "SvelteKit supports enhanced images with @sveltejs/enhanced-img."
|
|
104
|
-
howToFix: |
|
|
105
|
-
Install enhanced images:
|
|
106
|
-
|
|
107
|
-
```bash
|
|
108
|
-
npm install @sveltejs/enhanced-img
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
```svelte
|
|
112
|
-
<script>
|
|
113
|
-
import { Image } from '@sveltejs/enhanced-img';
|
|
114
|
-
import heroImage from '$lib/images/hero.jpg';
|
|
115
|
-
</script>
|
|
116
|
-
|
|
117
|
-
<Image src={heroImage} alt="Hero" />
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
- code: SVELTEKIT_NO_SITEMAP
|
|
121
|
-
severity: warning
|
|
122
|
-
title: "Missing sitemap"
|
|
123
|
-
description: "Use svelte-sitemap or generate manually."
|
|
124
|
-
howToFix: |
|
|
125
|
-
Option 1: Use svelte-sitemap
|
|
126
|
-
```bash
|
|
127
|
-
npm install svelte-sitemap
|
|
128
|
-
npx svelte-sitemap --domain https://yoursite.com
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
Option 2: Create src/routes/sitemap.xml/+server.ts:
|
|
132
|
-
```ts
|
|
133
|
-
export async function GET() {
|
|
134
|
-
const pages = ['/', '/about', '/products'];
|
|
135
|
-
const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
|
|
136
|
-
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
137
|
-
${pages.map(page => `
|
|
138
|
-
<url>
|
|
139
|
-
<loc>https://yoursite.com${page}</loc>
|
|
140
|
-
</url>
|
|
141
|
-
`).join('')}
|
|
142
|
-
</urlset>`;
|
|
143
|
-
return new Response(sitemap, {
|
|
144
|
-
headers: { 'Content-Type': 'application/xml' }
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
performance_tips:
|
|
150
|
-
- "Use load functions for SSR data"
|
|
151
|
-
- "Prerender static pages"
|
|
152
|
-
- "Use streaming for slow data sources"
|
|
153
|
-
- "Leverage Svelte's small runtime"
|
|
154
|
-
- "Use form actions for progressive enhancement"
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
# Vue.js SEO Recipe
|
|
2
|
-
# Similar challenges to React for client-side rendered apps
|
|
3
|
-
|
|
4
|
-
framework: vue
|
|
5
|
-
display_name: Vue.js
|
|
6
|
-
category: spa
|
|
7
|
-
ssr_default: false
|
|
8
|
-
|
|
9
|
-
seo_challenges:
|
|
10
|
-
- "Client-side rendering sends empty HTML to crawlers"
|
|
11
|
-
- "Vue Router requires proper server configuration"
|
|
12
|
-
- "Async components delay content rendering"
|
|
13
|
-
- "No built-in meta tag management"
|
|
14
|
-
|
|
15
|
-
checks:
|
|
16
|
-
- code: VUE_CSR_DETECTED
|
|
17
|
-
severity: error
|
|
18
|
-
title: "Client-side rendered Vue app detected"
|
|
19
|
-
description: "Vue apps without SSR send empty HTML to crawlers."
|
|
20
|
-
impact: "Your content may not be indexed by search engines"
|
|
21
|
-
howToFix: |
|
|
22
|
-
Option 1: Migrate to Nuxt for automatic SSR/SSG
|
|
23
|
-
Option 2: Add SSR with @vue/server-renderer
|
|
24
|
-
Option 3: Use prerendering with prerender-spa-plugin
|
|
25
|
-
|
|
26
|
-
For Nuxt migration, most Vue components work directly.
|
|
27
|
-
|
|
28
|
-
- code: VUE_NO_META_MANAGEMENT
|
|
29
|
-
severity: error
|
|
30
|
-
title: "No meta tag management library"
|
|
31
|
-
description: "Title and meta description are not dynamically managed."
|
|
32
|
-
howToFix: |
|
|
33
|
-
Install @vueuse/head or vue-meta:
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
npm install @vueuse/head
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
```ts
|
|
40
|
-
// main.ts
|
|
41
|
-
import { createHead } from '@vueuse/head';
|
|
42
|
-
const head = createHead();
|
|
43
|
-
app.use(head);
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
```vue
|
|
47
|
-
<script setup>
|
|
48
|
-
import { useHead } from '@vueuse/head';
|
|
49
|
-
|
|
50
|
-
useHead({
|
|
51
|
-
title: 'Page Title',
|
|
52
|
-
meta: [
|
|
53
|
-
{ name: 'description', content: 'Page description' },
|
|
54
|
-
],
|
|
55
|
-
});
|
|
56
|
-
</script>
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
- code: VUE_ROUTER_HISTORY_MODE
|
|
60
|
-
severity: warning
|
|
61
|
-
title: "Vue Router not in history mode"
|
|
62
|
-
description: "Hash mode (#/) creates ugly URLs and SEO issues."
|
|
63
|
-
howToFix: |
|
|
64
|
-
Use createWebHistory instead of createWebHashHistory:
|
|
65
|
-
|
|
66
|
-
```ts
|
|
67
|
-
import { createRouter, createWebHistory } from 'vue-router';
|
|
68
|
-
|
|
69
|
-
const router = createRouter({
|
|
70
|
-
history: createWebHistory(),
|
|
71
|
-
routes: [...],
|
|
72
|
-
});
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
Then configure your server to return index.html for all routes.
|
|
76
|
-
|
|
77
|
-
- code: VUE_ASYNC_COMPONENT_NO_LOADING
|
|
78
|
-
severity: warning
|
|
79
|
-
title: "Async components without loading state"
|
|
80
|
-
description: "Async components can cause CLS when they pop in."
|
|
81
|
-
howToFix: |
|
|
82
|
-
Provide a loading component:
|
|
83
|
-
|
|
84
|
-
```ts
|
|
85
|
-
import { defineAsyncComponent } from 'vue';
|
|
86
|
-
|
|
87
|
-
const AsyncComp = defineAsyncComponent({
|
|
88
|
-
loader: () => import('./HeavyComponent.vue'),
|
|
89
|
-
loadingComponent: LoadingSpinner,
|
|
90
|
-
delay: 200,
|
|
91
|
-
});
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
- code: VUE_NO_KEY_ON_LIST
|
|
95
|
-
severity: notice
|
|
96
|
-
title: "v-for without :key attribute"
|
|
97
|
-
description: "Missing keys can cause rendering issues and affect SEO crawling."
|
|
98
|
-
howToFix: |
|
|
99
|
-
Always use :key with v-for:
|
|
100
|
-
|
|
101
|
-
```vue
|
|
102
|
-
<div v-for="item in items" :key="item.id">
|
|
103
|
-
{{ item.name }}
|
|
104
|
-
</div>
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
- code: VUE_TRANSITION_CLS
|
|
108
|
-
severity: notice
|
|
109
|
-
title: "Transitions may cause layout shifts"
|
|
110
|
-
description: "CSS transitions that change element size cause CLS."
|
|
111
|
-
howToFix: |
|
|
112
|
-
Use transform instead of width/height changes:
|
|
113
|
-
|
|
114
|
-
```css
|
|
115
|
-
/* Bad - causes CLS */
|
|
116
|
-
.fade-enter-active { height: 0 to 100px; }
|
|
117
|
-
|
|
118
|
-
/* Good - no CLS */
|
|
119
|
-
.fade-enter-active { transform: scaleY(0) to scaleY(1); }
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
performance_tips:
|
|
123
|
-
- "Use Vite for faster development and optimized builds"
|
|
124
|
-
- "Lazy load routes with dynamic imports"
|
|
125
|
-
- "Use v-once for static content"
|
|
126
|
-
- "Use v-memo for expensive list items"
|
|
127
|
-
- "Consider Nuxt for SSR/SSG"
|
|
128
|
-
|
|
129
|
-
migration_paths:
|
|
130
|
-
nuxt:
|
|
131
|
-
effort: low
|
|
132
|
-
benefits:
|
|
133
|
-
- "Automatic SSR/SSG"
|
|
134
|
-
- "File-based routing"
|
|
135
|
-
- "Auto-imports"
|
|
136
|
-
- "Built-in SEO utilities"
|
|
137
|
-
guide: "https://nuxt.com/docs/migration/overview"
|