Skip to content

definePageMeta is ignored when parent directory contains .js #32663

@murisceman

Description

@murisceman

Environment

  • Operating System: Darwin
  • Node Version: v22.2.0
  • Nuxt Version: 4.0.0
  • CLI Version: 3.26.2
  • Nitro Version: 2.12.0
  • Package Manager: pnpm@9.7.0
  • Builder: -
  • User Config: compatibilityDate, devtools, extends, nitro
  • Runtime Modules: -
  • Build Modules: -

Reproduction

URL: https://stackblitz.com/edit/github-6rf3erfy?file=pages%2Ffoo.js%2Fbar.vue

  1. npm run dev
  2. Visit /foo.js/bar
  3. Check console logs
    • Expected: 1 middleware, 2, 3 {}
    • Received: 2, 3 {}
  4. Edit pages/foo.js/bar.vue
    • Remove generic type from ref at line 12
      • [-] const data = ref<Record<string, any>>({});
      • [+] const data = ref({});
  5. Save and refresh /foo.js/bar
  6. Console logs now display correctly

Describe the bug

When a Vue page component uses ⁠<script setup lang="ts">, its ⁠definePageMeta macro is ignored by the parser under a specific set of conditions:

  1. The component's parent directory name includes ⁠.js (e.g., ⁠pages/foo.js/).
  2. The script contains TypeScript syntax, such as a generic type argument on a ⁠ref.

This prevents page-specific metadata, like middleware, from being applied.

The issue appears to be that the parser incorrectly infers the file type as JavaScript instead of TypeScript due to the ⁠.js in the file path, causing it to fail when it encounters TS-specific syntax.

Additional context

The issue likely occurs in the parseAndWalk function from oxc-walker. See here:

parseAndWalk(script.code, absolutePath.replace(/\.\w+$/, '.' + script.loader), (node) => {

When the absolutePath contains a .js extension, the parser incorrectly assumes that our bar.vue component doesn't use TypeScript. As a result, it only walks through a single Program node instead of processing the complete setup script.


Impact and importance

This bug may seem like an edge case, but it has critical implications for projects using ⁠pnpm as a package manager. ⁠pnpm creates flattened dependency trees where package paths in ⁠node_modules are symlinks to a central store, often resulting in directory names that include package names and versions.

For example, a dependency path might look like this: ⁠.../node_modules/.pnpm/pruvious@4.0.0_fuse.js@7.1.0_.../

If a Nuxt module/layer that provides its own pages (e.g., an admin panel or a CMS) has a dependency like ⁠fuse.js, its directory path within ⁠node_modules will contain ⁠.js. Consequently, when Nuxt scans for pages, it will fail to correctly parse the metadata for all pages provided by that module/layer, leading to missing middleware.

Logs

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions