# Vite Plugin: Automatic File-based Routing 🚦 SigPro provides an optional Vite plugin that automatically generates routes based on your file structure. No configuration needed - just create pages and they're instantly available with the correct paths. ## Why Use This Plugin? While SigPro's router works perfectly with manually defined routes, this plugin: - **Eliminates boilerplate** - No need to write route configurations - **Enforces conventions** - Consistent URL structure across your app - **Supports dynamic routes** - Use `[param]` syntax for parameters - **Automatic code-splitting** - Each page becomes a separate chunk - **Type-safe** (with JSDoc) - Routes follow your file structure ## Installation The plugin is included with SigPro, but you need to add it to your Vite config: ```javascript // vite.config.js import { defineConfig } from 'vite'; import { sigproRouter } from 'sigpro/vite'; export default defineConfig({ plugins: [sigproRouter()] }); ``` ## How It Works The plugin scans your `src/pages` directory and automatically generates routes based on the file structure: ``` src/pages/ ├── index.js → '/' ├── about.js → '/about' ├── blog/ │ ├── index.js → '/blog' │ └── [slug].js → '/blog/:slug' └── users/ ├── [id].js → '/users/:id' └── [id]/edit.js → '/users/:id/edit' ``` ## Usage ### 1. Enable the Plugin Add the plugin to your Vite config as shown above. ### 2. Import the Generated Routes ```javascript // main.js import { $, html } from 'sigpro'; import { routes } from 'virtual:sigpro-routes'; // Use the generated routes directly const router = $.router(routes); document.body.appendChild(router); ``` ### 3. Create Pages ```javascript // src/pages/index.js import { $, html } from 'sigpro'; export default () => { return html`

Home Page

About
`; }; ``` ```javascript // src/pages/users/[id].js import { $, html } from 'sigpro'; export default (params) => { const userId = params.id; return html`

User Profile: ${userId}

Edit
`; }; ``` ## 📋 File-to-Route Mapping ### Static Routes | File Path | Generated Route | |-----------|-----------------| | `src/pages/index.js` | `/` | | `src/pages/about.js` | `/about` | | `src/pages/contact/index.js` | `/contact` | | `src/pages/blog/post.js` | `/blog/post` | ### Dynamic Routes | File Path | Generated Route | Example URL | |-----------|-----------------|-------------| | `src/pages/users/[id].js` | `/users/:id` | `/users/42` | | `src/pages/blog/[slug].js` | `/blog/:slug` | `/blog/hello-world` | | `src/pages/users/[id]/posts/[pid].js` | `/users/:id/posts/:pid` | `/users/42/posts/123` | ### Nested Routes | File Path | Generated Route | Notes | |-----------|-----------------|-------| | `src/pages/settings/index.js` | `/settings` | Index page | | `src/pages/settings/profile.js` | `/settings/profile` | Sub-page | | `src/pages/settings/security.js` | `/settings/security` | Sub-page | | `src/pages/settings/[section].js` | `/settings/:section` | Dynamic section | ## 🎯 Advanced Examples ### Blog with Posts ```javascript // src/pages/blog/index.js - Lists all posts export default () => { const posts = $([]); $.effect(() => { fetch('/api/posts') .then(res => res.json()) .then(data => posts(data)); }); return html`

Blog

${posts().map(post => html`

${post.title}

${post.excerpt}

`)}
`; }; ``` ```javascript // src/pages/blog/[slug].js - Single post export default (params) => { const post = $(null); const slug = params.slug; $.effect(() => { fetch(`/api/posts/${slug}`) .then(res => res.json()) .then(data => post(data)); }); return html`
← Back to blog ${() => post() ? html`

${post().title}

${post().content}
` : html`
Loading...
`}
`; }; ``` ### Dashboard with Nested Sections ```javascript // src/pages/dashboard/index.js export default () => { return html`

Dashboard Overview

`; }; ``` ```javascript // src/pages/dashboard/analytics.js export default () => { return html`

Analytics

