mirror of https://github.com/vuejs/core.git
Merge remote-tracking branch 'upstream/main'
This commit is contained in:
commit
af9f892afa
91
CHANGELOG.md
91
CHANGELOG.md
|
@ -1,3 +1,94 @@
|
||||||
|
## [3.4.13](https://github.com/vuejs/core/compare/v3.4.12...v3.4.13) (2024-01-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **reactivity:** fix dirtyLevel checks for recursive effects ([#10101](https://github.com/vuejs/core/issues/10101)) ([e45a8d2](https://github.com/vuejs/core/commit/e45a8d24b46c174deb46ed952bdaf54c81ad5a85)), closes [#10082](https://github.com/vuejs/core/issues/10082)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.4.12](https://github.com/vuejs/core/compare/v3.4.11...v3.4.12) (2024-01-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Reverts
|
||||||
|
|
||||||
|
* fix(reactivity): correct dirty assign in render function ([#10091](https://github.com/vuejs/core/issues/10091)) ([8b18481](https://github.com/vuejs/core/commit/8b1848173b0bc8fd84ce1da1af8d373c044bf073)), closes [#10098](https://github.com/vuejs/core/issues/10098) [#10100](https://github.com/vuejs/core/issues/10100)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.4.11](https://github.com/vuejs/core/compare/v3.4.10...v3.4.11) (2024-01-12)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **hydration:** improve mismatch when client value is null or undefined ([#10086](https://github.com/vuejs/core/issues/10086)) ([08b60f5](https://github.com/vuejs/core/commit/08b60f5d0d5b57fcf3347ef66cbeab472c475a88))
|
||||||
|
* **reactivity:** correct dirty assign in render function ([#10091](https://github.com/vuejs/core/issues/10091)) ([8d04205](https://github.com/vuejs/core/commit/8d042050411fdf04d9d1d6c153287164b12e0255)), closes [#10082](https://github.com/vuejs/core/issues/10082)
|
||||||
|
* **runtime-core:** filter single root for nested DEV_ROOT_FRAGMENT ([#8593](https://github.com/vuejs/core/issues/8593)) ([d35b877](https://github.com/vuejs/core/commit/d35b87725ab3e2bdc86fb5781ab34939f7ec1029)), closes [#5203](https://github.com/vuejs/core/issues/5203) [#8581](https://github.com/vuejs/core/issues/8581) [#10087](https://github.com/vuejs/core/issues/10087)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.4.10](https://github.com/vuejs/core/compare/v3.4.9...v3.4.10) (2024-01-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **hydration:** should not warn on falsy bindings of non-property keys ([3907c87](https://github.com/vuejs/core/commit/3907c87ce23cc6ef4a739b5a66ddb553e8723114))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.4.9](https://github.com/vuejs/core/compare/v3.4.8...v3.4.9) (2024-01-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **build:** avoid accessing __FEATURE_PROD_DEVTOOLS__ flag in root scope ([dfd9654](https://github.com/vuejs/core/commit/dfd9654665890d1bc7129f6e3c2faaa5b1f28f72))
|
||||||
|
* **hydration:** do not warn against bindings w/ object values ([dcc68ef](https://github.com/vuejs/core/commit/dcc68ef7d48973abd8dd3178b46e50e3b0785ea4))
|
||||||
|
* **runtime-dom:** unify behavior for v-show + style display binding ([#10075](https://github.com/vuejs/core/issues/10075)) ([cd419ae](https://github.com/vuejs/core/commit/cd419aec3cb615eaea8b2324356f38f4c0ff1fcc)), closes [#10074](https://github.com/vuejs/core/issues/10074)
|
||||||
|
* **suspense:** avoid double-patching nested suspense when parent suspense is not resolved ([#10055](https://github.com/vuejs/core/issues/10055)) ([bcda96b](https://github.com/vuejs/core/commit/bcda96b525801eb7a1d397300fb3f2f9b827ddfb)), closes [#8678](https://github.com/vuejs/core/issues/8678)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.4.8](https://github.com/vuejs/core/compare/v3.4.7...v3.4.8) (2024-01-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **hydration:** fix class and style hydration mismatch message ([5af3987](https://github.com/vuejs/core/commit/5af398729168481c3bee741b4f36fa4f375e0f4a)), closes [#10067](https://github.com/vuejs/core/issues/10067)
|
||||||
|
* **hydration:** improve attr hydration mismatch check for boolean attrs ([972face](https://github.com/vuejs/core/commit/972facee0d892a1b6d9d4ad1da5da9306ed45c3f)), closes [#10057](https://github.com/vuejs/core/issues/10057) [#10060](https://github.com/vuejs/core/issues/10060)
|
||||||
|
* **suspense:** fix more suspense patch before resolve edge cases ([70ad4ca](https://github.com/vuejs/core/commit/70ad4caad7d19938f8ccf1ede3228a81254dd4bf)), closes [#10017](https://github.com/vuejs/core/issues/10017)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.4.7](https://github.com/vuejs/core/compare/v3.4.6...v3.4.7) (2024-01-09)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **parser:** skip compat mode check for SFC root `<template>` tags ([#10034](https://github.com/vuejs/core/issues/10034)) ([923d560](https://github.com/vuejs/core/commit/923d560d0b6713144671809b6dfeb1e2da503b1f))
|
||||||
|
* **types:** fix functional component for `h` ([#9991](https://github.com/vuejs/core/issues/9991)) ([438a74a](https://github.com/vuejs/core/commit/438a74aad840183286fbdb488178510f37218a73))
|
||||||
|
|
||||||
|
|
||||||
|
### Reverts
|
||||||
|
|
||||||
|
* "dx(computed): warn incorrect use of getCurrentInstance inside computed" ([2fd3905](https://github.com/vuejs/core/commit/2fd39057386644c8bfee426c60a51f2b07a79b09))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.4.6](https://github.com/vuejs/core/compare/v3.4.5...v3.4.6) (2024-01-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **build:** revert "build: add production/development export conditions ([#9977](https://github.com/vuejs/core/issues/9977))" ([7bd4e90](https://github.com/vuejs/core/commit/7bd4e90506547c42234165776b01793abd37b148)), closes [#10012](https://github.com/vuejs/core/issues/10012) [#10020](https://github.com/vuejs/core/issues/10020)
|
||||||
|
* fix post watcher fire timing on nested app mounts ([3c3561e](https://github.com/vuejs/core/commit/3c3561e7203091f49d57f1da6d822c91e462bc46)), closes [#10005](https://github.com/vuejs/core/issues/10005)
|
||||||
|
* **hydration:** avoid hydration mismatch warning for styles with different order ([#10011](https://github.com/vuejs/core/issues/10011)) ([2701355](https://github.com/vuejs/core/commit/2701355e8eb07ab664e398d9fc05d6c4e2e9b20e)), closes [#10000](https://github.com/vuejs/core/issues/10000) [#10006](https://github.com/vuejs/core/issues/10006)
|
||||||
|
* **runtime-core:** handle fragment with null children ([#10010](https://github.com/vuejs/core/issues/10010)) ([3bf34b7](https://github.com/vuejs/core/commit/3bf34b767e4dd3cf6a974301ecf0363ae4dda4ec)), closes [#10007](https://github.com/vuejs/core/issues/10007)
|
||||||
|
* **scheduler:** sort nested postFlushCbs ([d9162df](https://github.com/vuejs/core/commit/d9162dfc2ee0c3a369fb9bf32ff413e74761bee6)), closes [#10003](https://github.com/vuejs/core/issues/10003)
|
||||||
|
* **suspense:** fix anchor for suspense with transition out-in ([#9999](https://github.com/vuejs/core/issues/9999)) ([a3fbf21](https://github.com/vuejs/core/commit/a3fbf2132b0cd3655e969e290548c8fabc08fd33)), closes [#9996](https://github.com/vuejs/core/issues/9996)
|
||||||
|
* **types:** allow `null` type for textarea value ([#9997](https://github.com/vuejs/core/issues/9997)) ([c379bc2](https://github.com/vuejs/core/commit/c379bc29efc70d6ac5840de10c357ee3dad998c0)), closes [#9904](https://github.com/vuejs/core/issues/9904)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [3.4.5](https://github.com/vuejs/core/compare/v3.4.4...v3.4.5) (2024-01-04)
|
## [3.4.5](https://github.com/vuejs/core/compare/v3.4.4...v3.4.5) (2024-01-04)
|
||||||
|
|
||||||
|
|
||||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2018-present, Yuxi (Evan) You
|
Copyright (c) 2018-present, Yuxi (Evan) You and Vue contributors
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
10
package.json
10
package.json
|
@ -70,11 +70,11 @@
|
||||||
"@rollup/plugin-terser": "^0.4.4",
|
"@rollup/plugin-terser": "^0.4.4",
|
||||||
"@types/hash-sum": "^1.0.2",
|
"@types/hash-sum": "^1.0.2",
|
||||||
"@types/minimist": "^1.2.5",
|
"@types/minimist": "^1.2.5",
|
||||||
"@types/node": "^20.10.6",
|
"@types/node": "^20.10.7",
|
||||||
"@types/semver": "^7.5.6",
|
"@types/semver": "^7.5.6",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.17.0",
|
"@typescript-eslint/eslint-plugin": "^6.17.0",
|
||||||
"@typescript-eslint/parser": "^6.17.0",
|
"@typescript-eslint/parser": "^6.17.0",
|
||||||
"@vitest/coverage-istanbul": "^1.1.1",
|
"@vitest/coverage-istanbul": "^1.1.3",
|
||||||
"@vue/consolidate": "0.17.3",
|
"@vue/consolidate": "0.17.3",
|
||||||
"conventional-changelog-cli": "^4.1.0",
|
"conventional-changelog-cli": "^4.1.0",
|
||||||
"enquirer": "^2.4.1",
|
"enquirer": "^2.4.1",
|
||||||
|
@ -86,7 +86,7 @@
|
||||||
"eslint-plugin-jest": "^27.6.1",
|
"eslint-plugin-jest": "^27.6.1",
|
||||||
"estree-walker": "^2.0.2",
|
"estree-walker": "^2.0.2",
|
||||||
"execa": "^8.0.1",
|
"execa": "^8.0.1",
|
||||||
"jsdom": "^23.0.1",
|
"jsdom": "^23.2.0",
|
||||||
"lint-staged": "^15.2.0",
|
"lint-staged": "^15.2.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"magic-string": "^0.30.5",
|
"magic-string": "^0.30.5",
|
||||||
|
@ -98,7 +98,7 @@
|
||||||
"prettier": "^3.1.1",
|
"prettier": "^3.1.1",
|
||||||
"pretty-bytes": "^6.1.1",
|
"pretty-bytes": "^6.1.1",
|
||||||
"pug": "^3.0.2",
|
"pug": "^3.0.2",
|
||||||
"puppeteer": "~21.6.1",
|
"puppeteer": "~21.7.0",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
"rollup": "^4.1.4",
|
"rollup": "^4.1.4",
|
||||||
"rollup-plugin-dts": "^6.1.0",
|
"rollup-plugin-dts": "^6.1.0",
|
||||||
|
@ -113,6 +113,6 @@
|
||||||
"tsx": "^4.7.0",
|
"tsx": "^4.7.0",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.2.2",
|
||||||
"vite": "^5.0.5",
|
"vite": "^5.0.5",
|
||||||
"vitest": "^1.1.1"
|
"vitest": "^1.1.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vue/compiler-core",
|
"name": "@vue/compiler-core",
|
||||||
"version": "3.4.5",
|
"version": "3.4.13",
|
||||||
"description": "@vue/compiler-core",
|
"description": "@vue/compiler-core",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"module": "dist/compiler-core.esm-bundler.js",
|
"module": "dist/compiler-core.esm-bundler.js",
|
||||||
|
@ -17,6 +17,7 @@
|
||||||
"development": "./dist/compiler-core.cjs.js",
|
"development": "./dist/compiler-core.cjs.js",
|
||||||
"default": "./index.js"
|
"default": "./index.js"
|
||||||
},
|
},
|
||||||
|
"module": "./dist/compiler-core.esm-bundler.js",
|
||||||
"import": "./dist/compiler-core.esm-bundler.js",
|
"import": "./dist/compiler-core.esm-bundler.js",
|
||||||
"require": "./index.js"
|
"require": "./index.js"
|
||||||
},
|
},
|
||||||
|
|
|
@ -50,7 +50,7 @@ export function walkIdentifiers(
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
node.type === 'ObjectProperty' &&
|
node.type === 'ObjectProperty' &&
|
||||||
parent!.type === 'ObjectPattern'
|
parent?.type === 'ObjectPattern'
|
||||||
) {
|
) {
|
||||||
// mark property in destructure pattern
|
// mark property in destructure pattern
|
||||||
;(node as any).inPattern = true
|
;(node as any).inPattern = true
|
||||||
|
|
|
@ -692,6 +692,7 @@ function onCloseTag(el: ElementNode, end: number, isImplied = false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
!tokenizer.inSFCRoot &&
|
||||||
isCompatEnabled(
|
isCompatEnabled(
|
||||||
CompilerDeprecationTypes.COMPILER_NATIVE_TEMPLATE,
|
CompilerDeprecationTypes.COMPILER_NATIVE_TEMPLATE,
|
||||||
currentOptions,
|
currentOptions,
|
||||||
|
|
|
@ -256,7 +256,7 @@ export function createTransformContext(
|
||||||
}
|
}
|
||||||
context.parent!.children.splice(removalIndex, 1)
|
context.parent!.children.splice(removalIndex, 1)
|
||||||
},
|
},
|
||||||
onNodeRemoved: () => {},
|
onNodeRemoved: NOOP,
|
||||||
addIdentifiers(exp) {
|
addIdentifiers(exp) {
|
||||||
// identifier tracking only happens in non-browser builds.
|
// identifier tracking only happens in non-browser builds.
|
||||||
if (!__BROWSER__) {
|
if (!__BROWSER__) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vue/compiler-dom",
|
"name": "@vue/compiler-dom",
|
||||||
"version": "3.4.5",
|
"version": "3.4.13",
|
||||||
"description": "@vue/compiler-dom",
|
"description": "@vue/compiler-dom",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"module": "dist/compiler-dom.esm-bundler.js",
|
"module": "dist/compiler-dom.esm-bundler.js",
|
||||||
|
@ -19,6 +19,7 @@
|
||||||
"development": "./dist/compiler-dom.cjs.js",
|
"development": "./dist/compiler-dom.cjs.js",
|
||||||
"default": "./index.js"
|
"default": "./index.js"
|
||||||
},
|
},
|
||||||
|
"module": "./dist/compiler-dom.esm-bundler.js",
|
||||||
"import": "./dist/compiler-dom.esm-bundler.js",
|
"import": "./dist/compiler-dom.esm-bundler.js",
|
||||||
"require": "./index.js"
|
"require": "./index.js"
|
||||||
},
|
},
|
||||||
|
|
|
@ -953,6 +953,38 @@ describe('SFC compile <script setup>', () => {
|
||||||
</script>`).content,
|
</script>`).content,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('defineModel() referencing local var', () => {
|
||||||
|
expect(() =>
|
||||||
|
compile(`<script setup>
|
||||||
|
let bar = 1
|
||||||
|
defineModel({
|
||||||
|
default: () => bar
|
||||||
|
})
|
||||||
|
</script>`),
|
||||||
|
).toThrow(`cannot reference locally declared variables`)
|
||||||
|
|
||||||
|
// allow const
|
||||||
|
expect(() =>
|
||||||
|
compile(`<script setup>
|
||||||
|
const bar = 1
|
||||||
|
defineModel({
|
||||||
|
default: () => bar
|
||||||
|
})
|
||||||
|
</script>`),
|
||||||
|
).not.toThrow(`cannot reference locally declared variables`)
|
||||||
|
|
||||||
|
// allow in get/set
|
||||||
|
expect(() =>
|
||||||
|
compile(`<script setup>
|
||||||
|
let bar = 1
|
||||||
|
defineModel({
|
||||||
|
get: () => bar,
|
||||||
|
set: () => bar
|
||||||
|
})
|
||||||
|
</script>`),
|
||||||
|
).not.toThrow(`cannot reference locally declared variables`)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vue/compiler-sfc",
|
"name": "@vue/compiler-sfc",
|
||||||
"version": "3.4.5",
|
"version": "3.4.13",
|
||||||
"description": "@vue/compiler-sfc",
|
"description": "@vue/compiler-sfc",
|
||||||
"main": "dist/compiler-sfc.cjs.js",
|
"main": "dist/compiler-sfc.cjs.js",
|
||||||
"module": "dist/compiler-sfc.esm-browser.js",
|
"module": "dist/compiler-sfc.esm-browser.js",
|
||||||
|
@ -12,6 +12,7 @@
|
||||||
".": {
|
".": {
|
||||||
"types": "./dist/compiler-sfc.d.ts",
|
"types": "./dist/compiler-sfc.d.ts",
|
||||||
"node": "./dist/compiler-sfc.cjs.js",
|
"node": "./dist/compiler-sfc.cjs.js",
|
||||||
|
"module": "./dist/compiler-sfc.esm-browser.js",
|
||||||
"import": "./dist/compiler-sfc.esm-browser.js",
|
"import": "./dist/compiler-sfc.esm-browser.js",
|
||||||
"require": "./dist/compiler-sfc.cjs.js"
|
"require": "./dist/compiler-sfc.cjs.js"
|
||||||
},
|
},
|
||||||
|
|
|
@ -672,6 +672,11 @@ export function compileScript(
|
||||||
checkInvalidScopeReference(ctx.propsDestructureDecl, DEFINE_PROPS)
|
checkInvalidScopeReference(ctx.propsDestructureDecl, DEFINE_PROPS)
|
||||||
checkInvalidScopeReference(ctx.emitsRuntimeDecl, DEFINE_EMITS)
|
checkInvalidScopeReference(ctx.emitsRuntimeDecl, DEFINE_EMITS)
|
||||||
checkInvalidScopeReference(ctx.optionsRuntimeDecl, DEFINE_OPTIONS)
|
checkInvalidScopeReference(ctx.optionsRuntimeDecl, DEFINE_OPTIONS)
|
||||||
|
for (const { runtimeOptionNodes } of Object.values(ctx.modelDecls)) {
|
||||||
|
for (const node of runtimeOptionNodes) {
|
||||||
|
checkInvalidScopeReference(node, DEFINE_MODEL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 5. remove non-script content
|
// 5. remove non-script content
|
||||||
if (script) {
|
if (script) {
|
||||||
|
|
|
@ -219,6 +219,7 @@ function doCompileTemplate({
|
||||||
// We need to parse a fresh one. Can't just use `source` here since we need
|
// We need to parse a fresh one. Can't just use `source` here since we need
|
||||||
// the AST location info to be relative to the entire SFC.
|
// the AST location info to be relative to the entire SFC.
|
||||||
const newAST = (ssr ? CompilerDOM : compiler).parse(inAST.source, {
|
const newAST = (ssr ? CompilerDOM : compiler).parse(inAST.source, {
|
||||||
|
prefixIdentifiers: true,
|
||||||
...compilerOptions,
|
...compilerOptions,
|
||||||
parseMode: 'sfc',
|
parseMode: 'sfc',
|
||||||
onError: e => errors.push(e),
|
onError: e => errors.push(e),
|
||||||
|
|
|
@ -15,6 +15,7 @@ export interface ModelDecl {
|
||||||
type: TSType | undefined
|
type: TSType | undefined
|
||||||
options: string | undefined
|
options: string | undefined
|
||||||
identifier: string | undefined
|
identifier: string | undefined
|
||||||
|
runtimeOptionNodes: Node[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function processDefineModel(
|
export function processDefineModel(
|
||||||
|
@ -48,6 +49,7 @@ export function processDefineModel(
|
||||||
|
|
||||||
let optionsString = options && ctx.getString(options)
|
let optionsString = options && ctx.getString(options)
|
||||||
let optionsRemoved = !options
|
let optionsRemoved = !options
|
||||||
|
const runtimeOptionNodes: Node[] = []
|
||||||
|
|
||||||
if (
|
if (
|
||||||
options &&
|
options &&
|
||||||
|
@ -75,6 +77,8 @@ export function processDefineModel(
|
||||||
// remove prop options from runtime options
|
// remove prop options from runtime options
|
||||||
removed++
|
removed++
|
||||||
ctx.s.remove(ctx.startOffset! + start, ctx.startOffset! + end)
|
ctx.s.remove(ctx.startOffset! + start, ctx.startOffset! + end)
|
||||||
|
// record prop options for invalid scope var reference check
|
||||||
|
runtimeOptionNodes.push(p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (removed === options.properties.length) {
|
if (removed === options.properties.length) {
|
||||||
|
@ -89,6 +93,7 @@ export function processDefineModel(
|
||||||
ctx.modelDecls[modelName] = {
|
ctx.modelDecls[modelName] = {
|
||||||
type,
|
type,
|
||||||
options: optionsString,
|
options: optionsString,
|
||||||
|
runtimeOptionNodes,
|
||||||
identifier:
|
identifier:
|
||||||
declId && declId.type === 'Identifier' ? declId.name : undefined,
|
declId && declId.type === 'Identifier' ? declId.name : undefined,
|
||||||
}
|
}
|
||||||
|
|
|
@ -908,7 +908,7 @@ function importSourceToScope(
|
||||||
resolved = resolveExt(filename, fs)
|
resolved = resolveExt(filename, fs)
|
||||||
} else {
|
} else {
|
||||||
// module or aliased import - use full TS resolution, only supported in Node
|
// module or aliased import - use full TS resolution, only supported in Node
|
||||||
if (!__NODE_JS__) {
|
if (!__CJS__) {
|
||||||
return ctx.error(
|
return ctx.error(
|
||||||
`Type import from non-relative sources is not supported in the browser build.`,
|
`Type import from non-relative sources is not supported in the browser build.`,
|
||||||
node,
|
node,
|
||||||
|
@ -975,7 +975,7 @@ function resolveWithTS(
|
||||||
ts: typeof TS,
|
ts: typeof TS,
|
||||||
fs: FS,
|
fs: FS,
|
||||||
): string | undefined {
|
): string | undefined {
|
||||||
if (!__NODE_JS__) return
|
if (!__CJS__) return
|
||||||
|
|
||||||
// 1. resolve tsconfig.json
|
// 1. resolve tsconfig.json
|
||||||
const configPath = ts.findConfigFile(containingFile, fs.fileExists)
|
const configPath = ts.findConfigFile(containingFile, fs.fileExists)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vue/compiler-ssr",
|
"name": "@vue/compiler-ssr",
|
||||||
"version": "3.4.5",
|
"version": "3.4.13",
|
||||||
"description": "@vue/compiler-ssr",
|
"description": "@vue/compiler-ssr",
|
||||||
"main": "dist/compiler-ssr.cjs.js",
|
"main": "dist/compiler-ssr.cjs.js",
|
||||||
"types": "dist/compiler-ssr.d.ts",
|
"types": "dist/compiler-ssr.d.ts",
|
||||||
|
|
|
@ -2,8 +2,10 @@ import {
|
||||||
type Component,
|
type Component,
|
||||||
type DefineComponent,
|
type DefineComponent,
|
||||||
Fragment,
|
Fragment,
|
||||||
|
type FunctionalComponent,
|
||||||
Suspense,
|
Suspense,
|
||||||
Teleport,
|
Teleport,
|
||||||
|
type VNode,
|
||||||
defineComponent,
|
defineComponent,
|
||||||
h,
|
h,
|
||||||
ref,
|
ref,
|
||||||
|
@ -77,6 +79,19 @@ describe('h inference w/ Suspense', () => {
|
||||||
h(Suspense, { onResolve: 1 })
|
h(Suspense, { onResolve: 1 })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
declare const fc: FunctionalComponent<
|
||||||
|
{
|
||||||
|
foo: string
|
||||||
|
bar?: number
|
||||||
|
onClick: (evt: MouseEvent) => void
|
||||||
|
},
|
||||||
|
['click'],
|
||||||
|
{
|
||||||
|
default: () => VNode
|
||||||
|
title: (scope: { id: number }) => VNode
|
||||||
|
}
|
||||||
|
>
|
||||||
|
declare const vnode: VNode
|
||||||
describe('h inference w/ functional component', () => {
|
describe('h inference w/ functional component', () => {
|
||||||
const Func = (_props: { foo: string; bar?: number }) => ''
|
const Func = (_props: { foo: string; bar?: number }) => ''
|
||||||
h(Func, { foo: 'hello' })
|
h(Func, { foo: 'hello' })
|
||||||
|
@ -87,6 +102,15 @@ describe('h inference w/ functional component', () => {
|
||||||
h(Func, {})
|
h(Func, {})
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
h(Func, { bar: 123 })
|
h(Func, { bar: 123 })
|
||||||
|
|
||||||
|
h(
|
||||||
|
fc,
|
||||||
|
{ foo: 'hello', onClick: () => {} },
|
||||||
|
{
|
||||||
|
default: () => vnode,
|
||||||
|
title: ({ id }: { id: number }) => vnode,
|
||||||
|
},
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('h support w/ plain object component', () => {
|
describe('h support w/ plain object component', () => {
|
||||||
|
|
|
@ -2,18 +2,18 @@ import {
|
||||||
type Ref,
|
type Ref,
|
||||||
type Slots,
|
type Slots,
|
||||||
type VNode,
|
type VNode,
|
||||||
|
defineComponent,
|
||||||
defineEmits,
|
defineEmits,
|
||||||
defineModel,
|
defineModel,
|
||||||
defineProps,
|
defineProps,
|
||||||
defineSlots,
|
defineSlots,
|
||||||
toRefs,
|
toRefs,
|
||||||
useAttrs,
|
useAttrs,
|
||||||
|
useModel,
|
||||||
useSlots,
|
useSlots,
|
||||||
withDefaults,
|
withDefaults,
|
||||||
} from 'vue'
|
} from 'vue'
|
||||||
import { describe, expectType } from './utils'
|
import { describe, expectType } from './utils'
|
||||||
import { defineComponent } from 'vue'
|
|
||||||
import { useModel } from 'vue'
|
|
||||||
|
|
||||||
describe('defineProps w/ type declaration', () => {
|
describe('defineProps w/ type declaration', () => {
|
||||||
// type declaration
|
// type declaration
|
||||||
|
|
|
@ -7,6 +7,7 @@ expectType<JSX.Element>(<div />)
|
||||||
expectType<JSX.Element>(<div id="foo" />)
|
expectType<JSX.Element>(<div id="foo" />)
|
||||||
expectType<JSX.Element>(<div>hello</div>)
|
expectType<JSX.Element>(<div>hello</div>)
|
||||||
expectType<JSX.Element>(<input value="foo" />)
|
expectType<JSX.Element>(<input value="foo" />)
|
||||||
|
expectType<JSX.Element>(<textarea value={null} />)
|
||||||
|
|
||||||
// @ts-expect-error style css property validation
|
// @ts-expect-error style css property validation
|
||||||
;<div style={{ unknown: 123 }} />
|
;<div style={{ unknown: 123 }} />
|
||||||
|
|
|
@ -7,7 +7,7 @@ declare var __BROWSER__: boolean
|
||||||
declare var __GLOBAL__: boolean
|
declare var __GLOBAL__: boolean
|
||||||
declare var __ESM_BUNDLER__: boolean
|
declare var __ESM_BUNDLER__: boolean
|
||||||
declare var __ESM_BROWSER__: boolean
|
declare var __ESM_BROWSER__: boolean
|
||||||
declare var __NODE_JS__: boolean
|
declare var __CJS__: boolean
|
||||||
declare var __SSR__: boolean
|
declare var __SSR__: boolean
|
||||||
declare var __COMMIT__: string
|
declare var __COMMIT__: string
|
||||||
declare var __VERSION__: string
|
declare var __VERSION__: string
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
ref,
|
ref,
|
||||||
toRaw,
|
toRaw,
|
||||||
} from '../src'
|
} from '../src'
|
||||||
|
import { DirtyLevels } from '../src/constants'
|
||||||
|
|
||||||
describe('reactivity/computed', () => {
|
describe('reactivity/computed', () => {
|
||||||
it('should return updated value', () => {
|
it('should return updated value', () => {
|
||||||
|
@ -451,4 +452,33 @@ describe('reactivity/computed', () => {
|
||||||
v.value = 2
|
v.value = 2
|
||||||
expect(fnSpy).toBeCalledTimes(2)
|
expect(fnSpy).toBeCalledTimes(2)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('...', () => {
|
||||||
|
const fnSpy = vi.fn()
|
||||||
|
const v = ref(1)
|
||||||
|
const c1 = computed(() => v.value)
|
||||||
|
const c2 = computed(() => {
|
||||||
|
fnSpy()
|
||||||
|
return c1.value
|
||||||
|
})
|
||||||
|
|
||||||
|
c1.effect.allowRecurse = true
|
||||||
|
c2.effect.allowRecurse = true
|
||||||
|
c2.value
|
||||||
|
|
||||||
|
expect(c1.effect._dirtyLevel).toBe(DirtyLevels.NotDirty)
|
||||||
|
expect(c2.effect._dirtyLevel).toBe(DirtyLevels.NotDirty)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should work when chained(ref+computed)', () => {
|
||||||
|
const value = ref(0)
|
||||||
|
const consumer = computed(() => {
|
||||||
|
value.value++
|
||||||
|
return 'foo'
|
||||||
|
})
|
||||||
|
const provider = computed(() => value.value + consumer.value)
|
||||||
|
expect(provider.value).toBe('0foo')
|
||||||
|
expect(provider.effect._dirtyLevel).toBe(DirtyLevels.Dirty)
|
||||||
|
expect(provider.value).toBe('1foo')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -13,6 +13,15 @@ import {
|
||||||
} from '../src/index'
|
} from '../src/index'
|
||||||
import { pauseScheduling, resetScheduling } from '../src/effect'
|
import { pauseScheduling, resetScheduling } from '../src/effect'
|
||||||
import { ITERATE_KEY, getDepFromReactive } from '../src/reactiveEffect'
|
import { ITERATE_KEY, getDepFromReactive } from '../src/reactiveEffect'
|
||||||
|
import {
|
||||||
|
computed,
|
||||||
|
h,
|
||||||
|
nextTick,
|
||||||
|
nodeOps,
|
||||||
|
ref,
|
||||||
|
render,
|
||||||
|
serializeInner,
|
||||||
|
} from '@vue/runtime-test'
|
||||||
|
|
||||||
describe('reactivity/effect', () => {
|
describe('reactivity/effect', () => {
|
||||||
it('should run the passed function once (wrapped by a effect)', () => {
|
it('should run the passed function once (wrapped by a effect)', () => {
|
||||||
|
@ -1011,6 +1020,35 @@ describe('reactivity/effect', () => {
|
||||||
expect(counterSpy).toHaveBeenCalledTimes(1)
|
expect(counterSpy).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #10082
|
||||||
|
it('should set dirtyLevel when effect is allowRecurse and is running', async () => {
|
||||||
|
const s = ref(0)
|
||||||
|
const n = computed(() => s.value + 1)
|
||||||
|
|
||||||
|
const Child = {
|
||||||
|
setup() {
|
||||||
|
s.value++
|
||||||
|
return () => n.value
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderSpy = vi.fn()
|
||||||
|
const Parent = {
|
||||||
|
setup() {
|
||||||
|
return () => {
|
||||||
|
renderSpy()
|
||||||
|
return [n.value, h(Child)]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
render(h(Parent), root)
|
||||||
|
await nextTick()
|
||||||
|
expect(serializeInner(root)).toBe('22')
|
||||||
|
expect(renderSpy).toHaveBeenCalledTimes(2)
|
||||||
|
})
|
||||||
|
|
||||||
describe('empty dep cleanup', () => {
|
describe('empty dep cleanup', () => {
|
||||||
it('should remove the dep when the effect is stopped', () => {
|
it('should remove the dep when the effect is stopped', () => {
|
||||||
const obj = reactive({ prop: 1 })
|
const obj = reactive({ prop: 1 })
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vue/reactivity",
|
"name": "@vue/reactivity",
|
||||||
"version": "3.4.5",
|
"version": "3.4.13",
|
||||||
"description": "@vue/reactivity",
|
"description": "@vue/reactivity",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"module": "dist/reactivity.esm-bundler.js",
|
"module": "dist/reactivity.esm-bundler.js",
|
||||||
|
@ -19,6 +19,7 @@
|
||||||
"development": "./dist/reactivity.cjs.js",
|
"development": "./dist/reactivity.cjs.js",
|
||||||
"default": "./index.js"
|
"default": "./index.js"
|
||||||
},
|
},
|
||||||
|
"module": "./dist/reactivity.esm-bundler.js",
|
||||||
"import": "./dist/reactivity.esm-bundler.js",
|
"import": "./dist/reactivity.esm-bundler.js",
|
||||||
"require": "./index.js"
|
"require": "./index.js"
|
||||||
},
|
},
|
||||||
|
|
|
@ -43,7 +43,7 @@ export class ComputedRefImpl<T> {
|
||||||
) {
|
) {
|
||||||
this.effect = new ReactiveEffect(
|
this.effect = new ReactiveEffect(
|
||||||
() => getter(this._value),
|
() => getter(this._value),
|
||||||
() => triggerRefValue(this, DirtyLevels.ComputedValueMaybeDirty),
|
() => triggerRefValue(this, DirtyLevels.MaybeDirty),
|
||||||
)
|
)
|
||||||
this.effect.computed = this
|
this.effect.computed = this
|
||||||
this.effect.active = this._cacheable = !isSSR
|
this.effect.active = this._cacheable = !isSSR
|
||||||
|
@ -53,12 +53,12 @@ export class ComputedRefImpl<T> {
|
||||||
get value() {
|
get value() {
|
||||||
// the computed ref may get wrapped by other proxies e.g. readonly() #3376
|
// the computed ref may get wrapped by other proxies e.g. readonly() #3376
|
||||||
const self = toRaw(this)
|
const self = toRaw(this)
|
||||||
trackRefValue(self)
|
|
||||||
if (!self._cacheable || self.effect.dirty) {
|
if (!self._cacheable || self.effect.dirty) {
|
||||||
if (hasChanged(self._value, (self._value = self.effect.run()!))) {
|
if (hasChanged(self._value, (self._value = self.effect.run()!))) {
|
||||||
triggerRefValue(self, DirtyLevels.ComputedValueDirty)
|
triggerRefValue(self, DirtyLevels.Dirty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
trackRefValue(self)
|
||||||
return self._value
|
return self._value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,6 @@ export enum ReactiveFlags {
|
||||||
|
|
||||||
export enum DirtyLevels {
|
export enum DirtyLevels {
|
||||||
NotDirty = 0,
|
NotDirty = 0,
|
||||||
ComputedValueMaybeDirty = 1,
|
MaybeDirty = 1,
|
||||||
ComputedValueDirty = 2,
|
Dirty = 2,
|
||||||
Dirty = 3,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ export class ReactiveEffect<T = any> {
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
_queryings = 0
|
_shouldSchedule = false
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
|
@ -76,22 +76,23 @@ export class ReactiveEffect<T = any> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public get dirty() {
|
public get dirty() {
|
||||||
if (this._dirtyLevel === DirtyLevels.ComputedValueMaybeDirty) {
|
if (this._dirtyLevel === DirtyLevels.MaybeDirty) {
|
||||||
this._dirtyLevel = DirtyLevels.NotDirty
|
|
||||||
this._queryings++
|
|
||||||
pauseTracking()
|
pauseTracking()
|
||||||
for (const dep of this.deps) {
|
for (let i = 0; i < this._depsLength; i++) {
|
||||||
|
const dep = this.deps[i]
|
||||||
if (dep.computed) {
|
if (dep.computed) {
|
||||||
triggerComputed(dep.computed)
|
triggerComputed(dep.computed)
|
||||||
if (this._dirtyLevel >= DirtyLevels.ComputedValueDirty) {
|
if (this._dirtyLevel >= DirtyLevels.Dirty) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (this._dirtyLevel < DirtyLevels.Dirty) {
|
||||||
|
this._dirtyLevel = DirtyLevels.NotDirty
|
||||||
|
}
|
||||||
resetTracking()
|
resetTracking()
|
||||||
this._queryings--
|
|
||||||
}
|
}
|
||||||
return this._dirtyLevel >= DirtyLevels.ComputedValueDirty
|
return this._dirtyLevel >= DirtyLevels.Dirty
|
||||||
}
|
}
|
||||||
|
|
||||||
public set dirty(v) {
|
public set dirty(v) {
|
||||||
|
@ -281,7 +282,7 @@ export function trackEffect(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const queueEffectSchedulers: (() => void)[] = []
|
const queueEffectSchedulers: EffectScheduler[] = []
|
||||||
|
|
||||||
export function triggerEffects(
|
export function triggerEffects(
|
||||||
dep: Dep,
|
dep: Dep,
|
||||||
|
@ -290,28 +291,29 @@ export function triggerEffects(
|
||||||
) {
|
) {
|
||||||
pauseScheduling()
|
pauseScheduling()
|
||||||
for (const effect of dep.keys()) {
|
for (const effect of dep.keys()) {
|
||||||
if (!effect.allowRecurse && effect._runnings) {
|
if (dep.get(effect) !== effect._trackId) {
|
||||||
|
// when recurse effect is running, dep map could have outdated items
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (
|
if (effect._dirtyLevel < dirtyLevel) {
|
||||||
effect._dirtyLevel < dirtyLevel &&
|
|
||||||
(!effect._runnings || dirtyLevel !== DirtyLevels.ComputedValueDirty)
|
|
||||||
) {
|
|
||||||
const lastDirtyLevel = effect._dirtyLevel
|
const lastDirtyLevel = effect._dirtyLevel
|
||||||
effect._dirtyLevel = dirtyLevel
|
effect._dirtyLevel = dirtyLevel
|
||||||
if (
|
if (lastDirtyLevel === DirtyLevels.NotDirty) {
|
||||||
lastDirtyLevel === DirtyLevels.NotDirty &&
|
effect._shouldSchedule = true
|
||||||
(!effect._queryings || dirtyLevel !== DirtyLevels.ComputedValueDirty)
|
|
||||||
) {
|
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
effect.onTrigger?.(extend({ effect }, debuggerEventExtraInfo))
|
effect.onTrigger?.(extend({ effect }, debuggerEventExtraInfo))
|
||||||
}
|
}
|
||||||
effect.trigger()
|
effect.trigger()
|
||||||
if (effect.scheduler) {
|
|
||||||
queueEffectSchedulers.push(effect.scheduler)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
effect.scheduler &&
|
||||||
|
effect._shouldSchedule &&
|
||||||
|
(!effect._runnings || effect.allowRecurse)
|
||||||
|
) {
|
||||||
|
effect._shouldSchedule = false
|
||||||
|
queueEffectSchedulers.push(effect.scheduler)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
resetScheduling()
|
resetScheduling()
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {
|
||||||
// The main WeakMap that stores {target -> key -> dep} connections.
|
// The main WeakMap that stores {target -> key -> dep} connections.
|
||||||
// Conceptually, it's easier to think of a dependency as a Dep class
|
// Conceptually, it's easier to think of a dependency as a Dep class
|
||||||
// which maintains a Set of subscribers, but we simply store them as
|
// which maintains a Set of subscribers, but we simply store them as
|
||||||
// raw Sets to reduce memory overhead.
|
// raw Maps to reduce memory overhead.
|
||||||
type KeyToDepMap = Map<any, Dep>
|
type KeyToDepMap = Map<any, Dep>
|
||||||
const targetMap = new WeakMap<object, KeyToDepMap>()
|
const targetMap = new WeakMap<object, KeyToDepMap>()
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,15 @@ import {
|
||||||
getCurrentInstance,
|
getCurrentInstance,
|
||||||
h,
|
h,
|
||||||
inject,
|
inject,
|
||||||
|
nextTick,
|
||||||
nodeOps,
|
nodeOps,
|
||||||
|
onMounted,
|
||||||
provide,
|
provide,
|
||||||
ref,
|
ref,
|
||||||
resolveComponent,
|
resolveComponent,
|
||||||
resolveDirective,
|
resolveDirective,
|
||||||
serializeInner,
|
serializeInner,
|
||||||
|
watch,
|
||||||
withDirectives,
|
withDirectives,
|
||||||
} from '@vue/runtime-test'
|
} from '@vue/runtime-test'
|
||||||
|
|
||||||
|
@ -551,6 +554,35 @@ describe('api: createApp', () => {
|
||||||
).not.toHaveBeenWarned()
|
).not.toHaveBeenWarned()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #10005
|
||||||
|
test('flush order edge case on nested createApp', async () => {
|
||||||
|
const order: string[] = []
|
||||||
|
const App = defineComponent({
|
||||||
|
setup(props) {
|
||||||
|
const message = ref('m1')
|
||||||
|
watch(
|
||||||
|
message,
|
||||||
|
() => {
|
||||||
|
order.push('post watcher')
|
||||||
|
},
|
||||||
|
{ flush: 'post' },
|
||||||
|
)
|
||||||
|
onMounted(() => {
|
||||||
|
message.value = 'm2'
|
||||||
|
createApp(() => '').mount(nodeOps.createElement('div'))
|
||||||
|
})
|
||||||
|
return () => {
|
||||||
|
order.push('render')
|
||||||
|
return h('div', [message.value])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
createApp(App).mount(nodeOps.createElement('div'))
|
||||||
|
await nextTick()
|
||||||
|
expect(order).toMatchObject(['render', 'render', 'post watcher'])
|
||||||
|
})
|
||||||
|
|
||||||
// config.compilerOptions is tested in packages/vue since it is only
|
// config.compilerOptions is tested in packages/vue since it is only
|
||||||
// supported in the full build.
|
// supported in the full build.
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,28 +1,18 @@
|
||||||
import {
|
import {
|
||||||
type ComponentInternalInstance,
|
type ComponentInternalInstance,
|
||||||
type ComputedRef,
|
type ComputedRef,
|
||||||
Fragment,
|
|
||||||
type Ref,
|
|
||||||
type SetupContext,
|
type SetupContext,
|
||||||
Suspense,
|
Suspense,
|
||||||
computed,
|
computed,
|
||||||
createApp,
|
createApp,
|
||||||
createBlock,
|
|
||||||
createElementBlock,
|
|
||||||
createElementVNode,
|
|
||||||
createVNode,
|
|
||||||
defineComponent,
|
defineComponent,
|
||||||
getCurrentInstance,
|
getCurrentInstance,
|
||||||
h,
|
h,
|
||||||
nextTick,
|
|
||||||
nodeOps,
|
nodeOps,
|
||||||
onMounted,
|
onMounted,
|
||||||
openBlock,
|
|
||||||
ref,
|
|
||||||
render,
|
render,
|
||||||
serializeInner,
|
serializeInner,
|
||||||
shallowReactive,
|
shallowReactive,
|
||||||
watch,
|
|
||||||
} from '@vue/runtime-test'
|
} from '@vue/runtime-test'
|
||||||
import {
|
import {
|
||||||
createPropsRestProxy,
|
createPropsRestProxy,
|
||||||
|
@ -32,7 +22,6 @@ import {
|
||||||
mergeDefaults,
|
mergeDefaults,
|
||||||
mergeModels,
|
mergeModels,
|
||||||
useAttrs,
|
useAttrs,
|
||||||
useModel,
|
|
||||||
useSlots,
|
useSlots,
|
||||||
withAsyncContext,
|
withAsyncContext,
|
||||||
withDefaults,
|
withDefaults,
|
||||||
|
@ -185,516 +174,6 @@ describe('SFC <script setup> helpers', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('useModel', () => {
|
|
||||||
test('basic', async () => {
|
|
||||||
let foo: any
|
|
||||||
const update = () => {
|
|
||||||
foo.value = 'bar'
|
|
||||||
}
|
|
||||||
|
|
||||||
const compRender = vi.fn()
|
|
||||||
const Comp = defineComponent({
|
|
||||||
props: ['modelValue'],
|
|
||||||
emits: ['update:modelValue'],
|
|
||||||
setup(props) {
|
|
||||||
foo = useModel(props, 'modelValue')
|
|
||||||
return () => {
|
|
||||||
compRender()
|
|
||||||
return foo.value
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const msg = ref('')
|
|
||||||
const setValue = vi.fn(v => (msg.value = v))
|
|
||||||
const root = nodeOps.createElement('div')
|
|
||||||
createApp(() =>
|
|
||||||
h(Comp, {
|
|
||||||
modelValue: msg.value,
|
|
||||||
'onUpdate:modelValue': setValue,
|
|
||||||
}),
|
|
||||||
).mount(root)
|
|
||||||
|
|
||||||
expect(foo.value).toBe('')
|
|
||||||
expect(msg.value).toBe('')
|
|
||||||
expect(setValue).not.toBeCalled()
|
|
||||||
expect(compRender).toBeCalledTimes(1)
|
|
||||||
expect(serializeInner(root)).toBe('')
|
|
||||||
|
|
||||||
// update from child
|
|
||||||
update()
|
|
||||||
|
|
||||||
await nextTick()
|
|
||||||
expect(msg.value).toBe('bar')
|
|
||||||
expect(foo.value).toBe('bar')
|
|
||||||
expect(setValue).toBeCalledTimes(1)
|
|
||||||
expect(compRender).toBeCalledTimes(2)
|
|
||||||
expect(serializeInner(root)).toBe('bar')
|
|
||||||
|
|
||||||
// update from parent
|
|
||||||
msg.value = 'qux'
|
|
||||||
expect(msg.value).toBe('qux')
|
|
||||||
|
|
||||||
await nextTick()
|
|
||||||
expect(msg.value).toBe('qux')
|
|
||||||
expect(foo.value).toBe('qux')
|
|
||||||
expect(setValue).toBeCalledTimes(1)
|
|
||||||
expect(compRender).toBeCalledTimes(3)
|
|
||||||
expect(serializeInner(root)).toBe('qux')
|
|
||||||
})
|
|
||||||
|
|
||||||
test('without parent value (local mutation)', async () => {
|
|
||||||
let foo: any
|
|
||||||
const update = () => {
|
|
||||||
foo.value = 'bar'
|
|
||||||
}
|
|
||||||
|
|
||||||
const compRender = vi.fn()
|
|
||||||
const Comp = defineComponent({
|
|
||||||
props: ['foo'],
|
|
||||||
emits: ['update:foo'],
|
|
||||||
setup(props) {
|
|
||||||
foo = useModel(props, 'foo')
|
|
||||||
return () => {
|
|
||||||
compRender()
|
|
||||||
return foo.value
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const root = nodeOps.createElement('div')
|
|
||||||
const updateFoo = vi.fn()
|
|
||||||
render(h(Comp, { 'onUpdate:foo': updateFoo }), root)
|
|
||||||
expect(compRender).toBeCalledTimes(1)
|
|
||||||
expect(serializeInner(root)).toBe('<!---->')
|
|
||||||
|
|
||||||
expect(foo.value).toBeUndefined()
|
|
||||||
update()
|
|
||||||
// when parent didn't provide value, local mutation is enabled
|
|
||||||
expect(foo.value).toBe('bar')
|
|
||||||
|
|
||||||
await nextTick()
|
|
||||||
expect(updateFoo).toBeCalledTimes(1)
|
|
||||||
expect(compRender).toBeCalledTimes(2)
|
|
||||||
expect(serializeInner(root)).toBe('bar')
|
|
||||||
})
|
|
||||||
|
|
||||||
test('without parent listener (local mutation)', async () => {
|
|
||||||
let foo: any
|
|
||||||
const update = () => {
|
|
||||||
foo.value = 'bar'
|
|
||||||
}
|
|
||||||
|
|
||||||
const compRender = vi.fn()
|
|
||||||
const Comp = defineComponent({
|
|
||||||
props: ['foo'],
|
|
||||||
emits: ['update:foo'],
|
|
||||||
setup(props) {
|
|
||||||
foo = useModel(props, 'foo')
|
|
||||||
return () => {
|
|
||||||
compRender()
|
|
||||||
return foo.value
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const root = nodeOps.createElement('div')
|
|
||||||
// provide initial value
|
|
||||||
render(h(Comp, { foo: 'initial' }), root)
|
|
||||||
expect(compRender).toBeCalledTimes(1)
|
|
||||||
expect(serializeInner(root)).toBe('initial')
|
|
||||||
|
|
||||||
expect(foo.value).toBe('initial')
|
|
||||||
update()
|
|
||||||
// when parent didn't provide value, local mutation is enabled
|
|
||||||
expect(foo.value).toBe('bar')
|
|
||||||
|
|
||||||
await nextTick()
|
|
||||||
expect(compRender).toBeCalledTimes(2)
|
|
||||||
expect(serializeInner(root)).toBe('bar')
|
|
||||||
})
|
|
||||||
|
|
||||||
test('kebab-case v-model (should not be local)', async () => {
|
|
||||||
let foo: any
|
|
||||||
|
|
||||||
const compRender = vi.fn()
|
|
||||||
const Comp = defineComponent({
|
|
||||||
props: ['fooBar'],
|
|
||||||
emits: ['update:fooBar'],
|
|
||||||
setup(props) {
|
|
||||||
foo = useModel(props, 'fooBar')
|
|
||||||
return () => {
|
|
||||||
compRender()
|
|
||||||
return foo.value
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const updateFooBar = vi.fn()
|
|
||||||
const root = nodeOps.createElement('div')
|
|
||||||
// v-model:foo-bar compiles to foo-bar and onUpdate:fooBar
|
|
||||||
render(
|
|
||||||
h(Comp, { 'foo-bar': 'initial', 'onUpdate:fooBar': updateFooBar }),
|
|
||||||
root,
|
|
||||||
)
|
|
||||||
expect(compRender).toBeCalledTimes(1)
|
|
||||||
expect(serializeInner(root)).toBe('initial')
|
|
||||||
|
|
||||||
expect(foo.value).toBe('initial')
|
|
||||||
foo.value = 'bar'
|
|
||||||
// should not be using local mode, so nothing should actually change
|
|
||||||
expect(foo.value).toBe('initial')
|
|
||||||
|
|
||||||
await nextTick()
|
|
||||||
expect(compRender).toBeCalledTimes(1)
|
|
||||||
expect(updateFooBar).toBeCalledTimes(1)
|
|
||||||
expect(updateFooBar).toHaveBeenCalledWith('bar')
|
|
||||||
expect(foo.value).toBe('initial')
|
|
||||||
expect(serializeInner(root)).toBe('initial')
|
|
||||||
})
|
|
||||||
|
|
||||||
test('kebab-case update listener (should not be local)', async () => {
|
|
||||||
let foo: any
|
|
||||||
|
|
||||||
const compRender = vi.fn()
|
|
||||||
const Comp = defineComponent({
|
|
||||||
props: ['fooBar'],
|
|
||||||
emits: ['update:fooBar'],
|
|
||||||
setup(props) {
|
|
||||||
foo = useModel(props, 'fooBar')
|
|
||||||
return () => {
|
|
||||||
compRender()
|
|
||||||
return foo.value
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const updateFooBar = vi.fn()
|
|
||||||
const root = nodeOps.createElement('div')
|
|
||||||
// The template compiler won't create hyphenated listeners, but it could have been passed manually
|
|
||||||
render(
|
|
||||||
h(Comp, { 'foo-bar': 'initial', 'onUpdate:foo-bar': updateFooBar }),
|
|
||||||
root,
|
|
||||||
)
|
|
||||||
expect(compRender).toBeCalledTimes(1)
|
|
||||||
expect(serializeInner(root)).toBe('initial')
|
|
||||||
|
|
||||||
expect(foo.value).toBe('initial')
|
|
||||||
foo.value = 'bar'
|
|
||||||
// should not be using local mode, so nothing should actually change
|
|
||||||
expect(foo.value).toBe('initial')
|
|
||||||
|
|
||||||
await nextTick()
|
|
||||||
expect(compRender).toBeCalledTimes(1)
|
|
||||||
expect(updateFooBar).toBeCalledTimes(1)
|
|
||||||
expect(updateFooBar).toHaveBeenCalledWith('bar')
|
|
||||||
expect(foo.value).toBe('initial')
|
|
||||||
expect(serializeInner(root)).toBe('initial')
|
|
||||||
})
|
|
||||||
|
|
||||||
test('default value', async () => {
|
|
||||||
let count: any
|
|
||||||
const inc = () => {
|
|
||||||
count.value++
|
|
||||||
}
|
|
||||||
|
|
||||||
const compRender = vi.fn()
|
|
||||||
const Comp = defineComponent({
|
|
||||||
props: { count: { default: 0 } },
|
|
||||||
emits: ['update:count'],
|
|
||||||
setup(props) {
|
|
||||||
count = useModel(props, 'count')
|
|
||||||
return () => {
|
|
||||||
compRender()
|
|
||||||
return count.value
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const root = nodeOps.createElement('div')
|
|
||||||
const updateCount = vi.fn()
|
|
||||||
render(h(Comp, { 'onUpdate:count': updateCount }), root)
|
|
||||||
expect(compRender).toBeCalledTimes(1)
|
|
||||||
expect(serializeInner(root)).toBe('0')
|
|
||||||
|
|
||||||
expect(count.value).toBe(0)
|
|
||||||
|
|
||||||
inc()
|
|
||||||
// when parent didn't provide value, local mutation is enabled
|
|
||||||
expect(count.value).toBe(1)
|
|
||||||
|
|
||||||
await nextTick()
|
|
||||||
|
|
||||||
expect(updateCount).toBeCalledTimes(1)
|
|
||||||
expect(compRender).toBeCalledTimes(2)
|
|
||||||
expect(serializeInner(root)).toBe('1')
|
|
||||||
})
|
|
||||||
|
|
||||||
test('parent limiting child value', async () => {
|
|
||||||
let childCount: Ref<number>
|
|
||||||
|
|
||||||
const compRender = vi.fn()
|
|
||||||
const Comp = defineComponent({
|
|
||||||
props: ['count'],
|
|
||||||
emits: ['update:count'],
|
|
||||||
setup(props) {
|
|
||||||
childCount = useModel(props, 'count')
|
|
||||||
return () => {
|
|
||||||
compRender()
|
|
||||||
return childCount.value
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const Parent = defineComponent({
|
|
||||||
setup() {
|
|
||||||
const count = ref(0)
|
|
||||||
watch(count, () => {
|
|
||||||
if (count.value < 0) {
|
|
||||||
count.value = 0
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return () =>
|
|
||||||
h(Comp, {
|
|
||||||
count: count.value,
|
|
||||||
'onUpdate:count': val => {
|
|
||||||
count.value = val
|
|
||||||
},
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const root = nodeOps.createElement('div')
|
|
||||||
render(h(Parent), root)
|
|
||||||
expect(serializeInner(root)).toBe('0')
|
|
||||||
|
|
||||||
// child update
|
|
||||||
childCount!.value = 1
|
|
||||||
// not yet updated
|
|
||||||
expect(childCount!.value).toBe(0)
|
|
||||||
|
|
||||||
await nextTick()
|
|
||||||
expect(childCount!.value).toBe(1)
|
|
||||||
expect(serializeInner(root)).toBe('1')
|
|
||||||
|
|
||||||
// child update to invalid value
|
|
||||||
childCount!.value = -1
|
|
||||||
// not yet updated
|
|
||||||
expect(childCount!.value).toBe(1)
|
|
||||||
|
|
||||||
await nextTick()
|
|
||||||
// limited to 0 by parent
|
|
||||||
expect(childCount!.value).toBe(0)
|
|
||||||
expect(serializeInner(root)).toBe('0')
|
|
||||||
})
|
|
||||||
|
|
||||||
test('has parent value -> no parent value', async () => {
|
|
||||||
let childCount: Ref<number>
|
|
||||||
|
|
||||||
const compRender = vi.fn()
|
|
||||||
const Comp = defineComponent({
|
|
||||||
props: ['count'],
|
|
||||||
emits: ['update:count'],
|
|
||||||
setup(props) {
|
|
||||||
childCount = useModel(props, 'count')
|
|
||||||
return () => {
|
|
||||||
compRender()
|
|
||||||
return childCount.value
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const toggle = ref(true)
|
|
||||||
const Parent = defineComponent({
|
|
||||||
setup() {
|
|
||||||
const count = ref(0)
|
|
||||||
return () =>
|
|
||||||
toggle.value
|
|
||||||
? h(Comp, {
|
|
||||||
count: count.value,
|
|
||||||
'onUpdate:count': val => {
|
|
||||||
count.value = val
|
|
||||||
},
|
|
||||||
})
|
|
||||||
: h(Comp)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const root = nodeOps.createElement('div')
|
|
||||||
render(h(Parent), root)
|
|
||||||
expect(serializeInner(root)).toBe('0')
|
|
||||||
|
|
||||||
// child update
|
|
||||||
childCount!.value = 1
|
|
||||||
// not yet updated
|
|
||||||
expect(childCount!.value).toBe(0)
|
|
||||||
|
|
||||||
await nextTick()
|
|
||||||
expect(childCount!.value).toBe(1)
|
|
||||||
expect(serializeInner(root)).toBe('1')
|
|
||||||
|
|
||||||
// parent change
|
|
||||||
toggle.value = false
|
|
||||||
|
|
||||||
await nextTick()
|
|
||||||
// localValue should be reset
|
|
||||||
expect(childCount!.value).toBeUndefined()
|
|
||||||
expect(serializeInner(root)).toBe('<!---->')
|
|
||||||
|
|
||||||
// child local mutation should continue to work
|
|
||||||
childCount!.value = 2
|
|
||||||
expect(childCount!.value).toBe(2)
|
|
||||||
|
|
||||||
await nextTick()
|
|
||||||
expect(serializeInner(root)).toBe('2')
|
|
||||||
})
|
|
||||||
|
|
||||||
// #9838
|
|
||||||
test('pass modelValue to slot (optimized mode) ', async () => {
|
|
||||||
let foo: any
|
|
||||||
const update = () => {
|
|
||||||
foo.value = 'bar'
|
|
||||||
}
|
|
||||||
|
|
||||||
const Comp = {
|
|
||||||
render(this: any) {
|
|
||||||
return this.$slots.default()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const childRender = vi.fn()
|
|
||||||
const slotRender = vi.fn()
|
|
||||||
const Child = defineComponent({
|
|
||||||
props: ['modelValue'],
|
|
||||||
emits: ['update:modelValue'],
|
|
||||||
setup(props) {
|
|
||||||
foo = useModel(props, 'modelValue')
|
|
||||||
return () => {
|
|
||||||
childRender()
|
|
||||||
return (
|
|
||||||
openBlock(),
|
|
||||||
createElementBlock(Fragment, null, [
|
|
||||||
createVNode(Comp, null, {
|
|
||||||
default: () => {
|
|
||||||
slotRender()
|
|
||||||
return createElementVNode('div', null, foo.value)
|
|
||||||
},
|
|
||||||
_: 1 /* STABLE */,
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const msg = ref('')
|
|
||||||
const setValue = vi.fn(v => (msg.value = v))
|
|
||||||
const root = nodeOps.createElement('div')
|
|
||||||
createApp({
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
openBlock(),
|
|
||||||
createBlock(
|
|
||||||
Child,
|
|
||||||
{
|
|
||||||
modelValue: msg.value,
|
|
||||||
'onUpdate:modelValue': setValue,
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
8 /* PROPS */,
|
|
||||||
['modelValue'],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
}).mount(root)
|
|
||||||
|
|
||||||
expect(foo.value).toBe('')
|
|
||||||
expect(msg.value).toBe('')
|
|
||||||
expect(setValue).not.toBeCalled()
|
|
||||||
expect(childRender).toBeCalledTimes(1)
|
|
||||||
expect(slotRender).toBeCalledTimes(1)
|
|
||||||
expect(serializeInner(root)).toBe('<div></div>')
|
|
||||||
|
|
||||||
// update from child
|
|
||||||
update()
|
|
||||||
|
|
||||||
await nextTick()
|
|
||||||
expect(msg.value).toBe('bar')
|
|
||||||
expect(foo.value).toBe('bar')
|
|
||||||
expect(setValue).toBeCalledTimes(1)
|
|
||||||
expect(childRender).toBeCalledTimes(2)
|
|
||||||
expect(slotRender).toBeCalledTimes(2)
|
|
||||||
expect(serializeInner(root)).toBe('<div>bar</div>')
|
|
||||||
})
|
|
||||||
|
|
||||||
test('with modifiers & transformers', async () => {
|
|
||||||
let childMsg: Ref<string>
|
|
||||||
let childModifiers: Record<string, true | undefined>
|
|
||||||
|
|
||||||
const compRender = vi.fn()
|
|
||||||
const Comp = defineComponent({
|
|
||||||
props: ['msg', 'msgModifiers'],
|
|
||||||
emits: ['update:msg'],
|
|
||||||
setup(props) {
|
|
||||||
;[childMsg, childModifiers] = useModel(props, 'msg', {
|
|
||||||
get(val) {
|
|
||||||
return val.toLowerCase()
|
|
||||||
},
|
|
||||||
set(val) {
|
|
||||||
if (childModifiers.upper) {
|
|
||||||
return val.toUpperCase()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
return () => {
|
|
||||||
compRender()
|
|
||||||
return childMsg.value
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const msg = ref('HI')
|
|
||||||
const Parent = defineComponent({
|
|
||||||
setup() {
|
|
||||||
return () =>
|
|
||||||
h(Comp, {
|
|
||||||
msg: msg.value,
|
|
||||||
msgModifiers: { upper: true },
|
|
||||||
'onUpdate:msg': val => {
|
|
||||||
msg.value = val
|
|
||||||
},
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const root = nodeOps.createElement('div')
|
|
||||||
render(h(Parent), root)
|
|
||||||
|
|
||||||
// should be lowered
|
|
||||||
expect(serializeInner(root)).toBe('hi')
|
|
||||||
|
|
||||||
// child update
|
|
||||||
childMsg!.value = 'Hmm'
|
|
||||||
|
|
||||||
await nextTick()
|
|
||||||
expect(childMsg!.value).toBe('hmm')
|
|
||||||
expect(serializeInner(root)).toBe('hmm')
|
|
||||||
// parent should get uppercase value
|
|
||||||
expect(msg.value).toBe('HMM')
|
|
||||||
|
|
||||||
// parent update
|
|
||||||
msg.value = 'Ughh'
|
|
||||||
await nextTick()
|
|
||||||
expect(serializeInner(root)).toBe('ughh')
|
|
||||||
expect(msg.value).toBe('Ughh')
|
|
||||||
|
|
||||||
// child update again
|
|
||||||
childMsg!.value = 'ughh'
|
|
||||||
await nextTick()
|
|
||||||
expect(msg.value).toBe('UGHH')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test('createPropsRestProxy', () => {
|
test('createPropsRestProxy', () => {
|
||||||
const original = shallowReactive({
|
const original = shallowReactive({
|
||||||
foo: 1,
|
foo: 1,
|
||||||
|
|
|
@ -1641,6 +1641,141 @@ describe('Suspense', () => {
|
||||||
expect(serializeInner(root)).toBe(expected)
|
expect(serializeInner(root)).toBe(expected)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
//#8678
|
||||||
|
test('nested suspense (child suspense update before parent suspense resolve)', async () => {
|
||||||
|
const calls: string[] = []
|
||||||
|
|
||||||
|
const InnerA = defineAsyncComponent(
|
||||||
|
{
|
||||||
|
setup: () => {
|
||||||
|
calls.push('innerA created')
|
||||||
|
onMounted(() => {
|
||||||
|
calls.push('innerA mounted')
|
||||||
|
})
|
||||||
|
return () => h('div', 'innerA')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
10,
|
||||||
|
)
|
||||||
|
|
||||||
|
const InnerB = defineAsyncComponent(
|
||||||
|
{
|
||||||
|
setup: () => {
|
||||||
|
calls.push('innerB created')
|
||||||
|
onMounted(() => {
|
||||||
|
calls.push('innerB mounted')
|
||||||
|
})
|
||||||
|
return () => h('div', 'innerB')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
10,
|
||||||
|
)
|
||||||
|
|
||||||
|
const OuterA = defineAsyncComponent(
|
||||||
|
{
|
||||||
|
setup: (_, { slots }: any) => {
|
||||||
|
calls.push('outerA created')
|
||||||
|
onMounted(() => {
|
||||||
|
calls.push('outerA mounted')
|
||||||
|
})
|
||||||
|
return () =>
|
||||||
|
h(Fragment, null, [h('div', 'outerA'), slots.default?.()])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
5,
|
||||||
|
)
|
||||||
|
|
||||||
|
const OuterB = defineAsyncComponent(
|
||||||
|
{
|
||||||
|
setup: (_, { slots }: any) => {
|
||||||
|
calls.push('outerB created')
|
||||||
|
onMounted(() => {
|
||||||
|
calls.push('outerB mounted')
|
||||||
|
})
|
||||||
|
return () =>
|
||||||
|
h(Fragment, null, [h('div', 'outerB'), slots.default?.()])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
5,
|
||||||
|
)
|
||||||
|
|
||||||
|
const outerToggle = ref(false)
|
||||||
|
const innerToggle = ref(false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <Suspense>
|
||||||
|
* <component :is="outerToggle ? outerB : outerA">
|
||||||
|
* <Suspense>
|
||||||
|
* <component :is="innerToggle ? innerB : innerA" />
|
||||||
|
* </Suspense>
|
||||||
|
* </component>
|
||||||
|
* </Suspense>
|
||||||
|
*/
|
||||||
|
const Comp = {
|
||||||
|
setup() {
|
||||||
|
return () =>
|
||||||
|
h(Suspense, null, {
|
||||||
|
default: [
|
||||||
|
h(outerToggle.value ? OuterB : OuterA, null, {
|
||||||
|
default: () =>
|
||||||
|
h(Suspense, null, {
|
||||||
|
default: h(innerToggle.value ? InnerB : InnerA),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
fallback: h('div', 'fallback outer'),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
render(h(Comp), root)
|
||||||
|
expect(serializeInner(root)).toBe(`<div>fallback outer</div>`)
|
||||||
|
|
||||||
|
// mount outer component
|
||||||
|
await Promise.all(deps)
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
|
expect(serializeInner(root)).toBe(`<div>outerA</div><!---->`)
|
||||||
|
expect(calls).toEqual([`outerA created`, `outerA mounted`])
|
||||||
|
|
||||||
|
// mount inner component
|
||||||
|
await Promise.all(deps)
|
||||||
|
await nextTick()
|
||||||
|
expect(serializeInner(root)).toBe(`<div>outerA</div><div>innerA</div>`)
|
||||||
|
|
||||||
|
expect(calls).toEqual([
|
||||||
|
'outerA created',
|
||||||
|
'outerA mounted',
|
||||||
|
'innerA created',
|
||||||
|
'innerA mounted',
|
||||||
|
])
|
||||||
|
|
||||||
|
calls.length = 0
|
||||||
|
deps.length = 0
|
||||||
|
|
||||||
|
// toggle both outer and inner components
|
||||||
|
outerToggle.value = true
|
||||||
|
innerToggle.value = true
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
|
await Promise.all(deps)
|
||||||
|
await nextTick()
|
||||||
|
expect(serializeInner(root)).toBe(`<div>outerB</div><!---->`)
|
||||||
|
|
||||||
|
await Promise.all(deps)
|
||||||
|
await nextTick()
|
||||||
|
expect(serializeInner(root)).toBe(`<div>outerB</div><div>innerB</div>`)
|
||||||
|
|
||||||
|
// innerB only mount once
|
||||||
|
expect(calls).toEqual([
|
||||||
|
'outerB created',
|
||||||
|
'outerB mounted',
|
||||||
|
'innerB created',
|
||||||
|
'innerB mounted',
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
// #6416
|
// #6416
|
||||||
test('KeepAlive with Suspense', async () => {
|
test('KeepAlive with Suspense', async () => {
|
||||||
const Async = defineAsyncComponent({
|
const Async = defineAsyncComponent({
|
||||||
|
@ -1692,7 +1827,7 @@ describe('Suspense', () => {
|
||||||
expect(serializeInner(root)).toBe(`<div>sync</div>`)
|
expect(serializeInner(root)).toBe(`<div>sync</div>`)
|
||||||
})
|
})
|
||||||
|
|
||||||
// #6416 follow up
|
// #6416 follow up / #10017
|
||||||
test('Suspense patched during HOC async component re-mount', async () => {
|
test('Suspense patched during HOC async component re-mount', async () => {
|
||||||
const key = ref('k')
|
const key = ref('k')
|
||||||
const data = ref('data')
|
const data = ref('data')
|
||||||
|
@ -1713,7 +1848,7 @@ describe('Suspense', () => {
|
||||||
const App = {
|
const App = {
|
||||||
render() {
|
render() {
|
||||||
return h(Suspense, null, {
|
return h(Suspense, null, {
|
||||||
default: h(Comp, { data: data.value }),
|
default: h(Comp, { k: key.value, data: data.value }),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,529 @@
|
||||||
|
import {
|
||||||
|
Fragment,
|
||||||
|
type Ref,
|
||||||
|
createApp,
|
||||||
|
createBlock,
|
||||||
|
createElementBlock,
|
||||||
|
createElementVNode,
|
||||||
|
createVNode,
|
||||||
|
defineComponent,
|
||||||
|
h,
|
||||||
|
nextTick,
|
||||||
|
nodeOps,
|
||||||
|
openBlock,
|
||||||
|
ref,
|
||||||
|
render,
|
||||||
|
serializeInner,
|
||||||
|
watch,
|
||||||
|
} from '@vue/runtime-test'
|
||||||
|
import { useModel } from '../../src/helpers/useModel'
|
||||||
|
|
||||||
|
describe('useModel', () => {
|
||||||
|
test('basic', async () => {
|
||||||
|
let foo: any
|
||||||
|
const update = () => {
|
||||||
|
foo.value = 'bar'
|
||||||
|
}
|
||||||
|
|
||||||
|
const compRender = vi.fn()
|
||||||
|
const Comp = defineComponent({
|
||||||
|
props: ['modelValue'],
|
||||||
|
emits: ['update:modelValue'],
|
||||||
|
setup(props) {
|
||||||
|
foo = useModel(props, 'modelValue')
|
||||||
|
return () => {
|
||||||
|
compRender()
|
||||||
|
return foo.value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const msg = ref('')
|
||||||
|
const setValue = vi.fn(v => (msg.value = v))
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
createApp(() =>
|
||||||
|
h(Comp, {
|
||||||
|
modelValue: msg.value,
|
||||||
|
'onUpdate:modelValue': setValue,
|
||||||
|
}),
|
||||||
|
).mount(root)
|
||||||
|
|
||||||
|
expect(foo.value).toBe('')
|
||||||
|
expect(msg.value).toBe('')
|
||||||
|
expect(setValue).not.toBeCalled()
|
||||||
|
expect(compRender).toBeCalledTimes(1)
|
||||||
|
expect(serializeInner(root)).toBe('')
|
||||||
|
|
||||||
|
// update from child
|
||||||
|
update()
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
expect(msg.value).toBe('bar')
|
||||||
|
expect(foo.value).toBe('bar')
|
||||||
|
expect(setValue).toBeCalledTimes(1)
|
||||||
|
expect(compRender).toBeCalledTimes(2)
|
||||||
|
expect(serializeInner(root)).toBe('bar')
|
||||||
|
|
||||||
|
// update from parent
|
||||||
|
msg.value = 'qux'
|
||||||
|
expect(msg.value).toBe('qux')
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
expect(msg.value).toBe('qux')
|
||||||
|
expect(foo.value).toBe('qux')
|
||||||
|
expect(setValue).toBeCalledTimes(1)
|
||||||
|
expect(compRender).toBeCalledTimes(3)
|
||||||
|
expect(serializeInner(root)).toBe('qux')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('without parent value (local mutation)', async () => {
|
||||||
|
let foo: any
|
||||||
|
const update = () => {
|
||||||
|
foo.value = 'bar'
|
||||||
|
}
|
||||||
|
|
||||||
|
const compRender = vi.fn()
|
||||||
|
const Comp = defineComponent({
|
||||||
|
props: ['foo'],
|
||||||
|
emits: ['update:foo'],
|
||||||
|
setup(props) {
|
||||||
|
foo = useModel(props, 'foo')
|
||||||
|
return () => {
|
||||||
|
compRender()
|
||||||
|
return foo.value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
const updateFoo = vi.fn()
|
||||||
|
render(h(Comp, { 'onUpdate:foo': updateFoo }), root)
|
||||||
|
expect(compRender).toBeCalledTimes(1)
|
||||||
|
expect(serializeInner(root)).toBe('<!---->')
|
||||||
|
|
||||||
|
expect(foo.value).toBeUndefined()
|
||||||
|
update()
|
||||||
|
// when parent didn't provide value, local mutation is enabled
|
||||||
|
expect(foo.value).toBe('bar')
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
expect(updateFoo).toBeCalledTimes(1)
|
||||||
|
expect(compRender).toBeCalledTimes(2)
|
||||||
|
expect(serializeInner(root)).toBe('bar')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('without parent listener (local mutation)', async () => {
|
||||||
|
let foo: any
|
||||||
|
const update = () => {
|
||||||
|
foo.value = 'bar'
|
||||||
|
}
|
||||||
|
|
||||||
|
const compRender = vi.fn()
|
||||||
|
const Comp = defineComponent({
|
||||||
|
props: ['foo'],
|
||||||
|
emits: ['update:foo'],
|
||||||
|
setup(props) {
|
||||||
|
foo = useModel(props, 'foo')
|
||||||
|
return () => {
|
||||||
|
compRender()
|
||||||
|
return foo.value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
// provide initial value
|
||||||
|
render(h(Comp, { foo: 'initial' }), root)
|
||||||
|
expect(compRender).toBeCalledTimes(1)
|
||||||
|
expect(serializeInner(root)).toBe('initial')
|
||||||
|
|
||||||
|
expect(foo.value).toBe('initial')
|
||||||
|
update()
|
||||||
|
// when parent didn't provide value, local mutation is enabled
|
||||||
|
expect(foo.value).toBe('bar')
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
expect(compRender).toBeCalledTimes(2)
|
||||||
|
expect(serializeInner(root)).toBe('bar')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('kebab-case v-model (should not be local)', async () => {
|
||||||
|
let foo: any
|
||||||
|
|
||||||
|
const compRender = vi.fn()
|
||||||
|
const Comp = defineComponent({
|
||||||
|
props: ['fooBar'],
|
||||||
|
emits: ['update:fooBar'],
|
||||||
|
setup(props) {
|
||||||
|
foo = useModel(props, 'fooBar')
|
||||||
|
return () => {
|
||||||
|
compRender()
|
||||||
|
return foo.value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const updateFooBar = vi.fn()
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
// v-model:foo-bar compiles to foo-bar and onUpdate:fooBar
|
||||||
|
render(
|
||||||
|
h(Comp, { 'foo-bar': 'initial', 'onUpdate:fooBar': updateFooBar }),
|
||||||
|
root,
|
||||||
|
)
|
||||||
|
expect(compRender).toBeCalledTimes(1)
|
||||||
|
expect(serializeInner(root)).toBe('initial')
|
||||||
|
|
||||||
|
expect(foo.value).toBe('initial')
|
||||||
|
foo.value = 'bar'
|
||||||
|
// should not be using local mode, so nothing should actually change
|
||||||
|
expect(foo.value).toBe('initial')
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
expect(compRender).toBeCalledTimes(1)
|
||||||
|
expect(updateFooBar).toBeCalledTimes(1)
|
||||||
|
expect(updateFooBar).toHaveBeenCalledWith('bar')
|
||||||
|
expect(foo.value).toBe('initial')
|
||||||
|
expect(serializeInner(root)).toBe('initial')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('kebab-case update listener (should not be local)', async () => {
|
||||||
|
let foo: any
|
||||||
|
|
||||||
|
const compRender = vi.fn()
|
||||||
|
const Comp = defineComponent({
|
||||||
|
props: ['fooBar'],
|
||||||
|
emits: ['update:fooBar'],
|
||||||
|
setup(props) {
|
||||||
|
foo = useModel(props, 'fooBar')
|
||||||
|
return () => {
|
||||||
|
compRender()
|
||||||
|
return foo.value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const updateFooBar = vi.fn()
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
// The template compiler won't create hyphenated listeners, but it could have been passed manually
|
||||||
|
render(
|
||||||
|
h(Comp, { 'foo-bar': 'initial', 'onUpdate:foo-bar': updateFooBar }),
|
||||||
|
root,
|
||||||
|
)
|
||||||
|
expect(compRender).toBeCalledTimes(1)
|
||||||
|
expect(serializeInner(root)).toBe('initial')
|
||||||
|
|
||||||
|
expect(foo.value).toBe('initial')
|
||||||
|
foo.value = 'bar'
|
||||||
|
// should not be using local mode, so nothing should actually change
|
||||||
|
expect(foo.value).toBe('initial')
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
expect(compRender).toBeCalledTimes(1)
|
||||||
|
expect(updateFooBar).toBeCalledTimes(1)
|
||||||
|
expect(updateFooBar).toHaveBeenCalledWith('bar')
|
||||||
|
expect(foo.value).toBe('initial')
|
||||||
|
expect(serializeInner(root)).toBe('initial')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('default value', async () => {
|
||||||
|
let count: any
|
||||||
|
const inc = () => {
|
||||||
|
count.value++
|
||||||
|
}
|
||||||
|
|
||||||
|
const compRender = vi.fn()
|
||||||
|
const Comp = defineComponent({
|
||||||
|
props: { count: { default: 0 } },
|
||||||
|
emits: ['update:count'],
|
||||||
|
setup(props) {
|
||||||
|
count = useModel(props, 'count')
|
||||||
|
return () => {
|
||||||
|
compRender()
|
||||||
|
return count.value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
const updateCount = vi.fn()
|
||||||
|
render(h(Comp, { 'onUpdate:count': updateCount }), root)
|
||||||
|
expect(compRender).toBeCalledTimes(1)
|
||||||
|
expect(serializeInner(root)).toBe('0')
|
||||||
|
|
||||||
|
expect(count.value).toBe(0)
|
||||||
|
|
||||||
|
inc()
|
||||||
|
// when parent didn't provide value, local mutation is enabled
|
||||||
|
expect(count.value).toBe(1)
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
|
expect(updateCount).toBeCalledTimes(1)
|
||||||
|
expect(compRender).toBeCalledTimes(2)
|
||||||
|
expect(serializeInner(root)).toBe('1')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('parent limiting child value', async () => {
|
||||||
|
let childCount: Ref<number>
|
||||||
|
|
||||||
|
const compRender = vi.fn()
|
||||||
|
const Comp = defineComponent({
|
||||||
|
props: ['count'],
|
||||||
|
emits: ['update:count'],
|
||||||
|
setup(props) {
|
||||||
|
childCount = useModel(props, 'count')
|
||||||
|
return () => {
|
||||||
|
compRender()
|
||||||
|
return childCount.value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const Parent = defineComponent({
|
||||||
|
setup() {
|
||||||
|
const count = ref(0)
|
||||||
|
watch(count, () => {
|
||||||
|
if (count.value < 0) {
|
||||||
|
count.value = 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return () =>
|
||||||
|
h(Comp, {
|
||||||
|
count: count.value,
|
||||||
|
'onUpdate:count': val => {
|
||||||
|
count.value = val
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
render(h(Parent), root)
|
||||||
|
expect(serializeInner(root)).toBe('0')
|
||||||
|
|
||||||
|
// child update
|
||||||
|
childCount!.value = 1
|
||||||
|
// not yet updated
|
||||||
|
expect(childCount!.value).toBe(0)
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
expect(childCount!.value).toBe(1)
|
||||||
|
expect(serializeInner(root)).toBe('1')
|
||||||
|
|
||||||
|
// child update to invalid value
|
||||||
|
childCount!.value = -1
|
||||||
|
// not yet updated
|
||||||
|
expect(childCount!.value).toBe(1)
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
// limited to 0 by parent
|
||||||
|
expect(childCount!.value).toBe(0)
|
||||||
|
expect(serializeInner(root)).toBe('0')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('has parent value -> no parent value', async () => {
|
||||||
|
let childCount: Ref<number>
|
||||||
|
|
||||||
|
const compRender = vi.fn()
|
||||||
|
const Comp = defineComponent({
|
||||||
|
props: ['count'],
|
||||||
|
emits: ['update:count'],
|
||||||
|
setup(props) {
|
||||||
|
childCount = useModel(props, 'count')
|
||||||
|
return () => {
|
||||||
|
compRender()
|
||||||
|
return childCount.value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const toggle = ref(true)
|
||||||
|
const Parent = defineComponent({
|
||||||
|
setup() {
|
||||||
|
const count = ref(0)
|
||||||
|
return () =>
|
||||||
|
toggle.value
|
||||||
|
? h(Comp, {
|
||||||
|
count: count.value,
|
||||||
|
'onUpdate:count': val => {
|
||||||
|
count.value = val
|
||||||
|
},
|
||||||
|
})
|
||||||
|
: h(Comp)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
render(h(Parent), root)
|
||||||
|
expect(serializeInner(root)).toBe('0')
|
||||||
|
|
||||||
|
// child update
|
||||||
|
childCount!.value = 1
|
||||||
|
// not yet updated
|
||||||
|
expect(childCount!.value).toBe(0)
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
expect(childCount!.value).toBe(1)
|
||||||
|
expect(serializeInner(root)).toBe('1')
|
||||||
|
|
||||||
|
// parent change
|
||||||
|
toggle.value = false
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
// localValue should be reset
|
||||||
|
expect(childCount!.value).toBeUndefined()
|
||||||
|
expect(serializeInner(root)).toBe('<!---->')
|
||||||
|
|
||||||
|
// child local mutation should continue to work
|
||||||
|
childCount!.value = 2
|
||||||
|
expect(childCount!.value).toBe(2)
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
expect(serializeInner(root)).toBe('2')
|
||||||
|
})
|
||||||
|
|
||||||
|
// #9838
|
||||||
|
test('pass modelValue to slot (optimized mode) ', async () => {
|
||||||
|
let foo: any
|
||||||
|
const update = () => {
|
||||||
|
foo.value = 'bar'
|
||||||
|
}
|
||||||
|
|
||||||
|
const Comp = {
|
||||||
|
render(this: any) {
|
||||||
|
return this.$slots.default()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const childRender = vi.fn()
|
||||||
|
const slotRender = vi.fn()
|
||||||
|
const Child = defineComponent({
|
||||||
|
props: ['modelValue'],
|
||||||
|
emits: ['update:modelValue'],
|
||||||
|
setup(props) {
|
||||||
|
foo = useModel(props, 'modelValue')
|
||||||
|
return () => {
|
||||||
|
childRender()
|
||||||
|
return (
|
||||||
|
openBlock(),
|
||||||
|
createElementBlock(Fragment, null, [
|
||||||
|
createVNode(Comp, null, {
|
||||||
|
default: () => {
|
||||||
|
slotRender()
|
||||||
|
return createElementVNode('div', null, foo.value)
|
||||||
|
},
|
||||||
|
_: 1 /* STABLE */,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const msg = ref('')
|
||||||
|
const setValue = vi.fn(v => (msg.value = v))
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
createApp({
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
openBlock(),
|
||||||
|
createBlock(
|
||||||
|
Child,
|
||||||
|
{
|
||||||
|
modelValue: msg.value,
|
||||||
|
'onUpdate:modelValue': setValue,
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
8 /* PROPS */,
|
||||||
|
['modelValue'],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}).mount(root)
|
||||||
|
|
||||||
|
expect(foo.value).toBe('')
|
||||||
|
expect(msg.value).toBe('')
|
||||||
|
expect(setValue).not.toBeCalled()
|
||||||
|
expect(childRender).toBeCalledTimes(1)
|
||||||
|
expect(slotRender).toBeCalledTimes(1)
|
||||||
|
expect(serializeInner(root)).toBe('<div></div>')
|
||||||
|
|
||||||
|
// update from child
|
||||||
|
update()
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
expect(msg.value).toBe('bar')
|
||||||
|
expect(foo.value).toBe('bar')
|
||||||
|
expect(setValue).toBeCalledTimes(1)
|
||||||
|
expect(childRender).toBeCalledTimes(2)
|
||||||
|
expect(slotRender).toBeCalledTimes(2)
|
||||||
|
expect(serializeInner(root)).toBe('<div>bar</div>')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('with modifiers & transformers', async () => {
|
||||||
|
let childMsg: Ref<string>
|
||||||
|
let childModifiers: Record<string, true | undefined>
|
||||||
|
|
||||||
|
const compRender = vi.fn()
|
||||||
|
const Comp = defineComponent({
|
||||||
|
props: ['msg', 'msgModifiers'],
|
||||||
|
emits: ['update:msg'],
|
||||||
|
setup(props) {
|
||||||
|
;[childMsg, childModifiers] = useModel(props, 'msg', {
|
||||||
|
get(val) {
|
||||||
|
return val.toLowerCase()
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
if (childModifiers.upper) {
|
||||||
|
return val.toUpperCase()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return () => {
|
||||||
|
compRender()
|
||||||
|
return childMsg.value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const msg = ref('HI')
|
||||||
|
const Parent = defineComponent({
|
||||||
|
setup() {
|
||||||
|
return () =>
|
||||||
|
h(Comp, {
|
||||||
|
msg: msg.value,
|
||||||
|
msgModifiers: { upper: true },
|
||||||
|
'onUpdate:msg': val => {
|
||||||
|
msg.value = val
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
render(h(Parent), root)
|
||||||
|
|
||||||
|
// should be lowered
|
||||||
|
expect(serializeInner(root)).toBe('hi')
|
||||||
|
|
||||||
|
// child update
|
||||||
|
childMsg!.value = 'Hmm'
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
expect(childMsg!.value).toBe('hmm')
|
||||||
|
expect(serializeInner(root)).toBe('hmm')
|
||||||
|
// parent should get uppercase value
|
||||||
|
expect(msg.value).toBe('HMM')
|
||||||
|
|
||||||
|
// parent update
|
||||||
|
msg.value = 'Ughh'
|
||||||
|
await nextTick()
|
||||||
|
expect(serializeInner(root)).toBe('ughh')
|
||||||
|
expect(msg.value).toBe('Ughh')
|
||||||
|
|
||||||
|
// child update again
|
||||||
|
childMsg!.value = 'ughh'
|
||||||
|
await nextTick()
|
||||||
|
expect(msg.value).toBe('UGHH')
|
||||||
|
})
|
||||||
|
})
|
|
@ -1080,13 +1080,11 @@ describe('SSR hydration', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test('force hydrate prop with `.prop` modifier', () => {
|
test('force hydrate prop with `.prop` modifier', () => {
|
||||||
const { container } = mountWithHydration(
|
const { container } = mountWithHydration('<input type="checkbox">', () =>
|
||||||
'<input type="checkbox" :indeterminate.prop="true">',
|
h('input', {
|
||||||
() =>
|
type: 'checkbox',
|
||||||
h('input', {
|
'.indeterminate': true,
|
||||||
type: 'checkbox',
|
}),
|
||||||
'.indeterminate': true,
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
expect((container.firstChild! as any).indeterminate).toBe(true)
|
expect((container.firstChild! as any).indeterminate).toBe(true)
|
||||||
})
|
})
|
||||||
|
@ -1431,11 +1429,35 @@ describe('SSR hydration', () => {
|
||||||
mountWithHydration(`<div style="color:red;"></div>`, () =>
|
mountWithHydration(`<div style="color:red;"></div>`, () =>
|
||||||
h('div', { style: `color:red;` }),
|
h('div', { style: `color:red;` }),
|
||||||
)
|
)
|
||||||
|
mountWithHydration(
|
||||||
|
`<div style="color:red; font-size: 12px;"></div>`,
|
||||||
|
() => h('div', { style: `font-size: 12px; color:red;` }),
|
||||||
|
)
|
||||||
|
mountWithHydration(`<div style="color:red;display:none;"></div>`, () =>
|
||||||
|
withDirectives(createVNode('div', { style: 'color: red' }, ''), [
|
||||||
|
[vShow, false],
|
||||||
|
]),
|
||||||
|
)
|
||||||
expect(`Hydration style mismatch`).not.toHaveBeenWarned()
|
expect(`Hydration style mismatch`).not.toHaveBeenWarned()
|
||||||
mountWithHydration(`<div style="color:red;"></div>`, () =>
|
mountWithHydration(`<div style="color:red;"></div>`, () =>
|
||||||
h('div', { style: { color: 'green' } }),
|
h('div', { style: { color: 'green' } }),
|
||||||
)
|
)
|
||||||
expect(`Hydration style mismatch`).toHaveBeenWarned()
|
expect(`Hydration style mismatch`).toHaveBeenWarnedTimes(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('style mismatch w/ v-show', () => {
|
||||||
|
mountWithHydration(`<div style="color:red;display:none"></div>`, () =>
|
||||||
|
withDirectives(createVNode('div', { style: 'color: red' }, ''), [
|
||||||
|
[vShow, false],
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
expect(`Hydration style mismatch`).not.toHaveBeenWarned()
|
||||||
|
mountWithHydration(`<div style="color:red;"></div>`, () =>
|
||||||
|
withDirectives(createVNode('div', { style: 'color: red' }, ''), [
|
||||||
|
[vShow, false],
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
expect(`Hydration style mismatch`).toHaveBeenWarnedTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('attr mismatch', () => {
|
test('attr mismatch', () => {
|
||||||
|
@ -1454,10 +1476,60 @@ describe('SSR hydration', () => {
|
||||||
expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
|
expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
|
||||||
|
|
||||||
mountWithHydration(`<div></div>`, () => h('div', { id: 'foo' }))
|
mountWithHydration(`<div></div>`, () => h('div', { id: 'foo' }))
|
||||||
expect(`Hydration attribute mismatch`).toHaveBeenWarned()
|
expect(`Hydration attribute mismatch`).toHaveBeenWarnedTimes(1)
|
||||||
|
|
||||||
mountWithHydration(`<div id="bar"></div>`, () => h('div', { id: 'foo' }))
|
mountWithHydration(`<div id="bar"></div>`, () => h('div', { id: 'foo' }))
|
||||||
expect(`Hydration attribute mismatch`).toHaveBeenWarnedTimes(2)
|
expect(`Hydration attribute mismatch`).toHaveBeenWarnedTimes(2)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('attr special case: textarea value', () => {
|
||||||
|
mountWithHydration(`<textarea>foo</textarea>`, () =>
|
||||||
|
h('textarea', { value: 'foo' }),
|
||||||
|
)
|
||||||
|
mountWithHydration(`<textarea></textarea>`, () =>
|
||||||
|
h('textarea', { value: '' }),
|
||||||
|
)
|
||||||
|
expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
|
||||||
|
|
||||||
|
mountWithHydration(`<textarea>foo</textarea>`, () =>
|
||||||
|
h('textarea', { value: 'bar' }),
|
||||||
|
)
|
||||||
|
expect(`Hydration attribute mismatch`).toHaveBeenWarned()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('boolean attr handling', () => {
|
||||||
|
mountWithHydration(`<input />`, () => h('input', { readonly: false }))
|
||||||
|
expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
|
||||||
|
|
||||||
|
mountWithHydration(`<input readonly />`, () =>
|
||||||
|
h('input', { readonly: true }),
|
||||||
|
)
|
||||||
|
expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
|
||||||
|
|
||||||
|
mountWithHydration(`<input readonly="readonly" />`, () =>
|
||||||
|
h('input', { readonly: true }),
|
||||||
|
)
|
||||||
|
expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('client value is null or undefined', () => {
|
||||||
|
mountWithHydration(`<div></div>`, () =>
|
||||||
|
h('div', { draggable: undefined }),
|
||||||
|
)
|
||||||
|
expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
|
||||||
|
|
||||||
|
mountWithHydration(`<input />`, () => h('input', { type: null }))
|
||||||
|
expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should not warn against object values', () => {
|
||||||
|
mountWithHydration(`<input />`, () => h('input', { from: {} }))
|
||||||
|
expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should not warn on falsy bindings of non-property keys', () => {
|
||||||
|
mountWithHydration(`<button />`, () => h('button', { href: undefined }))
|
||||||
|
expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -8,6 +8,8 @@ import {
|
||||||
type FunctionalComponent,
|
type FunctionalComponent,
|
||||||
createBlock,
|
createBlock,
|
||||||
createCommentVNode,
|
createCommentVNode,
|
||||||
|
createElementBlock,
|
||||||
|
createElementVNode,
|
||||||
defineComponent,
|
defineComponent,
|
||||||
h,
|
h,
|
||||||
mergeProps,
|
mergeProps,
|
||||||
|
@ -673,6 +675,58 @@ describe('attribute fallthrough', () => {
|
||||||
expect(click).toHaveBeenCalled()
|
expect(click).toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should support fallthrough for nested dev root fragments', async () => {
|
||||||
|
const toggle = ref(false)
|
||||||
|
|
||||||
|
const Child = {
|
||||||
|
setup() {
|
||||||
|
return () => (
|
||||||
|
openBlock(),
|
||||||
|
createElementBlock(
|
||||||
|
Fragment,
|
||||||
|
null,
|
||||||
|
[
|
||||||
|
createCommentVNode(' comment A '),
|
||||||
|
toggle.value
|
||||||
|
? (openBlock(), createElementBlock('span', { key: 0 }, 'Foo'))
|
||||||
|
: (openBlock(),
|
||||||
|
createElementBlock(
|
||||||
|
Fragment,
|
||||||
|
{ key: 1 },
|
||||||
|
[
|
||||||
|
createCommentVNode(' comment B '),
|
||||||
|
createElementVNode('div', null, 'Bar'),
|
||||||
|
],
|
||||||
|
PatchFlags.STABLE_FRAGMENT | PatchFlags.DEV_ROOT_FRAGMENT,
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
PatchFlags.STABLE_FRAGMENT | PatchFlags.DEV_ROOT_FRAGMENT,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const Root = {
|
||||||
|
setup() {
|
||||||
|
return () => (openBlock(), createBlock(Child, { class: 'red' }))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const root = document.createElement('div')
|
||||||
|
document.body.appendChild(root)
|
||||||
|
render(h(Root), root)
|
||||||
|
|
||||||
|
expect(root.innerHTML).toBe(
|
||||||
|
`<!-- comment A --><!-- comment B --><div class="red">Bar</div>`,
|
||||||
|
)
|
||||||
|
|
||||||
|
toggle.value = true
|
||||||
|
await nextTick()
|
||||||
|
expect(root.innerHTML).toBe(
|
||||||
|
`<!-- comment A --><span class=\"red\">Foo</span>`,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
// #1989
|
// #1989
|
||||||
it('should not fallthrough v-model listeners with corresponding declared prop', () => {
|
it('should not fallthrough v-model listeners with corresponding declared prop', () => {
|
||||||
let textFoo = ''
|
let textFoo = ''
|
||||||
|
|
|
@ -351,4 +351,16 @@ describe('renderer: fragment', () => {
|
||||||
render(renderFn(['two', 'one']), root)
|
render(renderFn(['two', 'one']), root)
|
||||||
expect(serializeInner(root)).toBe(`text<div>two</div>text<div>one</div>`)
|
expect(serializeInner(root)).toBe(`text<div>two</div>text<div>one</div>`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #10007
|
||||||
|
test('empty fragment', () => {
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
|
||||||
|
const renderFn = () => {
|
||||||
|
return openBlock(true), createBlock(Fragment, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
render(renderFn(), root)
|
||||||
|
expect(serializeInner(root)).toBe('')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -610,4 +610,25 @@ describe('scheduler', () => {
|
||||||
expect(await p).toBe(1)
|
expect(await p).toBe(1)
|
||||||
expect(fn).toHaveBeenCalledTimes(1)
|
expect(fn).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #10003
|
||||||
|
test('nested flushPostFlushCbs', async () => {
|
||||||
|
const calls: string[] = []
|
||||||
|
const cb1 = () => calls.push('cb1')
|
||||||
|
// cb1 has no id
|
||||||
|
const cb2 = () => calls.push('cb2')
|
||||||
|
cb2.id = -1
|
||||||
|
const queueAndFlush = (hook: Function) => {
|
||||||
|
queuePostFlushCb(hook)
|
||||||
|
flushPostFlushCbs()
|
||||||
|
}
|
||||||
|
|
||||||
|
queueAndFlush(() => {
|
||||||
|
queuePostFlushCb([cb1, cb2])
|
||||||
|
flushPostFlushCbs()
|
||||||
|
})
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
expect(calls).toEqual(['cb2', 'cb1'])
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,14 +1,23 @@
|
||||||
import {
|
import {
|
||||||
|
Fragment,
|
||||||
|
createBlock,
|
||||||
|
createCommentVNode,
|
||||||
|
createVNode,
|
||||||
|
defineComponent,
|
||||||
h,
|
h,
|
||||||
|
nextTick,
|
||||||
nodeOps,
|
nodeOps,
|
||||||
|
openBlock,
|
||||||
popScopeId,
|
popScopeId,
|
||||||
pushScopeId,
|
pushScopeId,
|
||||||
|
ref,
|
||||||
render,
|
render,
|
||||||
renderSlot,
|
renderSlot,
|
||||||
serializeInner,
|
serializeInner,
|
||||||
withScopeId,
|
withScopeId,
|
||||||
} from '@vue/runtime-test'
|
} from '@vue/runtime-test'
|
||||||
import { withCtx } from '../src/componentRenderContext'
|
import { withCtx } from '../src/componentRenderContext'
|
||||||
|
import { PatchFlags } from '@vue/shared'
|
||||||
|
|
||||||
describe('scopeId runtime support', () => {
|
describe('scopeId runtime support', () => {
|
||||||
test('should attach scopeId', () => {
|
test('should attach scopeId', () => {
|
||||||
|
@ -184,6 +193,55 @@ describe('scopeId runtime support', () => {
|
||||||
|
|
||||||
expect(serializeInner(root)).toBe(`<div parent></div>`)
|
expect(serializeInner(root)).toBe(`<div parent></div>`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('should inherit scopeId through nested DEV_ROOT_FRAGMENT with inheritAttrs: false', async () => {
|
||||||
|
const Parent = {
|
||||||
|
__scopeId: 'parent',
|
||||||
|
render() {
|
||||||
|
return h(Child, { class: 'foo' })
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const ok = ref(true)
|
||||||
|
const Child = defineComponent({
|
||||||
|
inheritAttrs: false,
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
openBlock(),
|
||||||
|
createBlock(
|
||||||
|
Fragment,
|
||||||
|
null,
|
||||||
|
[
|
||||||
|
createCommentVNode('comment1'),
|
||||||
|
ok.value
|
||||||
|
? (openBlock(), createBlock('div', { key: 0 }, 'div1'))
|
||||||
|
: (openBlock(),
|
||||||
|
createBlock(
|
||||||
|
Fragment,
|
||||||
|
{ key: 1 },
|
||||||
|
[
|
||||||
|
createCommentVNode('comment2'),
|
||||||
|
createVNode('div', null, 'div2'),
|
||||||
|
],
|
||||||
|
PatchFlags.STABLE_FRAGMENT | PatchFlags.DEV_ROOT_FRAGMENT,
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
PatchFlags.STABLE_FRAGMENT | PatchFlags.DEV_ROOT_FRAGMENT,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
render(h(Parent), root)
|
||||||
|
expect(serializeInner(root)).toBe(`<!--comment1--><div parent>div1</div>`)
|
||||||
|
|
||||||
|
ok.value = false
|
||||||
|
await nextTick()
|
||||||
|
expect(serializeInner(root)).toBe(
|
||||||
|
`<!--comment1--><!--comment2--><div parent>div2</div>`,
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('backwards compat with <=3.0.7', () => {
|
describe('backwards compat with <=3.0.7', () => {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vue/runtime-core",
|
"name": "@vue/runtime-core",
|
||||||
"version": "3.4.5",
|
"version": "3.4.13",
|
||||||
"description": "@vue/runtime-core",
|
"description": "@vue/runtime-core",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"module": "dist/runtime-core.esm-bundler.js",
|
"module": "dist/runtime-core.esm-bundler.js",
|
||||||
|
@ -17,6 +17,7 @@
|
||||||
"development": "./dist/runtime-core.cjs.js",
|
"development": "./dist/runtime-core.cjs.js",
|
||||||
"default": "./index.js"
|
"default": "./index.js"
|
||||||
},
|
},
|
||||||
|
"module": "./dist/runtime-core.esm-bundler.js",
|
||||||
"import": "./dist/runtime-core.esm-bundler.js",
|
"import": "./dist/runtime-core.esm-bundler.js",
|
||||||
"require": "./index.js"
|
"require": "./index.js"
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,7 +3,6 @@ import {
|
||||||
currentInstance,
|
currentInstance,
|
||||||
isInSSRComponentSetup,
|
isInSSRComponentSetup,
|
||||||
setCurrentInstance,
|
setCurrentInstance,
|
||||||
unsetCurrentInstance,
|
|
||||||
} from './component'
|
} from './component'
|
||||||
import type { ComponentPublicInstance } from './componentPublicInstance'
|
import type { ComponentPublicInstance } from './componentPublicInstance'
|
||||||
import { ErrorTypeStrings, callWithAsyncErrorHandling } from './errorHandling'
|
import { ErrorTypeStrings, callWithAsyncErrorHandling } from './errorHandling'
|
||||||
|
@ -41,9 +40,9 @@ export function injectHook(
|
||||||
// Set currentInstance during hook invocation.
|
// Set currentInstance during hook invocation.
|
||||||
// This assumes the hook does not synchronously trigger other hooks, which
|
// This assumes the hook does not synchronously trigger other hooks, which
|
||||||
// can only be false when the user does something really funky.
|
// can only be false when the user does something really funky.
|
||||||
setCurrentInstance(target)
|
const reset = setCurrentInstance(target)
|
||||||
const res = callWithAsyncErrorHandling(hook, target, type, args)
|
const res = callWithAsyncErrorHandling(hook, target, type, args)
|
||||||
unsetCurrentInstance()
|
reset()
|
||||||
resetTracking()
|
resetTracking()
|
||||||
return res
|
return res
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
import {
|
import {
|
||||||
EMPTY_OBJ,
|
|
||||||
type LooseRequired,
|
type LooseRequired,
|
||||||
type Prettify,
|
type Prettify,
|
||||||
type UnionToIntersection,
|
type UnionToIntersection,
|
||||||
camelize,
|
|
||||||
extend,
|
extend,
|
||||||
hasChanged,
|
|
||||||
hyphenate,
|
|
||||||
isArray,
|
isArray,
|
||||||
isFunction,
|
isFunction,
|
||||||
isPromise,
|
isPromise,
|
||||||
|
@ -29,13 +25,11 @@ import type {
|
||||||
ComponentObjectPropsOptions,
|
ComponentObjectPropsOptions,
|
||||||
ComponentPropsOptions,
|
ComponentPropsOptions,
|
||||||
ExtractPropTypes,
|
ExtractPropTypes,
|
||||||
NormalizedProps,
|
|
||||||
PropOptions,
|
PropOptions,
|
||||||
} from './componentProps'
|
} from './componentProps'
|
||||||
import { warn } from './warning'
|
import { warn } from './warning'
|
||||||
import type { SlotsType, StrictUnwrapSlotsType } from './componentSlots'
|
import type { SlotsType, StrictUnwrapSlotsType } from './componentSlots'
|
||||||
import { type Ref, customRef, ref } from '@vue/reactivity'
|
import type { Ref } from '@vue/reactivity'
|
||||||
import { watchSyncEffect } from '.'
|
|
||||||
|
|
||||||
// dev only
|
// dev only
|
||||||
const warnRuntimeUsage = (method: string) =>
|
const warnRuntimeUsage = (method: string) =>
|
||||||
|
@ -224,6 +218,11 @@ export function defineSlots<
|
||||||
export type ModelRef<T, M extends string | number | symbol = string> = Ref<T> &
|
export type ModelRef<T, M extends string | number | symbol = string> = Ref<T> &
|
||||||
[ModelRef<T, M>, Record<M, true | undefined>]
|
[ModelRef<T, M>, Record<M, true | undefined>]
|
||||||
|
|
||||||
|
export type DefineModelOptions<T = any> = {
|
||||||
|
get?: (v: T) => any
|
||||||
|
set?: (v: T) => any
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vue `<script setup>` compiler macro for declaring a
|
* Vue `<script setup>` compiler macro for declaring a
|
||||||
* two-way binding prop that can be consumed via `v-model` from the parent
|
* two-way binding prop that can be consumed via `v-model` from the parent
|
||||||
|
@ -258,25 +257,25 @@ export type ModelRef<T, M extends string | number | symbol = string> = Ref<T> &
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export function defineModel<T, M extends string | number | symbol = string>(
|
export function defineModel<T, M extends string | number | symbol = string>(
|
||||||
options: { required: true } & PropOptions<T> & UseModelOptions<T>,
|
options: { required: true } & PropOptions<T> & DefineModelOptions<T>,
|
||||||
): ModelRef<T, M>
|
): ModelRef<T, M>
|
||||||
export function defineModel<T, M extends string | number | symbol = string>(
|
export function defineModel<T, M extends string | number | symbol = string>(
|
||||||
options: { default: any } & PropOptions<T> & UseModelOptions<T>,
|
options: { default: any } & PropOptions<T> & DefineModelOptions<T>,
|
||||||
): ModelRef<T, M>
|
): ModelRef<T, M>
|
||||||
export function defineModel<T, M extends string | number | symbol = string>(
|
export function defineModel<T, M extends string | number | symbol = string>(
|
||||||
options?: PropOptions<T> & UseModelOptions<T>,
|
options?: PropOptions<T> & DefineModelOptions<T>,
|
||||||
): ModelRef<T | undefined, M>
|
): ModelRef<T | undefined, M>
|
||||||
export function defineModel<T, M extends string | number | symbol = string>(
|
export function defineModel<T, M extends string | number | symbol = string>(
|
||||||
name: string,
|
name: string,
|
||||||
options: { required: true } & PropOptions<T> & UseModelOptions<T>,
|
options: { required: true } & PropOptions<T> & DefineModelOptions<T>,
|
||||||
): ModelRef<T, M>
|
): ModelRef<T, M>
|
||||||
export function defineModel<T, M extends string | number | symbol = string>(
|
export function defineModel<T, M extends string | number | symbol = string>(
|
||||||
name: string,
|
name: string,
|
||||||
options: { default: any } & PropOptions<T> & UseModelOptions<T>,
|
options: { default: any } & PropOptions<T> & DefineModelOptions<T>,
|
||||||
): ModelRef<T, M>
|
): ModelRef<T, M>
|
||||||
export function defineModel<T, M extends string | number | symbol = string>(
|
export function defineModel<T, M extends string | number | symbol = string>(
|
||||||
name: string,
|
name: string,
|
||||||
options?: PropOptions<T> & UseModelOptions<T>,
|
options?: PropOptions<T> & DefineModelOptions<T>,
|
||||||
): ModelRef<T | undefined, M>
|
): ModelRef<T | undefined, M>
|
||||||
export function defineModel(): any {
|
export function defineModel(): any {
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
|
@ -356,92 +355,6 @@ export function useAttrs(): SetupContext['attrs'] {
|
||||||
return getContext().attrs
|
return getContext().attrs
|
||||||
}
|
}
|
||||||
|
|
||||||
type UseModelOptions<T = any> = {
|
|
||||||
get?: (v: T) => any
|
|
||||||
set?: (v: T) => any
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useModel<
|
|
||||||
M extends string | number | symbol,
|
|
||||||
T extends Record<string, any>,
|
|
||||||
K extends keyof T,
|
|
||||||
>(props: T, name: K, options?: UseModelOptions<T[K]>): ModelRef<T[K], M>
|
|
||||||
export function useModel(
|
|
||||||
props: Record<string, any>,
|
|
||||||
name: string,
|
|
||||||
options: UseModelOptions = EMPTY_OBJ,
|
|
||||||
): Ref {
|
|
||||||
const i = getCurrentInstance()!
|
|
||||||
if (__DEV__ && !i) {
|
|
||||||
warn(`useModel() called without active instance.`)
|
|
||||||
return ref() as any
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__DEV__ && !(i.propsOptions[0] as NormalizedProps)[name]) {
|
|
||||||
warn(`useModel() called with prop "${name}" which is not declared.`)
|
|
||||||
return ref() as any
|
|
||||||
}
|
|
||||||
|
|
||||||
const camelizedName = camelize(name)
|
|
||||||
const hyphenatedName = hyphenate(name)
|
|
||||||
|
|
||||||
const res = customRef((track, trigger) => {
|
|
||||||
let localValue: any
|
|
||||||
watchSyncEffect(() => {
|
|
||||||
const propValue = props[name]
|
|
||||||
if (hasChanged(localValue, propValue)) {
|
|
||||||
localValue = propValue
|
|
||||||
trigger()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return {
|
|
||||||
get() {
|
|
||||||
track()
|
|
||||||
return options.get ? options.get(localValue) : localValue
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
const rawProps = i.vnode!.props
|
|
||||||
if (
|
|
||||||
!(
|
|
||||||
rawProps &&
|
|
||||||
// check if parent has passed v-model
|
|
||||||
(name in rawProps ||
|
|
||||||
camelizedName in rawProps ||
|
|
||||||
hyphenatedName in rawProps) &&
|
|
||||||
(`onUpdate:${name}` in rawProps ||
|
|
||||||
`onUpdate:${camelizedName}` in rawProps ||
|
|
||||||
`onUpdate:${hyphenatedName}` in rawProps)
|
|
||||||
) &&
|
|
||||||
hasChanged(value, localValue)
|
|
||||||
) {
|
|
||||||
localValue = value
|
|
||||||
trigger()
|
|
||||||
}
|
|
||||||
i.emit(`update:${name}`, options.set ? options.set(value) : value)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const modifierKey =
|
|
||||||
name === 'modelValue' ? 'modelModifiers' : `${name}Modifiers`
|
|
||||||
|
|
||||||
// @ts-expect-error
|
|
||||||
res[Symbol.iterator] = () => {
|
|
||||||
let i = 0
|
|
||||||
return {
|
|
||||||
next() {
|
|
||||||
if (i < 2) {
|
|
||||||
return { value: i++ ? props[modifierKey] || {} : res, done: false }
|
|
||||||
} else {
|
|
||||||
return { done: true }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
function getContext(): SetupContext {
|
function getContext(): SetupContext {
|
||||||
const i = getCurrentInstance()!
|
const i = getCurrentInstance()!
|
||||||
if (__DEV__ && !i) {
|
if (__DEV__ && !i) {
|
||||||
|
|
|
@ -25,7 +25,6 @@ import {
|
||||||
currentInstance,
|
currentInstance,
|
||||||
isInSSRComponentSetup,
|
isInSSRComponentSetup,
|
||||||
setCurrentInstance,
|
setCurrentInstance,
|
||||||
unsetCurrentInstance,
|
|
||||||
} from './component'
|
} from './component'
|
||||||
import { handleError as handleErrorWithInstance } from './errorHandling'
|
import { handleError as handleErrorWithInstance } from './errorHandling'
|
||||||
import { createPostRenderScheduler } from './renderer'
|
import { createPostRenderScheduler } from './renderer'
|
||||||
|
@ -262,14 +261,9 @@ export function instanceWatch(
|
||||||
cb = value.handler as Function
|
cb = value.handler as Function
|
||||||
options = value
|
options = value
|
||||||
}
|
}
|
||||||
const cur = currentInstance
|
const reset = setCurrentInstance(this)
|
||||||
setCurrentInstance(this)
|
|
||||||
const res = doWatch(getter, cb.bind(publicThis), options)
|
const res = doWatch(getter, cb.bind(publicThis), options)
|
||||||
if (cur) {
|
reset()
|
||||||
setCurrentInstance(cur)
|
|
||||||
} else {
|
|
||||||
unsetCurrentInstance()
|
|
||||||
}
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -684,8 +684,13 @@ if (__SSR__) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const setCurrentInstance = (instance: ComponentInternalInstance) => {
|
export const setCurrentInstance = (instance: ComponentInternalInstance) => {
|
||||||
|
const prev = currentInstance
|
||||||
internalSetCurrentInstance(instance)
|
internalSetCurrentInstance(instance)
|
||||||
instance.scope.on()
|
instance.scope.on()
|
||||||
|
return () => {
|
||||||
|
instance.scope.off()
|
||||||
|
internalSetCurrentInstance(prev)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const unsetCurrentInstance = () => {
|
export const unsetCurrentInstance = () => {
|
||||||
|
@ -773,7 +778,7 @@ function setupStatefulComponent(
|
||||||
const setupContext = (instance.setupContext =
|
const setupContext = (instance.setupContext =
|
||||||
setup.length > 1 ? createSetupContext(instance) : null)
|
setup.length > 1 ? createSetupContext(instance) : null)
|
||||||
|
|
||||||
setCurrentInstance(instance)
|
const reset = setCurrentInstance(instance)
|
||||||
pauseTracking()
|
pauseTracking()
|
||||||
const setupResult = callWithErrorHandling(
|
const setupResult = callWithErrorHandling(
|
||||||
setup,
|
setup,
|
||||||
|
@ -785,7 +790,7 @@ function setupStatefulComponent(
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
resetTracking()
|
resetTracking()
|
||||||
unsetCurrentInstance()
|
reset()
|
||||||
|
|
||||||
if (isPromise(setupResult)) {
|
if (isPromise(setupResult)) {
|
||||||
setupResult.then(unsetCurrentInstance, unsetCurrentInstance)
|
setupResult.then(unsetCurrentInstance, unsetCurrentInstance)
|
||||||
|
@ -960,13 +965,13 @@ export function finishComponentSetup(
|
||||||
|
|
||||||
// support for 2.x options
|
// support for 2.x options
|
||||||
if (__FEATURE_OPTIONS_API__ && !(__COMPAT__ && skipOptions)) {
|
if (__FEATURE_OPTIONS_API__ && !(__COMPAT__ && skipOptions)) {
|
||||||
setCurrentInstance(instance)
|
const reset = setCurrentInstance(instance)
|
||||||
pauseTracking()
|
pauseTracking()
|
||||||
try {
|
try {
|
||||||
applyOptions(instance)
|
applyOptions(instance)
|
||||||
} finally {
|
} finally {
|
||||||
resetTracking()
|
resetTracking()
|
||||||
unsetCurrentInstance()
|
reset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,6 @@ import {
|
||||||
type ComponentOptions,
|
type ComponentOptions,
|
||||||
type ConcreteComponent,
|
type ConcreteComponent,
|
||||||
setCurrentInstance,
|
setCurrentInstance,
|
||||||
unsetCurrentInstance,
|
|
||||||
} from './component'
|
} from './component'
|
||||||
import { isEmitListener } from './componentEmits'
|
import { isEmitListener } from './componentEmits'
|
||||||
import { InternalObjectKey } from './vnode'
|
import { InternalObjectKey } from './vnode'
|
||||||
|
@ -470,7 +469,7 @@ function resolvePropValue(
|
||||||
if (key in propsDefaults) {
|
if (key in propsDefaults) {
|
||||||
value = propsDefaults[key]
|
value = propsDefaults[key]
|
||||||
} else {
|
} else {
|
||||||
setCurrentInstance(instance)
|
const reset = setCurrentInstance(instance)
|
||||||
value = propsDefaults[key] = defaultValue.call(
|
value = propsDefaults[key] = defaultValue.call(
|
||||||
__COMPAT__ &&
|
__COMPAT__ &&
|
||||||
isCompatEnabled(DeprecationTypes.PROPS_DEFAULT_THIS, instance)
|
isCompatEnabled(DeprecationTypes.PROPS_DEFAULT_THIS, instance)
|
||||||
|
@ -478,7 +477,7 @@ function resolvePropValue(
|
||||||
: null,
|
: null,
|
||||||
props,
|
props,
|
||||||
)
|
)
|
||||||
unsetCurrentInstance()
|
reset()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
value = defaultValue
|
value = defaultValue
|
||||||
|
|
|
@ -271,10 +271,17 @@ export function renderComponentRoot(
|
||||||
const getChildRoot = (vnode: VNode): [VNode, SetRootFn] => {
|
const getChildRoot = (vnode: VNode): [VNode, SetRootFn] => {
|
||||||
const rawChildren = vnode.children as VNodeArrayChildren
|
const rawChildren = vnode.children as VNodeArrayChildren
|
||||||
const dynamicChildren = vnode.dynamicChildren
|
const dynamicChildren = vnode.dynamicChildren
|
||||||
const childRoot = filterSingleRoot(rawChildren)
|
const childRoot = filterSingleRoot(rawChildren, false)
|
||||||
if (!childRoot) {
|
if (!childRoot) {
|
||||||
return [vnode, undefined]
|
return [vnode, undefined]
|
||||||
|
} else if (
|
||||||
|
__DEV__ &&
|
||||||
|
childRoot.patchFlag > 0 &&
|
||||||
|
childRoot.patchFlag & PatchFlags.DEV_ROOT_FRAGMENT
|
||||||
|
) {
|
||||||
|
return getChildRoot(childRoot)
|
||||||
}
|
}
|
||||||
|
|
||||||
const index = rawChildren.indexOf(childRoot)
|
const index = rawChildren.indexOf(childRoot)
|
||||||
const dynamicIndex = dynamicChildren ? dynamicChildren.indexOf(childRoot) : -1
|
const dynamicIndex = dynamicChildren ? dynamicChildren.indexOf(childRoot) : -1
|
||||||
const setRoot: SetRootFn = (updatedRoot: VNode) => {
|
const setRoot: SetRootFn = (updatedRoot: VNode) => {
|
||||||
|
@ -292,6 +299,7 @@ const getChildRoot = (vnode: VNode): [VNode, SetRootFn] => {
|
||||||
|
|
||||||
export function filterSingleRoot(
|
export function filterSingleRoot(
|
||||||
children: VNodeArrayChildren,
|
children: VNodeArrayChildren,
|
||||||
|
recurse = true,
|
||||||
): VNode | undefined {
|
): VNode | undefined {
|
||||||
let singleRoot
|
let singleRoot
|
||||||
for (let i = 0; i < children.length; i++) {
|
for (let i = 0; i < children.length; i++) {
|
||||||
|
@ -304,6 +312,14 @@ export function filterSingleRoot(
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
singleRoot = child
|
singleRoot = child
|
||||||
|
if (
|
||||||
|
__DEV__ &&
|
||||||
|
recurse &&
|
||||||
|
singleRoot.patchFlag > 0 &&
|
||||||
|
singleRoot.patchFlag & PatchFlags.DEV_ROOT_FRAGMENT
|
||||||
|
) {
|
||||||
|
return filterSingleRoot(singleRoot.children as VNodeArrayChildren)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -433,7 +449,6 @@ export function updateHOCHostEl(
|
||||||
{ vnode, parent }: ComponentInternalInstance,
|
{ vnode, parent }: ComponentInternalInstance,
|
||||||
el: typeof vnode.el, // HostNode
|
el: typeof vnode.el, // HostNode
|
||||||
) {
|
) {
|
||||||
if (!el) return
|
|
||||||
while (parent) {
|
while (parent) {
|
||||||
const root = parent.subTree
|
const root = parent.subTree
|
||||||
if (root.suspense && root.suspense.activeBranch === vnode) {
|
if (root.suspense && root.suspense.activeBranch === vnode) {
|
||||||
|
|
|
@ -91,6 +91,18 @@ export const SuspenseImpl = {
|
||||||
rendererInternals,
|
rendererInternals,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
// #8678 if the current suspense needs to be patched and parentSuspense has
|
||||||
|
// not been resolved. this means that both the current suspense and parentSuspense
|
||||||
|
// need to be patched. because parentSuspense's pendingBranch includes the
|
||||||
|
// current suspense, it will be processed twice:
|
||||||
|
// 1. current patch
|
||||||
|
// 2. mounting along with the pendingBranch of parentSuspense
|
||||||
|
// it is necessary to skip the current patch to avoid multiple mounts
|
||||||
|
// of inner components.
|
||||||
|
if (parentSuspense && parentSuspense.deps > 0) {
|
||||||
|
n2.suspense = n1.suspense
|
||||||
|
return
|
||||||
|
}
|
||||||
patchSuspense(
|
patchSuspense(
|
||||||
n1,
|
n1,
|
||||||
n2,
|
n2,
|
||||||
|
@ -400,7 +412,6 @@ export interface SuspenseBoundary {
|
||||||
namespace: ElementNamespace
|
namespace: ElementNamespace
|
||||||
container: RendererElement
|
container: RendererElement
|
||||||
hiddenContainer: RendererElement
|
hiddenContainer: RendererElement
|
||||||
anchor: RendererNode | null
|
|
||||||
activeBranch: VNode | null
|
activeBranch: VNode | null
|
||||||
pendingBranch: VNode | null
|
pendingBranch: VNode | null
|
||||||
deps: number
|
deps: number
|
||||||
|
@ -473,6 +484,7 @@ function createSuspenseBoundary(
|
||||||
assertNumber(timeout, `Suspense timeout`)
|
assertNumber(timeout, `Suspense timeout`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const initialAnchor = anchor
|
||||||
const suspense: SuspenseBoundary = {
|
const suspense: SuspenseBoundary = {
|
||||||
vnode,
|
vnode,
|
||||||
parent: parentSuspense,
|
parent: parentSuspense,
|
||||||
|
@ -480,7 +492,6 @@ function createSuspenseBoundary(
|
||||||
namespace,
|
namespace,
|
||||||
container,
|
container,
|
||||||
hiddenContainer,
|
hiddenContainer,
|
||||||
anchor,
|
|
||||||
deps: 0,
|
deps: 0,
|
||||||
pendingId: suspenseId++,
|
pendingId: suspenseId++,
|
||||||
timeout: typeof timeout === 'number' ? timeout : -1,
|
timeout: typeof timeout === 'number' ? timeout : -1,
|
||||||
|
@ -529,20 +540,28 @@ function createSuspenseBoundary(
|
||||||
move(
|
move(
|
||||||
pendingBranch!,
|
pendingBranch!,
|
||||||
container,
|
container,
|
||||||
next(activeBranch!),
|
anchor === initialAnchor ? next(activeBranch!) : anchor,
|
||||||
MoveType.ENTER,
|
MoveType.ENTER,
|
||||||
)
|
)
|
||||||
queuePostFlushCb(effects)
|
queuePostFlushCb(effects)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// this is initial anchor on mount
|
|
||||||
let { anchor } = suspense
|
|
||||||
// unmount current active tree
|
// unmount current active tree
|
||||||
if (activeBranch) {
|
if (activeBranch) {
|
||||||
// if the fallback tree was mounted, it may have been moved
|
// if the fallback tree was mounted, it may have been moved
|
||||||
// as part of a parent suspense. get the latest anchor for insertion
|
// as part of a parent suspense. get the latest anchor for insertion
|
||||||
anchor = next(activeBranch)
|
// #8105 if `delayEnter` is true, it means that the mounting of
|
||||||
|
// `activeBranch` will be delayed. if the branch switches before
|
||||||
|
// transition completes, both `activeBranch` and `pendingBranch` may
|
||||||
|
// coexist in the `hiddenContainer`. This could result in
|
||||||
|
// `next(activeBranch!)` obtaining an incorrect anchor
|
||||||
|
// (got `pendingBranch.el`).
|
||||||
|
// Therefore, after the mounting of activeBranch is completed,
|
||||||
|
// it is necessary to get the latest anchor.
|
||||||
|
if (parentNode(activeBranch.el!) !== suspense.hiddenContainer) {
|
||||||
|
anchor = next(activeBranch)
|
||||||
|
}
|
||||||
unmount(activeBranch, parentComponent, suspense, true)
|
unmount(activeBranch, parentComponent, suspense, true)
|
||||||
}
|
}
|
||||||
if (!delayEnter) {
|
if (!delayEnter) {
|
||||||
|
@ -857,7 +876,14 @@ export function queueEffectWithSuspense(
|
||||||
function setActiveBranch(suspense: SuspenseBoundary, branch: VNode) {
|
function setActiveBranch(suspense: SuspenseBoundary, branch: VNode) {
|
||||||
suspense.activeBranch = branch
|
suspense.activeBranch = branch
|
||||||
const { vnode, parentComponent } = suspense
|
const { vnode, parentComponent } = suspense
|
||||||
const el = (vnode.el = branch.el)
|
let el = branch.el
|
||||||
|
// if branch has no el after patch, it's a HOC wrapping async components
|
||||||
|
// drill and locate the placeholder comment node
|
||||||
|
while (!el && branch.component) {
|
||||||
|
branch = branch.component.subTree
|
||||||
|
el = branch.el
|
||||||
|
}
|
||||||
|
vnode.el = el
|
||||||
// in case suspense is the root node of a component,
|
// in case suspense is the root node of a component,
|
||||||
// recursively update the HOC el
|
// recursively update the HOC el
|
||||||
if (parentComponent && parentComponent.subTree === vnode) {
|
if (parentComponent && parentComponent.subTree === vnode) {
|
||||||
|
|
|
@ -88,14 +88,13 @@ export function withDirectives<T extends VNode>(
|
||||||
vnode: T,
|
vnode: T,
|
||||||
directives: DirectiveArguments,
|
directives: DirectiveArguments,
|
||||||
): T {
|
): T {
|
||||||
const internalInstance = currentRenderingInstance
|
if (currentRenderingInstance === null) {
|
||||||
if (internalInstance === null) {
|
|
||||||
__DEV__ && warn(`withDirectives can only be used inside render functions.`)
|
__DEV__ && warn(`withDirectives can only be used inside render functions.`)
|
||||||
return vnode
|
return vnode
|
||||||
}
|
}
|
||||||
const instance =
|
const instance =
|
||||||
(getExposeProxy(internalInstance) as ComponentPublicInstance) ||
|
(getExposeProxy(currentRenderingInstance) as ComponentPublicInstance) ||
|
||||||
internalInstance.proxy
|
currentRenderingInstance.proxy
|
||||||
const bindings: DirectiveBinding[] = vnode.dirs || (vnode.dirs = [])
|
const bindings: DirectiveBinding[] = vnode.dirs || (vnode.dirs = [])
|
||||||
for (let i = 0; i < directives.length; i++) {
|
for (let i = 0; i < directives.length; i++) {
|
||||||
let [dir, value, arg, modifiers = EMPTY_OBJ] = directives[i]
|
let [dir, value, arg, modifiers = EMPTY_OBJ] = directives[i]
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
} from './vnode'
|
} from './vnode'
|
||||||
import type { Teleport, TeleportProps } from './components/Teleport'
|
import type { Teleport, TeleportProps } from './components/Teleport'
|
||||||
import type { Suspense, SuspenseProps } from './components/Suspense'
|
import type { Suspense, SuspenseProps } from './components/Suspense'
|
||||||
import { isArray, isObject } from '@vue/shared'
|
import { type IfAny, isArray, isObject } from '@vue/shared'
|
||||||
import type { RawSlots } from './componentSlots'
|
import type { RawSlots } from './componentSlots'
|
||||||
import type {
|
import type {
|
||||||
Component,
|
Component,
|
||||||
|
@ -140,11 +140,11 @@ export function h(
|
||||||
export function h<
|
export function h<
|
||||||
P,
|
P,
|
||||||
E extends EmitsOptions = {},
|
E extends EmitsOptions = {},
|
||||||
S extends Record<string, any> = {},
|
S extends Record<string, any> = any,
|
||||||
>(
|
>(
|
||||||
type: FunctionalComponent<P, E, S>,
|
type: FunctionalComponent<P, any, S, any>,
|
||||||
props?: (RawProps & P) | ({} extends P ? null : never),
|
props?: (RawProps & P) | ({} extends P ? null : never),
|
||||||
children?: RawChildren | RawSlots,
|
children?: RawChildren | IfAny<S, RawSlots, S>,
|
||||||
): VNode
|
): VNode
|
||||||
|
|
||||||
// catch-all for generic component types
|
// catch-all for generic component types
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
import { type Ref, customRef, ref } from '@vue/reactivity'
|
||||||
|
import { EMPTY_OBJ, camelize, hasChanged, hyphenate } from '@vue/shared'
|
||||||
|
import type { DefineModelOptions, ModelRef } from '../apiSetupHelpers'
|
||||||
|
import { getCurrentInstance } from '../component'
|
||||||
|
import { warn } from '../warning'
|
||||||
|
import type { NormalizedProps } from '../componentProps'
|
||||||
|
import { watchSyncEffect } from '../apiWatch'
|
||||||
|
|
||||||
|
export function useModel<
|
||||||
|
M extends string | number | symbol,
|
||||||
|
T extends Record<string, any>,
|
||||||
|
K extends keyof T,
|
||||||
|
>(props: T, name: K, options?: DefineModelOptions<T[K]>): ModelRef<T[K], M>
|
||||||
|
export function useModel(
|
||||||
|
props: Record<string, any>,
|
||||||
|
name: string,
|
||||||
|
options: DefineModelOptions = EMPTY_OBJ,
|
||||||
|
): Ref {
|
||||||
|
const i = getCurrentInstance()!
|
||||||
|
if (__DEV__ && !i) {
|
||||||
|
warn(`useModel() called without active instance.`)
|
||||||
|
return ref() as any
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__DEV__ && !(i.propsOptions[0] as NormalizedProps)[name]) {
|
||||||
|
warn(`useModel() called with prop "${name}" which is not declared.`)
|
||||||
|
return ref() as any
|
||||||
|
}
|
||||||
|
|
||||||
|
const camelizedName = camelize(name)
|
||||||
|
const hyphenatedName = hyphenate(name)
|
||||||
|
|
||||||
|
const res = customRef((track, trigger) => {
|
||||||
|
let localValue: any
|
||||||
|
watchSyncEffect(() => {
|
||||||
|
const propValue = props[name]
|
||||||
|
if (hasChanged(localValue, propValue)) {
|
||||||
|
localValue = propValue
|
||||||
|
trigger()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
get() {
|
||||||
|
track()
|
||||||
|
return options.get ? options.get(localValue) : localValue
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
const rawProps = i.vnode!.props
|
||||||
|
if (
|
||||||
|
!(
|
||||||
|
rawProps &&
|
||||||
|
// check if parent has passed v-model
|
||||||
|
(name in rawProps ||
|
||||||
|
camelizedName in rawProps ||
|
||||||
|
hyphenatedName in rawProps) &&
|
||||||
|
(`onUpdate:${name}` in rawProps ||
|
||||||
|
`onUpdate:${camelizedName}` in rawProps ||
|
||||||
|
`onUpdate:${hyphenatedName}` in rawProps)
|
||||||
|
) &&
|
||||||
|
hasChanged(value, localValue)
|
||||||
|
) {
|
||||||
|
localValue = value
|
||||||
|
trigger()
|
||||||
|
}
|
||||||
|
i.emit(`update:${name}`, options.set ? options.set(value) : value)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const modifierKey =
|
||||||
|
name === 'modelValue' ? 'modelModifiers' : `${name}Modifiers`
|
||||||
|
|
||||||
|
// @ts-expect-error
|
||||||
|
res[Symbol.iterator] = () => {
|
||||||
|
let i = 0
|
||||||
|
return {
|
||||||
|
next() {
|
||||||
|
if (i < 2) {
|
||||||
|
return { value: i++ ? props[modifierKey] || {} : res, done: false }
|
||||||
|
} else {
|
||||||
|
return { done: true }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ import {
|
||||||
isBooleanAttr,
|
isBooleanAttr,
|
||||||
isKnownHtmlAttr,
|
isKnownHtmlAttr,
|
||||||
isKnownSvgAttr,
|
isKnownSvgAttr,
|
||||||
|
isObject,
|
||||||
isOn,
|
isOn,
|
||||||
isReservedProp,
|
isReservedProp,
|
||||||
isString,
|
isString,
|
||||||
|
@ -448,7 +449,7 @@ export function createHydrationFunctions(
|
||||||
) {
|
) {
|
||||||
for (const key in props) {
|
for (const key in props) {
|
||||||
// check hydration mismatch
|
// check hydration mismatch
|
||||||
if (__DEV__ && propHasMismatch(el, key, props[key])) {
|
if (__DEV__ && propHasMismatch(el, key, props[key], vnode)) {
|
||||||
hasMismatch = true
|
hasMismatch = true
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
|
@ -712,7 +713,12 @@ export function createHydrationFunctions(
|
||||||
/**
|
/**
|
||||||
* Dev only
|
* Dev only
|
||||||
*/
|
*/
|
||||||
function propHasMismatch(el: Element, key: string, clientValue: any): boolean {
|
function propHasMismatch(
|
||||||
|
el: Element,
|
||||||
|
key: string,
|
||||||
|
clientValue: any,
|
||||||
|
vnode: VNode,
|
||||||
|
): boolean {
|
||||||
let mismatchType: string | undefined
|
let mismatchType: string | undefined
|
||||||
let mismatchKey: string | undefined
|
let mismatchKey: string | undefined
|
||||||
let actual: any
|
let actual: any
|
||||||
|
@ -720,31 +726,55 @@ function propHasMismatch(el: Element, key: string, clientValue: any): boolean {
|
||||||
if (key === 'class') {
|
if (key === 'class') {
|
||||||
// classes might be in different order, but that doesn't affect cascade
|
// classes might be in different order, but that doesn't affect cascade
|
||||||
// so we just need to check if the class lists contain the same classes.
|
// so we just need to check if the class lists contain the same classes.
|
||||||
actual = toClassSet(el.getAttribute('class') || '')
|
actual = el.getAttribute('class')
|
||||||
expected = toClassSet(normalizeClass(clientValue))
|
expected = normalizeClass(clientValue)
|
||||||
if (!isSetEqual(actual, expected)) {
|
if (!isSetEqual(toClassSet(actual || ''), toClassSet(expected))) {
|
||||||
mismatchType = mismatchKey = `class`
|
mismatchType = mismatchKey = `class`
|
||||||
}
|
}
|
||||||
} else if (key === 'style') {
|
} else if (key === 'style') {
|
||||||
|
// style might be in different order, but that doesn't affect cascade
|
||||||
actual = el.getAttribute('style')
|
actual = el.getAttribute('style')
|
||||||
expected = isString(clientValue)
|
expected = isString(clientValue)
|
||||||
? clientValue
|
? clientValue
|
||||||
: stringifyStyle(normalizeStyle(clientValue))
|
: stringifyStyle(normalizeStyle(clientValue))
|
||||||
if (actual !== expected) {
|
const actualMap = toStyleMap(actual)
|
||||||
|
const expectedMap = toStyleMap(expected)
|
||||||
|
// If `v-show=false`, `display: 'none'` should be added to expected
|
||||||
|
if (vnode.dirs) {
|
||||||
|
for (const { dir, value } of vnode.dirs) {
|
||||||
|
// @ts-expect-error only vShow has this internal name
|
||||||
|
if (dir.name === 'show' && !value) {
|
||||||
|
expectedMap.set('display', 'none')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isMapEqual(actualMap, expectedMap)) {
|
||||||
mismatchType = mismatchKey = 'style'
|
mismatchType = mismatchKey = 'style'
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
(el instanceof SVGElement && isKnownSvgAttr(key)) ||
|
(el instanceof SVGElement && isKnownSvgAttr(key)) ||
|
||||||
(el instanceof HTMLElement && (isBooleanAttr(key) || isKnownHtmlAttr(key)))
|
(el instanceof HTMLElement && (isBooleanAttr(key) || isKnownHtmlAttr(key)))
|
||||||
) {
|
) {
|
||||||
actual = el.hasAttribute(key) && el.getAttribute(key)
|
if (isBooleanAttr(key)) {
|
||||||
expected = isBooleanAttr(key)
|
actual = el.hasAttribute(key)
|
||||||
? includeBooleanAttr(clientValue)
|
expected = includeBooleanAttr(clientValue)
|
||||||
? ''
|
} else if (clientValue == null) {
|
||||||
: false
|
actual = el.hasAttribute(key)
|
||||||
: clientValue == null
|
expected = false
|
||||||
? false
|
} else {
|
||||||
: String(clientValue)
|
if (el.hasAttribute(key)) {
|
||||||
|
actual = el.getAttribute(key)
|
||||||
|
} else {
|
||||||
|
// #10000 some attrs such as textarea.value can't be retrieved by `hasAttribute`
|
||||||
|
const serverValue = el[key as keyof typeof el]
|
||||||
|
actual =
|
||||||
|
isObject(serverValue) || serverValue == null
|
||||||
|
? ''
|
||||||
|
: String(serverValue)
|
||||||
|
}
|
||||||
|
expected =
|
||||||
|
isObject(clientValue) || clientValue == null ? '' : String(clientValue)
|
||||||
|
}
|
||||||
if (actual !== expected) {
|
if (actual !== expected) {
|
||||||
mismatchType = `attribute`
|
mismatchType = `attribute`
|
||||||
mismatchKey = key
|
mismatchKey = key
|
||||||
|
@ -754,15 +784,20 @@ function propHasMismatch(el: Element, key: string, clientValue: any): boolean {
|
||||||
if (mismatchType) {
|
if (mismatchType) {
|
||||||
const format = (v: any) =>
|
const format = (v: any) =>
|
||||||
v === false ? `(not rendered)` : `${mismatchKey}="${v}"`
|
v === false ? `(not rendered)` : `${mismatchKey}="${v}"`
|
||||||
warn(
|
const preSegment = `Hydration ${mismatchType} mismatch on`
|
||||||
`Hydration ${mismatchType} mismatch on`,
|
const postSegment =
|
||||||
el,
|
|
||||||
`\n - rendered on server: ${format(actual)}` +
|
`\n - rendered on server: ${format(actual)}` +
|
||||||
`\n - expected on client: ${format(expected)}` +
|
`\n - expected on client: ${format(expected)}` +
|
||||||
`\n Note: this mismatch is check-only. The DOM will not be rectified ` +
|
`\n Note: this mismatch is check-only. The DOM will not be rectified ` +
|
||||||
`in production due to performance overhead.` +
|
`in production due to performance overhead.` +
|
||||||
`\n You should fix the source of the mismatch.`,
|
`\n You should fix the source of the mismatch.`
|
||||||
)
|
if (__TEST__) {
|
||||||
|
// during tests, log the full message in one single string for easier
|
||||||
|
// debugging.
|
||||||
|
warn(`${preSegment} ${el.tagName}${postSegment}`)
|
||||||
|
} else {
|
||||||
|
warn(preSegment, el, postSegment)
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -783,3 +818,28 @@ function isSetEqual(a: Set<string>, b: Set<string>): boolean {
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toStyleMap(str: string): Map<string, string> {
|
||||||
|
const styleMap: Map<string, string> = new Map()
|
||||||
|
for (const item of str.split(';')) {
|
||||||
|
let [key, value] = item.split(':')
|
||||||
|
key = key?.trim()
|
||||||
|
value = value?.trim()
|
||||||
|
if (key && value) {
|
||||||
|
styleMap.set(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return styleMap
|
||||||
|
}
|
||||||
|
|
||||||
|
function isMapEqual(a: Map<string, string>, b: Map<string, string>): boolean {
|
||||||
|
if (a.size !== b.size) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for (const [key, value] of a) {
|
||||||
|
if (value !== b.get(key)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@ export { nextTick } from './scheduler'
|
||||||
export { defineComponent } from './apiDefineComponent'
|
export { defineComponent } from './apiDefineComponent'
|
||||||
export { defineAsyncComponent } from './apiAsyncComponent'
|
export { defineAsyncComponent } from './apiAsyncComponent'
|
||||||
export { useAttrs, useSlots } from './apiSetupHelpers'
|
export { useAttrs, useSlots } from './apiSetupHelpers'
|
||||||
|
export { useModel } from './helpers/useModel'
|
||||||
|
|
||||||
// <script setup> API ----------------------------------------------------------
|
// <script setup> API ----------------------------------------------------------
|
||||||
|
|
||||||
|
@ -74,7 +75,6 @@ export {
|
||||||
defineSlots,
|
defineSlots,
|
||||||
defineModel,
|
defineModel,
|
||||||
withDefaults,
|
withDefaults,
|
||||||
useModel,
|
|
||||||
type DefineProps,
|
type DefineProps,
|
||||||
type ModelRef,
|
type ModelRef,
|
||||||
} from './apiSetupHelpers'
|
} from './apiSetupHelpers'
|
||||||
|
@ -151,7 +151,7 @@ import { ErrorTypeStrings as _ErrorTypeStrings } from './errorHandling'
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
export const ErrorTypeStrings = (
|
export const ErrorTypeStrings = (
|
||||||
__ESM_BUNDLER__ || __NODE_JS__ || __DEV__ ? _ErrorTypeStrings : null
|
__ESM_BUNDLER__ || __CJS__ || __DEV__ ? _ErrorTypeStrings : null
|
||||||
) as typeof _ErrorTypeStrings
|
) as typeof _ErrorTypeStrings
|
||||||
|
|
||||||
// For devtools
|
// For devtools
|
||||||
|
@ -162,13 +162,13 @@ import {
|
||||||
} from './devtools'
|
} from './devtools'
|
||||||
|
|
||||||
export const devtools = (
|
export const devtools = (
|
||||||
__DEV__ || __FEATURE_PROD_DEVTOOLS__ ? _devtools : undefined
|
__DEV__ || __ESM_BUNDLER__ ? _devtools : undefined
|
||||||
) as DevtoolsHook
|
) as DevtoolsHook
|
||||||
export const setDevtoolsHook = (
|
export const setDevtoolsHook = (
|
||||||
__DEV__ || __FEATURE_PROD_DEVTOOLS__ ? _setDevtoolsHook : NOOP
|
__DEV__ || __ESM_BUNDLER__ ? _setDevtoolsHook : NOOP
|
||||||
) as typeof _setDevtoolsHook
|
) as typeof _setDevtoolsHook
|
||||||
|
|
||||||
// Types -------------------------------------------------------------------------
|
// Types -----------------------------------------------------------------------
|
||||||
|
|
||||||
import type { VNode } from './vnode'
|
import type { VNode } from './vnode'
|
||||||
import type { ComponentInternalInstance } from './component'
|
import type { ComponentInternalInstance } from './component'
|
||||||
|
|
|
@ -1099,7 +1099,11 @@ function baseCreateRenderer(
|
||||||
// since they are either generated by the compiler, or implicitly created
|
// since they are either generated by the compiler, or implicitly created
|
||||||
// from arrays.
|
// from arrays.
|
||||||
mountChildren(
|
mountChildren(
|
||||||
n2.children as VNodeArrayChildren,
|
// #10007
|
||||||
|
// such fragment like `<></>` will be compiled into
|
||||||
|
// a fragment which doesn't have a children.
|
||||||
|
// In this case fallback to an empty array
|
||||||
|
(n2.children || []) as VNodeArrayChildren,
|
||||||
container,
|
container,
|
||||||
fragmentEndAnchor,
|
fragmentEndAnchor,
|
||||||
parentComponent,
|
parentComponent,
|
||||||
|
@ -2361,6 +2365,7 @@ function baseCreateRenderer(
|
||||||
return hostNextSibling((vnode.anchor || vnode.el)!)
|
return hostNextSibling((vnode.anchor || vnode.el)!)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let isFlushing = false
|
||||||
const render: RootRenderFunction = (vnode, container, namespace) => {
|
const render: RootRenderFunction = (vnode, container, namespace) => {
|
||||||
if (vnode == null) {
|
if (vnode == null) {
|
||||||
if (container._vnode) {
|
if (container._vnode) {
|
||||||
|
@ -2377,8 +2382,12 @@ function baseCreateRenderer(
|
||||||
namespace,
|
namespace,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
flushPreFlushCbs()
|
if (!isFlushing) {
|
||||||
flushPostFlushCbs()
|
isFlushing = true
|
||||||
|
flushPreFlushCbs()
|
||||||
|
flushPostFlushCbs()
|
||||||
|
isFlushing = false
|
||||||
|
}
|
||||||
container._vnode = vnode
|
container._vnode = vnode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -165,7 +165,9 @@ export function flushPreFlushCbs(
|
||||||
|
|
||||||
export function flushPostFlushCbs(seen?: CountMap) {
|
export function flushPostFlushCbs(seen?: CountMap) {
|
||||||
if (pendingPostFlushCbs.length) {
|
if (pendingPostFlushCbs.length) {
|
||||||
const deduped = [...new Set(pendingPostFlushCbs)]
|
const deduped = [...new Set(pendingPostFlushCbs)].sort(
|
||||||
|
(a, b) => getId(a) - getId(b),
|
||||||
|
)
|
||||||
pendingPostFlushCbs.length = 0
|
pendingPostFlushCbs.length = 0
|
||||||
|
|
||||||
// #1947 already has active queue, nested flushPostFlushCbs call
|
// #1947 already has active queue, nested flushPostFlushCbs call
|
||||||
|
@ -179,8 +181,6 @@ export function flushPostFlushCbs(seen?: CountMap) {
|
||||||
seen = seen || new Map()
|
seen = seen || new Map()
|
||||||
}
|
}
|
||||||
|
|
||||||
activePostFlushCbs.sort((a, b) => getId(a) - getId(b))
|
|
||||||
|
|
||||||
for (
|
for (
|
||||||
postFlushIndex = 0;
|
postFlushIndex = 0;
|
||||||
postFlushIndex < activePostFlushCbs.length;
|
postFlushIndex < activePostFlushCbs.length;
|
||||||
|
@ -243,7 +243,6 @@ function flushJobs(seen?: CountMap) {
|
||||||
if (__DEV__ && check(job)) {
|
if (__DEV__ && check(job)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// console.log(`running:`, job.id)
|
|
||||||
callWithErrorHandling(job, null, ErrorCodes.SCHEDULER)
|
callWithErrorHandling(job, null, ErrorCodes.SCHEDULER)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ describe('runtime-dom: v-show directive', () => {
|
||||||
})
|
})
|
||||||
render(h(component), root)
|
render(h(component), root)
|
||||||
|
|
||||||
const $div = root.querySelector('div')
|
const $div = root.children[0]
|
||||||
|
|
||||||
expect($div.style.display).toEqual('')
|
expect($div.style.display).toEqual('')
|
||||||
})
|
})
|
||||||
|
@ -46,7 +46,7 @@ describe('runtime-dom: v-show directive', () => {
|
||||||
})
|
})
|
||||||
render(h(component), root)
|
render(h(component), root)
|
||||||
|
|
||||||
const $div = root.querySelector('div')
|
const $div = root.children[0]
|
||||||
|
|
||||||
expect($div.style.display).toEqual('none')
|
expect($div.style.display).toEqual('none')
|
||||||
})
|
})
|
||||||
|
@ -62,7 +62,7 @@ describe('runtime-dom: v-show directive', () => {
|
||||||
})
|
})
|
||||||
render(h(component), root)
|
render(h(component), root)
|
||||||
|
|
||||||
const $div = root.querySelector('div')
|
const $div = root.children[0]
|
||||||
const data = root._vnode.component.data
|
const data = root._vnode.component.data
|
||||||
|
|
||||||
expect($div.style.display).toEqual('')
|
expect($div.style.display).toEqual('')
|
||||||
|
@ -113,7 +113,7 @@ describe('runtime-dom: v-show directive', () => {
|
||||||
})
|
})
|
||||||
render(h(component), root)
|
render(h(component), root)
|
||||||
|
|
||||||
const $div = root.querySelector('div')
|
const $div = root.children[0]
|
||||||
const data = root._vnode.component.data
|
const data = root._vnode.component.data
|
||||||
|
|
||||||
expect($div.style.display).toEqual('block')
|
expect($div.style.display).toEqual('block')
|
||||||
|
@ -138,7 +138,7 @@ describe('runtime-dom: v-show directive', () => {
|
||||||
})
|
})
|
||||||
render(h(component), root)
|
render(h(component), root)
|
||||||
|
|
||||||
const $div = root.querySelector('div')
|
const $div = root.children[0]
|
||||||
|
|
||||||
expect($div.style.display).toEqual('none')
|
expect($div.style.display).toEqual('none')
|
||||||
|
|
||||||
|
@ -151,6 +151,32 @@ describe('runtime-dom: v-show directive', () => {
|
||||||
expect($div.style.display).toEqual('')
|
expect($div.style.display).toEqual('')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('the value of `display` set by v-show should not be overwritten by the style attribute when updated (object value)', async () => {
|
||||||
|
const style = ref({
|
||||||
|
display: 'block',
|
||||||
|
width: '100px',
|
||||||
|
})
|
||||||
|
const display = ref(false)
|
||||||
|
const component = defineComponent({
|
||||||
|
render() {
|
||||||
|
return withVShow(h('div', { style: style.value }), display.value)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
render(h(component), root)
|
||||||
|
|
||||||
|
const $div = root.children[0]
|
||||||
|
|
||||||
|
expect($div.style.display).toEqual('none')
|
||||||
|
|
||||||
|
style.value.width = '50px'
|
||||||
|
await nextTick()
|
||||||
|
expect($div.style.display).toEqual('none')
|
||||||
|
|
||||||
|
display.value = true
|
||||||
|
await nextTick()
|
||||||
|
expect($div.style.display).toEqual('block')
|
||||||
|
})
|
||||||
|
|
||||||
// #2583, #2757
|
// #2583, #2757
|
||||||
test('the value of `display` set by v-show should not be overwritten by the style attribute when updated (with Transition)', async () => {
|
test('the value of `display` set by v-show should not be overwritten by the style attribute when updated (with Transition)', async () => {
|
||||||
const style = ref('width: 100px')
|
const style = ref('width: 100px')
|
||||||
|
@ -173,7 +199,7 @@ describe('runtime-dom: v-show directive', () => {
|
||||||
})
|
})
|
||||||
render(h(component), root)
|
render(h(component), root)
|
||||||
|
|
||||||
const $div = root.querySelector('div')
|
const $div = root.children[0]
|
||||||
|
|
||||||
expect($div.style.display).toEqual('none')
|
expect($div.style.display).toEqual('none')
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vue/runtime-dom",
|
"name": "@vue/runtime-dom",
|
||||||
"version": "3.4.5",
|
"version": "3.4.13",
|
||||||
"description": "@vue/runtime-dom",
|
"description": "@vue/runtime-dom",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"module": "dist/runtime-dom.esm-bundler.js",
|
"module": "dist/runtime-dom.esm-bundler.js",
|
||||||
|
@ -18,6 +18,7 @@
|
||||||
"development": "./dist/runtime-dom.cjs.js",
|
"development": "./dist/runtime-dom.cjs.js",
|
||||||
"default": "./index.js"
|
"default": "./index.js"
|
||||||
},
|
},
|
||||||
|
"module": "./dist/runtime-dom.esm-bundler.js",
|
||||||
"import": "./dist/runtime-dom.esm-bundler.js",
|
"import": "./dist/runtime-dom.esm-bundler.js",
|
||||||
"require": "./index.js"
|
"require": "./index.js"
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,7 +7,7 @@ interface VShowElement extends HTMLElement {
|
||||||
[vShowOldKey]: string
|
[vShowOldKey]: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const vShow: ObjectDirective<VShowElement> = {
|
export const vShow: ObjectDirective<VShowElement> & { name?: 'show' } = {
|
||||||
beforeMount(el, { value }, { transition }) {
|
beforeMount(el, { value }, { transition }) {
|
||||||
el[vShowOldKey] = el.style.display === 'none' ? '' : el.style.display
|
el[vShowOldKey] = el.style.display === 'none' ? '' : el.style.display
|
||||||
if (transition && value) {
|
if (transition && value) {
|
||||||
|
@ -42,6 +42,10 @@ export const vShow: ObjectDirective<VShowElement> = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (__DEV__) {
|
||||||
|
vShow.name = 'show'
|
||||||
|
}
|
||||||
|
|
||||||
function setDisplay(el: VShowElement, value: unknown): void {
|
function setDisplay(el: VShowElement, value: unknown): void {
|
||||||
el.style.display = value ? el[vShowOldKey] : 'none'
|
el.style.display = value ? el[vShowOldKey] : 'none'
|
||||||
}
|
}
|
||||||
|
|
|
@ -739,7 +739,7 @@ export interface TextareaHTMLAttributes extends HTMLAttributes {
|
||||||
readonly?: Booleanish
|
readonly?: Booleanish
|
||||||
required?: Booleanish
|
required?: Booleanish
|
||||||
rows?: Numberish
|
rows?: Numberish
|
||||||
value?: string | ReadonlyArray<string> | number
|
value?: string | ReadonlyArray<string> | number | null
|
||||||
wrap?: string
|
wrap?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ type Style = string | Record<string, string | string[]> | null
|
||||||
|
|
||||||
export function patchStyle(el: Element, prev: Style, next: Style) {
|
export function patchStyle(el: Element, prev: Style, next: Style) {
|
||||||
const style = (el as HTMLElement).style
|
const style = (el as HTMLElement).style
|
||||||
|
const currentDisplay = style.display
|
||||||
const isCssString = isString(next)
|
const isCssString = isString(next)
|
||||||
if (next && !isCssString) {
|
if (next && !isCssString) {
|
||||||
if (prev && !isString(prev)) {
|
if (prev && !isString(prev)) {
|
||||||
|
@ -20,7 +21,6 @@ export function patchStyle(el: Element, prev: Style, next: Style) {
|
||||||
setStyle(style, key, next[key])
|
setStyle(style, key, next[key])
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const currentDisplay = style.display
|
|
||||||
if (isCssString) {
|
if (isCssString) {
|
||||||
if (prev !== next) {
|
if (prev !== next) {
|
||||||
// #9821
|
// #9821
|
||||||
|
@ -33,12 +33,12 @@ export function patchStyle(el: Element, prev: Style, next: Style) {
|
||||||
} else if (prev) {
|
} else if (prev) {
|
||||||
el.removeAttribute('style')
|
el.removeAttribute('style')
|
||||||
}
|
}
|
||||||
// indicates that the `display` of the element is controlled by `v-show`,
|
}
|
||||||
// so we always keep the current `display` value regardless of the `style`
|
// indicates that the `display` of the element is controlled by `v-show`,
|
||||||
// value, thus handing over control to `v-show`.
|
// so we always keep the current `display` value regardless of the `style`
|
||||||
if (vShowOldKey in el) {
|
// value, thus handing over control to `v-show`.
|
||||||
style.display = currentDisplay
|
if (vShowOldKey in el) {
|
||||||
}
|
style.display = currentDisplay
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vue/server-renderer",
|
"name": "@vue/server-renderer",
|
||||||
"version": "3.4.5",
|
"version": "3.4.13",
|
||||||
"description": "@vue/server-renderer",
|
"description": "@vue/server-renderer",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"module": "dist/server-renderer.esm-bundler.js",
|
"module": "dist/server-renderer.esm-bundler.js",
|
||||||
|
@ -17,6 +17,7 @@
|
||||||
"development": "./dist/server-renderer.cjs.js",
|
"development": "./dist/server-renderer.cjs.js",
|
||||||
"default": "./index.js"
|
"default": "./index.js"
|
||||||
},
|
},
|
||||||
|
"module": "./dist/server-renderer.esm-bundler.js",
|
||||||
"import": "./dist/server-renderer.esm-bundler.js",
|
"import": "./dist/server-renderer.esm-bundler.js",
|
||||||
"require": "./index.js"
|
"require": "./index.js"
|
||||||
},
|
},
|
||||||
|
|
|
@ -24,7 +24,7 @@ export function ssrCompile(
|
||||||
instance: ComponentInternalInstance,
|
instance: ComponentInternalInstance,
|
||||||
): SSRRenderFunction {
|
): SSRRenderFunction {
|
||||||
// TODO: this branch should now work in ESM builds, enable it in a minor
|
// TODO: this branch should now work in ESM builds, enable it in a minor
|
||||||
if (!__NODE_JS__) {
|
if (!__CJS__) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`On-the-fly template compilation is not supported in the ESM build of ` +
|
`On-the-fly template compilation is not supported in the ESM build of ` +
|
||||||
`@vue/server-renderer. All templates must be pre-compiled into ` +
|
`@vue/server-renderer. All templates must be pre-compiled into ` +
|
||||||
|
|
|
@ -107,7 +107,7 @@ export function renderComponentVNode(
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
// Note: error display is already done by the wrapped lifecycle hook function.
|
// Note: error display is already done by the wrapped lifecycle hook function.
|
||||||
.catch(() => {})
|
.catch(NOOP)
|
||||||
}
|
}
|
||||||
return p.then(() => renderComponentSubTree(instance, slotScopeId))
|
return p.then(() => renderComponentSubTree(instance, slotScopeId))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -108,7 +108,7 @@ export function renderToNodeStream(
|
||||||
input: App | VNode,
|
input: App | VNode,
|
||||||
context: SSRContext = {},
|
context: SSRContext = {},
|
||||||
): Readable {
|
): Readable {
|
||||||
const stream: Readable = __NODE_JS__
|
const stream: Readable = __CJS__
|
||||||
? new (require('node:stream').Readable)({ read() {} })
|
? new (require('node:stream').Readable)({ read() {} })
|
||||||
: null
|
: null
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vue/shared",
|
"name": "@vue/shared",
|
||||||
"version": "3.4.5",
|
"version": "3.4.13",
|
||||||
"description": "internal utils shared across @vue packages",
|
"description": "internal utils shared across @vue packages",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"module": "dist/shared.esm-bundler.js",
|
"module": "dist/shared.esm-bundler.js",
|
||||||
|
@ -17,6 +17,7 @@
|
||||||
"development": "./dist/shared.cjs.js",
|
"development": "./dist/shared.cjs.js",
|
||||||
"default": "./index.js"
|
"default": "./index.js"
|
||||||
},
|
},
|
||||||
|
"module": "./dist/shared.esm-bundler.js",
|
||||||
"import": "./dist/shared.esm-bundler.js",
|
"import": "./dist/shared.esm-bundler.js",
|
||||||
"require": "./index.js"
|
"require": "./index.js"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vue/compat",
|
"name": "@vue/compat",
|
||||||
"version": "3.4.5",
|
"version": "3.4.13",
|
||||||
"description": "Vue 3 compatibility build for Vue 2",
|
"description": "Vue 3 compatibility build for Vue 2",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"module": "dist/vue.runtime.esm-bundler.js",
|
"module": "dist/vue.runtime.esm-bundler.js",
|
||||||
|
@ -18,6 +18,7 @@
|
||||||
"development": "./dist/vue.cjs.js",
|
"development": "./dist/vue.cjs.js",
|
||||||
"default": "./index.js"
|
"default": "./index.js"
|
||||||
},
|
},
|
||||||
|
"module": "./dist/vue.esm-bundler.js",
|
||||||
"import": "./dist/vue.esm-bundler.js",
|
"import": "./dist/vue.esm-bundler.js",
|
||||||
"require": "./index.js"
|
"require": "./index.js"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1652,6 +1652,77 @@ describe('e2e: Transition', () => {
|
||||||
},
|
},
|
||||||
E2E_TIMEOUT,
|
E2E_TIMEOUT,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// #9996
|
||||||
|
test(
|
||||||
|
'trigger again when transition is not finished & correctly anchor',
|
||||||
|
async () => {
|
||||||
|
await page().evaluate(duration => {
|
||||||
|
const { createApp, shallowRef, h } = (window as any).Vue
|
||||||
|
const One = {
|
||||||
|
async setup() {
|
||||||
|
return () => h('div', { class: 'test' }, 'one')
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const Two = {
|
||||||
|
async setup() {
|
||||||
|
return () => h('div', { class: 'test' }, 'two')
|
||||||
|
},
|
||||||
|
}
|
||||||
|
createApp({
|
||||||
|
template: `
|
||||||
|
<div id="container">
|
||||||
|
<div>Top</div>
|
||||||
|
<transition name="test" mode="out-in" :duration="${duration}">
|
||||||
|
<Suspense>
|
||||||
|
<component :is="view"/>
|
||||||
|
</Suspense>
|
||||||
|
</transition>
|
||||||
|
<div>Bottom</div>
|
||||||
|
</div>
|
||||||
|
<button id="toggleBtn" @click="click">button</button>
|
||||||
|
`,
|
||||||
|
setup: () => {
|
||||||
|
const view = shallowRef(One)
|
||||||
|
const click = () => {
|
||||||
|
view.value = view.value === One ? Two : One
|
||||||
|
}
|
||||||
|
return { view, click }
|
||||||
|
},
|
||||||
|
}).mount('#app')
|
||||||
|
}, duration)
|
||||||
|
|
||||||
|
await nextFrame()
|
||||||
|
expect(await html('#container')).toBe(
|
||||||
|
'<div>Top</div><div class="test test-enter-active test-enter-to">one</div><div>Bottom</div>',
|
||||||
|
)
|
||||||
|
|
||||||
|
await transitionFinish()
|
||||||
|
expect(await html('#container')).toBe(
|
||||||
|
'<div>Top</div><div class="test">one</div><div>Bottom</div>',
|
||||||
|
)
|
||||||
|
|
||||||
|
// trigger twice
|
||||||
|
classWhenTransitionStart()
|
||||||
|
await nextFrame()
|
||||||
|
expect(await html('#container')).toBe(
|
||||||
|
'<div>Top</div><div class="test test-leave-active test-leave-to">one</div><div>Bottom</div>',
|
||||||
|
)
|
||||||
|
|
||||||
|
await transitionFinish()
|
||||||
|
await nextFrame()
|
||||||
|
expect(await html('#container')).toBe(
|
||||||
|
'<div>Top</div><div class="test test-enter-active test-enter-to">two</div><div>Bottom</div>',
|
||||||
|
)
|
||||||
|
|
||||||
|
await transitionFinish()
|
||||||
|
await nextFrame()
|
||||||
|
expect(await html('#container')).toBe(
|
||||||
|
'<div>Top</div><div class="test">two</div><div>Bottom</div>',
|
||||||
|
)
|
||||||
|
},
|
||||||
|
E2E_TIMEOUT,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('transition with v-show', () => {
|
describe('transition with v-show', () => {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "vue",
|
"name": "vue",
|
||||||
"version": "3.4.5",
|
"version": "3.4.13",
|
||||||
"description": "The progressive JavaScript framework for building modern web UI.",
|
"description": "The progressive JavaScript framework for building modern web UI.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"module": "dist/vue.runtime.esm-bundler.js",
|
"module": "dist/vue.runtime.esm-bundler.js",
|
||||||
|
@ -20,15 +20,16 @@
|
||||||
".": {
|
".": {
|
||||||
"import": {
|
"import": {
|
||||||
"types": "./dist/vue.d.mts",
|
"types": "./dist/vue.d.mts",
|
||||||
"node": {
|
"node": "./index.mjs",
|
||||||
"production": "./dist/vue.cjs.prod.js",
|
|
||||||
"development": "./dist/vue.cjs.js",
|
|
||||||
"default": "./index.mjs"
|
|
||||||
},
|
|
||||||
"default": "./dist/vue.runtime.esm-bundler.js"
|
"default": "./dist/vue.runtime.esm-bundler.js"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"types": "./dist/vue.d.ts",
|
"types": "./dist/vue.d.ts",
|
||||||
|
"node": {
|
||||||
|
"production": "./dist/vue.cjs.prod.js",
|
||||||
|
"development": "./dist/vue.cjs.js",
|
||||||
|
"default": "./index.js"
|
||||||
|
},
|
||||||
"default": "./index.js"
|
"default": "./index.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
230
pnpm-lock.yaml
230
pnpm-lock.yaml
|
@ -16,7 +16,7 @@ importers:
|
||||||
version: 7.23.6
|
version: 7.23.6
|
||||||
'@codspeed/vitest-plugin':
|
'@codspeed/vitest-plugin':
|
||||||
specifier: ^2.3.1
|
specifier: ^2.3.1
|
||||||
version: 2.3.1(vite@5.0.10)(vitest@1.1.1)
|
version: 2.3.1(vite@5.0.10)(vitest@1.2.0)
|
||||||
'@rollup/plugin-alias':
|
'@rollup/plugin-alias':
|
||||||
specifier: ^5.0.1
|
specifier: ^5.0.1
|
||||||
version: 5.0.1(rollup@4.4.1)
|
version: 5.0.1(rollup@4.4.1)
|
||||||
|
@ -42,8 +42,8 @@ importers:
|
||||||
specifier: ^1.2.5
|
specifier: ^1.2.5
|
||||||
version: 1.2.5
|
version: 1.2.5
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^20.10.6
|
specifier: ^20.10.7
|
||||||
version: 20.10.6
|
version: 20.11.0
|
||||||
'@types/semver':
|
'@types/semver':
|
||||||
specifier: ^7.5.6
|
specifier: ^7.5.6
|
||||||
version: 7.5.6
|
version: 7.5.6
|
||||||
|
@ -54,8 +54,8 @@ importers:
|
||||||
specifier: ^6.17.0
|
specifier: ^6.17.0
|
||||||
version: 6.17.0(eslint@8.56.0)(typescript@5.2.2)
|
version: 6.17.0(eslint@8.56.0)(typescript@5.2.2)
|
||||||
'@vitest/coverage-istanbul':
|
'@vitest/coverage-istanbul':
|
||||||
specifier: ^1.1.1
|
specifier: ^1.1.3
|
||||||
version: 1.1.1(vitest@1.1.1)
|
version: 1.2.0(vitest@1.2.0)
|
||||||
'@vue/consolidate':
|
'@vue/consolidate':
|
||||||
specifier: 0.17.3
|
specifier: 0.17.3
|
||||||
version: 0.17.3
|
version: 0.17.3
|
||||||
|
@ -90,8 +90,8 @@ importers:
|
||||||
specifier: ^8.0.1
|
specifier: ^8.0.1
|
||||||
version: 8.0.1
|
version: 8.0.1
|
||||||
jsdom:
|
jsdom:
|
||||||
specifier: ^23.0.1
|
specifier: ^23.2.0
|
||||||
version: 23.0.1
|
version: 23.2.0
|
||||||
lint-staged:
|
lint-staged:
|
||||||
specifier: ^15.2.0
|
specifier: ^15.2.0
|
||||||
version: 15.2.0
|
version: 15.2.0
|
||||||
|
@ -126,8 +126,8 @@ importers:
|
||||||
specifier: ^3.0.2
|
specifier: ^3.0.2
|
||||||
version: 3.0.2
|
version: 3.0.2
|
||||||
puppeteer:
|
puppeteer:
|
||||||
specifier: ~21.6.1
|
specifier: ~21.7.0
|
||||||
version: 21.6.1(typescript@5.2.2)
|
version: 21.7.0(typescript@5.2.2)
|
||||||
rimraf:
|
rimraf:
|
||||||
specifier: ^5.0.5
|
specifier: ^5.0.5
|
||||||
version: 5.0.5
|
version: 5.0.5
|
||||||
|
@ -169,10 +169,10 @@ importers:
|
||||||
version: 5.2.2
|
version: 5.2.2
|
||||||
vite:
|
vite:
|
||||||
specifier: ^5.0.5
|
specifier: ^5.0.5
|
||||||
version: 5.0.10(@types/node@20.10.6)(terser@5.22.0)
|
version: 5.0.10(@types/node@20.11.0)(terser@5.22.0)
|
||||||
vitest:
|
vitest:
|
||||||
specifier: ^1.1.1
|
specifier: ^1.1.3
|
||||||
version: 1.1.1(@types/node@20.10.6)(jsdom@23.0.1)(terser@5.22.0)
|
version: 1.2.0(@types/node@20.11.0)(jsdom@23.2.0)(terser@5.22.0)
|
||||||
|
|
||||||
packages/compiler-core:
|
packages/compiler-core:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -369,7 +369,7 @@ importers:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/repl':
|
'@vue/repl':
|
||||||
specifier: ^3.1.1
|
specifier: ^3.1.1
|
||||||
version: 3.2.0
|
version: 3.3.0
|
||||||
file-saver:
|
file-saver:
|
||||||
specifier: ^2.0.5
|
specifier: ^2.0.5
|
||||||
version: 2.0.5
|
version: 2.0.5
|
||||||
|
@ -385,7 +385,7 @@ importers:
|
||||||
version: 4.4.0(vite@5.0.10)(vue@packages+vue)
|
version: 4.4.0(vite@5.0.10)(vue@packages+vue)
|
||||||
vite:
|
vite:
|
||||||
specifier: ^5.0.5
|
specifier: ^5.0.5
|
||||||
version: 5.0.10(@types/node@20.10.6)(terser@5.22.0)
|
version: 5.0.10(@types/node@20.11.0)(terser@5.22.0)
|
||||||
|
|
||||||
packages/shared: {}
|
packages/shared: {}
|
||||||
|
|
||||||
|
@ -460,10 +460,10 @@ importers:
|
||||||
version: 4.5.0(vite@5.0.2)(vue@packages+vue)
|
version: 4.5.0(vite@5.0.2)(vue@packages+vue)
|
||||||
vite:
|
vite:
|
||||||
specifier: ^5.0.2
|
specifier: ^5.0.2
|
||||||
version: 5.0.2(@types/node@20.10.6)(terser@5.22.0)
|
version: 5.0.2(@types/node@20.11.0)(terser@5.22.0)
|
||||||
vite-hyper-config:
|
vite-hyper-config:
|
||||||
specifier: ^0.2.1
|
specifier: ^0.2.1
|
||||||
version: 0.2.1(@types/node@20.10.6)(terser@5.22.0)(vite@5.0.2)
|
version: 0.2.1(@types/node@20.11.0)(terser@5.22.0)(vite@5.0.2)
|
||||||
vite-plugin-inspect:
|
vite-plugin-inspect:
|
||||||
specifier: ^0.7.42
|
specifier: ^0.7.42
|
||||||
version: 0.7.42(rollup@4.4.1)(vite@5.0.2)
|
version: 0.7.42(rollup@4.4.1)(vite@5.0.2)
|
||||||
|
@ -487,6 +487,14 @@ packages:
|
||||||
resolution: {integrity: sha512-pvFiLP2BeOKA/ZOS6jxx4XhKzdVLHDhGlFEaZ2flWWYf2xOqVniqpk38I04DFRyz+L0ASggl7SkItTc+ZLju4w==}
|
resolution: {integrity: sha512-pvFiLP2BeOKA/ZOS6jxx4XhKzdVLHDhGlFEaZ2flWWYf2xOqVniqpk38I04DFRyz+L0ASggl7SkItTc+ZLju4w==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@asamuzakjp/dom-selector@2.0.2:
|
||||||
|
resolution: {integrity: sha512-x1KXOatwofR6ZAYzXRBL5wrdV0vwNxlTCK9NCuLqAzQYARqGcvFwiJA6A1ERuh+dgeA4Dxm3JBYictIes+SqUQ==}
|
||||||
|
dependencies:
|
||||||
|
bidi-js: 1.0.3
|
||||||
|
css-tree: 2.3.1
|
||||||
|
is-potential-custom-element-name: 1.0.1
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@babel/code-frame@7.23.5:
|
/@babel/code-frame@7.23.5:
|
||||||
resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==}
|
resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
@ -684,15 +692,15 @@ packages:
|
||||||
node-gyp-build: 4.7.1
|
node-gyp-build: 4.7.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@codspeed/vitest-plugin@2.3.1(vite@5.0.10)(vitest@1.1.1):
|
/@codspeed/vitest-plugin@2.3.1(vite@5.0.10)(vitest@1.2.0):
|
||||||
resolution: {integrity: sha512-/e4G2B/onX/hG/EjUU/NpDxnIryeTDamVRTBeWfgQDoex3g7GDzTwoQktaU5l/Asw3ZjEErQg+oQVToQ6jYZlA==}
|
resolution: {integrity: sha512-/e4G2B/onX/hG/EjUU/NpDxnIryeTDamVRTBeWfgQDoex3g7GDzTwoQktaU5l/Asw3ZjEErQg+oQVToQ6jYZlA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vite: ^4.2.0 || ^5.0.0
|
vite: ^4.2.0 || ^5.0.0
|
||||||
vitest: '>=1.0.0-beta.4 || >=1'
|
vitest: '>=1.0.0-beta.4 || >=1'
|
||||||
dependencies:
|
dependencies:
|
||||||
'@codspeed/core': 2.3.1
|
'@codspeed/core': 2.3.1
|
||||||
vite: 5.0.10(@types/node@20.10.6)(terser@5.22.0)
|
vite: 5.0.10(@types/node@20.11.0)(terser@5.22.0)
|
||||||
vitest: 1.1.1(@types/node@20.10.6)(jsdom@23.0.1)(terser@5.22.0)
|
vitest: 1.2.0(@types/node@20.11.0)(jsdom@23.2.0)(terser@5.22.0)
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@esbuild/aix-ppc64@0.19.10:
|
/@esbuild/aix-ppc64@0.19.10:
|
||||||
|
@ -1060,8 +1068,8 @@ packages:
|
||||||
resolution: {integrity: sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==}
|
resolution: {integrity: sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@puppeteer/browsers@1.9.0:
|
/@puppeteer/browsers@1.9.1:
|
||||||
resolution: {integrity: sha512-QwguOLy44YBGC8vuPP2nmpX4MUN2FzWbsnvZJtiCzecU3lHmVZkaC1tq6rToi9a200m8RzlVtDyxCS0UIDrxUg==}
|
resolution: {integrity: sha512-PuvK6xZzGhKPvlx3fpfdM2kYY3P/hB1URtK8wA7XUJ6prn6pp22zvJHu48th0SGcHL9SutbPHrFuQgfXTFobWA==}
|
||||||
engines: {node: '>=16.3.0'}
|
engines: {node: '>=16.3.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -1317,8 +1325,8 @@ packages:
|
||||||
resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==}
|
resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@types/node@20.10.6:
|
/@types/node@20.11.0:
|
||||||
resolution: {integrity: sha512-Vac8H+NlRNNlAmDfGUP7b5h/KA+AtWIzuXy0E6OyP8f1tCLYAtPvKRRDJjAPqhpCb0t6U2j7/xqAuLEebW2kiw==}
|
resolution: {integrity: sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 5.26.5
|
undici-types: 5.26.5
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -1339,7 +1347,7 @@ packages:
|
||||||
resolution: {integrity: sha512-Km7XAtUIduROw7QPgvcft0lIupeG8a8rdKL8RiSyKvlE7dYY31fEn41HVuQsRFDuROA8tA4K2UVL+WdfFmErBA==}
|
resolution: {integrity: sha512-Km7XAtUIduROw7QPgvcft0lIupeG8a8rdKL8RiSyKvlE7dYY31fEn41HVuQsRFDuROA8tA4K2UVL+WdfFmErBA==}
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.10.6
|
'@types/node': 20.11.0
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
@ -1548,7 +1556,7 @@ packages:
|
||||||
vite: ^4.0.0
|
vite: ^4.0.0
|
||||||
vue: ^3.2.25
|
vue: ^3.2.25
|
||||||
dependencies:
|
dependencies:
|
||||||
vite: 5.0.10(@types/node@20.10.6)(terser@5.22.0)
|
vite: 5.0.10(@types/node@20.11.0)(terser@5.22.0)
|
||||||
vue: link:packages/vue
|
vue: link:packages/vue
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
@ -1559,12 +1567,12 @@ packages:
|
||||||
vite: ^4.0.0 || ^5.0.0
|
vite: ^4.0.0 || ^5.0.0
|
||||||
vue: ^3.2.25
|
vue: ^3.2.25
|
||||||
dependencies:
|
dependencies:
|
||||||
vite: 5.0.2(@types/node@20.10.6)(terser@5.22.0)
|
vite: 5.0.2(@types/node@20.11.0)(terser@5.22.0)
|
||||||
vue: link:packages/vue
|
vue: link:packages/vue
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@vitest/coverage-istanbul@1.1.1(vitest@1.1.1):
|
/@vitest/coverage-istanbul@1.2.0(vitest@1.2.0):
|
||||||
resolution: {integrity: sha512-Ikq6k2/KJ3MqEnGJCZBctcgxW1JRPzyVetVz1AYqLxrHNiG/epGFPZ74kIc3AK0HGaf0RsqZkc8riCTmxfH/dQ==}
|
resolution: {integrity: sha512-hNN/pUR5la6P/L78+YcRl05Lpf6APXlH9ujkmCxxjVWtVG6WuKuqUMhHgYQBYfiOORBwDZ1MBgSUGCMPh4kpmQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vitest: ^1.0.0
|
vitest: ^1.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -1577,45 +1585,46 @@ packages:
|
||||||
magicast: 0.3.2
|
magicast: 0.3.2
|
||||||
picocolors: 1.0.0
|
picocolors: 1.0.0
|
||||||
test-exclude: 6.0.0
|
test-exclude: 6.0.0
|
||||||
vitest: 1.1.1(@types/node@20.10.6)(jsdom@23.0.1)(terser@5.22.0)
|
vitest: 1.2.0(@types/node@20.11.0)(jsdom@23.2.0)(terser@5.22.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@vitest/expect@1.1.1:
|
/@vitest/expect@1.2.0:
|
||||||
resolution: {integrity: sha512-Qpw01C2Hyb3085jBkOJLQ7HRX0Ncnh2qV4p+xWmmhcIUlMykUF69zsnZ1vPmAjZpomw9+5tWEGOQ0GTfR8U+kA==}
|
resolution: {integrity: sha512-H+2bHzhyvgp32o7Pgj2h9RTHN0pgYaoi26Oo3mE+dCi1PAqV31kIIVfTbqMO3Bvshd5mIrJLc73EwSRrbol9Lw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/spy': 1.1.1
|
'@vitest/spy': 1.2.0
|
||||||
'@vitest/utils': 1.1.1
|
'@vitest/utils': 1.2.0
|
||||||
chai: 4.3.10
|
chai: 4.3.10
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@vitest/runner@1.1.1:
|
/@vitest/runner@1.2.0:
|
||||||
resolution: {integrity: sha512-8HokyJo1SnSi3uPFKfWm/Oq1qDwLC4QDcVsqpXIXwsRPAg3gIDh8EbZ1ri8cmQkBxdOu62aOF9B4xcqJhvt4xQ==}
|
resolution: {integrity: sha512-vaJkDoQaNUTroT70OhM0NPznP7H3WyRwt4LvGwCVYs/llLaqhoSLnlIhUClZpbF5RgAee29KRcNz0FEhYcgxqA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/utils': 1.1.1
|
'@vitest/utils': 1.2.0
|
||||||
p-limit: 5.0.0
|
p-limit: 5.0.0
|
||||||
pathe: 1.1.1
|
pathe: 1.1.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@vitest/snapshot@1.1.1:
|
/@vitest/snapshot@1.2.0:
|
||||||
resolution: {integrity: sha512-WnMHjv4VdHLbFGgCdVVvyRkRPnOKN75JJg+LLTdr6ah7YnL75W+7CTIMdzPEPzaDxA8r5yvSVlc1d8lH3yE28w==}
|
resolution: {integrity: sha512-P33EE7TrVgB3HDLllrjK/GG6WSnmUtWohbwcQqmm7TAk9AVHpdgf7M3F3qRHKm6vhr7x3eGIln7VH052Smo6Kw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
magic-string: 0.30.5
|
magic-string: 0.30.5
|
||||||
pathe: 1.1.1
|
pathe: 1.1.1
|
||||||
pretty-format: 29.7.0
|
pretty-format: 29.7.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@vitest/spy@1.1.1:
|
/@vitest/spy@1.2.0:
|
||||||
resolution: {integrity: sha512-hDU2KkOTfFp4WFFPWwHFauddwcKuGQ7gF6Un/ZZkCogoAiTMN7/7YKvUDbywPZZ754iCQGjdUmXN3t4k0jm1IQ==}
|
resolution: {integrity: sha512-MNxSAfxUaCeowqyyGwC293yZgk7cECZU9wGb8N1pYQ0yOn/SIr8t0l9XnGRdQZvNV/ZHBYu6GO/W3tj5K3VN1Q==}
|
||||||
dependencies:
|
dependencies:
|
||||||
tinyspy: 2.2.0
|
tinyspy: 2.2.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@vitest/utils@1.1.1:
|
/@vitest/utils@1.2.0:
|
||||||
resolution: {integrity: sha512-E9LedH093vST/JuBSyHLFMpxJKW3dLhe/flUSPFedoyj4wKiFX7Jm8gYLtOIiin59dgrssfmFv0BJ1u8P/LC/A==}
|
resolution: {integrity: sha512-FyD5bpugsXlwVpTcGLDf3wSPYy8g541fQt14qtzo8mJ4LdEpDKZ9mQy2+qdJm2TZRpjY5JLXihXCgIxiRJgi5g==}
|
||||||
dependencies:
|
dependencies:
|
||||||
diff-sequences: 29.6.3
|
diff-sequences: 29.6.3
|
||||||
|
estree-walker: 3.0.3
|
||||||
loupe: 2.3.7
|
loupe: 2.3.7
|
||||||
pretty-format: 29.7.0
|
pretty-format: 29.7.0
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -1625,8 +1634,8 @@ packages:
|
||||||
engines: {node: '>= 0.12.0'}
|
engines: {node: '>= 0.12.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@vue/repl@3.2.0:
|
/@vue/repl@3.3.0:
|
||||||
resolution: {integrity: sha512-heKXXwAm4p3wYqVsYqW5i9bAkiGqwbZygfBx8stZ48QqTvaTGiGY3qASJwvhc5FrZDPGoGcFRjab6XDImKxPvA==}
|
resolution: {integrity: sha512-A9tdO7obt/kpFUHdgGoRnan6bZjfz/WAJ5+DpPkvgNEc960W+bJraURv8MUVtH2Id/byWotKbUve2jTakiccSw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@zeit/schemas@2.29.0:
|
/@zeit/schemas@2.29.0:
|
||||||
|
@ -1858,6 +1867,12 @@ packages:
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/bidi-js@1.0.3:
|
||||||
|
resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==}
|
||||||
|
dependencies:
|
||||||
|
require-from-string: 2.0.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
/big-integer@1.6.51:
|
/big-integer@1.6.51:
|
||||||
resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==}
|
resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==}
|
||||||
engines: {node: '>=0.6'}
|
engines: {node: '>=0.6'}
|
||||||
|
@ -2053,8 +2068,8 @@ packages:
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/chromium-bidi@0.5.1(devtools-protocol@0.0.1203626):
|
/chromium-bidi@0.5.2(devtools-protocol@0.0.1203626):
|
||||||
resolution: {integrity: sha512-dcCqOgq9fHKExc2R4JZs/oKbOghWpUNFAJODS8WKRtLhp3avtIH5UDCBrutdqZdh3pARogH8y1ObXm87emwb3g==}
|
resolution: {integrity: sha512-PbVOSddxgKyj+JByqavWMNqWPCoCaT6XK5Z1EFe168sxnB/BM51LnZEPXSbFcFAJv/+u2B4XNTs9uXxy4GW3cQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
devtools-protocol: '*'
|
devtools-protocol: '*'
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -2372,15 +2387,23 @@ packages:
|
||||||
which: 2.0.2
|
which: 2.0.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/css-tree@2.3.1:
|
||||||
|
resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==}
|
||||||
|
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
|
||||||
|
dependencies:
|
||||||
|
mdn-data: 2.0.30
|
||||||
|
source-map-js: 1.0.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
/cssesc@3.0.0:
|
/cssesc@3.0.0:
|
||||||
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
|
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/cssstyle@3.0.0:
|
/cssstyle@4.0.1:
|
||||||
resolution: {integrity: sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==}
|
resolution: {integrity: sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=18'}
|
||||||
dependencies:
|
dependencies:
|
||||||
rrweb-cssom: 0.6.0
|
rrweb-cssom: 0.6.0
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -2935,6 +2958,12 @@ packages:
|
||||||
/estree-walker@2.0.2:
|
/estree-walker@2.0.2:
|
||||||
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
||||||
|
|
||||||
|
/estree-walker@3.0.3:
|
||||||
|
resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
|
||||||
|
dependencies:
|
||||||
|
'@types/estree': 1.0.3
|
||||||
|
dev: true
|
||||||
|
|
||||||
/esutils@2.0.3:
|
/esutils@2.0.3:
|
||||||
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
@ -3877,8 +3906,8 @@ packages:
|
||||||
argparse: 2.0.1
|
argparse: 2.0.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/jsdom@23.0.1:
|
/jsdom@23.2.0:
|
||||||
resolution: {integrity: sha512-2i27vgvlUsGEBO9+/kJQRbtqtm+191b5zAZrU/UezVmnC2dlDAFLgDYJvAEi94T4kjsRKkezEtLQTgsNEsW2lQ==}
|
resolution: {integrity: sha512-L88oL7D/8ufIES+Zjz7v0aes+oBMh2Xnh3ygWvL0OaICOomKEPKuPnIfBJekiXr+BHbbMjrWn/xqrDQuxFTeyA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
canvas: ^2.11.2
|
canvas: ^2.11.2
|
||||||
|
@ -3886,7 +3915,8 @@ packages:
|
||||||
canvas:
|
canvas:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
cssstyle: 3.0.0
|
'@asamuzakjp/dom-selector': 2.0.2
|
||||||
|
cssstyle: 4.0.1
|
||||||
data-urls: 5.0.0
|
data-urls: 5.0.0
|
||||||
decimal.js: 10.4.3
|
decimal.js: 10.4.3
|
||||||
form-data: 4.0.0
|
form-data: 4.0.0
|
||||||
|
@ -3894,7 +3924,6 @@ packages:
|
||||||
http-proxy-agent: 7.0.0
|
http-proxy-agent: 7.0.0
|
||||||
https-proxy-agent: 7.0.2
|
https-proxy-agent: 7.0.2
|
||||||
is-potential-custom-element-name: 1.0.1
|
is-potential-custom-element-name: 1.0.1
|
||||||
nwsapi: 2.2.7
|
|
||||||
parse5: 7.1.2
|
parse5: 7.1.2
|
||||||
rrweb-cssom: 0.6.0
|
rrweb-cssom: 0.6.0
|
||||||
saxes: 6.0.0
|
saxes: 6.0.0
|
||||||
|
@ -3905,7 +3934,7 @@ packages:
|
||||||
whatwg-encoding: 3.1.1
|
whatwg-encoding: 3.1.1
|
||||||
whatwg-mimetype: 4.0.0
|
whatwg-mimetype: 4.0.0
|
||||||
whatwg-url: 14.0.0
|
whatwg-url: 14.0.0
|
||||||
ws: 8.15.1
|
ws: 8.16.0
|
||||||
xml-name-validator: 5.0.0
|
xml-name-validator: 5.0.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- bufferutil
|
- bufferutil
|
||||||
|
@ -4182,6 +4211,10 @@ packages:
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/mdn-data@2.0.30:
|
||||||
|
resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/memorystream@0.3.1:
|
/memorystream@0.3.1:
|
||||||
resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==}
|
resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==}
|
||||||
engines: {node: '>= 0.10.0'}
|
engines: {node: '>= 0.10.0'}
|
||||||
|
@ -4414,10 +4447,6 @@ packages:
|
||||||
path-key: 4.0.0
|
path-key: 4.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/nwsapi@2.2.7:
|
|
||||||
resolution: {integrity: sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/object-assign@4.1.1:
|
/object-assign@4.1.1:
|
||||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
@ -4950,16 +4979,16 @@ packages:
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/puppeteer-core@21.6.1:
|
/puppeteer-core@21.7.0:
|
||||||
resolution: {integrity: sha512-0chaaK/RL9S1U3bsyR4fUeUfoj51vNnjWvXgG6DcsyMjwYNpLcAThv187i1rZCo7QhJP0wZN8plQkjNyrq2h+A==}
|
resolution: {integrity: sha512-elPYPozrgiM3phSy7VDUJCVWQ07SPnOm78fpSaaSNFoQx5sur/MqhTSro9Wz8lOEjqCykGC6WRkwxDgmqcy1dQ==}
|
||||||
engines: {node: '>=16.13.2'}
|
engines: {node: '>=16.13.2'}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@puppeteer/browsers': 1.9.0
|
'@puppeteer/browsers': 1.9.1
|
||||||
chromium-bidi: 0.5.1(devtools-protocol@0.0.1203626)
|
chromium-bidi: 0.5.2(devtools-protocol@0.0.1203626)
|
||||||
cross-fetch: 4.0.0
|
cross-fetch: 4.0.0
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
devtools-protocol: 0.0.1203626
|
devtools-protocol: 0.0.1203626
|
||||||
ws: 8.15.1
|
ws: 8.16.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- bufferutil
|
- bufferutil
|
||||||
- encoding
|
- encoding
|
||||||
|
@ -4967,15 +4996,15 @@ packages:
|
||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/puppeteer@21.6.1(typescript@5.2.2):
|
/puppeteer@21.7.0(typescript@5.2.2):
|
||||||
resolution: {integrity: sha512-O+pbc61oj8ln6m8EJKncrsQFmytgRyFYERtk190PeLbJn5JKpmmynn2p1PiFrlhCitAQXLJ0MOy7F0TeyCRqBg==}
|
resolution: {integrity: sha512-Yy+UUy0b9siJezbhHO/heYUoZQUwyqDK1yOQgblTt0l97tspvDVFkcW9toBlnSvSfkDmMI3Dx9cZL6R8bDArHA==}
|
||||||
engines: {node: '>=16.13.2'}
|
engines: {node: '>=16.13.2'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@puppeteer/browsers': 1.9.0
|
'@puppeteer/browsers': 1.9.1
|
||||||
cosmiconfig: 8.3.6(typescript@5.2.2)
|
cosmiconfig: 8.3.6(typescript@5.2.2)
|
||||||
puppeteer-core: 21.6.1
|
puppeteer-core: 21.7.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- bufferutil
|
- bufferutil
|
||||||
- encoding
|
- encoding
|
||||||
|
@ -6019,7 +6048,7 @@ packages:
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/vite-hyper-config@0.2.1(@types/node@20.10.6)(terser@5.22.0)(vite@5.0.2):
|
/vite-hyper-config@0.2.1(@types/node@20.11.0)(terser@5.22.0)(vite@5.0.2):
|
||||||
resolution: {integrity: sha512-ItRIpzWp0XMh/Sn1H0GCWnQIUcBjnSaZy/EbOpJcRr9H/KTBHUSTCEOigE9K0KTN01Z0GDi/8WgVT9+RPL932A==}
|
resolution: {integrity: sha512-ItRIpzWp0XMh/Sn1H0GCWnQIUcBjnSaZy/EbOpJcRr9H/KTBHUSTCEOigE9K0KTN01Z0GDi/8WgVT9+RPL932A==}
|
||||||
engines: {node: '>=18.0.0'}
|
engines: {node: '>=18.0.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -6027,8 +6056,8 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
cac: 6.7.14
|
cac: 6.7.14
|
||||||
picocolors: 1.0.0
|
picocolors: 1.0.0
|
||||||
vite: 5.0.2(@types/node@20.10.6)(terser@5.22.0)
|
vite: 5.0.2(@types/node@20.11.0)(terser@5.22.0)
|
||||||
vite-node: 1.1.1(@types/node@20.10.6)(terser@5.22.0)
|
vite-node: 1.1.1(@types/node@20.11.0)(terser@5.22.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@types/node'
|
- '@types/node'
|
||||||
- less
|
- less
|
||||||
|
@ -6040,7 +6069,7 @@ packages:
|
||||||
- terser
|
- terser
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/vite-node@1.1.1(@types/node@20.10.6)(terser@5.22.0):
|
/vite-node@1.1.1(@types/node@20.11.0)(terser@5.22.0):
|
||||||
resolution: {integrity: sha512-2bGE5w4jvym5v8llF6Gu1oBrmImoNSs4WmRVcavnG2me6+8UQntTqLiAMFyiAobp+ZXhj5ZFhI7SmLiFr/jrow==}
|
resolution: {integrity: sha512-2bGE5w4jvym5v8llF6Gu1oBrmImoNSs4WmRVcavnG2me6+8UQntTqLiAMFyiAobp+ZXhj5ZFhI7SmLiFr/jrow==}
|
||||||
engines: {node: ^18.0.0 || >=20.0.0}
|
engines: {node: ^18.0.0 || >=20.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
@ -6049,7 +6078,28 @@ packages:
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
pathe: 1.1.1
|
pathe: 1.1.1
|
||||||
picocolors: 1.0.0
|
picocolors: 1.0.0
|
||||||
vite: 5.0.10(@types/node@20.10.6)(terser@5.22.0)
|
vite: 5.0.10(@types/node@20.11.0)(terser@5.22.0)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@types/node'
|
||||||
|
- less
|
||||||
|
- lightningcss
|
||||||
|
- sass
|
||||||
|
- stylus
|
||||||
|
- sugarss
|
||||||
|
- supports-color
|
||||||
|
- terser
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/vite-node@1.2.0(@types/node@20.11.0)(terser@5.22.0):
|
||||||
|
resolution: {integrity: sha512-ETnQTHeAbbOxl7/pyBck9oAPZZZo+kYnFt1uQDD+hPReOc+wCjXw4r4jHriBRuVDB5isHmPXxrfc1yJnfBERqg==}
|
||||||
|
engines: {node: ^18.0.0 || >=20.0.0}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
cac: 6.7.14
|
||||||
|
debug: 4.3.4
|
||||||
|
pathe: 1.1.1
|
||||||
|
picocolors: 1.0.0
|
||||||
|
vite: 5.0.10(@types/node@20.11.0)(terser@5.22.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@types/node'
|
- '@types/node'
|
||||||
- less
|
- less
|
||||||
|
@ -6079,13 +6129,13 @@ packages:
|
||||||
open: 9.1.0
|
open: 9.1.0
|
||||||
picocolors: 1.0.0
|
picocolors: 1.0.0
|
||||||
sirv: 2.0.3
|
sirv: 2.0.3
|
||||||
vite: 5.0.2(@types/node@20.10.6)(terser@5.22.0)
|
vite: 5.0.2(@types/node@20.11.0)(terser@5.22.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- rollup
|
- rollup
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/vite@5.0.10(@types/node@20.10.6)(terser@5.22.0):
|
/vite@5.0.10(@types/node@20.11.0)(terser@5.22.0):
|
||||||
resolution: {integrity: sha512-2P8J7WWgmc355HUMlFrwofacvr98DAjoE52BfdbwQtyLH06XKwaL/FMnmKM2crF0iX4MpmMKoDlNCB1ok7zHCw==}
|
resolution: {integrity: sha512-2P8J7WWgmc355HUMlFrwofacvr98DAjoE52BfdbwQtyLH06XKwaL/FMnmKM2crF0iX4MpmMKoDlNCB1ok7zHCw==}
|
||||||
engines: {node: ^18.0.0 || >=20.0.0}
|
engines: {node: ^18.0.0 || >=20.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
@ -6113,7 +6163,7 @@ packages:
|
||||||
terser:
|
terser:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.10.6
|
'@types/node': 20.11.0
|
||||||
esbuild: 0.19.10
|
esbuild: 0.19.10
|
||||||
postcss: 8.4.32
|
postcss: 8.4.32
|
||||||
rollup: 4.4.1
|
rollup: 4.4.1
|
||||||
|
@ -6122,7 +6172,7 @@ packages:
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/vite@5.0.2(@types/node@20.10.6)(terser@5.22.0):
|
/vite@5.0.2(@types/node@20.11.0)(terser@5.22.0):
|
||||||
resolution: {integrity: sha512-6CCq1CAJCNM1ya2ZZA7+jS2KgnhbzvxakmlIjN24cF/PXhRMzpM/z8QgsVJA/Dm5fWUWnVEsmtBoMhmerPxT0g==}
|
resolution: {integrity: sha512-6CCq1CAJCNM1ya2ZZA7+jS2KgnhbzvxakmlIjN24cF/PXhRMzpM/z8QgsVJA/Dm5fWUWnVEsmtBoMhmerPxT0g==}
|
||||||
engines: {node: ^18.0.0 || >=20.0.0}
|
engines: {node: ^18.0.0 || >=20.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
@ -6150,7 +6200,7 @@ packages:
|
||||||
terser:
|
terser:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.10.6
|
'@types/node': 20.11.0
|
||||||
esbuild: 0.19.10
|
esbuild: 0.19.10
|
||||||
postcss: 8.4.32
|
postcss: 8.4.32
|
||||||
rollup: 4.4.1
|
rollup: 4.4.1
|
||||||
|
@ -6159,8 +6209,8 @@ packages:
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/vitest@1.1.1(@types/node@20.10.6)(jsdom@23.0.1)(terser@5.22.0):
|
/vitest@1.2.0(@types/node@20.11.0)(jsdom@23.2.0)(terser@5.22.0):
|
||||||
resolution: {integrity: sha512-Ry2qs4UOu/KjpXVfOCfQkTnwSXYGrqTbBZxw6reIYEFjSy1QUARRg5pxiI5BEXy+kBVntxUYNMlq4Co+2vD3fQ==}
|
resolution: {integrity: sha512-Ixs5m7BjqvLHXcibkzKRQUvD/XLw0E3rvqaCMlrm/0LMsA0309ZqYvTlPzkhh81VlEyVZXFlwWnkhb6/UMtcaQ==}
|
||||||
engines: {node: ^18.0.0 || >=20.0.0}
|
engines: {node: ^18.0.0 || >=20.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -6184,18 +6234,18 @@ packages:
|
||||||
jsdom:
|
jsdom:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.10.6
|
'@types/node': 20.11.0
|
||||||
'@vitest/expect': 1.1.1
|
'@vitest/expect': 1.2.0
|
||||||
'@vitest/runner': 1.1.1
|
'@vitest/runner': 1.2.0
|
||||||
'@vitest/snapshot': 1.1.1
|
'@vitest/snapshot': 1.2.0
|
||||||
'@vitest/spy': 1.1.1
|
'@vitest/spy': 1.2.0
|
||||||
'@vitest/utils': 1.1.1
|
'@vitest/utils': 1.2.0
|
||||||
acorn-walk: 8.3.1
|
acorn-walk: 8.3.1
|
||||||
cac: 6.7.14
|
cac: 6.7.14
|
||||||
chai: 4.3.10
|
chai: 4.3.10
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
execa: 8.0.1
|
execa: 8.0.1
|
||||||
jsdom: 23.0.1
|
jsdom: 23.2.0
|
||||||
local-pkg: 0.5.0
|
local-pkg: 0.5.0
|
||||||
magic-string: 0.30.5
|
magic-string: 0.30.5
|
||||||
pathe: 1.1.1
|
pathe: 1.1.1
|
||||||
|
@ -6204,8 +6254,8 @@ packages:
|
||||||
strip-literal: 1.3.0
|
strip-literal: 1.3.0
|
||||||
tinybench: 2.5.1
|
tinybench: 2.5.1
|
||||||
tinypool: 0.8.1
|
tinypool: 0.8.1
|
||||||
vite: 5.0.10(@types/node@20.10.6)(terser@5.22.0)
|
vite: 5.0.10(@types/node@20.11.0)(terser@5.22.0)
|
||||||
vite-node: 1.1.1(@types/node@20.10.6)(terser@5.22.0)
|
vite-node: 1.2.0(@types/node@20.11.0)(terser@5.22.0)
|
||||||
why-is-node-running: 2.2.2
|
why-is-node-running: 2.2.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- less
|
- less
|
||||||
|
@ -6362,8 +6412,8 @@ packages:
|
||||||
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/ws@8.15.1:
|
/ws@8.16.0:
|
||||||
resolution: {integrity: sha512-W5OZiCjXEmk0yZ66ZN82beM5Sz7l7coYxpRkzS+p9PP+ToQry8szKh+61eNktr7EA9DOwvFGhfC605jDHbP6QQ==}
|
resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==}
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
bufferutil: ^4.0.1
|
bufferutil: ^4.0.1
|
||||||
|
|
|
@ -122,7 +122,7 @@ function createConfig(format, output, plugins = []) {
|
||||||
const isBundlerESMBuild = /esm-bundler/.test(format)
|
const isBundlerESMBuild = /esm-bundler/.test(format)
|
||||||
const isBrowserESMBuild = /esm-browser/.test(format)
|
const isBrowserESMBuild = /esm-browser/.test(format)
|
||||||
const isServerRenderer = name === 'server-renderer'
|
const isServerRenderer = name === 'server-renderer'
|
||||||
const isNodeBuild = format === 'cjs'
|
const isCJSBuild = format === 'cjs'
|
||||||
const isGlobalBuild = /global/.test(format)
|
const isGlobalBuild = /global/.test(format)
|
||||||
const isCompatPackage =
|
const isCompatPackage =
|
||||||
pkg.name === '@vue/compat' || pkg.name === '@vue/compat-canary'
|
pkg.name === '@vue/compat' || pkg.name === '@vue/compat-canary'
|
||||||
|
@ -131,8 +131,14 @@ function createConfig(format, output, plugins = []) {
|
||||||
(isGlobalBuild || isBrowserESMBuild || isBundlerESMBuild) &&
|
(isGlobalBuild || isBrowserESMBuild || isBundlerESMBuild) &&
|
||||||
!packageOptions.enableNonBrowserBranches
|
!packageOptions.enableNonBrowserBranches
|
||||||
|
|
||||||
|
output.banner = `/**
|
||||||
|
* ${pkg.name} v${masterVersion}
|
||||||
|
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
||||||
|
* @license MIT
|
||||||
|
**/`
|
||||||
|
|
||||||
output.exports = isCompatPackage ? 'auto' : 'named'
|
output.exports = isCompatPackage ? 'auto' : 'named'
|
||||||
if (isNodeBuild) {
|
if (isCJSBuild) {
|
||||||
output.esModule = true
|
output.esModule = true
|
||||||
}
|
}
|
||||||
output.sourcemap = !!process.env.SOURCE_MAP
|
output.sourcemap = !!process.env.SOURCE_MAP
|
||||||
|
@ -170,7 +176,7 @@ function createConfig(format, output, plugins = []) {
|
||||||
tsconfig: path.resolve(__dirname, 'tsconfig.json'),
|
tsconfig: path.resolve(__dirname, 'tsconfig.json'),
|
||||||
sourceMap: output.sourcemap,
|
sourceMap: output.sourcemap,
|
||||||
minify: false,
|
minify: false,
|
||||||
target: isServerRenderer || isNodeBuild ? 'es2019' : 'es2015',
|
target: isServerRenderer || isCJSBuild ? 'es2019' : 'es2015',
|
||||||
define: resolveDefine(),
|
define: resolveDefine(),
|
||||||
}),
|
}),
|
||||||
...resolveNodePlugins(),
|
...resolveNodePlugins(),
|
||||||
|
@ -200,9 +206,9 @@ function createConfig(format, output, plugins = []) {
|
||||||
__ESM_BUNDLER__: String(isBundlerESMBuild),
|
__ESM_BUNDLER__: String(isBundlerESMBuild),
|
||||||
__ESM_BROWSER__: String(isBrowserESMBuild),
|
__ESM_BROWSER__: String(isBrowserESMBuild),
|
||||||
// is targeting Node (SSR)?
|
// is targeting Node (SSR)?
|
||||||
__NODE_JS__: String(isNodeBuild),
|
__CJS__: String(isCJSBuild),
|
||||||
// need SSR-specific branches?
|
// need SSR-specific branches?
|
||||||
__SSR__: String(isNodeBuild || isBundlerESMBuild || isServerRenderer),
|
__SSR__: String(isCJSBuild || isBundlerESMBuild || isServerRenderer),
|
||||||
|
|
||||||
// 2.x compat build
|
// 2.x compat build
|
||||||
__COMPAT__: String(isCompatBuild),
|
__COMPAT__: String(isCompatBuild),
|
||||||
|
|
|
@ -120,7 +120,7 @@ for (const target of targets) {
|
||||||
__GLOBAL__: String(format === 'global'),
|
__GLOBAL__: String(format === 'global'),
|
||||||
__ESM_BUNDLER__: String(format.includes('esm-bundler')),
|
__ESM_BUNDLER__: String(format.includes('esm-bundler')),
|
||||||
__ESM_BROWSER__: String(format.includes('esm-browser')),
|
__ESM_BROWSER__: String(format.includes('esm-browser')),
|
||||||
__NODE_JS__: String(format === 'cjs'),
|
__CJS__: String(format === 'cjs'),
|
||||||
__SSR__: String(format === 'cjs' || format.includes('esm-bundler')),
|
__SSR__: String(format === 'cjs' || format.includes('esm-bundler')),
|
||||||
__COMPAT__: String(target === 'vue-compat'),
|
__COMPAT__: String(target === 'vue-compat'),
|
||||||
__FEATURE_SUSPENSE__: `true`,
|
__FEATURE_SUSPENSE__: `true`,
|
||||||
|
|
|
@ -6,7 +6,10 @@ import { createRequire } from 'node:module'
|
||||||
const require = createRequire(import.meta.url)
|
const require = createRequire(import.meta.url)
|
||||||
|
|
||||||
export const targets = fs.readdirSync('packages').filter(f => {
|
export const targets = fs.readdirSync('packages').filter(f => {
|
||||||
if (!fs.statSync(`packages/${f}`).isDirectory()) {
|
if (
|
||||||
|
!fs.statSync(`packages/${f}`).isDirectory() ||
|
||||||
|
!fs.existsSync(`packages/${f}/package.json`)
|
||||||
|
) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
const pkg = require(`../packages/${f}/package.json`)
|
const pkg = require(`../packages/${f}/package.json`)
|
||||||
|
|
|
@ -11,7 +11,7 @@ export default defineConfig({
|
||||||
__GLOBAL__: false,
|
__GLOBAL__: false,
|
||||||
__ESM_BUNDLER__: true,
|
__ESM_BUNDLER__: true,
|
||||||
__ESM_BROWSER__: false,
|
__ESM_BROWSER__: false,
|
||||||
__NODE_JS__: true,
|
__CJS__: true,
|
||||||
__SSR__: true,
|
__SSR__: true,
|
||||||
__FEATURE_OPTIONS_API__: true,
|
__FEATURE_OPTIONS_API__: true,
|
||||||
__FEATURE_SUSPENSE__: true,
|
__FEATURE_SUSPENSE__: true,
|
||||||
|
|
Loading…
Reference in New Issue