261 lines
6.9 KiB
TypeScript
261 lines
6.9 KiB
TypeScript
/**
|
|
* SigPro Vite Plugin
|
|
* Provides file-based routing and development tools for Vite
|
|
*
|
|
* @example
|
|
* ```javascript
|
|
* // vite.config.js
|
|
* import { defineConfig } from 'vite';
|
|
* import sigproRouter from 'sigpro/vite';
|
|
*
|
|
* export default defineConfig({
|
|
* plugins: [sigproRouter()]
|
|
* });
|
|
* ```
|
|
*/
|
|
|
|
import type { Plugin } from 'vite';
|
|
|
|
/**
|
|
* File-based routing configuration options
|
|
*/
|
|
export interface SigProRouterOptions {
|
|
/**
|
|
* Directory where page components are stored
|
|
* @default 'src/pages'
|
|
* @example
|
|
* ```javascript
|
|
* sigproRouter({ pagesDir: 'src/views' })
|
|
* ```
|
|
*/
|
|
pagesDir?: string;
|
|
|
|
/**
|
|
* File extensions to consider as pages
|
|
* @default ['.js', '.jsx', '.ts', '.tsx']
|
|
* @example
|
|
* ```javascript
|
|
* sigproRouter({ extensions: ['.js', '.jsx'] })
|
|
* ```
|
|
*/
|
|
extensions?: string[];
|
|
|
|
/**
|
|
* Custom route transformation function
|
|
* @param filePath - Absolute path to the file
|
|
* @returns Custom route path or null to skip
|
|
* @example
|
|
* ```javascript
|
|
* sigproRouter({
|
|
* transformRoute: (path) => {
|
|
* // Convert 'src/pages/blog/post.js' to '/blog/post'
|
|
* return path.replace(/^src\/pages/, '').replace(/\.js$/, '');
|
|
* }
|
|
* })
|
|
* ```
|
|
*/
|
|
transformRoute?: (filePath: string) => string | null;
|
|
|
|
/**
|
|
* Base path prefix for all routes
|
|
* @default ''
|
|
* @example
|
|
* ```javascript
|
|
* sigproRouter({ basePath: '/app' }) // Routes become /app/about, /app/users, etc.
|
|
* ```
|
|
*/
|
|
basePath?: string;
|
|
|
|
/**
|
|
* Custom 404 component path
|
|
* @default null (uses default "404 - Not Found")
|
|
* @example
|
|
* ```javascript
|
|
* sigproRouter({ notFoundComponent: 'src/pages/NotFound.js' })
|
|
* ```
|
|
*/
|
|
notFoundComponent?: string;
|
|
}
|
|
|
|
/**
|
|
* Route configuration generated by the plugin
|
|
*/
|
|
export interface GeneratedRoute {
|
|
/** URL path pattern (supports :params and * wildcard) */
|
|
path: string;
|
|
/** Lazy-loaded component */
|
|
component: () => Promise<any>;
|
|
}
|
|
|
|
/**
|
|
* Virtual module ID for generated routes
|
|
* @example
|
|
* ```javascript
|
|
* import { routes } from 'virtual:sigpro-routes';
|
|
* ```
|
|
*/
|
|
export const virtualModuleId = 'virtual:sigpro-routes';
|
|
|
|
/**
|
|
* Vite plugin for SigPro file-based routing
|
|
*
|
|
* Features:
|
|
* - 📁 File-based routing from `src/pages` directory
|
|
* - 🔄 Automatic route generation
|
|
* - 🚀 Lazy-loading support with code splitting
|
|
* - 📦 Dynamic routes with `[param]` syntax → `/:param`
|
|
* - ⭐ Catch-all routes with `[...param]` syntax → `/*`
|
|
* - 🎯 Index routes (`index.js` becomes `/`)
|
|
* - 🧹 Automatic sorting (static routes first, then dynamic)
|
|
* - 🎨 404 fallback generation
|
|
*
|
|
* @example
|
|
* **File Structure:**
|
|
* ```
|
|
* src/pages/
|
|
* ├── index.js → '/'
|
|
* ├── about.js → '/about'
|
|
* ├── blog/
|
|
* │ ├── index.js → '/blog'
|
|
* │ ├── [slug].js → '/blog/:slug'
|
|
* │ └── [...catch].js → '/blog/*'
|
|
* └── user/
|
|
* ├── index.js → '/user'
|
|
* └── [id].js → '/user/:id'
|
|
* ```
|
|
*
|
|
* @example
|
|
* **Generated Routes:**
|
|
* ```javascript
|
|
* // virtual:sigpro-routes
|
|
* export const routes = [
|
|
* { path: '/', component: () => import('src/pages/index.js') },
|
|
* { path: '/about', component: () => import('src/pages/about.js') },
|
|
* { path: '/blog', component: () => import('src/pages/blog/index.js') },
|
|
* { path: '/blog/:slug', component: () => import('src/pages/blog/[slug].js') },
|
|
* { path: '/blog/*', component: () => import('src/pages/blog/[...catch].js') },
|
|
* { path: '/user', component: () => import('src/pages/user/index.js') },
|
|
* { path: '/user/:id', component: () => import('src/pages/user/[id].js') },
|
|
* { path: '*', component: () => import('src/pages/NotFound.js') } // If exists
|
|
* ];
|
|
* ```
|
|
*
|
|
* @example
|
|
* **Usage with SigPro:**
|
|
* ```javascript
|
|
* // main.js
|
|
* import { routes } from 'virtual:sigpro-routes';
|
|
* import { $ } from 'sigpro';
|
|
*
|
|
* const router = $.router(routes);
|
|
* $.mount(router, '#app');
|
|
* ```
|
|
*
|
|
* @param options - Plugin configuration options
|
|
* @returns Vite plugin object
|
|
*/
|
|
export default function sigproRouter(options?: SigProRouterOptions): Plugin;
|
|
|
|
/**
|
|
* Page component props for route components
|
|
* @template Params - Type of route parameters
|
|
*/
|
|
export interface PageProps<Params = Record<string, string>> {
|
|
/** URL parameters from dynamic routes (e.g., :id, :slug) */
|
|
params: Params;
|
|
/** URL search parameters (query string) */
|
|
query: URLSearchParams;
|
|
/** Current pathname without query string */
|
|
pathname: string;
|
|
/** Children components (for nested routes) */
|
|
children?: any;
|
|
}
|
|
|
|
/**
|
|
* Route component type
|
|
* @template Params - Type of route parameters
|
|
*/
|
|
export type PageComponent<Params = Record<string, string>> = (
|
|
props: PageProps<Params>
|
|
) => HTMLElement | Promise<HTMLElement>;
|
|
|
|
/**
|
|
* Helper function to create typed route components
|
|
* Provides better TypeScript support and autocompletion
|
|
*
|
|
* @example
|
|
* ```javascript
|
|
* // pages/user/[id].js
|
|
* import { createPage } from 'sigpro/vite';
|
|
*
|
|
* export default createPage(({ params, query }) => {
|
|
* const { id } = params; // TypeScript knows this is a string
|
|
* const page = query.get('page') || 1;
|
|
*
|
|
* return div({ class: 'user-profile' }, [
|
|
* h1(`User ${id}`),
|
|
* p(`Page: ${page}`),
|
|
* button({
|
|
* onclick: () => console.log('Viewing user', id)
|
|
* }, 'View Profile')
|
|
* ]);
|
|
* });
|
|
* ```
|
|
*
|
|
* @example
|
|
* **With TypeScript:**
|
|
* ```typescript
|
|
* // pages/user/[id].tsx
|
|
* interface UserParams {
|
|
* id: string;
|
|
* }
|
|
*
|
|
* export default createPage<UserParams>(({ params, query }) => {
|
|
* const userId = params.id; // TypeScript knows this is string
|
|
* // ... rest of component
|
|
* });
|
|
* ```
|
|
*/
|
|
export function createPage<Params = Record<string, string>>(
|
|
component: (props: PageProps<Params>) => HTMLElement | Promise<HTMLElement>
|
|
): PageComponent<Params>;
|
|
|
|
/**
|
|
* Type guard to check if a component is lazy-loaded
|
|
* @param component - Component to check
|
|
* @returns True if component is a lazy-loaded module
|
|
*/
|
|
export function isLazyComponent(component: any): component is () => Promise<any>;
|
|
|
|
/**
|
|
* Utility to preload routes for better performance
|
|
* @example
|
|
* ```javascript
|
|
* import { preloadRoutes } from 'sigpro/vite';
|
|
*
|
|
* // Preload routes after initial load
|
|
* preloadRoutes(['/about', '/blog']);
|
|
* ```
|
|
*/
|
|
export function preloadRoutes(paths: string[]): Promise<void>;
|
|
|
|
/**
|
|
* Debug helper to inspect generated routes
|
|
* @example
|
|
* ```javascript
|
|
* // Only in development
|
|
* if (import.meta.env.DEV) {
|
|
* const routes = await import('virtual:sigpro-routes');
|
|
* console.table(routes);
|
|
* }
|
|
* ```
|
|
*/
|
|
export function inspectRoutes(): void;
|
|
|
|
/**
|
|
* Virtual module declarations for client-side code
|
|
* This allows TypeScript to understand the virtual module
|
|
*/
|
|
declare module 'virtual:sigpro-routes' {
|
|
export const routes: GeneratedRoute[];
|
|
} |