webspresso 0.0.30 → 0.0.32

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/README.md CHANGED
@@ -12,7 +12,7 @@ A minimal, file-based SSR framework for Node.js with Nunjucks templating.
12
12
  - **Lifecycle Hooks**: Global and route-level hooks for request processing
13
13
  - **Template Helpers**: Laravel-inspired helper functions available in templates
14
14
  - **Plugin System**: Extensible architecture with version control and inter-plugin communication
15
- - **Built-in Plugins**: Development dashboard, sitemap generator, analytics integration (Google, Yandex, Bing)
15
+ - **Built-in Plugins**: Development dashboard, sitemap generator, SEO checker, analytics integration (Google, Yandex, Bing)
16
16
 
17
17
  ## Installation
18
18
 
@@ -527,6 +527,49 @@ Template helpers from analytics plugin:
527
527
 
528
528
  Individual helpers: `gtag()`, `gtm()`, `gtmNoscript()`, `yandexMetrika()`, `bingUET()`, `facebookPixel()`, `allAnalytics()`
529
529
 
530
+ **SEO Checker Plugin:**
531
+ - Client-side SEO analysis tool (inspired by django-check-seo)
532
+ - Integrated with dev toolbar
533
+ - 40+ SEO checks across 7 categories
534
+ - Real-time analysis with score calculation
535
+ - Only active in development mode
536
+
537
+ ```javascript
538
+ const { seoCheckerPlugin } = require('webspresso/plugins');
539
+
540
+ const { app } = createApp({
541
+ pagesDir: './pages',
542
+ plugins: [
543
+ seoCheckerPlugin({
544
+ settings: {
545
+ titleLength: [30, 60], // Min/max title length
546
+ descriptionLength: [50, 160], // Min/max description length
547
+ minContentWords: 300, // Minimum content words
548
+ minInternalLinks: 1, // Minimum internal links
549
+ minExternalLinks: 1, // Minimum external links
550
+ maxUrlLength: 75, // Maximum URL length
551
+ maxUrlDepth: 3 // Maximum URL depth
552
+ }
553
+ })
554
+ ]
555
+ });
556
+ ```
557
+
558
+ SEO Check Categories:
559
+ | Category | Checks |
560
+ |----------|--------|
561
+ | **Meta** | Title, Description, Canonical, Viewport, Robots, Charset, Lang |
562
+ | **Headings** | H1 existence, Single H1, Hierarchy, Non-empty headings |
563
+ | **Content** | Word count, Paragraphs, Keyword usage, Keywords early |
564
+ | **Links** | Internal links, External links, Nofollow, Anchor text |
565
+ | **Images** | Alt text, Descriptive alt, Dimensions, Lazy loading |
566
+ | **Structured** | Open Graph, Twitter Card, JSON-LD, Hreflang |
567
+ | **URL** | Length, Depth, Readability, HTTPS |
568
+
569
+ The SEO Checker panel appears as a floating widget and can be opened via:
570
+ - Dev toolbar "SEO Check" button
571
+ - Floating toggle button (🔍) in bottom-right corner
572
+
530
573
  ### Creating Custom Plugins
531
574
 
532
575
  ```javascript
@@ -682,9 +682,22 @@ function extractColumnsFromSchema(schema) {
682
682
  const shape = schema.shape;
683
683
 
684
684
  for (const [key, fieldSchema] of Object.entries(shape)) {
685
+ let schemaToCheck = fieldSchema;
686
+
687
+ // Handle SchemaBuilder instances - finalize them first to get metadata
688
+ if (fieldSchema && typeof fieldSchema._finalize === 'function') {
689
+ schemaToCheck = fieldSchema._finalize();
690
+ }
691
+
692
+ // Also check if it's a SchemaBuilder with _baseMeta (for unfinalized builders)
693
+ if (fieldSchema && fieldSchema._baseMeta) {
694
+ columns.set(key, fieldSchema._baseMeta);
695
+ continue;
696
+ }
697
+
685
698
  // Unwrap optional/nullable wrappers to get to the base schema
686
- let current = fieldSchema;
687
- while (current._def) {
699
+ let current = schemaToCheck;
700
+ while (current && current._def) {
688
701
  if (current._def.innerType) {
689
702
  current = current._def.innerType;
690
703
  } else if (current._def.schema) {
@@ -694,8 +707,8 @@ function extractColumnsFromSchema(schema) {
694
707
  }
695
708
  }
696
709
 
697
- // Check the original field schema for metadata
698
- const meta = getColumnMeta(fieldSchema) || getColumnMeta(current);
710
+ // Check the schema for metadata
711
+ const meta = getColumnMeta(schemaToCheck) || (current ? getColumnMeta(current) : null);
699
712
  if (meta) {
700
713
  columns.set(key, meta);
701
714
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webspresso",
3
- "version": "0.0.30",
3
+ "version": "0.0.32",
4
4
  "description": "Minimal, production-ready SSR framework for Node.js with file-based routing, Nunjucks templating, built-in i18n, and CLI tooling",
5
5
  "main": "index.js",
6
6
  "bin": {
package/plugins/index.js CHANGED
@@ -8,6 +8,7 @@ const analyticsPlugin = require('./analytics');
8
8
  const dashboardPlugin = require('./dashboard/index');
9
9
  const schemaExplorerPlugin = require('./schema-explorer');
10
10
  const adminPanelPlugin = require('./admin-panel');
11
+ const seoCheckerPlugin = require('./seo-checker');
11
12
 
12
13
  module.exports = {
13
14
  sitemapPlugin,
@@ -15,5 +16,6 @@ module.exports = {
15
16
  dashboardPlugin,
16
17
  schemaExplorerPlugin,
17
18
  adminPanelPlugin,
19
+ seoCheckerPlugin,
18
20
  };
19
21