diff --git a/packages/devtools/package.json b/packages/devtools/package.json index 8b9629a57d..b0cc97fa0b 100644 --- a/packages/devtools/package.json +++ b/packages/devtools/package.json @@ -29,7 +29,8 @@ "dev:playground": "pnpm build && nuxi dev playground", "dev:prepare": "pnpm run stub && nuxi prepare client", "prepare": "tsx scripts/prepare.ts", - "prepack": "turbo run build --filter=." + "prepack": "turbo run build --filter=.", + "test": "vitest run" }, "peerDependencies": { "@nuxt/devtools-assets": "workspace:*", @@ -64,15 +65,19 @@ "destr": "catalog:prod", "devframe": "catalog:prod", "error-stack-parser-es": "catalog:frontend", + "escape-string-regexp": "catalog:prod", "fast-npm-meta": "catalog:prod", "hookable": "catalog:frontend", "image-meta": "catalog:prod", "local-pkg": "catalog:prod", + "magic-string": "catalog:prod", "magicast": "catalog:prod", + "mlly": "catalog:prod", "pathe": "catalog:frontend", "perfect-debounce": "catalog:frontend", "pkg-types": "catalog:prod", "tinyglobby": "catalog:prod", + "unplugin": "catalog:prod", "unstorage": "catalog:prod", "verkit": "catalog:prod", "vite-plugin-vue-tracer": "catalog:prod" @@ -88,6 +93,7 @@ "@iconify-json/tabler": "catalog:icons", "@nuxt/devtools-assets": "workspace:*", "@nuxt/kit": "catalog:prod", + "@nuxt/schema": "catalog:types", "@parcel/watcher": "catalog:buildtools", "@types/markdown-it-link-attributes": "catalog:types", "@unhead/schema": "catalog:types", @@ -128,6 +134,7 @@ "vis-data": "catalog:frontend", "vis-network": "catalog:frontend", "vite-plugin-inspect": "catalog:prod", + "vitest": "catalog:cli", "vue-tsc": "catalog:cli", "vue-virtual-scroller": "catalog:frontend" } diff --git a/packages/devtools/src/integrations/timeline-wrap.ts b/packages/devtools/src/integrations/timeline-wrap.ts new file mode 100644 index 0000000000..67c93f798d --- /dev/null +++ b/packages/devtools/src/integrations/timeline-wrap.ts @@ -0,0 +1,82 @@ +import type { SourceMap } from 'magic-string' +import MagicString from 'magic-string' +import { findStaticImports, parseStaticImport } from 'mlly' + +export const HELPER_NAME = '__nuxtTimelineWrap' +export const HELPER_NAME_RE = /__nuxtTimelineWrap/ +const RENAME_PREFIX = '_$__' + +export const TRANSFORM_ID_INCLUDE: RegExp[] = [ + /^[^?]*\.(?:m?[jt]sx?|vue)(?:$|\?)/, +] +export const TRANSFORM_ID_EXCLUDE: RegExp[] = [ + /^\0/, + /[\\/]node_modules[\\/]/, + /[?&]macro=true/, + /[?&]type=(?:style|template|custom)\b/, +] + +export function wrapTimelineImports( + code: string, + isWrappable: (source: string, name: string) => boolean, + helperPath: string, +): { code: string, map: SourceMap } | undefined { + if (!code.includes('import') || code.includes(HELPER_NAME)) + return + + const staticImports = findStaticImports(code) + if (!staticImports.length) + return + + const s = new MagicString(code) + const wrappers: string[] = [] + + for (const imp of staticImports) { + const { specifier, defaultImport, namespacedImport, namedImports } = parseStaticImport(imp) + let wrapped = false + + // returns the local binding for an imported name, renamed when it gets wrapped + const bind = (name: string, local: string): string => { + if (!isWrappable(specifier, name)) + return local + wrapped = true + // a default import has no meaningful exported name, record it under its local name + wrappers.push(`const ${local} = ${HELPER_NAME}(${JSON.stringify(name === 'default' ? local : name)}, ${RENAME_PREFIX}${local});`) + return RENAME_PREFIX + local + } + + const clause: string[] = [] + if (defaultImport) + clause.push(bind('default', defaultImport)) + if (namespacedImport) + clause.push(`* as ${namespacedImport}`) + const named = Object.entries(namedImports ?? {}).map(([name, local]) => { + const bound = bind(name, local) + return name === bound ? name : `${name} as ${bound}` + }) + + if (named.length) + clause.push(`{ ${named.join(', ')} }`) + + if (!wrapped) + continue + + // rebuild only the clause between `import` and `from`, keeping the specifier untouched + const clauseStart = imp.start + imp.code.indexOf(imp.imports) + s.overwrite(clauseStart, clauseStart + imp.imports.length, `${clause.join(', ')} `) + } + + if (!wrappers.length) + return + + s.prepend([ + `import { ${HELPER_NAME} } from ${JSON.stringify(helperPath)};`, + ...wrappers, + '', + ].join('\n')) + + return { + code: s.toString(), + map: s.generateMap({ hires: 'boundary' }), + } +} diff --git a/packages/devtools/src/integrations/timeline.ts b/packages/devtools/src/integrations/timeline.ts index 0cd2ef19c0..a4eaab4e21 100644 --- a/packages/devtools/src/integrations/timeline.ts +++ b/packages/devtools/src/integrations/timeline.ts @@ -1,10 +1,16 @@ +import type { NuxtHooks, NuxtOptions } from '@nuxt/schema' import type { Import } from 'unimport' import type { NuxtDevtoolsServerContext } from '../types' +import { addBuildPlugin } from '@nuxt/kit' +import escapeRE from 'escape-string-regexp' import { resolve } from 'pathe' -import { isGreaterOrEqual } from 'verkit' +import { createUnplugin } from 'unplugin' import { runtimeDir } from '../dirs' +import { HELPER_NAME_RE, TRANSFORM_ID_EXCLUDE, TRANSFORM_ID_INCLUDE, wrapTimelineImports } from './timeline-wrap' const DEFINE_UPPER_RE = /^define[A-Z]/ +const RUNTIME_DIR_RE = new RegExp(`^${escapeRE(runtimeDir)}`) +const IMPORT_RE = /\bimport\b/ export function setup({ nuxt, options }: NuxtDevtoolsServerContext) { const helperPath = resolve(runtimeDir, 'function-metrics-helpers') @@ -34,50 +40,100 @@ export function setup({ nuxt, options }: NuxtDevtoolsServerContext) { return true } - nuxt.hook('imports:context', (unimport) => { - const ctx = unimport.getInternalContext() + let unimport: Parameters[0] | undefined + nuxt.hook('imports:context', (ctx) => { + unimport = ctx + }) + + // wrappable auto-imports keyed by `${source}\0${name}`, cached until the import list changes + const wrappableCache = new WeakMap>>() + const resolvedFrom = new Map>() - if (!ctx.version || !isGreaterOrEqual(ctx.version, '3.1.0')) - throw new Error(`[Nuxt DevTools] The timeline feature requires \`unimport\` >= v3.1.0, but got \`${ctx.version || '(unknown)'}\`. Please upgrade using \`nuxi upgrade --force\`.`) + async function getWrappable(): Promise> { + if (!unimport) + return new Map() + const imports = await unimport.getImports() + let cached = wrappableCache.get(imports) + if (!cached) { + cached = buildWrappable(imports) + wrappableCache.set(imports, cached) + } + return cached + } - ctx.addons.push( - { - injectImportsResolved(imports, _code, id) { - if (id?.includes('?macro=true')) - return - return imports.map((i) => { - if (!filter(i)) - return i + async function buildWrappable(imports: Import[]): Promise> { + const map = new Map() + // never wrap keyed-function factory macros (`createUseFetch`, etc.) + // the option exists since Nuxt 4.4 and is not yet part of the schema types we build against (+ we need it as optional for backwards compat) + const { keyedComposableFactories } = nuxt.options.optimization as NuxtOptions['optimization'] & { + keyedComposableFactories?: { name: string }[] + } + const factoryNames = new Set(keyedComposableFactories?.map(f => f.name) ?? []) + const ctx = unimport?.getInternalContext() - const name = i.as || i.name + // group by source so that each unique `from` is only resolved once + const bySource = new Map() + for (const i of imports) { + if (!filter(i) || factoryNames.has(i.name)) + continue + map.set(`${i.from}\0${i.name}`, i) + const group = bySource.get(i.from) + if (group) + group.push(i) + else + bySource.set(i.from, [i]) + } - return { - ...i, - meta: { - wrapperOriginalAs: name, - }, - as: `_$__${name}`, - } - }) - }, - injectImportsStringified(str, imports, s, id) { - if (id?.includes('?macro=true')) - return - const code = s.toString() - const injected = imports.filter(i => i.meta?.wrapperOriginalAs) - if (injected.length) { - const result = [ - str, - code.includes('__nuxtTimelineWrap') - ? '' - : `import { __nuxtTimelineWrap } from ${JSON.stringify(helperPath)}`, - ...injected.map(i => `const ${i.meta!.wrapperOriginalAs} = __nuxtTimelineWrap(${JSON.stringify(i.name)}, ${i.as})`), - '', - ].join(';') - return result - } + if (!ctx?.resolveId) + return map + + // unimport injects imports with the resolved specifier, which may differ from `i.from` + await Promise.all(Array.from(bySource, async ([from, items]) => { + let resolving = resolvedFrom.get(from) + if (!resolving) { + resolving = Promise.resolve(ctx.resolveId(from)).then(r => r || undefined, () => undefined) + resolvedFrom.set(from, resolving) + } + const resolved = await resolving + if (resolved && resolved !== from) { + for (const i of items) + map.set(`${resolved}\0${i.name}`, i) + } + })) + return map + } + + // the wrapping must happen AFTER Nuxt's key injection and keyed function factory macro rewriting + + // Nuxt registers these plugins in the `build:before` hook during core module setup, so we register ours + // from `modules:done` to be queued after them + nuxt.hook('modules:done', () => { + nuxt.hook('build:before', () => { + addBuildPlugin(createUnplugin(() => ({ + name: 'nuxt:devtools:timeline-function-wrap', + enforce: 'post', + transform: { + filter: { + id: { + include: TRANSFORM_ID_INCLUDE, + exclude: [ + ...TRANSFORM_ID_EXCLUDE, + RUNTIME_DIR_RE, + ], + }, + code: { + include: IMPORT_RE, + exclude: HELPER_NAME_RE, + }, + }, + async handler(code) { + const wrappable = await getWrappable() + if (!wrappable.size) + return + return wrapTimelineImports(code, (source, name) => wrappable.has(`${source}\0${name}`), helperPath) + }, }, - }, - ) + }))) + }) }) } diff --git a/packages/devtools/test/timeline-wrap.test.ts b/packages/devtools/test/timeline-wrap.test.ts new file mode 100644 index 0000000000..00e0d80369 --- /dev/null +++ b/packages/devtools/test/timeline-wrap.test.ts @@ -0,0 +1,149 @@ +import { describe, expect, it } from 'vitest' +import { TRANSFORM_ID_EXCLUDE, TRANSFORM_ID_INCLUDE, wrapTimelineImports } from '../src/integrations/timeline-wrap' + +function shouldTransform(id: string): boolean { + return TRANSFORM_ID_INCLUDE.some(re => re.test(id)) && !TRANSFORM_ID_EXCLUDE.some(re => re.test(id)) +} + +const HELPER_PATH = '/runtime/function-metrics-helpers' + +function wrap(code: string, wrappable: [source: string, name: string][]) { + return wrapTimelineImports( + code, + (source, name) => wrappable.some(([s, n]) => s === source && n === name), + HELPER_PATH, + )?.code +} + +describe('wrapTimelineImports', () => { + it('wraps a bare named import and keeps call sites untouched', () => { + const result = wrap( + [ + `import { useState } from '#app/composables/state';`, + `const counter = useState(() => 0, '$key123' /* nuxt-injected */);`, + ].join('\n'), + [['#app/composables/state', 'useState']], + ) + expect(result).toMatchInlineSnapshot(` + "import { __nuxtTimelineWrap } from "/runtime/function-metrics-helpers"; + const useState = __nuxtTimelineWrap("useState", _$__useState); + import { useState as _$__useState } from '#app/composables/state'; + const counter = useState(() => 0, '$key123' /* nuxt-injected */);" + `) + }) + + it('wraps an aliased import under its local name', () => { + const result = wrap( + `import { useState as myState } from '#app/composables/state';`, + [['#app/composables/state', 'useState']], + ) + expect(result).toMatchInlineSnapshot(` + "import { __nuxtTimelineWrap } from "/runtime/function-metrics-helpers"; + const myState = __nuxtTimelineWrap("useState", _$__myState); + import { useState as _$__myState } from '#app/composables/state';" + `) + }) + + it('only wraps matched specifiers within an import statement', () => { + const result = wrap( + `import { ref, useState, useStateFoo } from '#app/composables/state';`, + [['#app/composables/state', 'useState']], + ) + expect(result).toMatchInlineSnapshot(` + "import { __nuxtTimelineWrap } from "/runtime/function-metrics-helpers"; + const useState = __nuxtTimelineWrap("useState", _$__useState); + import { ref, useState as _$__useState, useStateFoo } from '#app/composables/state';" + `) + }) + + it('wraps imports from multiple sources with a single helper import', () => { + const result = wrap( + [ + `import { useState } from '#app/composables/state';`, + `import { useHead } from '@unhead/vue';`, + ].join('\n'), + [ + ['#app/composables/state', 'useState'], + ['@unhead/vue', 'useHead'], + ], + ) + expect(result).toMatchInlineSnapshot(` + "import { __nuxtTimelineWrap } from "/runtime/function-metrics-helpers"; + const useState = __nuxtTimelineWrap("useState", _$__useState); + const useHead = __nuxtTimelineWrap("useHead", _$__useHead); + import { useState as _$__useState } from '#app/composables/state'; + import { useHead as _$__useHead } from '@unhead/vue';" + `) + }) + + it('keeps default imports untouched while wrapping named ones', () => { + const result = wrap( + `import myDefault, { useState } from '#app/composables/state';`, + [['#app/composables/state', 'useState']], + ) + expect(result).toMatchInlineSnapshot(` + "import { __nuxtTimelineWrap } from "/runtime/function-metrics-helpers"; + const useState = __nuxtTimelineWrap("useState", _$__useState); + import myDefault, { useState as _$__useState } from '#app/composables/state';" + `) + }) + + it('wraps a default import under its local name', () => { + const result = wrap( + `import myComposable from '~/composables/myComposable';`, + [['~/composables/myComposable', 'default']], + ) + expect(result).toMatchInlineSnapshot(` + "import { __nuxtTimelineWrap } from "/runtime/function-metrics-helpers"; + const myComposable = __nuxtTimelineWrap("myComposable", _$__myComposable); + import _$__myComposable from '~/composables/myComposable';" + `) + }) + + it('ignores imports from other sources', () => { + expect(wrap( + `import { useState } from '@vueuse/core';`, + [['#app/composables/state', 'useState']], + )).toBeUndefined() + }) + + it('ignores re-exports', () => { + expect(wrap( + `export { useState } from '#app/composables/state';`, + [['#app/composables/state', 'useState']], + )).toBeUndefined() + }) + + it('ignores code without imports', () => { + expect(wrap('const useState = () => {}', [['#app/composables/state', 'useState']])).toBeUndefined() + }) + + it('is idempotent', () => { + const code = [ + `import { useState } from '#app/composables/state';`, + `useState();`, + ].join('\n') + const wrappable: [string, string][] = [['#app/composables/state', 'useState']] + const once = wrap(code, wrappable) + expect(once).toBeDefined() + expect(wrap(once!, wrappable)).toBeUndefined() + }) +}) + +describe('shouldTransform', () => { + it.each([ + ['/app/pages/index.vue', true], + ['/app/pages/index.vue?vue&type=script&setup=true&lang.ts', true], + ['/app/composables/foo.ts', true], + ['/app/utils/bar.mjs', true], + ['/app/pages/index.vue?vue&type=style&index=0&lang.css', false], + ['/app/composables/foo.ts?macro=true', false], + ['/node_modules/some-lib/dist/index.mjs', false], + ['\0virtual:my-module', false], + ['/app/assets/style.css', false], + // a code extension in the query string must not match a non-code pathname + ['/app/assets/icon.svg?import&fallback=x.js', false], + ])('%s -> %s', (id, expected) => { + expect(shouldTransform(id)).toBe(expected) + }) +}) diff --git a/packages/devtools/vitest.config.ts b/packages/devtools/vitest.config.ts new file mode 100644 index 0000000000..3e4279747d --- /dev/null +++ b/packages/devtools/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + include: ['test/**/*.test.ts'], + }, +}) diff --git a/playgrounds/tab-timeline/components/GlobalNav.vue b/playgrounds/tab-timeline/components/GlobalNav.vue index e40e8d8d9c..d8698133d2 100644 --- a/playgrounds/tab-timeline/components/GlobalNav.vue +++ b/playgrounds/tab-timeline/components/GlobalNav.vue @@ -26,6 +26,9 @@ /error + + /keyed + diff --git a/playgrounds/tab-timeline/nuxt.config.ts b/playgrounds/tab-timeline/nuxt.config.ts index bc88d51a27..b3d871c670 100644 --- a/playgrounds/tab-timeline/nuxt.config.ts +++ b/playgrounds/tab-timeline/nuxt.config.ts @@ -11,7 +11,6 @@ export default defineNuxtConfig({ clearScreen: false, }, devtools: { - enabled: false, experimental: { timeline: true, }, diff --git a/playgrounds/tab-timeline/pages/keyed.vue b/playgrounds/tab-timeline/pages/keyed.vue new file mode 100644 index 0000000000..9d2014346e --- /dev/null +++ b/playgrounds/tab-timeline/pages/keyed.vue @@ -0,0 +1,20 @@ + + + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6ee2acbf3f..3682f51628 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -263,6 +263,9 @@ catalogs: destr: specifier: ^2.0.5 version: 2.0.5 + escape-string-regexp: + specifier: ^5.0.0 + version: 5.0.0 fast-npm-meta: specifier: ^2.2.0 version: 2.2.0 @@ -272,9 +275,15 @@ catalogs: local-pkg: specifier: ^1.2.1 version: 1.2.1 + magic-string: + specifier: ^0.30.21 + version: 0.30.21 magicast: specifier: ^0.5.4 version: 0.5.4 + mlly: + specifier: ^1.8.1 + version: 1.8.2 nostics: specifier: ^1.2.0 version: 1.2.0 @@ -290,6 +299,9 @@ catalogs: tinyglobby: specifier: ^0.2.17 version: 0.2.17 + unplugin: + specifier: ^2.3.11 + version: 2.3.11 unstorage: specifier: ^1.17.5 version: 1.17.5 @@ -482,6 +494,9 @@ importers: error-stack-parser-es: specifier: catalog:frontend version: 2.0.1 + escape-string-regexp: + specifier: catalog:prod + version: 5.0.0 fast-npm-meta: specifier: catalog:prod version: 2.2.0 @@ -494,9 +509,15 @@ importers: local-pkg: specifier: catalog:prod version: 1.2.1 + magic-string: + specifier: catalog:prod + version: 0.30.21 magicast: specifier: catalog:prod version: 0.5.4 + mlly: + specifier: catalog:prod + version: 1.8.2 pathe: specifier: catalog:frontend version: 2.0.3 @@ -509,6 +530,9 @@ importers: tinyglobby: specifier: catalog:prod version: 0.2.17 + unplugin: + specifier: catalog:prod + version: 2.3.11 unstorage: specifier: catalog:prod version: 1.17.5(db0@0.3.4)(ioredis@5.11.1(supports-color@10.2.2)) @@ -551,7 +575,10 @@ importers: version: link:../devtools-assets '@nuxt/kit': specifier: catalog:prod - version: '@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@1.2.0)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)))' + version: '@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@0.30.21)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@2.3.11)' + '@nuxt/schema': + specifier: catalog:types + version: '@nuxt/schema-nightly@5.0.0-29755283.b4586ef2' '@parcel/watcher': specifier: catalog:buildtools version: 2.6.0 @@ -563,7 +590,7 @@ importers: version: 3.3.2 '@unocss/nuxt': specifier: catalog:buildtools - version: 66.8.0(esbuild@0.28.2)(magic-string@1.2.0)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(rollup@4.62.4)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)))(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)) + version: 66.8.0(esbuild@0.28.2)(magic-string@0.30.21)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(rollup@4.62.4)(unplugin@2.3.11)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)) '@unocss/preset-icons': specifier: catalog:buildtools version: 66.8.0 @@ -575,7 +602,7 @@ importers: version: 66.8.0 '@vueuse/nuxt': specifier: catalog:buildtools - version: 14.4.0(magic-string@1.2.0)(magicast@0.5.4)(nuxt-nightly@5.0.0-29755283.b4586ef2)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)))(vue@3.5.41(typescript@6.0.3)) + version: 14.4.0(magic-string@0.30.21)(magicast@0.5.4)(nuxt-nightly@5.0.0-29755283.b4586ef2)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@2.3.11)(vue@3.5.41(typescript@6.0.3)) cronstrue: specifier: catalog:frontend version: 3.24.0 @@ -587,7 +614,7 @@ importers: version: 1.1.1 floating-vue: specifier: catalog:frontend - version: 5.2.2(@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@1.2.0)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26))))(vue@3.5.41(typescript@6.0.3)) + version: 5.2.2(@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@0.30.21)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@2.3.11))(vue@3.5.41(typescript@6.0.3)) fuse.js: specifier: catalog:frontend version: 7.5.0 @@ -668,7 +695,10 @@ importers: version: 10.1.2(@egjs/hammerjs@2.0.17)(component-emitter@2.0.0)(keycharm@0.4.0)(uuid@14.0.1)(vis-data@8.0.5(uuid@14.0.1)(vis-util@6.0.2(@egjs/hammerjs@2.0.17)(component-emitter@2.0.0)))(vis-util@6.0.2(@egjs/hammerjs@2.0.17)(component-emitter@2.0.0)) vite-plugin-inspect: specifier: catalog:prod - version: 12.0.2(@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@1.2.0)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26))))(cac@7.0.0)(crossws@0.4.10(srvx@0.11.22))(srvx@0.11.22)(vite@8.2.2) + version: 12.0.2(@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@0.30.21)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@2.3.11))(cac@7.0.0)(crossws@0.4.10(srvx@0.11.22))(srvx@0.11.22)(vite@8.2.2) + vitest: + specifier: catalog:cli + version: 4.1.11(@types/node@26.2.0)(vite@8.2.2) vue-tsc: specifier: ^3.3.10 version: 3.3.10(typescript@6.0.3) @@ -1675,8 +1705,8 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@nuxt/cli-nightly@4.0.0-20260820-224244-a3dee96': - resolution: {integrity: sha512-tchjrNiusVwkT+gR/OxCclt/0p/G5/jEHx2bVRnG6h/xAyKRWUW+rJOOtGHOE0nGGE4jdllp2ggBx5ORM/qpLA==} + '@nuxt/cli-nightly@4.0.0-20260822-122548-4186332': + resolution: {integrity: sha512-HygGUs20LzwS8MDLOAHGHyJfJsKU8WE8hP1Sgo137umHzZv6FJ0ogRUTm+HWradFgv1KvzctNjRedhLoqjYyDA==} engines: {node: ^22.19.0 || ^24.11.0 || >=26.0.0} hasBin: true peerDependencies: @@ -8361,7 +8391,7 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 - '@nuxt/cli-nightly@4.0.0-20260820-224244-a3dee96(@nuxt/schema-nightly@5.0.0-29755283.b4586ef2)(jiti@2.7.0)(oxc-parser@0.131.0)(rolldown@1.2.4)': + '@nuxt/cli-nightly@4.0.0-20260822-122548-4186332(@nuxt/schema-nightly@5.0.0-29755283.b4586ef2)(jiti@2.7.0)(oxc-parser@0.131.0)(rolldown@1.2.4)': dependencies: '@clack/prompts': 1.7.0 args-tokenizer: 0.3.0 @@ -8390,7 +8420,7 @@ snapshots: oxc-parser: 0.131.0 rolldown: 1.2.4 - '@nuxt/cli-nightly@4.0.0-20260820-224244-a3dee96(@nuxt/schema-nightly@5.0.0-29755283.b4586ef2)(jiti@2.7.0)(oxc-parser@0.143.0)(rolldown@1.2.4)': + '@nuxt/cli-nightly@4.0.0-20260822-122548-4186332(@nuxt/schema-nightly@5.0.0-29755283.b4586ef2)(jiti@2.7.0)(oxc-parser@0.143.0)(rolldown@1.2.4)': dependencies: '@clack/prompts': 1.7.0 args-tokenizer: 0.3.0 @@ -8560,6 +8590,38 @@ snapshots: - vite - webpack + '@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@0.30.21)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@2.3.11)': + dependencies: + c12: 3.3.4(magicast@0.5.4) + consola: 3.4.2 + defu: 6.1.7 + destr: 2.0.5 + errx: 0.1.2 + exsolve: 1.1.1 + ignore: 7.0.6 + jiti: 2.7.0 + klona: 2.0.6 + mlly: 1.8.2 + nostics: 1.2.0 + nypm: 0.6.9 + ohash: 2.0.12 + pathe: 2.0.3 + pkg-types: 2.3.1 + rc9: 3.0.1 + scule: 1.3.0 + std-env: 4.2.0 + tinyglobby: 0.2.17 + ufo: 1.6.4 + unctx: 3.0.0(magic-string@0.30.21)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@2.3.11) + untyped: 2.0.0 + verkit: 0.3.2 + transitivePeerDependencies: + - magic-string + - magicast + - oxc-parser + - rolldown + - unplugin + '@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@1.2.0)(magicast@0.5.4)(oxc-parser@0.131.0)(rolldown@1.2.4)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)))': dependencies: c12: 3.3.4(magicast@0.5.4) @@ -8650,6 +8712,36 @@ snapshots: transitivePeerDependencies: - magicast + '@nuxt/kit@4.5.2(magic-string@0.30.21)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@2.3.11)': + dependencies: + c12: 3.3.4(magicast@0.5.4) + consola: 3.4.2 + defu: 6.1.7 + destr: 2.0.5 + errx: 0.1.2 + exsolve: 1.1.1 + ignore: 7.0.6 + jiti: 2.7.0 + klona: 2.0.6 + mlly: 1.8.2 + nostics: 1.2.0 + ohash: 2.0.12 + pathe: 2.0.3 + pkg-types: 2.3.1 + rc9: 3.0.1 + scule: 1.3.0 + tinyglobby: 0.2.17 + ufo: 1.6.4 + unctx: 3.0.0(magic-string@0.30.21)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@2.3.11) + untyped: 2.0.0 + verkit: 0.3.2 + transitivePeerDependencies: + - magic-string + - magicast + - oxc-parser + - rolldown + - unplugin + '@nuxt/kit@4.5.2(magic-string@1.2.0)(magicast@0.5.4)(oxc-parser@0.131.0)(rolldown@1.2.4)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)))': dependencies: c12: 3.3.4(magicast@0.5.4) @@ -9017,6 +9109,15 @@ snapshots: pkg-types: 2.3.1 std-env: 4.2.0 + '@nuxt/telemetry@2.8.0(@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@0.30.21)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@2.3.11))': + dependencies: + '@nuxt/kit': '@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@0.30.21)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@2.3.11)' + citty: 0.2.2 + consola: 3.4.2 + ofetch: 2.0.0-alpha.3 + rc9: 3.0.1 + std-env: 4.2.0 + '@nuxt/telemetry@2.8.0(@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@1.2.0)(magicast@0.5.4)(oxc-parser@0.131.0)(rolldown@1.2.4)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26))))': dependencies: '@nuxt/kit': '@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@1.2.0)(magicast@0.5.4)(oxc-parser@0.131.0)(rolldown@1.2.4)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)))' @@ -10179,6 +10280,39 @@ snapshots: gzip-size: 6.0.0 sirv: 3.0.2 + '@unocss/nuxt@66.8.0(esbuild@0.28.2)(magic-string@0.30.21)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(rollup@4.62.4)(unplugin@2.3.11)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26))': + dependencies: + '@nuxt/kit': 4.5.2(magic-string@0.30.21)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@2.3.11) + '@unocss/config': 66.8.0 + '@unocss/core': 66.8.0 + '@unocss/preset-attributify': 66.8.0 + '@unocss/preset-icons': 66.8.0 + '@unocss/preset-tagify': 66.8.0 + '@unocss/preset-typography': 66.8.0 + '@unocss/preset-web-fonts': 66.8.0 + '@unocss/preset-wind3': 66.8.0 + '@unocss/preset-wind4': 66.8.0 + '@unocss/reset': 66.8.0 + '@unocss/vite': 66.8.0(vite@8.2.2) + '@unocss/webpack': 66.8.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)) + unocss: 66.8.0(@unocss/webpack@66.8.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)))(vite@8.2.2) + transitivePeerDependencies: + - '@farmfe/core' + - '@rspack/core' + - '@unocss/astro' + - '@unocss/postcss' + - bun-types-no-globals + - esbuild + - magic-string + - magicast + - oxc-parser + - rolldown + - rollup + - unloader + - unplugin + - vite + - webpack + '@unocss/nuxt@66.8.0(esbuild@0.28.2)(magic-string@1.2.0)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(rollup@4.62.4)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)))(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26))': dependencies: '@nuxt/kit': 4.5.2(magic-string@1.2.0)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26))) @@ -10693,13 +10827,28 @@ snapshots: '@vueuse/metadata@14.4.0': {} + '@vueuse/nuxt@14.4.0(magic-string@0.30.21)(magicast@0.5.4)(nuxt-nightly@5.0.0-29755283.b4586ef2)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@2.3.11)(vue@3.5.41(typescript@6.0.3))': + dependencies: + '@nuxt/kit': 4.5.2(magic-string@0.30.21)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@2.3.11) + '@vueuse/core': 14.4.0(vue@3.5.41(typescript@6.0.3)) + '@vueuse/metadata': 14.4.0 + local-pkg: 1.2.1 + nuxt: nuxt-nightly@5.0.0-29755283.b4586ef2(@oxc-project/types@0.144.0)(@parcel/watcher@2.6.0)(@types/node@26.2.0)(@vitejs/devtools-kit@0.5.2(cac@7.0.0)(crossws@0.4.10(srvx@0.11.22))(srvx@0.11.22)(vite@8.2.2))(@vitejs/devtools@0.5.2)(@vue/compiler-sfc@3.5.41)(autoprefixer@10.5.4(postcss@8.5.26))(cssnano@7.1.9(postcss@8.5.26))(db0@0.3.4)(dotenv@17.4.2)(esbuild@0.28.2)(eslint@10.8.1(jiti@2.7.0)(supports-color@10.2.2))(giget@3.3.1)(ioredis@5.11.1(supports-color@10.2.2))(lightningcss@1.33.0)(magicast@0.5.4)(nuxt-nightly@5.0.0-29755283.b4586ef2)(optionator@0.9.4)(oxc-parser@0.143.0)(rollup-plugin-visualizer@7.1.1(rolldown@1.2.4)(rollup@4.62.4))(rollup@4.62.4)(terser@5.50.0)(tsx@4.23.12)(typescript@6.0.3)(vite@8.2.2)(vue-tsc@3.3.10(typescript@6.0.3))(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26))(yaml@2.9.0) + vue: 3.5.41(typescript@6.0.3) + transitivePeerDependencies: + - magic-string + - magicast + - oxc-parser + - rolldown + - unplugin + '@vueuse/nuxt@14.4.0(magic-string@1.2.0)(magicast@0.5.4)(nuxt-nightly@5.0.0-29755283.b4586ef2)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)))(vue@3.5.41(typescript@6.0.3))': dependencies: '@nuxt/kit': 4.5.2(magic-string@1.2.0)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26))) '@vueuse/core': 14.4.0(vue@3.5.41(typescript@6.0.3)) '@vueuse/metadata': 14.4.0 local-pkg: 1.2.1 - nuxt: nuxt-nightly@5.0.0-29755283.b4586ef2(@oxc-project/types@0.144.0)(@parcel/watcher@2.6.0)(@types/node@26.2.0)(@vitejs/devtools-kit@0.5.2(cac@7.0.0)(crossws@0.4.10(srvx@0.11.22))(srvx@0.11.22)(vite@8.2.2))(@vitejs/devtools@0.5.2)(@vue/compiler-sfc@3.5.41)(autoprefixer@10.5.4(postcss@8.5.26))(cssnano@7.1.9(postcss@8.5.26))(db0@0.3.4)(dotenv@17.4.2)(esbuild@0.28.2)(eslint@10.8.1(jiti@2.7.0)(supports-color@10.2.2))(giget@3.3.1)(ioredis@5.11.1(supports-color@10.2.2))(lightningcss@1.33.0)(magicast@0.5.4)(nuxt-nightly@5.0.0-29755283.b4586ef2)(optionator@0.9.4)(oxc-parser@0.143.0)(rollup-plugin-visualizer@7.1.1(rolldown@1.2.4)(rollup@4.62.4))(rollup@4.62.4)(terser@5.50.0)(tsx@4.23.12)(typescript@6.0.3)(vite@8.2.2)(vue-tsc@3.3.10(typescript@6.0.3))(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26))(yaml@2.9.0) + nuxt: nuxt-nightly@5.0.0-29755283.b4586ef2(@oxc-project/types@0.144.0)(@parcel/watcher@2.6.0)(@types/node@26.2.0)(@vitejs/devtools-kit@0.5.2(cac@7.0.0)(srvx@0.11.22)(vite@8.2.2))(@vitejs/devtools@0.5.2)(@vue/compiler-sfc@3.5.41)(autoprefixer@10.5.4(postcss@8.5.26))(cssnano@7.1.9(postcss@8.5.26))(db0@0.3.4)(dotenv@17.4.2)(esbuild@0.28.2)(eslint@10.8.1(jiti@2.7.0)(supports-color@10.2.2))(giget@3.3.1)(ioredis@5.11.1(supports-color@10.2.2))(lightningcss@1.33.0)(magicast@0.5.4)(nuxt-nightly@5.0.0-29755283.b4586ef2)(optionator@0.9.4)(oxc-parser@0.143.0)(rollup-plugin-visualizer@7.1.1(rolldown@1.2.4)(rollup@4.62.4))(rollup@4.62.4)(terser@5.50.0)(tsx@4.23.12)(typescript@6.0.3)(vite@8.2.2)(vue-tsc@3.3.10(typescript@6.0.3))(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26))(yaml@2.9.0) vue: 3.5.41(typescript@6.0.3) transitivePeerDependencies: - magic-string @@ -11919,13 +12068,13 @@ snapshots: flatted@3.4.4: {} - floating-vue@5.2.2(@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@1.2.0)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26))))(vue@3.5.41(typescript@6.0.3)): + floating-vue@5.2.2(@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@0.30.21)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@2.3.11))(vue@3.5.41(typescript@6.0.3)): dependencies: '@floating-ui/dom': 1.1.1 vue: 3.5.41(typescript@6.0.3) vue-resize: 2.0.0-alpha.1(vue@3.5.41(typescript@6.0.3)) optionalDependencies: - '@nuxt/kit': '@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@1.2.0)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)))' + '@nuxt/kit': '@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@0.30.21)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@2.3.11)' fnv1a-64@0.1.2: {} @@ -13395,12 +13544,12 @@ snapshots: nuxt-nightly@5.0.0-29755283.b4586ef2(@oxc-project/types@0.144.0)(@parcel/watcher@2.6.0)(@types/node@26.2.0)(@vitejs/devtools-kit@0.5.2(cac@7.0.0)(crossws@0.4.10(srvx@0.11.22))(srvx@0.11.22)(vite@8.2.2))(@vitejs/devtools@0.5.2)(@vue/compiler-sfc@3.5.41)(autoprefixer@10.5.4(postcss@8.5.26))(cssnano@7.1.9(postcss@8.5.26))(db0@0.3.4)(dotenv@17.4.2)(esbuild@0.28.2)(eslint@10.8.1(jiti@2.7.0)(supports-color@10.2.2))(giget@3.3.1)(ioredis@5.11.1(supports-color@10.2.2))(lightningcss@1.33.0)(magicast@0.5.4)(nuxt-nightly@5.0.0-29755283.b4586ef2)(optionator@0.9.4)(oxc-parser@0.143.0)(rollup-plugin-visualizer@7.1.1(rolldown@1.2.4)(rollup@4.62.4))(rollup@4.62.4)(terser@5.50.0)(tsx@4.23.12)(typescript@6.0.3)(vite@8.2.2)(vue-tsc@3.3.10(typescript@6.0.3))(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26))(yaml@2.9.0): dependencies: '@dxup/nuxt': 0.5.8(esbuild@0.28.2)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)) - '@nuxt/cli': '@nuxt/cli-nightly@4.0.0-20260820-224244-a3dee96(@nuxt/schema-nightly@5.0.0-29755283.b4586ef2)(jiti@2.7.0)(oxc-parser@0.143.0)(rolldown@1.2.4)' + '@nuxt/cli': '@nuxt/cli-nightly@4.0.0-20260822-122548-4186332(@nuxt/schema-nightly@5.0.0-29755283.b4586ef2)(jiti@2.7.0)(oxc-parser@0.143.0)(rolldown@1.2.4)' '@nuxt/devtools': link:packages/devtools '@nuxt/kit': '@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@1.2.0)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)))' '@nuxt/nitro-server': '@nuxt/nitro-server-nightly@5.0.0-29755283.b4586ef2(@oxc-project/types@0.144.0)(@vitejs/devtools-kit@0.5.2(cac@7.0.0)(crossws@0.4.10(srvx@0.11.22))(srvx@0.11.22)(vite@8.2.2))(chokidar@5.0.0)(db0@0.3.4)(dotenv@17.4.2)(esbuild@0.28.2)(giget@3.3.1)(ioredis@5.11.1(supports-color@10.2.2))(jiti@2.7.0)(lightningcss@1.33.0)(magicast@0.5.4)(nuxt-nightly@5.0.0-29755283.b4586ef2)(ofetch@2.0.0-alpha.3)(oxc-parser@0.143.0)(rolldown@1.2.4)(rollup@4.62.4)(typescript@6.0.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)))(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26))' '@nuxt/schema': '@nuxt/schema-nightly@5.0.0-29755283.b4586ef2' - '@nuxt/telemetry': 2.8.0(@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@1.2.0)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)))) + '@nuxt/telemetry': 2.8.0(@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@0.30.21)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@2.3.11)) '@nuxt/vite-builder': '@nuxt/vite-builder-nightly@5.0.0-29755283.b4586ef2(@types/node@26.2.0)(@vitejs/devtools@0.5.2)(autoprefixer@10.5.4(postcss@8.5.26))(cssnano@7.1.9(postcss@8.5.26))(esbuild@0.28.2)(eslint@10.8.1(jiti@2.7.0)(supports-color@10.2.2))(magic-string@1.2.0)(magicast@0.5.4)(nuxt-nightly@5.0.0-29755283.b4586ef2)(optionator@0.9.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(rollup-plugin-visualizer@7.1.1(rolldown@1.2.4)(rollup@4.62.4))(terser@5.50.0)(tsx@4.23.12)(typescript@6.0.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)))(vue-tsc@3.3.10(typescript@6.0.3))(vue@3.5.41(typescript@6.0.3))(yaml@2.9.0)' '@unhead/vue': 3.3.2(@oxc-project/types@0.144.0)(@vitejs/devtools-kit@0.5.2(cac@7.0.0)(crossws@0.4.10(srvx@0.11.22))(srvx@0.11.22)(vite@8.2.2))(esbuild@0.28.2)(lightningcss@1.33.0)(oxc-parser@0.143.0)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(vue@3.5.41(typescript@6.0.3))(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)) '@vue/shared': 3.5.41 @@ -13539,7 +13688,7 @@ snapshots: nuxt-nightly@5.0.0-29755283.b4586ef2(@oxc-project/types@0.144.0)(@parcel/watcher@2.6.0)(@types/node@26.2.0)(@vitejs/devtools-kit@0.5.2(cac@7.0.0)(srvx@0.11.22)(vite@8.2.2))(@vitejs/devtools@0.5.2)(@vue/compiler-sfc@3.5.41)(autoprefixer@10.5.4(postcss@8.5.26))(cssnano@7.1.9(postcss@8.5.26))(db0@0.3.4)(dotenv@17.4.2)(esbuild@0.28.2)(eslint@10.8.1(jiti@2.7.0)(supports-color@10.2.2))(giget@3.3.1)(ioredis@5.11.1(supports-color@10.2.2))(lightningcss@1.33.0)(magicast@0.5.4)(nuxt-nightly@5.0.0-29755283.b4586ef2)(optionator@0.9.4)(oxc-parser@0.131.0)(rollup-plugin-visualizer@7.1.1(rolldown@1.2.4)(rollup@4.62.4))(rollup@4.62.4)(terser@5.50.0)(tsx@4.23.12)(typescript@6.0.3)(vite@8.2.2)(vue-tsc@3.3.10(typescript@6.0.3))(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26))(yaml@2.9.0): dependencies: '@dxup/nuxt': 0.5.8(esbuild@0.28.2)(magicast@0.5.4)(oxc-parser@0.131.0)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)) - '@nuxt/cli': '@nuxt/cli-nightly@4.0.0-20260820-224244-a3dee96(@nuxt/schema-nightly@5.0.0-29755283.b4586ef2)(jiti@2.7.0)(oxc-parser@0.131.0)(rolldown@1.2.4)' + '@nuxt/cli': '@nuxt/cli-nightly@4.0.0-20260822-122548-4186332(@nuxt/schema-nightly@5.0.0-29755283.b4586ef2)(jiti@2.7.0)(oxc-parser@0.131.0)(rolldown@1.2.4)' '@nuxt/devtools': link:packages/devtools '@nuxt/kit': '@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@1.2.0)(magicast@0.5.4)(oxc-parser@0.131.0)(rolldown@1.2.4)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)))' '@nuxt/nitro-server': '@nuxt/nitro-server-nightly@5.0.0-29755283.b4586ef2(@oxc-project/types@0.144.0)(@vitejs/devtools-kit@0.5.2(cac@7.0.0)(srvx@0.11.22)(vite@8.2.2))(chokidar@5.0.0)(db0@0.3.4)(dotenv@17.4.2)(esbuild@0.28.2)(giget@3.3.1)(ioredis@5.11.1(supports-color@10.2.2))(jiti@2.7.0)(lightningcss@1.33.0)(magicast@0.5.4)(nuxt-nightly@5.0.0-29755283.b4586ef2)(ofetch@2.0.0-alpha.3)(oxc-parser@0.131.0)(rolldown@1.2.4)(rollup@4.62.4)(typescript@6.0.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)))(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26))' @@ -13683,7 +13832,7 @@ snapshots: nuxt-nightly@5.0.0-29755283.b4586ef2(@oxc-project/types@0.144.0)(@parcel/watcher@2.6.0)(@types/node@26.2.0)(@vitejs/devtools-kit@0.5.2(cac@7.0.0)(srvx@0.11.22)(vite@8.2.2))(@vitejs/devtools@0.5.2)(@vue/compiler-sfc@3.5.41)(autoprefixer@10.5.4(postcss@8.5.26))(cssnano@7.1.9(postcss@8.5.26))(db0@0.3.4)(dotenv@17.4.2)(esbuild@0.28.2)(eslint@10.8.1(jiti@2.7.0)(supports-color@10.2.2))(giget@3.3.1)(ioredis@5.11.1(supports-color@10.2.2))(lightningcss@1.33.0)(magicast@0.5.4)(nuxt-nightly@5.0.0-29755283.b4586ef2)(optionator@0.9.4)(oxc-parser@0.143.0)(rollup-plugin-visualizer@7.1.1(rolldown@1.2.4)(rollup@4.62.4))(rollup@4.62.4)(terser@5.50.0)(tsx@4.23.12)(typescript@6.0.3)(vite@8.2.2)(vue-tsc@3.3.10(typescript@6.0.3))(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26))(yaml@2.9.0): dependencies: '@dxup/nuxt': 0.5.8(esbuild@0.28.2)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)) - '@nuxt/cli': '@nuxt/cli-nightly@4.0.0-20260820-224244-a3dee96(@nuxt/schema-nightly@5.0.0-29755283.b4586ef2)(jiti@2.7.0)(oxc-parser@0.143.0)(rolldown@1.2.4)' + '@nuxt/cli': '@nuxt/cli-nightly@4.0.0-20260822-122548-4186332(@nuxt/schema-nightly@5.0.0-29755283.b4586ef2)(jiti@2.7.0)(oxc-parser@0.143.0)(rolldown@1.2.4)' '@nuxt/devtools': link:packages/devtools '@nuxt/kit': '@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@1.2.0)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)))' '@nuxt/nitro-server': '@nuxt/nitro-server-nightly@5.0.0-29755283.b4586ef2(@oxc-project/types@0.144.0)(@vitejs/devtools-kit@0.5.2(cac@7.0.0)(srvx@0.11.22)(vite@8.2.2))(chokidar@5.0.0)(db0@0.3.4)(dotenv@17.4.2)(esbuild@0.28.2)(giget@3.3.1)(ioredis@5.11.1(supports-color@10.2.2))(jiti@2.7.0)(lightningcss@1.33.0)(magicast@0.5.4)(nuxt-nightly@5.0.0-29755283.b4586ef2)(ofetch@2.0.0-alpha.3)(oxc-parser@0.143.0)(rolldown@1.2.4)(rollup@4.62.4)(typescript@6.0.3)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)))(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26))' @@ -15015,6 +15164,13 @@ snapshots: magic-string: 0.30.21 unplugin: 2.3.11 + unctx@3.0.0(magic-string@0.30.21)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@2.3.11): + optionalDependencies: + magic-string: 0.30.21 + oxc-parser: 0.143.0 + rolldown: 1.2.4 + unplugin: 2.3.11 + unctx@3.0.0(magic-string@1.2.0)(oxc-parser@0.131.0)(rolldown@1.2.4)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26))): optionalDependencies: magic-string: 1.2.0 @@ -15454,7 +15610,7 @@ snapshots: typescript: 6.0.3 vue-tsc: 3.3.10(typescript@6.0.3) - vite-plugin-inspect@12.0.2(@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@1.2.0)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26))))(cac@7.0.0)(crossws@0.4.10(srvx@0.11.22))(srvx@0.11.22)(vite@8.2.2): + vite-plugin-inspect@12.0.2(@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@0.30.21)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@2.3.11))(cac@7.0.0)(crossws@0.4.10(srvx@0.11.22))(srvx@0.11.22)(vite@8.2.2): dependencies: '@vitejs/devtools-kit': 0.5.2(cac@7.0.0)(crossws@0.4.10(srvx@0.11.22))(srvx@0.11.22)(vite@8.2.2) ansis: 4.3.1 @@ -15467,7 +15623,7 @@ snapshots: unplugin-utils: 0.3.2 vite: 8.2.2(@types/node@26.2.0)(@vitejs/devtools@0.5.2)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.50.0)(tsx@4.23.12)(yaml@2.9.0) optionalDependencies: - '@nuxt/kit': '@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@1.2.0)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.2)(webpack@5.109.2(cssnano@7.1.9(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(lightningcss@1.33.0)(postcss@8.5.26)))' + '@nuxt/kit': '@nuxt/kit-nightly@5.0.0-29755283.b4586ef2(magic-string@0.30.21)(magicast@0.5.4)(oxc-parser@0.143.0)(rolldown@1.2.4)(unplugin@2.3.11)' transitivePeerDependencies: - '@modelcontextprotocol/client' - '@modelcontextprotocol/server' diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index c3c5468438..87f2df482f 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -207,15 +207,19 @@ catalogs: defu: ^6.1.7 destr: ^2.0.5 devframe: *devframe + escape-string-regexp: ^5.0.0 fast-npm-meta: ^2.2.0 image-meta: ^0.2.2 local-pkg: ^1.2.1 + magic-string: ^0.30.21 magicast: ^0.5.4 + mlly: ^1.8.1 nostics: ^1.2.0 pkg-types: ^2.3.1 sirv: ^3.0.2 tinyexec: ^1.3.0 tinyglobby: ^0.2.17 + unplugin: ^2.3.11 unstorage: ^1.17.5 verkit: ^0.4.0 vite-plugin-inspect: ^12.0.2 diff --git a/tests/e2e/playwright.config.ts b/tests/e2e/playwright.config.ts index 2862b1622a..c4337f1ee9 100644 --- a/tests/e2e/playwright.config.ts +++ b/tests/e2e/playwright.config.ts @@ -5,7 +5,7 @@ import { matchesProjectFilter } from './shared/glob' const REPO_ROOT = fileURLToPath(new URL('../..', import.meta.url)) -const PLAYGROUNDS = ['empty', 'spa', 'tab-seo'] as const +const PLAYGROUNDS = ['empty', 'spa', 'tab-seo', 'tab-timeline'] as const const MODES = ['dev', 'built'] as const type Mode = typeof MODES[number] diff --git a/tests/e2e/specs/playground-tab-timeline.spec.ts b/tests/e2e/specs/playground-tab-timeline.spec.ts new file mode 100644 index 0000000000..698522da73 --- /dev/null +++ b/tests/e2e/specs/playground-tab-timeline.spec.ts @@ -0,0 +1,22 @@ +import { expect, test } from '../fixtures/devtools' + +test.skip( + ({ playground }) => playground !== 'tab-timeline', + 'tab-timeline playground only', +) + +test('does not break key injection of keyed composables', async ({ page }) => { + await page.goto('/keyed') + await expect(page.getByTestId('counter')).toHaveText('counter: 1') + await expect(page.getByTestId('data')).toHaveText('async data') +}) + +test('applies both key injection and timeline wrapping to the module', async ({ page }) => { + await page.goto('/keyed') + const res = await page.request.get('/_nuxt/pages/keyed.vue') + expect(res.ok()).toBe(true) + const code = await res.text() + expect(code).toContain('__nuxtTimelineWrap("useState", _$__useState)') + expect(code).toContain('__nuxtTimelineWrap("callOnce", _$__callOnce)') + expect(code).toContain('/* nuxt-injected */') +})