nuxt-i18n-micro icon indicating copy to clipboard operation
nuxt-i18n-micro copied to clipboard

Catch-all route `[...path].vue` intercepts static files like sitemap-en.xml

Open Met96 opened this issue 6 months ago • 2 comments

Bug Description

When using nuxt-i18n-micro with a catch-all page [...path].vue, static files like sitemap-en.xml are being intercepted by the catch-all route instead of being handled directly by the server. This causes the locale detection logic to trigger unnecessarily and leads to errors or incorrect behavior.

Expected Behavior

Static files such as sitemap-en.xml, or other non-localized resources should bypass the i18n routing system and be served directly by the server without triggering the catch-all page.

Current Behavior

When accessing http://localhost:3000/sitemap-en.xml, the request is captured by the [...path].vue page, which then attempts to process it through the i18n locale detection system, causing errors or unwanted redirects to error pages.

Reproduction Steps

  1. Setup a Nuxt 3 project with nuxt-i18n-micro
  2. Create a catch-all page at pages/[...path].vue
  3. Try to access a static file like http://localhost:3000/sitemap-en.xml
  4. Observe that the catch-all page is triggered instead of serving the file directly

Configuration

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['nuxt-i18n-micro'],
  
  i18n: {
    locales: [
      { code: 'en', iso: 'en-US' },
      { code: 'it', iso: 'it-IT' }
    ],
    defaultLocale: 'en'
  }
})
<!-- pages/[...path].vue -->
<template>
  <div>Catch-all page content</div>
</template>

<script setup>
// Catch-all logic here
</script>

Suggested Solutions

  1. Module Enhancement: Add a configuration option to exclude specific patterns from i18n routing:

    i18n: {
      excludePatterns: [
        /^\/sitemap.*\.xml$/,
        /^\/robots\.txt$/,
        /\.(xml|txt|ico|json)$/
      ]
    }
    
  2. Built-in Static File Detection: The module could automatically detect and exclude common static file patterns.

  3. Route Priority: Ensure that static files and server routes have higher priority than the i18n catch-all routing.

Environment

  • Nuxt: 4.x
  • nuxt-i18n-micro: v1.93.0
  • Node.js: v24
  • Package Manager: bun

Additional Context

This issue is particularly problematic for SEO-related files (sitemaps, robots.txt) and API endpoints that should not be processed through the i18n system. The current workarounds involve using route rules or middleware, but a native solution within the module would be more elegant and reliable.

Attempted Workarounds (All Failed)

I've tried multiple approaches to resolve this issue, but none of them work effectively:

1. Route Rules (Doesn't Work)

// nuxt.config.ts - FAILED ATTEMPT
export default defineNuxtConfig({
  routeRules: {
    '/sitemap*.xml': { 
      headers: { 'content-type': 'application/xml' },
      prerender: true 
    },
    '/sitemap-*.xml': { proxy: '/api/sitemap' }
  }
})

Result: The catch-all route still intercepts the request before route rules can take effect.

2. Nitro Configuration Override (Doesn't Work)

// nuxt.config.ts - FAILED ATTEMPT
export default defineNuxtConfig({
  nitro: {
    prerender: {
      ignore: ['/sitemap*.xml']
    },
    routeRules: {
      '/sitemap-*.xml': { headers: { 'content-type': 'application/xml' } }
    }
  }
})

Result: Still gets intercepted by the i18n routing system.

3. Global Middleware (Doesn't Work)

// middleware/static-files.global.ts - FAILED ATTEMPT
export default defineNuxtRouteMiddleware((to) => {
  const staticFilePatterns = [
    /^\/sitemap.*\.xml$/,
    /^\/robots\.txt$/,
    /\.(xml|txt|ico)$/
  ]
  
  const isStaticFile = staticFilePatterns.some(pattern => 
    pattern.test(to.path)
  )
  
  if (isStaticFile) {
    // Tried various approaches: return, navigateTo, throw createError
    return // This doesn't prevent the catch-all from executing
  }
})

Result: Middleware runs but doesn't prevent the catch-all route from being processed.

4. Direct Check in Catch-all Page (Doesn't Work)

<!-- pages/[...path].vue - FAILED ATTEMPT -->
<script setup>
const route = useRoute()

// Check for static files at the very beginning
const excludePatterns = [
  /^\/sitemap.*\.xml$/,
  /^\/robots\.txt$/,
  /\.(xml|txt|ico)$/
]

const shouldExclude = excludePatterns.some(pattern => 
  pattern.test(route.path)
)

if (shouldExclude) {
  // Tried: throw createError, navigateTo, return
  throw createError({
    statusCode: 404,
    statusMessage: 'Static file - should not reach catch-all'
  })
}

// Rest of the i18n logic...
</script>

Result: By the time this check runs, the i18n routing has already been processed, and throwing an error just leads to the error page.

Root Cause Analysis

The issue appears to be that nuxt-i18n-micro's routing system operates at a lower level than these workarounds, intercepting requests before:

  • Route rules can be applied
  • Middleware can redirect/abort the request
  • The catch-all page logic can prevent processing

This suggests the module's regex-based dynamic routing system has higher priority than standard Nuxt routing mechanisms, making it impossible to bypass through conventional means.

Met96 avatar Sep 24 '25 20:09 Met96

Hi, I’ve added a new feature in version v1.97.0 - Excluding Static Files. You can read more here: docs

In theory, now you can exclude any routes.

s00d avatar Sep 25 '25 15:09 s00d

Thank you so much!

Met96 avatar Sep 25 '25 15:09 Met96