@coherent.js/seo 1.0.0-beta.2 → 1.0.0-beta.5

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.
Files changed (2) hide show
  1. package/README.md +681 -0
  2. package/package.json +3 -2
package/README.md ADDED
@@ -0,0 +1,681 @@
1
+ # @coherent.js/seo
2
+
3
+ SEO optimization tools for Coherent.js applications - Meta tags, structured data, and search engine optimization utilities.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @coherent.js/seo
9
+ # or
10
+ pnpm add @coherent.js/seo
11
+ # or
12
+ yarn add @coherent.js/seo
13
+ ```
14
+
15
+ ## Overview
16
+
17
+ The `@coherent.js/seo` package provides comprehensive SEO tools for Coherent.js applications, including:
18
+
19
+ - Dynamic meta tag management
20
+ - Open Graph and Twitter Card support
21
+ - JSON-LD structured data generation
22
+ - Sitemap generation
23
+ - Robots.txt management
24
+ - SEO-friendly URL generation
25
+ - Canonical URL support
26
+ - Internationalization SEO
27
+
28
+ ## Quick Start
29
+
30
+ ```javascript
31
+ import { createSEOHooks } from '@coherent.js/seo';
32
+
33
+ // Create SEO hooks
34
+ const seo = createSEOHooks();
35
+
36
+ // Add to your Coherent.js component
37
+ function BlogPost({ post }) {
38
+ // Set SEO metadata
39
+ seo.setMetadata({
40
+ title: `${post.title} - My Blog`,
41
+ description: post.excerpt,
42
+ keywords: post.tags,
43
+ author: post.author.name,
44
+ publishedTime: post.publishedAt,
45
+ image: post.featuredImage
46
+ });
47
+
48
+ return {
49
+ div: {
50
+ children: [
51
+ { h1: { text: post.title } },
52
+ { div: {
53
+ innerHTML: post.content,
54
+ className: 'post-content'
55
+ }}
56
+ ]
57
+ }
58
+ };
59
+ }
60
+ ```
61
+
62
+ ## Features
63
+
64
+ ### Dynamic Meta Tags
65
+
66
+ Automatically generate meta tags for search engines:
67
+
68
+ ```javascript
69
+ import { createSEOHooks } from '@coherent.js/seo';
70
+
71
+ const seo = createSEOHooks();
72
+
73
+ function ProductPage({ product }) {
74
+ seo.setMetadata({
75
+ title: product.name,
76
+ description: product.description,
77
+ keywords: [product.category, product.brand, ...product.tags],
78
+ image: product.images[0],
79
+ locale: 'en_US',
80
+ type: 'product',
81
+ url: `https://example.com/products/${product.slug}`
82
+ });
83
+
84
+ return {
85
+ div: {
86
+ children: [
87
+ { h1: { text: product.name } },
88
+ { p: { text: product.description } },
89
+ { img: { src: product.images[0], alt: product.name } }
90
+ ]
91
+ }
92
+ };
93
+ }
94
+ ```
95
+
96
+ ### Open Graph Support
97
+
98
+ Generate Open Graph meta tags for social sharing:
99
+
100
+ ```javascript
101
+ seo.setMetadata({
102
+ title: 'Awesome Product',
103
+ description: 'This product will change your life',
104
+ image: 'https://example.com/product-image.jpg',
105
+ type: 'product.item',
106
+ siteName: 'My E-commerce Store',
107
+ locale: 'en_US',
108
+
109
+ // Open Graph specific
110
+ og: {
111
+ price: {
112
+ amount: '29.99',
113
+ currency: 'USD'
114
+ },
115
+ availability: 'instock'
116
+ }
117
+ });
118
+ ```
119
+
120
+ ### Twitter Card Support
121
+
122
+ Generate Twitter Card meta tags:
123
+
124
+ ```javascript
125
+ seo.setMetadata({
126
+ title: 'Check out this awesome content!',
127
+ description: 'You won\'t believe what happens next',
128
+ image: 'https://example.com/twitter-card-image.jpg',
129
+
130
+ // Twitter specific
131
+ twitter: {
132
+ card: 'summary_large_image',
133
+ site: '@mywebsite',
134
+ creator: '@author'
135
+ }
136
+ });
137
+ ```
138
+
139
+ ### JSON-LD Structured Data
140
+
141
+ Generate structured data for rich search results:
142
+
143
+ ```javascript
144
+ import { createArticleSchema, createBreadcrumbSchema } from '@coherent.js/seo';
145
+
146
+ function BlogPost({ post, breadcrumbs }) {
147
+ // Add article structured data
148
+ seo.addSchema(createArticleSchema({
149
+ headline: post.title,
150
+ description: post.excerpt,
151
+ author: {
152
+ name: post.author.name,
153
+ url: `/authors/${post.author.slug}`
154
+ },
155
+ datePublished: post.publishedAt,
156
+ dateModified: post.updatedAt,
157
+ image: post.featuredImage,
158
+ keywords: post.tags,
159
+ articleBody: post.content
160
+ }));
161
+
162
+ // Add breadcrumb schema
163
+ seo.addSchema(createBreadcrumbSchema(breadcrumbs));
164
+
165
+ return {
166
+ div: {
167
+ children: [
168
+ { h1: { text: post.title } },
169
+ { div: { innerHTML: post.content } }
170
+ ]
171
+ }
172
+ };
173
+ }
174
+ ```
175
+
176
+ ## SEO Hooks
177
+
178
+ ### Basic Usage
179
+
180
+ ```javascript
181
+ import { createSEOHooks } from '@coherent.js/seo';
182
+
183
+ const seo = createSEOHooks({
184
+ defaultTitle: 'My Website',
185
+ defaultDescription: 'Welcome to my awesome website',
186
+ defaultImage: '/default-social-image.jpg',
187
+ siteUrl: 'https://example.com'
188
+ });
189
+
190
+ function Page({ title, description }) {
191
+ seo.setMetadata({
192
+ title: title,
193
+ description: description
194
+ });
195
+
196
+ return {
197
+ div: {
198
+ children: [
199
+ { h1: { text: title } },
200
+ { p: { text: description } }
201
+ ]
202
+ }
203
+ };
204
+ }
205
+ ```
206
+
207
+ ### Advanced Configuration
208
+
209
+ ```javascript
210
+ const seo = createSEOHooks({
211
+ // Default metadata
212
+ defaultTitle: 'My Website',
213
+ defaultDescription: 'Default description',
214
+ defaultImage: '/images/default.jpg',
215
+ siteUrl: 'https://example.com',
216
+
217
+ // SEO settings
218
+ titleTemplate: '%s | My Website', // "Page Title | My Website"
219
+ truncateTitle: 60, // Truncate titles to 60 chars
220
+ truncateDescription: 160, // Truncate descriptions to 160 chars
221
+
222
+ // Social media
223
+ social: {
224
+ twitter: '@mytwitterhandle',
225
+ facebook: 'myfacebookpage',
226
+ linkedin: 'mylinkedincompany'
227
+ },
228
+
229
+ // Default Open Graph
230
+ og: {
231
+ type: 'website',
232
+ siteName: 'My Website'
233
+ }
234
+ });
235
+ ```
236
+
237
+ ## Sitemap Generation
238
+
239
+ Generate dynamic sitemaps:
240
+
241
+ ```javascript
242
+ import { createSitemap } from '@coherent.js/seo';
243
+
244
+ const sitemap = createSitemap({
245
+ siteUrl: 'https://example.com',
246
+ changefreq: 'daily',
247
+ priority: 0.7,
248
+ lastmod: new Date()
249
+ });
250
+
251
+ // Add URLs to sitemap
252
+ sitemap.add({
253
+ url: '/',
254
+ changefreq: 'daily',
255
+ priority: 1.0
256
+ });
257
+
258
+ sitemap.add({
259
+ url: '/about',
260
+ changefreq: 'monthly',
261
+ priority: 0.8
262
+ });
263
+
264
+ sitemap.add({
265
+ url: '/blog',
266
+ changefreq: 'weekly',
267
+ priority: 0.9
268
+ });
269
+
270
+ // Generate sitemap XML
271
+ const sitemapXml = sitemap.toXML();
272
+ ```
273
+
274
+ ## Robots.txt Management
275
+
276
+ Generate robots.txt files:
277
+
278
+ ```javascript
279
+ import { createRobotsTxt } from '@coherent.js/seo';
280
+
281
+ const robots = createRobotsTxt({
282
+ userAgent: '*', // Default user agent
283
+ allow: ['/'], // Allow all paths
284
+ disallow: ['/admin', '/private'], // Disallow specific paths
285
+ sitemap: 'https://example.com/sitemap.xml',
286
+ host: 'https://example.com'
287
+ });
288
+
289
+ // Add custom rules
290
+ robots.addRule({
291
+ userAgent: 'Googlebot',
292
+ allow: ['/'],
293
+ crawlDelay: 10
294
+ });
295
+
296
+ // Generate robots.txt content
297
+ const robotsTxt = robots.toString();
298
+ ```
299
+
300
+ ## Canonical URLs
301
+
302
+ Manage canonical URLs to prevent duplicate content issues:
303
+
304
+ ```javascript
305
+ function ProductPage({ product, queryParams }) {
306
+ // Set canonical URL without tracking parameters
307
+ const canonicalUrl = `https://example.com/products/${product.slug}`;
308
+
309
+ seo.setCanonical(canonicalUrl);
310
+
311
+ // Add alternate URLs for internationalization
312
+ seo.addAlternate({
313
+ href: `https://example.com/en/products/${product.slug}`,
314
+ hreflang: 'en'
315
+ });
316
+
317
+ seo.addAlternate({
318
+ href: `https://example.com/es/products/${product.slug}`,
319
+ hreflang: 'es'
320
+ });
321
+
322
+ return {
323
+ div: {
324
+ children: [
325
+ { h1: { text: product.name } },
326
+ { p: { text: product.description } }
327
+ ]
328
+ }
329
+ };
330
+ }
331
+ ```
332
+
333
+ ## Internationalization SEO
334
+
335
+ Support for multilingual SEO:
336
+
337
+ ```javascript
338
+ function MultilingualPage({ content, language, translations }) {
339
+ // Set language
340
+ seo.setLanguage(language);
341
+
342
+ // Add alternate language versions
343
+ Object.entries(translations).forEach(([lang, url]) => {
344
+ seo.addAlternate({
345
+ href: url,
346
+ hreflang: lang
347
+ });
348
+ });
349
+
350
+ // Set direction for RTL languages
351
+ seo.setDirection(language === 'ar' || language === 'he' ? 'rtl' : 'ltr');
352
+
353
+ return {
354
+ div: {
355
+ lang: language,
356
+ children: [
357
+ { h1: { text: content.title } },
358
+ { div: { innerHTML: content.body } }
359
+ ]
360
+ }
361
+ };
362
+ }
363
+ ```
364
+
365
+ ## API Reference
366
+
367
+ ### createSEOHooks(options)
368
+
369
+ Create SEO hooks for metadata management.
370
+
371
+ **Parameters:**
372
+ - `options.defaultTitle` - Default page title
373
+ - `options.defaultDescription` - Default page description
374
+ - `options.defaultImage` - Default social image
375
+ - `options.siteUrl` - Base site URL
376
+ - `options.titleTemplate` - Title template string
377
+ - `options.truncateTitle` - Title character limit
378
+ - `options.truncateDescription` - Description character limit
379
+
380
+ **Returns:** SEO hooks object with methods
381
+
382
+ ### SEO Hooks Methods
383
+
384
+ - `seo.setMetadata(metadata)` - Set page metadata
385
+ - `seo.setTitle(title)` - Set page title
386
+ - `seo.setDescription(description)` - Set page description
387
+ - `seo.setCanonical(url)` - Set canonical URL
388
+ - `seo.addAlternate(options)` - Add alternate language URL
389
+ - `seo.addSchema(schema)` - Add JSON-LD schema
390
+ - `seo.setLanguage(lang)` - Set page language
391
+ - `seo.setDirection(dir)` - Set text direction
392
+
393
+ ### createSitemap(options)
394
+
395
+ Create a sitemap generator.
396
+
397
+ **Parameters:**
398
+ - `options.siteUrl` - Base site URL
399
+ - `options.changefreq` - Default change frequency
400
+ - `options.priority` - Default priority
401
+ - `options.lastmod` - Default last modified date
402
+
403
+ **Returns:** Sitemap generator object
404
+
405
+ ### createRobotsTxt(options)
406
+
407
+ Create a robots.txt generator.
408
+
409
+ **Parameters:**
410
+ - `options.userAgent` - Default user agent
411
+ - `options.allow` - Allowed paths
412
+ - `options.disallow` - Disallowed paths
413
+ - `options.sitemap` - Sitemap URL
414
+ - `options.host` - Host URL
415
+
416
+ **Returns:** Robots.txt generator object
417
+
418
+ ## Schema Generators
419
+
420
+ ### createArticleSchema(options)
421
+
422
+ Generate Article JSON-LD schema.
423
+
424
+ **Parameters:**
425
+ - `options.headline` - Article headline
426
+ - `options.description` - Article description
427
+ - `options.author` - Author information
428
+ - `options.datePublished` - Publication date
429
+ - `options.dateModified` - Modification date
430
+ - `options.image` - Featured image
431
+ - `options.keywords` - Article keywords
432
+ - `options.articleBody` - Article content
433
+
434
+ ### createBreadcrumbSchema(breadcrumbs)
435
+
436
+ Generate Breadcrumb JSON-LD schema.
437
+
438
+ **Parameters:**
439
+ - `breadcrumbs` - Array of breadcrumb objects with name and url
440
+
441
+ ### createProductSchema(options)
442
+
443
+ Generate Product JSON-LD schema.
444
+
445
+ **Parameters:**
446
+ - `options.name` - Product name
447
+ - `options.description` - Product description
448
+ - `options.image` - Product images
449
+ - `options.offers` - Product offers/pricing
450
+ - `options.brand` - Product brand
451
+ - `options.category` - Product category
452
+ - `options.sku` - Product SKU
453
+
454
+ ## Examples
455
+
456
+ ### Blog with Full SEO
457
+
458
+ ```javascript
459
+ import {
460
+ createSEOHooks,
461
+ createArticleSchema,
462
+ createBreadcrumbSchema
463
+ } from '@coherent.js/seo';
464
+
465
+ const seo = createSEOHooks({
466
+ siteUrl: 'https://myblog.com',
467
+ defaultTitle: 'My Blog',
468
+ titleTemplate: '%s | My Blog'
469
+ });
470
+
471
+ function BlogPost({ post }) {
472
+ // Set basic metadata
473
+ seo.setMetadata({
474
+ title: post.title,
475
+ description: post.excerpt,
476
+ image: post.featuredImage,
477
+ publishedTime: post.publishedAt,
478
+ modifiedTime: post.updatedAt,
479
+ type: 'article',
480
+ author: post.author.name,
481
+ tags: post.tags
482
+ });
483
+
484
+ // Add structured data
485
+ seo.addSchema(createArticleSchema({
486
+ headline: post.title,
487
+ description: post.excerpt,
488
+ author: {
489
+ name: post.author.name,
490
+ url: `/authors/${post.author.slug}`
491
+ },
492
+ datePublished: post.publishedAt,
493
+ dateModified: post.updatedAt,
494
+ image: post.featuredImage,
495
+ keywords: post.tags,
496
+ articleBody: post.content
497
+ }));
498
+
499
+ // Add breadcrumbs
500
+ seo.addSchema(createBreadcrumbSchema([
501
+ { name: 'Home', url: '/' },
502
+ { name: 'Blog', url: '/blog' },
503
+ { name: post.title, url: `/blog/${post.slug}` }
504
+ ]));
505
+
506
+ // Set canonical URL
507
+ seo.setCanonical(`https://myblog.com/blog/${post.slug}`);
508
+
509
+ return {
510
+ article: {
511
+ className: 'blog-post',
512
+ children: [
513
+ { h1: { text: post.title } },
514
+ {
515
+ div: {
516
+ className: 'post-meta',
517
+ children: [
518
+ { span: { text: `By ${post.author.name}` } },
519
+ { time: {
520
+ text: formatDate(post.publishedAt),
521
+ datetime: post.publishedAt
522
+ }}
523
+ ]
524
+ }
525
+ },
526
+ { div: {
527
+ className: 'post-content',
528
+ innerHTML: post.content
529
+ }}
530
+ ]
531
+ }
532
+ };
533
+ }
534
+ ```
535
+
536
+ ### E-commerce Product Page
537
+
538
+ ```javascript
539
+ import {
540
+ createSEOHooks,
541
+ createProductSchema
542
+ } from '@coherent.js/seo';
543
+
544
+ const seo = createSEOHooks({
545
+ siteUrl: 'https://mystore.com'
546
+ });
547
+
548
+ function ProductPage({ product, reviews }) {
549
+ // Basic SEO metadata
550
+ seo.setMetadata({
551
+ title: `${product.name} | My Store`,
552
+ description: product.description,
553
+ image: product.images[0],
554
+ type: 'product.item',
555
+
556
+ // Open Graph for social sharing
557
+ og: {
558
+ price: {
559
+ amount: product.price.toString(),
560
+ currency: product.currency
561
+ },
562
+ availability: product.inStock ? 'instock' : 'outofstock',
563
+ condition: 'new'
564
+ },
565
+
566
+ // Twitter Card
567
+ twitter: {
568
+ card: 'summary_large_image',
569
+ label1: 'Price',
570
+ data1: `${product.currency} ${product.price}`,
571
+ label2: 'Availability',
572
+ data2: product.inStock ? 'In Stock' : 'Out of Stock'
573
+ }
574
+ });
575
+
576
+ // Product structured data
577
+ seo.addSchema(createProductSchema({
578
+ name: product.name,
579
+ description: product.description,
580
+ image: product.images,
581
+ offers: {
582
+ price: product.price.toString(),
583
+ priceCurrency: product.currency,
584
+ availability: product.inStock ? 'InStock' : 'OutOfStock',
585
+ url: `https://mystore.com/products/${product.slug}`,
586
+ seller: {
587
+ name: 'My Store'
588
+ }
589
+ },
590
+ brand: product.brand,
591
+ category: product.category,
592
+ sku: product.sku,
593
+ gtin: product.gtin,
594
+ aggregateRating: {
595
+ ratingValue: reviews.averageRating,
596
+ reviewCount: reviews.count
597
+ }
598
+ }));
599
+
600
+ // Set canonical and alternates
601
+ seo.setCanonical(`https://mystore.com/products/${product.slug}`);
602
+
603
+ return {
604
+ div: {
605
+ className: 'product-page',
606
+ children: [
607
+ { h1: { text: product.name } },
608
+ {
609
+ div: {
610
+ className: 'product-images',
611
+ children: product.images.map(img => ({
612
+ img: { src: img, alt: product.name }
613
+ }))
614
+ }
615
+ },
616
+ { p: { text: product.description } },
617
+ { p: { text: `${product.currency} ${product.price}` } },
618
+ {
619
+ button: {
620
+ text: product.inStock ? 'Add to Cart' : 'Out of Stock',
621
+ disabled: !product.inStock
622
+ }
623
+ }
624
+ ]
625
+ }
626
+ };
627
+ }
628
+ ```
629
+
630
+ ## Best Practices
631
+
632
+ ### 1. Unique Titles and Descriptions
633
+
634
+ ```javascript
635
+ // Good: Unique for each page
636
+ seo.setMetadata({
637
+ title: `How to Master Coherent.js | Developer Guide`,
638
+ description: 'Learn advanced techniques for building high-performance Coherent.js applications with this comprehensive guide.'
639
+ });
640
+
641
+ // Avoid: Generic/duplicated content
642
+ seo.setMetadata({
643
+ title: 'Page Title',
644
+ description: 'This is a description'
645
+ });
646
+ ```
647
+
648
+ ### 2. Optimal Lengths
649
+
650
+ ```javascript
651
+ // Title: 50-60 characters
652
+ // Description: 150-160 characters
653
+ seo.setMetadata({
654
+ title: 'Coherent.js Performance Optimization Guide', // 42 chars - good
655
+ description: 'Maximize your Coherent.js application performance with these proven optimization techniques and best practices.' // 117 chars - good
656
+ });
657
+ ```
658
+
659
+ ### 3. Image Optimization
660
+
661
+ ```javascript
662
+ seo.setMetadata({
663
+ // Use appropriately sized images
664
+ image: {
665
+ url: 'https://example.com/social-image.jpg',
666
+ width: 1200,
667
+ height: 630,
668
+ alt: 'Description of image content'
669
+ }
670
+ });
671
+ ```
672
+
673
+ ## Related Packages
674
+
675
+ - [@coherent.js/core](../core/README.md) - Core framework
676
+ - [@coherent.js/i18n](../i18n/README.md) - Internationalization
677
+ - [@coherent.js/client](../client/README.md) - Client-side utilities
678
+
679
+ ## License
680
+
681
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coherent.js/seo",
3
- "version": "1.0.0-beta.2",
3
+ "version": "1.0.0-beta.5",
4
4
  "description": "SEO utilities for Coherent.js applications",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -20,7 +20,7 @@
20
20
  "author": "Coherent.js Team",
21
21
  "license": "MIT",
22
22
  "peerDependencies": {
23
- "@coherent.js/core": "1.0.0-beta.2"
23
+ "@coherent.js/core": "1.0.0-beta.5"
24
24
  },
25
25
  "repository": {
26
26
  "type": "git",
@@ -35,6 +35,7 @@
35
35
  "README.md",
36
36
  "types/"
37
37
  ],
38
+ "sideEffects": false,
38
39
  "scripts": {
39
40
  "build": "node build.mjs",
40
41
  "clean": "rm -rf dist"