Templates engine#67
Conversation
This commit updates the middleware to detect subdomains in both production and development environments. It implements URL rewriting to redirect users to the appropriate store page based on the detected subdomain, improving navigation and user experience. Additionally, the matcher configuration has been simplified to exclude specific paths, streamlining route handling.
… sanitization Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
…logic This commit refactors the middleware to enhance the subdomain extraction process and streamline URL rewriting based on detected subdomains. It introduces a dedicated function for subdomain extraction, improving code clarity and maintainability. Additionally, it updates the URL rewriting logic to handle root paths and ensure proper redirection for valid hostnames, enhancing user navigation.
WalkthroughThis update introduces a new React component for handling dynamic store pages, displaying the store name or an error if not found. The middleware logic is refactored to validate hostnames, extract subdomains, and rewrite URLs accordingly, with a simplified matcher pattern for route protection and handling. Changes
Poem
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (4)
middleware.ts (2)
11-11: Consider adding null check for the host header.While the fallback to empty string is good, you should also handle the case where the hostname might be invalid or malformed.
- const hostname = request.headers.get('host') || '' + const hostname = request.headers.get('host') || '' + if (!hostname) { + console.error('Missing host header') + return NextResponse.next() + }
28-43: Simplify and improve subdomain extraction logic.The subdomain extraction function could be simplified and made more robust.
- const extractSubdomain = (hostname: string, isProduction: boolean): string => { - const cleanHostname = hostname.split(':')[0] // Remove port if present - const parts = cleanHostname.split('.') - if (isProduction) { - // En producción: verificar si hay un subdominio (ej: tienda.fasttify.com) - if (parts.length > 2 && cleanHostname.endsWith('fasttify.com')) { - return parts[0] - } - } else { - // En desarrollo: usar el formato subdominio.localhost:3000 - if (parts.length > 1 && cleanHostname.endsWith('localhost')) { - return parts[0] - } - } - return '' - } + const extractSubdomain = (hostname: string): string => { + const cleanHostname = hostname.split(':')[0].toLowerCase() + const parts = cleanHostname.split('.') + + // Check for subdomain pattern + const expectedDomain = isProduction ? 'fasttify.com' : 'localhost' + const expectedParts = isProduction ? 3 : 2 // subdomain.fasttify.com vs subdomain.localhost + + if (parts.length >= expectedParts && cleanHostname.endsWith(expectedDomain)) { + const subdomain = parts[0] + // Return subdomain if it's not www + return subdomain === 'www' ? '' : subdomain + } + + return '' + }app/[store]/page.tsx (2)
6-8: Simplify the store parameter extraction.The double casting and undefined fallback is unnecessary since
params.storewill already bestring | string[] | undefined.- const params = useParams() - const store = (params.store as string) || undefined + const params = useParams() + const store = params.store as string
9-11: Enhance the error message for better UX.Consider providing a more helpful error message when the store is not found.
if (!store) { - return <div>No se encontró la tienda</div> + return ( + <div className="flex flex-col items-center justify-center min-h-screen"> + <h1 className="text-2xl font-bold mb-4">Tienda no encontrada</h1> + <p className="text-gray-600">La tienda que buscas no existe o ha sido eliminada.</p> + </div> + ) }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
app/[store]/page.tsx(1 hunks)middleware.ts(2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: Aplicar Prettier
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Ejecutar pruebas unitarias
🔇 Additional comments (4)
middleware.ts (3)
44-44: Fix the function call to match the updated signature.The function call needs to be updated if you apply the suggested refactor above.
98-98: LGTM! The matcher simplification is appropriate.The new matcher pattern correctly excludes API routes, static assets, images, and favicon while matching all other routes. This is cleaner than the previous explicit path list.
47-60:Details
❌ Incorrect review comment
Consider adding subdomain validation.
The current implementation accepts any subdomain without validation. Consider adding a check to ensure the subdomain exists before rewriting URLs.
Consider adding validation like:
if (subdomain && subdomain !== 'www') { + // TODO: Add validation to check if the store/subdomain exists + // This could prevent invalid subdomain access const url = request.nextUrl.clone()
🏁 Script executed:
#!/bin/bash # Description: Check if there's any store validation logic in the codebase # Search for store validation or existence checks rg -A 5 'validateStore|checkStore|storeExists|getStore' --type ts --type tsxLength of output: 106
Refining the search to locate any dynamic route handlers and store‐lookup logic:
🏁 Script executed:
#!/bin/bash # List any files with dynamic segments (e.g., [subdomain], [store]) in their names echo "=== Dynamic route files ===" find . -type f | grep '\[[^]]*\]' | grep -E '\.ts(x)?$' || echo "No dynamic route files found" # Search for store lookup or validation functions echo "=== Store lookup / validation functions ===" rg -Hn "getStore|storeExists|checkStore|validateStore" || echo "None found" # Search for Next.js notFound() calls (indicating page‐level 404 handling) echo "=== notFound() usage ===" rg -Hn "notFound" || echo "None found"Length of output: 13828
Middleware rewrites are safe: store validation happens at page level
The dynamic store page (
app/[store]/page.tsx) fetches store data and invokesnotFound()when the slug doesn’t exist—your custom 404 is rendered viaapp/[...not_found]/page.tsx. As a result, adding a subdomain existence check in the middleware is optional, not required for correctness.Relevant locations:
app/[store]/page.tsx(calls your store‐data API andnotFound()on missing stores)app/[...not_found]/page.tsx(renders the 404 UI)If you still want to short-circuit invalid subdomains at the edge, you could call your
/check-store-domainLambda API in the middleware, but this isn’t necessary with the existing fallback.Likely an incorrect or invalid review comment.
app/[store]/page.tsx (1)
1-1:Details
❌ Incorrect review comment
Consider if this component needs to be a client component.
The component doesn't use any client-side features like state, effects, or browser APIs. It could be a server component for better performance.
🌐 Web query:
Can Next.js useParams hook be used in server components in the App Router?💡 Result:
No, the
useParamshook in Next.js cannot be used in server components when using the App Router. TheuseParamshook is a React hook meant to be used in client components because it relies on React's client-side hooks and context to access route parameters.In Next.js with the App Router, server components do not support client-only hooks like
useParams. Instead, in server components, you retrieve route parameters directly from the props passed to the component or via theparamsargument in the page or layout component.For example, in a server component file inside a dynamic route like
app/[id]/page.js, you can accessparamslike this:export default function Page({ params }) { const { id } = params; // Use `id` here in the server component return <div>{id}</div>; }If you need to use
useParams, you would have to mark the component as a client component by adding'use client'at the top and then use it inside that client component. However, this pushes the rendering to the client side.So, in summary:
- Server components: use
paramsfrom props or function arguments.- Client components: use
useParamshook.Let me know if you'd like an example!
🏁 Script executed:
#!/bin/bash # Search for any use of the useParams hook in the repository rg "useParams" -nLength of output: 3720
‘use client’ is required here:
useParamsis client-only
useParamsfromnext/navigationcannot be used in server components. This page imports and callsuseParams, so it must remain a client component.• app/[store]/page.tsx (lines 1–6):
'use client' -import { useParams } from 'next/navigation' +// `use client` is needed because useParams() is a client-only hook const params = useParams()Likely an incorrect or invalid review comment.
| const isValidHostname = allowedDomains.some( | ||
| domain => hostname === domain || hostname.endsWith(`.${domain}`) | ||
| ) | ||
|
|
||
| // Si el hostname es válido, redirigir a la landing | ||
|
|
||
| if (isValidHostname) { | ||
| return NextResponse.redirect(new URL('/', request.url)) | ||
| } |
There was a problem hiding this comment.
Fix the inverted domain validation logic.
The current logic redirects to the root landing page when the hostname matches the main domain (fasttify.com or localhost), which appears to be inverted. This would prevent users from accessing the main site and only allow access via subdomains.
- const isValidHostname = allowedDomains.some(
- domain => hostname === domain || hostname.endsWith(`.${domain}`)
- )
-
- // Si el hostname es válido, redirigir a la landing
-
- if (isValidHostname) {
- return NextResponse.redirect(new URL('/', request.url))
- }
+ // Check if hostname is main domain (without subdomain)
+ const isMainDomain = allowedDomains.some(domain => {
+ const cleanHostname = hostname.split(':')[0]
+ return cleanHostname === domain || cleanHostname === `www.${domain}`
+ })
+
+ // If accessing main domain, continue with normal routing
+ if (isMainDomain) {
+ return NextResponse.next()
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const isValidHostname = allowedDomains.some( | |
| domain => hostname === domain || hostname.endsWith(`.${domain}`) | |
| ) | |
| // Si el hostname es válido, redirigir a la landing | |
| if (isValidHostname) { | |
| return NextResponse.redirect(new URL('/', request.url)) | |
| } | |
| // Check if hostname is main domain (without subdomain) | |
| const isMainDomain = allowedDomains.some(domain => { | |
| const cleanHostname = hostname.split(':')[0] | |
| return cleanHostname === domain || cleanHostname === `www.${domain}` | |
| }) | |
| // If accessing main domain, continue with normal routing | |
| if (isMainDomain) { | |
| return NextResponse.next() | |
| } |
🤖 Prompt for AI Agents
In middleware.ts around lines 17 to 25, the domain validation logic is inverted,
causing redirection to the root landing page when the hostname matches the main
domain instead of subdomains. To fix this, reverse the condition so that
redirection happens only when the hostname is not the main domain or localhost,
allowing access to the main site and restricting subdomains as intended.
| return ( | ||
| <div> | ||
| <h1>Tienda: {store}</h1> | ||
| </div> | ||
| ) |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add proper page structure and metadata.
The current implementation is minimal. Consider adding proper HTML structure, metadata, and actual store content.
Would you like me to help implement a more complete store page component with:
- Proper page title and metadata
- Store details fetching
- Loading states
- Error boundaries
- SEO optimization
🤖 Prompt for AI Agents
In app/[store]/page.tsx around lines 13 to 17, the current page component lacks
proper HTML structure, metadata, and meaningful store content. Enhance the
component by adding a head section with a descriptive page title and metadata
for SEO. Implement logic to fetch store details dynamically, include loading and
error states to handle asynchronous data fetching gracefully, and structure the
page content to display store information clearly. This will improve user
experience and SEO performance.
Summary by CodeRabbit
New Features
Bug Fixes
Refactor