routerino 2.5.1-rc9 → 2.6.0

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
@@ -86,7 +86,7 @@ This simple configuration automatically handles routing, meta tags, and SEO opti
86
86
  - Generate static HTML files for each route with proper meta tags
87
87
  - Implement SEO best practices out-of-the-box
88
88
  - Optimize for Googlebot with pre-rendering support
89
- - Image Component: Optimized images with automatic responsive generation, WebP format, and LQIP (Low Quality Image Placeholders)
89
+ - Delegate image optimization to `vite-plugin-image-optimizer`
90
90
 
91
91
  - Enhanced User Experience
92
92
  - Support for sharing and social preview metadata
@@ -500,171 +500,6 @@ Please note that the `updateHeadTag` function requires at least one attribute to
500
500
 
501
501
  See [HeadTag props](#headtag-props) for arguments and some common tag attributes.
502
502
 
503
- ## Image Component
504
-
505
- Routerino includes an optimized Image component that automatically generates responsive images with WebP format, Low Quality Image Placeholders (LQIP), and smart loading attributes. No configuration required - it works out of the box!
506
-
507
- ### Optimization
508
-
509
- The Image component provides powerful performance optimizations with no configuration:
510
-
511
- - Responsive Images: Automatic generation of multiple sizes (480, 800, 1200, 1920px), configurable if needed
512
- - Modern Formats: WebP with fallback for maximum compatibility
513
- - LQIP: Low Quality Image Placeholders prevent layout shift during loading
514
- - Smart Loading: `lazy` by default, `eager` for hero/LCP images (auto-detected)
515
- - Performance: `fetchpriority="high"` for above-the-fold images
516
- - Accessibility: Required `alt` attributes enforced
517
-
518
- ### Usage
519
-
520
- Import the Image component:
521
-
522
- ```jsx
523
- import { Image } from "routerino/image";
524
- ```
525
-
526
- ### Image Props
527
-
528
- | Prop | Type | Required | Description |
529
- | --------------- | --------------------------- | -------- | ---------------------------------------------------------------- |
530
- | `src` | string | ✅ | Image source URL (supports jpg, png, webp, avif, gif, bmp, tiff) |
531
- | `alt` | string | ✅ | Alt text for accessibility |
532
- | `priority` | boolean | ❌ | Override lazy loading for hero/LCP images |
533
- | `widths` | number[] | ❌ | Custom responsive widths (default: [480, 800, 1200, 1920]) |
534
- | `sizes` | string | ❌ | Responsive sizes attribute (has smart default) |
535
- | `className` | string | ❌ | CSS classes (Tailwind/DaisyUI ready) |
536
- | `style` | object | ❌ | Inline styles |
537
- | `width` | number | ❌ | Explicit width attribute (CLS prevention) |
538
- | `height` | number | ❌ | Explicit height attribute (CLS prevention) |
539
- | `loading` | "lazy" \| "eager" | ❌ | Loading behavior (auto-set based on priority) |
540
- | `decoding` | "sync" \| "async" \| "auto" | ❌ | Decode timing (default: "async") |
541
- | `fetchpriority` | "high" \| "low" \| "auto" | ❌ | Fetch priority (auto-set based on priority) |
542
- | `ref` | React.Ref | ❌ | Forwarded to the underlying `<img>` element |
543
-
544
- ### Image Usage Examples
545
-
546
- #### Basic Usage
547
-
548
- ```jsx
549
- import { Image } from 'routerino/image';
550
-
551
- // Hero image - automatically gets priority
552
- <Image src="/hero.jpg" alt="Hero banner" className="w-full h-screen object-cover" />
553
-
554
- // Regular image - lazy loaded by default
555
- <Image src="/product.jpg" alt="Amazing product" className="rounded-xl shadow-lg" />
556
-
557
- // Explicit priority control
558
- <Image src="/above-fold.jpg" alt="Important image" priority={true} />
559
-
560
- // Custom responsive breakpoints
561
- <Image
562
- src="/gallery.jpg"
563
- alt="Gallery image"
564
- widths={[320, 640, 1280]}
565
- className="w-full"
566
- />
567
- ```
568
-
569
- #### Generated HTML Output
570
-
571
- The Image component generates optimized HTML during static site generation:
572
-
573
- ```html
574
- <style>
575
- .routerino-img-abc123 {
576
- position: relative;
577
- display: inline-block;
578
- aspect-ratio: 1.5; /* Prevents layout shift */
579
- }
580
- .routerino-img-abc123::before {
581
- content: "";
582
- position: absolute;
583
- top: 0;
584
- left: 0;
585
- right: 0;
586
- bottom: 0;
587
- background-image: url("data:image/png;base64,..."); /* LQIP */
588
- background-size: cover;
589
- background-position: center;
590
- filter: blur(4px);
591
- z-index: -1;
592
- }
593
- </style>
594
- <div class="routerino-img-abc123">
595
- <picture>
596
- <source
597
- srcset="
598
- /hero-480w.webp 480w,
599
- /hero-800w.webp 800w,
600
- /hero-1200w.webp 1200w,
601
- /hero-1920w.webp 1920w
602
- "
603
- type="image/webp"
604
- sizes="(max-width: 480px) 100vw, (max-width: 800px) 800px, (max-width: 1200px) 1200px, 1920px"
605
- />
606
- <img
607
- src="/hero.jpg"
608
- alt="Hero banner"
609
- srcset="
610
- /hero-480w.jpg 480w,
611
- /hero-800w.jpg 800w,
612
- /hero-1200w.jpg 1200w,
613
- /hero-1920w.jpg 1920w
614
- "
615
- sizes="(max-width: 480px) 100vw, (max-width: 800px) 800px, (max-width: 1200px) 1200px, 1920px"
616
- loading="eager"
617
- decoding="async"
618
- fetchpriority="high"
619
- class="w-full h-screen object-cover"
620
- style="opacity: 0"
621
- />
622
- </picture>
623
- </div>
624
- ```
625
-
626
- #### Smart Priority Detection
627
-
628
- The Image component automatically detects hero/LCP images:
629
-
630
- ```jsx
631
- // These automatically get priority={true}
632
- <Image src="/hero.jpg" className="hero" />
633
- <Image src="/banner.jpg" className="w-full h-screen" />
634
- <Image src="/hero-background.jpg" /> // Detected by filename
635
- ```
636
-
637
- #### Tailwind/DaisyUI Integration
638
-
639
- Works perfectly with your favorite CSS frameworks:
640
-
641
- ```jsx
642
- <Image
643
- src="/photo.jpg"
644
- alt="Beautiful photo"
645
- className="w-full max-w-md mx-auto rounded-lg shadow-xl hover:shadow-2xl transition-shadow duration-300"
646
- />
647
- ```
648
-
649
- ### Requirements
650
-
651
- - **FFmpeg**: Required for image processing during build
652
- - **Static Site Generation**: Only works with Routerino Forge SSG
653
- - **Local Images**: External URLs are not processed
654
-
655
- Install FFmpeg:
656
-
657
- ```sh
658
- # macOS
659
- brew install ffmpeg
660
-
661
- # Ubuntu/Debian
662
- sudo apt install ffmpeg
663
-
664
- # Windows (via Chocolatey)
665
- choco install ffmpeg
666
- ```
667
-
668
503
  ## TypeScript Support
669
504
 
670
505
  Routerino includes TypeScript definitions out of the box. The types are automatically available when you import Routerino.
@@ -903,6 +738,37 @@ These files are generated automatically when you build with the Routerino Forge
903
738
  ✓ Generated 42 static pages + 404.html
904
739
  ```
905
740
 
741
+ ## Image Optimization
742
+
743
+ Routerino delegates image optimization to [`vite-plugin-image-optimizer`](https://github.com/FatehAK/vite-plugin-image-optimizer). Install it and add it to your Vite config **before** `routerinoForge`:
744
+
745
+ ```bash
746
+ npm install --save-dev vite-plugin-image-optimizer sharp
747
+ ```
748
+
749
+ ```js
750
+ // vite.config.js
751
+ import { defineConfig } from "vite";
752
+ import react from "@vitejs/plugin-react";
753
+ import { ViteImageOptimizer } from "vite-plugin-image-optimizer";
754
+ import { routerinoForge } from "routerino/forge";
755
+
756
+ export default defineConfig({
757
+ plugins: [
758
+ react(),
759
+ ViteImageOptimizer({
760
+ jpg: { quality: 80 },
761
+ jpeg: { quality: 80 },
762
+ png: { quality: 80 },
763
+ webp: { quality: 80 },
764
+ }),
765
+ routerinoForge({ baseUrl: "https://example.com" }),
766
+ ],
767
+ });
768
+ ```
769
+
770
+ Use standard HTML `<img>` tags in your components — the plugin optimizes source images in `public/` and imported assets during the Vite build. No special component or props needed.
771
+
906
772
  ## Static Site Generation
907
773
 
908
774
  Routerino provides static site generation (SSG), creating fully-rendered HTML files at build time with "just clean JSX elements that render identically on server and client."
@@ -929,7 +795,7 @@ export default defineConfig({
929
795
  // useTrailingSlash: true, // Set to false for /about instead of /about/
930
796
  // verbose: false,
931
797
  // ssgCacheDir: "node_modules/.cache/routerino-forge", // SSG cache directory
932
- // imageOptions: {}, // Customize image optimization (see Image Optimization below)
798
+ // verbose: false,
933
799
  }),
934
800
  ],
935
801
  });
@@ -958,153 +824,9 @@ export default defineConfig({
958
824
  - Creates a 404.html page
959
825
  - Skips dynamic routes (with `:param` syntax)
960
826
  - SEO optimized: Complete HTML with meta tags
961
- - Image optimization: Automatic responsive variants + blur placeholders (LQIP)
827
+ - Image optimization: Automatic responsive variants + blur placeholders (LQIP) — now delegated to [`vite-plugin-image-optimizer`](https://github.com/FatehAK/vite-plugin-image-optimizer)
962
828
  - Easy configuration: Works out of the box with Vite and minimal setup
963
829
 
964
- #### Image Optimization
965
-
966
- Routerino Forge automatically processes `<Image>` components during the build to generate responsive image variants and LQIP (Low Quality Image Placeholder) blur-up effects. Image optimization is always enabled when ffmpeg is available — no flag needed to turn it on. Use `imageOptions` to customize:
967
-
968
- ```js
969
- routerinoForge({
970
- baseUrl: "https://example.com",
971
- imageOptions: {
972
- widths: [480, 800, 1200, 1920], // Responsive widths to generate
973
- formats: ["webp"], // Extra formats (webp is always generated)
974
- placeholderSize: 20, // Height of LQIP placeholder in px
975
- blur: 4, // Blur radius for LQIP placeholder
976
- maxSize: 10485760, // Max source image size to process (10MB)
977
- minSize: 1024, // Min source image size to process (1KB)
978
- cacheDir: "node_modules/.cache/routerino-forge",
979
- },
980
- });
981
- ```
982
-
983
- All keys in `imageOptions` are optional — omit any to keep the default.
984
-
985
- **What it does:**
986
-
987
- - Generates responsive image variants at each configured width (WebP + original format)
988
- - Generates LQIP blur placeholders (tiny base64 PNG shown while image loads)
989
- - Anti-upscaling: never generates variants wider than the source image
990
- - Caches generated variants to speed up subsequent builds
991
- - Skips external URLs (http/https), data URIs, and SVGs
992
- - Skips images below `minSize` or above `maxSize`
993
- - Adds `width`/`height` attributes to `<img>` tags for CLS prevention
994
- - Stale cache entries are automatically cleaned up (50 most recent kept)
995
-
996
- **Note:** Image optimization requires `ffmpeg` to be installed on your system. Install with `brew install ffmpeg` (Mac), `apt install ffmpeg` (Debian/Ubuntu), or `choco install ffmpeg` (Windows). Without ffmpeg, the Image component still works but falls back to the original image without responsive variants or LQIP. A warning is shown during build if ffmpeg is not found but Image components are used.
997
-
998
- ##### CI/CD Setup for Image Optimization
999
-
1000
- For CI/CD environments without ffmpeg pre-installed, you'll need to install it as part of your build process. Here are examples:
1001
-
1002
- ###### GitHub Actions
1003
-
1004
- Add the `setup-ffmpeg` action to your workflow:
1005
-
1006
- ```yaml
1007
- name: Build and Deploy
1008
-
1009
- on:
1010
- push:
1011
- branches: [main]
1012
-
1013
- jobs:
1014
- build:
1015
- runs-on: ubuntu-latest
1016
-
1017
- steps:
1018
- - uses: actions/checkout@v4
1019
-
1020
- - uses: actions/setup-node@v4
1021
- with:
1022
- node-version: "20"
1023
- cache: "npm"
1024
-
1025
- # Install ffmpeg for image optimization
1026
- - name: Setup FFmpeg
1027
- uses: FedericoCarboni/setup-ffmpeg@v3
1028
- with:
1029
- ffmpeg-version: release
1030
-
1031
- - run: npm ci
1032
- - run: npm run build
1033
-
1034
- # Deploy to GitHub Pages (optional)
1035
- - uses: peaceiris/actions-gh-pages@v3
1036
- if: github.ref == 'refs/heads/main'
1037
- with:
1038
- github_token: ${{ secrets.GITHUB_TOKEN }}
1039
- publish_dir: ./dist
1040
- ```
1041
-
1042
- ###### Docker
1043
-
1044
- For containerized deployments, install ffmpeg in your Dockerfile:
1045
-
1046
- ```dockerfile
1047
- FROM node:20-alpine
1048
-
1049
- # Install ffmpeg
1050
- RUN apk add --no-cache ffmpeg
1051
-
1052
- WORKDIR /app
1053
-
1054
- # Copy package files
1055
- COPY package*.json ./
1056
- RUN npm ci
1057
-
1058
- # Copy source and build
1059
- COPY . .
1060
- RUN npm run build
1061
-
1062
- # Production stage with nginx
1063
- FROM nginx:alpine
1064
- COPY --from=0 /app/dist /usr/share/nginx/html
1065
- ```
1066
-
1067
- ###### Netlify
1068
-
1069
- Netlify builds run on Ubuntu images, so you can install ffmpeg using apt-get in your build command.
1070
-
1071
- In your netlify.toml:
1072
-
1073
- ```
1074
- [build]
1075
- command = "apt-get update && apt-get install -y ffmpeg && npm ci && npm run build"
1076
- publish = "dist"
1077
- ```
1078
-
1079
- ###### Cloudflare Pages
1080
-
1081
- Cloudflare Pages doesn't allow `apt-get`. Use the `ffmpeg-static` / `ffprobe-static` npm packages instead.
1082
-
1083
- In the **Cloudflare Pages dashboard** under **Settings > Build & Deployments > Build command**:
1084
-
1085
- ```
1086
- npm ci && npm install --no-save ffmpeg-static ffprobe-static && ln -sf "$(node -e "console.log(require('ffmpeg-static'))")" /tmp/ffmpeg && ln -sf "$(node -e "console.log(require('ffprobe-static').path)")" /tmp/ffprobe && export PATH="/tmp:$PATH" && npm run build
1087
- ```
1088
-
1089
- Or in your `wrangler.toml`:
1090
-
1091
- ```toml
1092
- [build]
1093
- command = """
1094
- npm ci && \
1095
- npm install --no-save ffmpeg-static ffprobe-static && \
1096
- ln -sf "$(node -e "console.log(require('ffmpeg-static'))")" /tmp/ffmpeg && \
1097
- ln -sf "$(node -e "console.log(require('ffprobe-static').path)")" /tmp/ffprobe && \
1098
- export PATH="/tmp:$PATH" && \
1099
- npm run build
1100
- """
1101
-
1102
- [build.environment]
1103
- NODE_VERSION = "20"
1104
- ```
1105
-
1106
- > **Note:** Without ffmpeg, the SSG still builds successfully — the forge plugin automatically strips responsive image references so browsers load the original images without 404s. Install ffmpeg to enable WebP variants, LQIP blur placeholders, and responsive image sets for better Lighthouse scores.
1107
-
1108
830
  #### Routes Configuration
1109
831
 
1110
832
  **Critical for SSG**: Routes MUST be exported for the build plugin to discover them. The plugin needs to import your routes at build time, so inline route definitions won't work.