`; }; ``` ### E-commerce Product Routes ```javascript // src/pages/products/[category]/[id].js export default (params) => { const { category, id } = params; const product = $(null); $.effect(() => { fetch(`/api/products/${category}/${id}`) .then(res => res.json()) .then(data => product(data)); }); return html`
${() => product() ? html`

${product().name}

$${product().price}

${product().description}

` : html`
Loading...
`}
`; }; ``` ## 🔧 Configuration Options The plugin accepts an optional configuration object: ```javascript // vite.config.js import { defineConfig } from 'vite'; import { sigproRouter } from 'sigpro/vite'; export default defineConfig({ plugins: [ sigproRouter({ pagesDir: 'src/pages', // Default: 'src/pages' extensions: ['.js', '.jsx'], // Default: ['.js', '.jsx'] exclude: ['**/_*', '**/components/**'] // Glob patterns to exclude }) ] }); ``` ### Options | Option | Type | Default | Description | |--------|------|---------|-------------| | `pagesDir` | `string` | `'src/pages'` | Directory containing your pages | | `extensions` | `string[]` | `['.js', '.jsx']` | File extensions to include | | `exclude` | `string[]` | `[]` | Glob patterns to exclude | ## 🎯 Route Priority The plugin automatically sorts routes to ensure correct matching: 1. **Static routes** take precedence over dynamic ones 2. **More specific routes** (deeper paths) come first 3. **Alphabetical order** for routes at the same level Example sorting: ``` /users/new (static, specific) /users/[id]/edit (dynamic, deeper) /users/[id] (dynamic, shallower) /users/profile (static, shallower) ``` ## 📦 Output Example When you import `virtual:sigpro-routes`, you get: ```javascript // Generated module import Page_0 from '/src/pages/index.js'; import Page_1 from '/src/pages/about.js'; import Page_2 from '/src/pages/blog/index.js'; import Page_3 from '/src/pages/blog/[slug].js'; import Page_4 from '/src/pages/users/[id].js'; import Page_5 from '/src/pages/users/[id]/edit.js'; export const routes = [ { path: '/', component: Page_0 }, { path: '/about', component: Page_1 }, { path: '/blog', component: Page_2 }, { path: '/blog/:slug', component: Page_3 }, { path: '/users/:id', component: Page_4 }, { path: '/users/:id/edit', component: Page_5 }, ]; ``` ## 🚀 Performance Benefits - **Automatic code splitting** - Each page becomes a separate chunk - **Lazy loading ready** - Import pages dynamically - **Tree shaking** - Only used routes are included ```javascript // With dynamic imports (automatic with Vite) const routes = [ { path: '/', component: () => import('./pages/index.js') }, { path: '/about', component: () => import('./pages/about.js') }, // ... ]; ``` ## 💡 Pro Tips ### 1. Group Related Pages ``` src/pages/ ├── dashboard/ │ ├── index.js │ ├── analytics.js │ └── settings.js └── dashboard.js # ❌ Don't mix with folder ``` ### 2. Use Index Files for Clean URLs ``` ✅ Good: pages/blog/index.js → /blog pages/blog/post.js → /blog/post ❌ Avoid: pages/blog.js → /blog (conflicts with folder) ``` ### 3. Private Components Prefix with underscore to exclude from routing: ``` src/pages/ ├── index.js ├── about.js └── _components/ # ❌ Not scanned └── Header.js ``` ### 4. Layout Components Create a layout wrapper in your main entry: ```javascript // main.js import { $, html } from 'sigpro'; import { routes } from 'virtual:sigpro-routes'; // Wrap all routes with layout const routesWithLayout = routes.map(route => ({ ...route, component: (params) => Layout(route.component(params)) })); const router = $.router(routesWithLayout); document.body.appendChild(router); ``` --- > **Note:** This plugin is completely optional. You can always define routes manually if you prefer. The plugin just saves you from writing boilerplate route configurations. > **Pro Tip:** The plugin works great with hot module replacement (HMR) - add a new page and it's instantly available in your dev server without restarting!