-
-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
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
npm run dev
- Visit
/foo.js/bar
- Check console logs
- Expected:
1 middleware
,2
,3 {}
- Received:
2
,3 {}
- Expected:
- Edit
pages/foo.js/bar.vue
- Remove generic type from
ref
at line12
- [-]
const data = ref<Record<string, any>>({});
- [+]
const data = ref({});
- [-]
- Remove generic type from
- Save and refresh
/foo.js/bar
- 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:
- The component's parent directory name includes
.js
(e.g., pages/foo.js/
). - 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:
nuxt/packages/nuxt/src/pages/utils.ts
Line 252 in ef9b937
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.