|
| 1 | +# Preact ISO URL Pattern Matching - Polyglot Utils |
| 2 | + |
| 3 | +Multi-language implementations of URL pattern matching utilities for building bespoke server setups that need to preload JS/CSS resources or handle early 404 responses. |
| 4 | + |
| 5 | +## Use Case |
| 6 | + |
| 7 | +This utility is designed for server languages that **cannot do SSR/prerendering** but still want to provide better experiences. It enables servers to: |
| 8 | + |
| 9 | +- 🚀 **Add preload head tags** for JS,CSS before serving HTML |
| 10 | +- ⚡ **Return early 404 pages** for unmatched routes |
| 11 | +- 🎨 **Generate dynamic titles** based on route parameters |
| 12 | +- 📦 **Optimize resource loading** without full SSR capability |
| 13 | + |
| 14 | +## How can I implement preloading of JS, CSS? |
| 15 | + |
| 16 | +Typical implementation flow: |
| 17 | + |
| 18 | +1. **Build-time Setup:** |
| 19 | + - Write your routes as an array in a JS file |
| 20 | + - Create a build script that exports route patterns and entry files to a `.json` file |
| 21 | + - Configure your frontend build tool to output a `manifest` file mapping entry files to final fingerprinted/hashed output JS/CSS files and dependencies |
| 22 | + |
| 23 | +2. **Server-time Processing:** |
| 24 | + - Load the JSON route file when a request comes in |
| 25 | + - Match the requested URL against each route pattern until you find a match |
| 26 | + - Once matched, you have the source entry `.jsx` file |
| 27 | + - Load the build manifest file to find which JS chunk contains that code and its dependency files |
| 28 | + - Generate `<link rel="preload">` tags for each dependency (JS, CSS, images, icons) |
| 29 | + - Inject those head tags into the HTML before serving |
| 30 | + |
| 31 | +3. **Result:** |
| 32 | + - Browsers start downloading critical resources immediately |
| 33 | + - Faster page loads without full SSR complexity |
| 34 | + - Early 404s for invalid routes |
| 35 | + |
| 36 | +### Example - preloading of JS, CSS |
| 37 | + |
| 38 | +Here's how you might integrate this into a server setup: |
| 39 | + |
| 40 | +### 1. Route Configuration (routes.json) |
| 41 | +```json |
| 42 | +[ |
| 43 | + { |
| 44 | + "path": "/users/:userId/posts", |
| 45 | + "component": "pages/UserPosts.jsx", |
| 46 | + "title": "Posts by :userId" |
| 47 | + }, |
| 48 | + { |
| 49 | + "path": "/products/:category/:id", |
| 50 | + "component": "pages/Product.jsx", |
| 51 | + "title": "Product :id" |
| 52 | + } |
| 53 | +] |
| 54 | +``` |
| 55 | + |
| 56 | +### 2. Build Manifest (manifest.json) |
| 57 | +```json |
| 58 | +{ |
| 59 | + "pages/UserPosts.jsx": { |
| 60 | + "file": "assets/UserPosts-abc123.js", |
| 61 | + "css": ["assets/UserPosts-def456.css"], |
| 62 | + "imports": ["chunks/shared-ghi789.js"] |
| 63 | + } |
| 64 | +} |
| 65 | +``` |
| 66 | + |
| 67 | +### 3. Server Implementation |
| 68 | +```python |
| 69 | +# Python example |
| 70 | +import json |
| 71 | + |
| 72 | +routes = json.load(open('routes.json')) |
| 73 | +manifest = json.load(open('manifest.json')) |
| 74 | + |
| 75 | +def handle_request(url_path): |
| 76 | + for route in routes: |
| 77 | + matches = preact_iso_url_pattern_match(url_path, route['path']) |
| 78 | + if matches: |
| 79 | + # Generate preload tags |
| 80 | + component = route['component'] |
| 81 | + entry_info = manifest[component] |
| 82 | + |
| 83 | + preload_tags = [] |
| 84 | + for js_file in [entry_info['file']] + entry_info.get('imports', []): |
| 85 | + preload_tags.append(f'<link rel="modulepreload" crossorigin href="{js_file}">') |
| 86 | + |
| 87 | + for css_file in entry_info.get('css', []): |
| 88 | + preload_tags.append(f'<link rel="stylesheet" crossorigin href="{css_file}">') |
| 89 | + # Generate dynamic title |
| 90 | + title = route['title'] |
| 91 | + for param, value in matches['params'].items(): |
| 92 | + title = title.replace(f':{param}', value) |
| 93 | + |
| 94 | + return { |
| 95 | + 'preload_tags': preload_tags, |
| 96 | + 'title': title, |
| 97 | + 'params': matches['params'] |
| 98 | + } |
| 99 | + |
| 100 | + # No match found - return early 404 |
| 101 | + return None |
| 102 | +``` |
| 103 | + |
| 104 | +This approach gives you the performance benefits of resource preloading without the complexity of full server-side rendering! |
| 105 | + |
| 106 | +## Available Languages |
| 107 | + |
| 108 | +| Language | Implementation | Tests | Status | |
| 109 | +|----------|----------------|-------|---------| |
| 110 | +| **Go** | `go/preact_iso_url_pattern.go` | `go/preact_iso_url_pattern_test.go` | ✅ 51/51 tests | |
| 111 | +| **Python** | `python/preact_iso_url_pattern.py` | `python/test_preact_iso_url_pattern.py` | ✅ 51/51 tests | |
| 112 | +| **Ruby** | `ruby/preact-iso-url-pattern.rb` | `ruby/test_preact_iso_url_pattern.rb` | ✅ 51/51 tests | |
| 113 | +| **PHP** | `php/preact-iso-url-pattern.php` | `php/test_preact_iso_url_pattern.php` | ✅ 51/51 tests | |
| 114 | + |
| 115 | +## Running Tests |
| 116 | + |
| 117 | +```bash |
| 118 | +# Run all tests across all languages |
| 119 | +./run_tests.sh |
| 120 | + |
| 121 | +# Or run individual language tests |
| 122 | +cd go && go test -v |
| 123 | +cd python && python3 test_preact_iso_url_pattern.py |
| 124 | +cd ruby && ruby test_preact_iso_url_pattern.rb |
| 125 | +cd php && php test_preact_iso_url_pattern.php |
| 126 | +``` |
| 127 | + |
| 128 | +## Language-Specific Documentation |
| 129 | + |
| 130 | +Each language implementation has detailed documentation with usage examples and API references: |
| 131 | + |
| 132 | +- **[Go](go/README.md)** - Static typing with struct returns |
| 133 | +- **[Python](python/README.md)** - Dictionary-based with optional typing |
| 134 | +- **[Ruby](ruby/README.md)** - Hash-based with flexible syntax |
| 135 | +- **[PHP](php/README.md)** - Mixed array/object approach for JSON compatibility |
| 136 | + |
0 commit comments