STX Router

raw JSON →
0.2.12 verified Thu Apr 23 auth: no javascript

STX Router is a file-based routing solution specifically designed for the Stacks.js full-stack framework. It facilitates automatic discovery of `.stx` templates, enables nested layouts, offers typed route parameters for enhanced developer experience and compile-time safety, supports middleware for request processing, and provides robust client-side SPA navigation. As of version 0.2.12, the package is in active pre-1.0 development, integrating seamlessly into the Stacks.js ecosystem which leverages TypeScript and Bun for performance and type-safety. The project generally follows a convention-over-configuration philosophy, aiming for rapid application development. Its current release cadence is frequent, indicating ongoing feature development and potential for breaking changes between minor versions as it approaches a stable 1.0 release.

error Error: Route not found for path '/your/path'
cause The requested URL path does not match any defined file-based route in your `.stx` template directory, or the router configuration is incorrect.
fix
Verify that a corresponding .stx file exists for the requested path (e.g., views/your/path.stx or views/your/[param].stx). Check the routes configuration in createRouter to ensure it points to the correct base directory. Also, confirm no typos in the URL or route definition.
error TypeError: Cannot read properties of undefined (reading 'params')
cause Attempting to access `req.params` or `ctx.params` when no route parameters are present for the matched route, or when the request context (`ctx`/`req`) is not correctly populated by the router.
fix
Ensure that the route being handled actually defines dynamic parameters (e.g., /users/:id). Before accessing params, consider optional chaining (req.params?.id) or a null/undefined check to handle cases where parameters might not exist gracefully.
error SyntaxError: Named export 'defineMiddleware' not found in module '@stacksjs/router'
cause This usually indicates a mismatch between CommonJS `require()` syntax and an ESM module, or an incorrect named import from a module that uses default exports (or vice-versa).
fix
Ensure you are using import { defineMiddleware } from '@stacksjs/router' for named exports. If the module primarily offers a default export, you would use import Router from '@stacksjs/router' (though stx-router uses named exports). Also, verify your project's tsconfig.json and package.json ("type": "module") are correctly configured for ESM.
breaking As a pre-1.0 release, `stx-router` may introduce breaking changes in minor versions (e.g., 0.2.x to 0.3.x). APIs, configuration options, and internal behaviors are subject to change without strict adherence to semantic versioning until a stable 1.0 release.
fix Always review the release notes or changelog when upgrading minor versions. Pin exact versions in your `package.json` to prevent unexpected breaking changes in production, and test thoroughly before deploying updates.
gotcha File-based routing relies on specific directory structures and naming conventions for `.stx` templates. Deviating from these conventions will result in routes not being discovered or matched correctly, leading to 404 errors.
fix Consult the Stacks.js documentation for the exact file-based routing conventions, especially regarding dynamic segments (e.g., `[id].stx`), nested layouts, and index files. Ensure your template directory path is correctly configured in `createRouter`.
gotcha Middleware execution order and application scope can be a common source of bugs. Middleware might not execute for certain routes, or the order of execution might be unexpected, especially with overlapping paths.
fix Carefully define your middleware paths and ensure they are specified in the correct order in your router configuration. Use logging within your middleware to verify their execution flow for specific requests. Broad wildcard (`*`) paths should be used with caution.
gotcha Typed route parameters, while beneficial, require careful definition in your route files (or inferred types). Incorrectly accessing or assuming the type of a route parameter (e.g., treating a string ID as a number without parsing) can lead to runtime `TypeError`s.
fix Always validate and parse route parameters explicitly in your route handlers or middleware, especially when converting between string path segments and numerical/boolean types. Leverage TypeScript's type inference and type guards to handle parameter types safely.
npm install stx-router
yarn add stx-router
pnpm add stx-router

This quickstart demonstrates how to initialize `stx-router` with a file-based route directory, apply a simple authentication middleware to protected paths, and shows a basic request handling flow within a simulated Stacks.js server environment. It highlights the use of `createRouter` and `defineMiddleware`.

import { createRouter, defineMiddleware } from '@stacksjs/router';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

// Define a simple authentication middleware
const authMiddleware = defineMiddleware((req, res, next) => {
  const isAuthenticated = req.headers.get('authorization') === 'Bearer my-secret-token';
  if (isAuthenticated) {
    console.log('User is authenticated');
    next();
  } else {
    console.warn('Authentication failed: Missing or invalid token');
    res.status(401).send('Unauthorized');
  }
});

// Imagine your .stx templates are in a 'views' directory
// For a file-based router, you'd typically have files like:
// views/index.stx, views/users/[id].stx, views/admin/dashboard.stx
const router = createRouter({
  routes: join(__dirname, 'views'), // Points to your .stx template directory
  middleware: {
    '/admin/*': [authMiddleware], // Apply authMiddleware to all /admin routes
  },
  // You might define custom error handlers or other router options here
  onNotFound: (req, res) => {
    res.status(404).send('Custom 404 Not Found Page');
  },
});

// Example: How to manually handle a request (in a server context, e.g., Bun.serve)
// In a real Stacks.js app, this would be abstracted away by the framework's server.
async function handleRequest(request: Request) {
  const url = new URL(request.url);
  console.log(`Incoming request: ${request.method} ${url.pathname}`);

  // Simulate router matching and processing
  // In a full Stacks.js app, this would trigger .stx template rendering
  const response = await router.handle(request);

  // For demonstration, a simple placeholder response if router doesn't explicitly respond
  if (!response.headers.has('X-Router-Handled')) {
    if (url.pathname === '/') {
      return new Response('Welcome to the STX App!', { status: 200 });
    } else if (url.pathname.startsWith('/users/')) {
      const userId = url.pathname.split('/').pop();
      return new Response(`User profile for ID: ${userId}`, { status: 200 });
    }
    return new Response('Default response for unmatched routes or handled by custom 404', { status: 404 });
  }
  return response;
}

// This part would typically be part of your Stacks.js server setup
// Bun.serve({
//   fetch: handleRequest,
//   port: 3000,
// });

// console.log('STX Router example server running on http://localhost:3000');

// To test manually:
// await handleRequest(new Request('http://localhost:3000/'));
// await handleRequest(new Request('http://localhost:3000/users/123'));
// await handleRequest(new Request('http://localhost:3000/admin/dashboard', { headers: { 'Authorization': 'Bearer my-secret-token' } }));
// await handleRequest(new Request('http://localhost:3000/admin/settings')); // Should be unauthorized
// await handleRequest(new Request('http://localhost:3000/nonexistent')); // Should trigger custom 404