,
) {
const { tag } = node
@@ -172,29 +177,43 @@ function transformNativeElement(
template += `<${tag}`
if (scopeId) template += ` ${scopeId}`
+ let staticProps = false
+ const dynamicProps: string[] = []
if (propsResult[0] /* dynamic props */) {
const [, dynamicArgs, expressions] = propsResult
context.registerEffect(expressions, {
type: IRNodeTypes.SET_DYNAMIC_PROPS,
element: context.reference(),
props: dynamicArgs,
+ root: singleRoot,
})
} else {
for (const prop of propsResult[1]) {
const { key, values } = prop
if (key.isStatic && values.length === 1 && values[0].isStatic) {
+ staticProps = true
template += ` ${key.content}`
if (values[0].content) template += `="${values[0].content}"`
} else {
+ dynamicProps.push(key.content)
context.registerEffect(values, {
type: IRNodeTypes.SET_PROP,
element: context.reference(),
prop,
+ root: singleRoot,
})
}
}
}
+ if (singleRoot) {
+ context.registerOperation({
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ staticProps: staticProps,
+ dynamicProps: propsResult[0] ? true : dynamicProps,
+ })
+ }
+
template += `>` + context.childrenTemplate.join('')
// TODO remove unnecessary close tag, e.g. if it's the last element of the template
if (!isVoidTag(tag)) {
diff --git a/packages/runtime-vapor/__tests__/apiSetupContext.spec.ts b/packages/runtime-vapor/__tests__/apiSetupContext.spec.ts
index 7bee76beb..947e70421 100644
--- a/packages/runtime-vapor/__tests__/apiSetupContext.spec.ts
+++ b/packages/runtime-vapor/__tests__/apiSetupContext.spec.ts
@@ -11,6 +11,7 @@ import {
ref,
renderEffect,
setDynamicProps,
+ setInheritAttrs,
template,
watchEffect,
} from '../src'
@@ -77,9 +78,7 @@ describe('api: setup context', () => {
inheritAttrs: false,
setup(props, { attrs }) {
const el = document.createElement('div')
- renderEffect(() => {
- setDynamicProps(el, attrs)
- })
+ renderEffect(() => setDynamicProps(el, [attrs]))
return el
},
})
@@ -103,23 +102,24 @@ describe('api: setup context', () => {
const toggle = ref(true)
const Wrapper = defineComponent({
- setup(_, { slots }) {
- return slots.default!()
+ setup(_) {
+ const n0 = createSlot('default')
+ setInheritAttrs(false, true)
+ return n0
},
})
const Child = defineComponent({
inheritAttrs: false,
setup(_: any, { attrs }: any) {
- return createComponent(Wrapper, null, {
+ const n0 = createComponent(Wrapper, null, {
default: () => {
const n0 = template('')() as HTMLDivElement
- renderEffect(() => {
- setDynamicProps(n0, attrs)
- })
+ renderEffect(() => setDynamicProps(n0, [attrs], true))
return n0
},
})
+ return n0
},
})
diff --git a/packages/runtime-vapor/__tests__/componentAttrs.spec.ts b/packages/runtime-vapor/__tests__/componentAttrs.spec.ts
index 18effd8e0..d66474559 100644
--- a/packages/runtime-vapor/__tests__/componentAttrs.spec.ts
+++ b/packages/runtime-vapor/__tests__/componentAttrs.spec.ts
@@ -3,6 +3,7 @@ import {
getCurrentInstance,
nextTick,
ref,
+ setInheritAttrs,
setText,
template,
watchEffect,
@@ -18,7 +19,8 @@ describe('attribute fallthrough', () => {
props: ['foo'],
render() {
const instance = getCurrentInstance()!
- const n0 = t0()
+ const n0 = t0() as Element
+ setInheritAttrs()
watchEffect(() => setText(n0, instance.props.foo))
return n0
},
@@ -62,7 +64,8 @@ describe('attribute fallthrough', () => {
inheritAttrs: false,
render() {
const instance = getCurrentInstance()!
- const n0 = t0()
+ const n0 = t0() as Element
+ setInheritAttrs()
watchEffect(() => setText(n0, instance.props.foo))
return n0
},
@@ -105,7 +108,8 @@ describe('attribute fallthrough', () => {
props: ['custom-attr'],
render() {
const instance = getCurrentInstance()!
- const n0 = t0()
+ const n0 = t0() as Element
+ setInheritAttrs()
watchEffect(() => setText(n0, instance.attrs.foo))
return n0
},
diff --git a/packages/runtime-vapor/__tests__/dom/prop.spec.ts b/packages/runtime-vapor/__tests__/dom/prop.spec.ts
index ab5a3d4e6..7ccb1f51e 100644
--- a/packages/runtime-vapor/__tests__/dom/prop.spec.ts
+++ b/packages/runtime-vapor/__tests__/dom/prop.spec.ts
@@ -407,25 +407,25 @@ describe('patchProp', () => {
describe('setDynamicProps', () => {
test('basic set dynamic props', () => {
const el = document.createElement('div')
- setDynamicProps(el, { foo: 'val' }, { bar: 'val' })
+ setDynamicProps(el, [{ foo: 'val' }, { bar: 'val' }])
expect(el.getAttribute('foo')).toBe('val')
expect(el.getAttribute('bar')).toBe('val')
})
test('should merge props', () => {
const el = document.createElement('div')
- setDynamicProps(el, { foo: 'val' }, { foo: 'newVal' })
+ setDynamicProps(el, [{ foo: 'val' }, { foo: 'newVal' }])
expect(el.getAttribute('foo')).toBe('newVal')
})
test('should reset old props', () => {
const el = document.createElement('div')
- setDynamicProps(el, { foo: 'val' })
+ setDynamicProps(el, [{ foo: 'val' }])
expect(el.attributes.length).toBe(1)
expect(el.getAttribute('foo')).toBe('val')
- setDynamicProps(el, { bar: 'val' })
+ setDynamicProps(el, [{ bar: 'val' }])
expect(el.attributes.length).toBe(1)
expect(el.getAttribute('bar')).toBe('val')
expect(el.getAttribute('foo')).toBeNull()
@@ -434,18 +434,18 @@ describe('patchProp', () => {
test('should reset old modifier props', () => {
const el = document.createElement('div')
- setDynamicProps(el, { ['.foo']: 'val' })
+ setDynamicProps(el, [{ ['.foo']: 'val' }])
expect((el as any).foo).toBe('val')
- setDynamicProps(el, { ['.bar']: 'val' })
+ setDynamicProps(el, [{ ['.bar']: 'val' }])
expect((el as any).bar).toBe('val')
expect((el as any).foo).toBe('')
- setDynamicProps(el, { ['^foo']: 'val' })
+ setDynamicProps(el, [{ ['^foo']: 'val' }])
expect(el.attributes.length).toBe(1)
expect(el.getAttribute('foo')).toBe('val')
- setDynamicProps(el, { ['^bar']: 'val' })
+ setDynamicProps(el, [{ ['^bar']: 'val' }])
expect(el.attributes.length).toBe(1)
expect(el.getAttribute('bar')).toBe('val')
expect(el.getAttribute('foo')).toBeNull()
diff --git a/packages/runtime-vapor/src/apiCreateComponent.ts b/packages/runtime-vapor/src/apiCreateComponent.ts
index 7b9198832..326a3b2f8 100644
--- a/packages/runtime-vapor/src/apiCreateComponent.ts
+++ b/packages/runtime-vapor/src/apiCreateComponent.ts
@@ -5,18 +5,13 @@ import {
currentInstance,
} from './component'
import { setupComponent } from './apiRender'
-import {
- type NormalizedRawProps,
- type RawProps,
- normalizeRawProps,
- walkRawProps,
-} from './componentProps'
+import { type RawProps, normalizeRawProps } from './componentProps'
import { type RawSlots, isDynamicSlotFn } from './componentSlots'
-import { withAttrs } from './componentAttrs'
+import { setInheritAttrs, withAttrs } from './componentAttrs'
import { isString } from '@vue/shared'
import { renderEffect } from './renderEffect'
import { normalizeBlock } from './dom/element'
-import { setDynamicProp } from './dom/prop'
+import { setDynamicProps } from './dom/prop'
export function createComponent(
comp: Component | string,
@@ -25,11 +20,12 @@ export function createComponent(
singleRoot: boolean = false,
once: boolean = false,
): ComponentInternalInstance | HTMLElement {
+ const current = currentInstance!
+
if (isString(comp)) {
- return fallbackComponent(comp, rawProps, slots)
+ return fallbackComponent(comp, rawProps, slots, current, singleRoot)
}
- const current = currentInstance!
const instance = createComponentInstance(
comp,
singleRoot ? withAttrs(rawProps) : rawProps,
@@ -48,17 +44,16 @@ function fallbackComponent(
comp: string,
rawProps: RawProps | null,
slots: RawSlots | null,
+ instance: ComponentInternalInstance,
+ singleRoot: boolean = false,
): HTMLElement {
// eslint-disable-next-line no-restricted-globals
const el = document.createElement(comp)
- if (rawProps) {
- rawProps = normalizeRawProps(rawProps)
- renderEffect(() => {
- walkRawProps(rawProps as NormalizedRawProps, (key, value, getter) => {
- setDynamicProp(el, key, getter ? value() : value)
- })
- })
+ if (rawProps || Object.keys(instance.attrs).length) {
+ renderEffect(() =>
+ setDynamicProps(el, normalizeRawProps(rawProps), singleRoot),
+ )
}
if (slots) {
@@ -72,5 +67,9 @@ function fallbackComponent(
}
}
+ if (singleRoot) {
+ setInheritAttrs(true)
+ }
+
return el
}
diff --git a/packages/runtime-vapor/src/apiRender.ts b/packages/runtime-vapor/src/apiRender.ts
index 7dd97193e..751a92c05 100644
--- a/packages/runtime-vapor/src/apiRender.ts
+++ b/packages/runtime-vapor/src/apiRender.ts
@@ -16,10 +16,10 @@ import {
shallowReadonly,
} from '@vue/reactivity'
import { isArray, isFunction, isObject } from '@vue/shared'
-import { fallThroughAttrs } from './componentAttrs'
import { VaporErrorCodes, callWithErrorHandling } from './errorHandling'
import { endMeasure, startMeasure } from './profiling'
import { devtoolsComponentAdded } from './devtools'
+import { fallThroughAttrs } from './componentAttrs'
export const fragmentKey: unique symbol = Symbol(__DEV__ ? `fragmentKey` : ``)
@@ -86,9 +86,6 @@ export function setupComponent(instance: ComponentInternalInstance): void {
resetTracking()
}
- if (block instanceof DocumentFragment) {
- block = Array.from(block.childNodes)
- }
if (!block) {
// TODO: warn no template
block = []
diff --git a/packages/runtime-vapor/src/component.ts b/packages/runtime-vapor/src/component.ts
index ca0cb7fa0..fdfcd55f0 100644
--- a/packages/runtime-vapor/src/component.ts
+++ b/packages/runtime-vapor/src/component.ts
@@ -174,6 +174,13 @@ export interface ComponentInternalInstance {
emit: EmitFn
emitted: Record | null
attrs: Data
+ /**
+ * - `undefined` : no props
+ * - `false` : all props are static
+ * - `string[]` : list of props are dynamic
+ * - `true` : all props as dynamic
+ */
+ dynamicAttrs?: string[] | boolean
slots: StaticSlots
refs: Data
// exposed properties via expose()
diff --git a/packages/runtime-vapor/src/componentAttrs.ts b/packages/runtime-vapor/src/componentAttrs.ts
index 53f951299..ce0ad86ca 100644
--- a/packages/runtime-vapor/src/componentAttrs.ts
+++ b/packages/runtime-vapor/src/componentAttrs.ts
@@ -1,11 +1,14 @@
-import { camelize, isArray } from '@vue/shared'
+import { camelize, isArray, normalizeClass, normalizeStyle } from '@vue/shared'
import { type ComponentInternalInstance, currentInstance } from './component'
import { isEmitListener } from './componentEmits'
-import { setDynamicProps } from './dom/prop'
import { type RawProps, walkRawProps } from './componentProps'
import { renderEffect } from './renderEffect'
+import { mergeProp, setDynamicProp } from './dom/prop'
-export function patchAttrs(instance: ComponentInternalInstance): void {
+export function patchAttrs(
+ instance: ComponentInternalInstance,
+ hasDynamicProps?: boolean,
+): void {
const {
attrs,
rawProps,
@@ -14,6 +17,8 @@ export function patchAttrs(instance: ComponentInternalInstance): void {
if (!rawProps.length) return
const keys = new Set()
+ const classes: any[] = []
+ const styles: any[] = []
walkRawProps(rawProps, registerAttr)
for (const key in attrs) {
@@ -22,14 +27,42 @@ export function patchAttrs(instance: ComponentInternalInstance): void {
}
}
+ setClassOrStyle(classes, 'class', normalizeClass)
+ setClassOrStyle(styles, 'style', normalizeStyle)
+
+ function setClassOrStyle(
+ values: any[],
+ field: 'class' | 'style',
+ normalize: (value: any) => any,
+ ) {
+ if (values.length) {
+ if (hasDynamicProps) {
+ Object.defineProperty(attrs, field, {
+ get() {
+ return normalize(values.map(value => value()))
+ },
+ enumerable: true,
+ configurable: true,
+ })
+ } else {
+ attrs[field] = normalizeClass(values)
+ }
+ }
+ }
+
function registerAttr(key: string, value: any, getter?: boolean) {
if (
(!options || !(camelize(key) in options)) &&
!isEmitListener(instance.emitsOptions, key) &&
- !keys.has(key)
+ (key === 'class' || key === 'style' || !keys.has(key))
) {
keys.add(key)
- if (getter) {
+
+ if (key === 'class' || key === 'style') {
+ ;(key === 'class' ? classes : styles).push(
+ hasDynamicProps ? (getter ? value : () => value) : value,
+ )
+ } else if (getter) {
Object.defineProperty(attrs, key, {
get: value,
enumerable: true,
@@ -57,16 +90,47 @@ export function fallThroughAttrs(instance: ComponentInternalInstance): void {
const {
block,
type: { inheritAttrs },
+ dynamicAttrs,
} = instance
- if (inheritAttrs === false) return
+ if (
+ inheritAttrs === false ||
+ !(block instanceof Element) ||
+ // all props as dynamic
+ dynamicAttrs === true
+ )
+ return
- if (block instanceof Element) {
+ const hasStaticAttrs = dynamicAttrs || dynamicAttrs === false
+
+ let initial: Record | undefined
+ if (hasStaticAttrs) {
// attrs in static template
- const initial: Record = {}
+ initial = {}
for (let i = 0; i < block.attributes.length; i++) {
const attr = block.attributes[i]
+ if (dynamicAttrs && dynamicAttrs.includes(attr.name)) continue
initial[attr.name] = attr.value
}
- renderEffect(() => setDynamicProps(block, instance.attrs, initial))
}
+
+ renderEffect(() => {
+ for (const key in instance.attrs) {
+ if (dynamicAttrs && dynamicAttrs.includes(key)) continue
+
+ let value: unknown
+ if (hasStaticAttrs) {
+ value = mergeProp(key, instance.attrs[key], initial![key])
+ } else {
+ value = instance.attrs[key]
+ }
+
+ setDynamicProp(block, key, value)
+ }
+ })
+}
+
+export function setInheritAttrs(dynamicAttrs?: string[] | boolean): void {
+ const instance = currentInstance!
+ if (instance.type.inheritAttrs === false) return
+ instance.dynamicAttrs = dynamicAttrs
}
diff --git a/packages/runtime-vapor/src/componentProps.ts b/packages/runtime-vapor/src/componentProps.ts
index 6e2332881..1fb8d79f6 100644
--- a/packages/runtime-vapor/src/componentProps.ts
+++ b/packages/runtime-vapor/src/componentProps.ts
@@ -116,7 +116,7 @@ export function initProps(
}
if (hasDynamicProps) {
- firstEffect(instance, () => patchAttrs(instance))
+ firstEffect(instance, () => patchAttrs(instance, true))
} else {
patchAttrs(instance)
}
diff --git a/packages/runtime-vapor/src/dom/prop.ts b/packages/runtime-vapor/src/dom/prop.ts
index 411533722..a00caedee 100644
--- a/packages/runtime-vapor/src/dom/prop.ts
+++ b/packages/runtime-vapor/src/dom/prop.ts
@@ -18,9 +18,20 @@ import {
} from '../componentMetadata'
import { on } from './event'
import type { Data } from '@vue/runtime-shared'
+import { currentInstance } from '../component'
+
+export function mergeInheritAttr(key: string, value: any): unknown {
+ const instance = currentInstance!
+ return mergeProp(key, instance.attrs[key], value)
+}
+
+export function setClass(el: Element, value: any, root?: boolean): void {
+ const prev = recordPropMetadata(
+ el,
+ 'class',
+ (value = normalizeClass(root ? mergeInheritAttr('class', value) : value)),
+ )
-export function setClass(el: Element, value: any): void {
- const prev = recordPropMetadata(el, 'class', (value = normalizeClass(value)))
if (value !== prev && (value || prev)) {
el.className = value
}
@@ -109,7 +120,12 @@ export function setDOMProp(el: any, key: string, value: any): void {
needRemove && el.removeAttribute(key)
}
-export function setDynamicProp(el: Element, key: string, value: any): void {
+export function setDynamicProp(
+ el: Element,
+ key: string,
+ value: any,
+ root?: boolean,
+): void {
// TODO
const isSVG = false
if (key === 'class') {
@@ -132,8 +148,15 @@ export function setDynamicProp(el: Element, key: string, value: any): void {
}
}
-export function setDynamicProps(el: Element, ...args: any): void {
+export function setDynamicProps(
+ el: Element,
+ args: any[],
+ root?: boolean,
+): void {
const oldProps = getMetadata(el)[MetadataKind.prop]
+ if (root) {
+ args.unshift(currentInstance!.attrs)
+ }
const props = args.length > 1 ? mergeProps(...args) : args[0]
for (const key in oldProps) {
@@ -153,32 +176,36 @@ export function setDynamicProps(el: Element, ...args: any): void {
}
}
-// TODO copied from runtime-core
+export function mergeProp(
+ key: string,
+ existing: unknown,
+ incoming: unknown,
+): unknown {
+ if (key === 'class') {
+ if (existing !== incoming) {
+ return normalizeClass([existing, incoming])
+ }
+ } else if (key === 'style') {
+ return normalizeStyle([existing, incoming])
+ } else if (isOn(key)) {
+ if (
+ incoming &&
+ existing !== incoming &&
+ !(isArray(existing) && existing.includes(incoming))
+ ) {
+ return existing ? [].concat(existing as any, incoming as any) : incoming
+ }
+ }
+ return incoming
+}
+
export function mergeProps(...args: Data[]): Data {
const ret: Data = {}
for (let i = 0; i < args.length; i++) {
const toMerge = args[i]
for (const key in toMerge) {
- if (key === 'class') {
- if (ret.class !== toMerge.class) {
- ret.class = normalizeClass([ret.class, toMerge.class])
- }
- } else if (key === 'style') {
- ret.style = normalizeStyle([ret.style, toMerge.style])
- } else if (isOn(key)) {
- const existing = ret[key]
- const incoming = toMerge[key]
- if (
- incoming &&
- existing !== incoming &&
- !(isArray(existing) && existing.includes(incoming))
- ) {
- ret[key] = existing
- ? [].concat(existing as any, incoming as any)
- : incoming
- }
- } else if (key !== '') {
- ret[key] = toMerge[key]
+ if (key !== '') {
+ ret[key] = mergeProp(key, ret[key], toMerge[key])
}
}
}
diff --git a/packages/runtime-vapor/src/dom/style.ts b/packages/runtime-vapor/src/dom/style.ts
index b7ecfa53c..5ee233a0c 100644
--- a/packages/runtime-vapor/src/dom/style.ts
+++ b/packages/runtime-vapor/src/dom/style.ts
@@ -8,9 +8,14 @@ import {
} from '@vue/shared'
import { warn } from '../warning'
import { recordPropMetadata } from '../componentMetadata'
+import { mergeInheritAttr } from './prop'
-export function setStyle(el: HTMLElement, value: any): void {
- const prev = recordPropMetadata(el, 'style', (value = normalizeStyle(value)))
+export function setStyle(el: HTMLElement, value: any, root?: boolean): void {
+ const prev = recordPropMetadata(
+ el,
+ 'style',
+ (value = normalizeStyle(root ? mergeInheritAttr('style', value) : value)),
+ )
patchStyle(el, prev, value)
}
diff --git a/packages/runtime-vapor/src/index.ts b/packages/runtime-vapor/src/index.ts
index 0a652b208..f1d77f2ee 100644
--- a/packages/runtime-vapor/src/index.ts
+++ b/packages/runtime-vapor/src/index.ts
@@ -130,6 +130,7 @@ export { createIf } from './apiCreateIf'
export { createFor, createForSlots } from './apiCreateFor'
export { createComponent } from './apiCreateComponent'
export { createSelector } from './apiCreateSelector'
+export { setInheritAttrs } from './componentAttrs'
export {
resolveComponent,
diff --git a/playground/package.json b/playground/package.json
index 8c28097d5..c3e21f038 100644
--- a/playground/package.json
+++ b/playground/package.json
@@ -12,7 +12,7 @@
"vue": "workspace:*"
},
"devDependencies": {
- "@vitejs/plugin-vue": "https://pkg.pr.new/@vitejs/plugin-vue@e3c5ce5",
+ "@vitejs/plugin-vue": "https://pkg.pr.new/@vitejs/plugin-vue@481bcd4",
"vite": "catalog:",
"vite-hyper-config": "^0.4.0",
"vite-plugin-inspect": "^0.8.7"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 45a506eda..37f7290fd 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -521,8 +521,8 @@ importers:
version: link:../packages/vue
devDependencies:
'@vitejs/plugin-vue':
- specifier: https://pkg.pr.new/@vitejs/plugin-vue@e3c5ce5
- version: https://pkg.pr.new/@vitejs/plugin-vue@e3c5ce5(vite@5.4.8(@types/node@22.8.7)(sass@1.80.6)(terser@5.33.0))(vue@packages+vue)
+ specifier: https://pkg.pr.new/@vitejs/plugin-vue@481bcd4
+ version: https://pkg.pr.new/@vitejs/plugin-vue@481bcd4(vite@5.4.8(@types/node@22.8.7)(sass@1.80.6)(terser@5.33.0))(vue@packages+vue)
vite:
specifier: 'catalog:'
version: 5.4.8(@types/node@22.8.7)(sass@1.80.6)(terser@5.33.0)
@@ -1416,6 +1416,14 @@ packages:
vite: ^5.0.0
vue: ^3.2.25
+ '@vitejs/plugin-vue@https://pkg.pr.new/@vitejs/plugin-vue@481bcd4':
+ resolution: {tarball: https://pkg.pr.new/@vitejs/plugin-vue@481bcd4}
+ version: 5.1.5
+ engines: {node: ^18.0.0 || >=20.0.0}
+ peerDependencies:
+ vite: ^5.0.0
+ vue: ^3.2.25
+
'@vitejs/plugin-vue@https://pkg.pr.new/@vitejs/plugin-vue@e3c5ce5':
resolution: {tarball: https://pkg.pr.new/@vitejs/plugin-vue@e3c5ce5}
version: 5.1.4
@@ -4495,15 +4503,15 @@ snapshots:
vite: 5.4.8(@types/node@22.8.7)(sass@1.80.6)(terser@5.33.0)
vue: link:packages/vue
- '@vitejs/plugin-vue@https://pkg.pr.new/@vitejs/plugin-vue@e3c5ce5(vite@5.4.8(@types/node@22.8.7)(sass@1.80.6)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2))':
+ '@vitejs/plugin-vue@https://pkg.pr.new/@vitejs/plugin-vue@481bcd4(vite@5.4.8(@types/node@22.8.7)(sass@1.80.6)(terser@5.33.0))(vue@packages+vue)':
dependencies:
vite: 5.4.8(@types/node@22.8.7)(sass@1.80.6)(terser@5.33.0)
- vue: 3.5.12(typescript@5.6.2)
+ vue: link:packages/vue
- '@vitejs/plugin-vue@https://pkg.pr.new/@vitejs/plugin-vue@e3c5ce5(vite@5.4.8(@types/node@22.8.7)(sass@1.80.6)(terser@5.33.0))(vue@packages+vue)':
+ '@vitejs/plugin-vue@https://pkg.pr.new/@vitejs/plugin-vue@e3c5ce5(vite@5.4.8(@types/node@22.8.7)(sass@1.80.6)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2))':
dependencies:
vite: 5.4.8(@types/node@22.8.7)(sass@1.80.6)(terser@5.33.0)
- vue: link:packages/vue
+ vue: 3.5.12(typescript@5.6.2)
'@vitest/coverage-v8@2.1.1(vitest@2.1.1)':
dependencies: