Skip to content

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

@Met96

Description

@Met96

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions