mirror of https://github.com/vuejs/core.git
chore: Merge branch 'main' into minor
This commit is contained in:
commit
bb5c31e614
|
@ -26,13 +26,23 @@ module.exports = {
|
||||||
'no-restricted-syntax': [
|
'no-restricted-syntax': [
|
||||||
'error',
|
'error',
|
||||||
banConstEnum,
|
banConstEnum,
|
||||||
// since we target ES2015 for baseline support, we need to forbid object
|
{
|
||||||
// rest spread usage in destructure as it compiles into a verbose helper.
|
selector: 'ObjectPattern > RestElement',
|
||||||
'ObjectPattern > RestElement',
|
message:
|
||||||
// tsc compiles assignment spread into Object.assign() calls, but esbuild
|
'Our output target is ES2016, and object rest spread results in ' +
|
||||||
// still generates verbose helpers, so spread assignment is also prohiboted
|
'verbose helpers and should be avoided.',
|
||||||
'ObjectExpression > SpreadElement',
|
},
|
||||||
'AwaitExpression',
|
{
|
||||||
|
selector: 'ObjectExpression > SpreadElement',
|
||||||
|
message:
|
||||||
|
'esbuild transpiles object spread into very verbose inline helpers.\n' +
|
||||||
|
'Please use the `extend` helper from @vue/shared instead.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selector: 'AwaitExpression',
|
||||||
|
message:
|
||||||
|
'Our output target is ES2016, so async/await syntax should be avoided.',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
'sort-imports': ['error', { ignoreDeclarationSort: true }],
|
'sort-imports': ['error', { ignoreDeclarationSort: true }],
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ jobs:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v2
|
uses: pnpm/action-setup@v3.0.0
|
||||||
|
|
||||||
- name: Set node version to 18
|
- name: Set node version to 18
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
|
|
|
@ -17,7 +17,7 @@ jobs:
|
||||||
ref: minor
|
ref: minor
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v2
|
uses: pnpm/action-setup@v3.0.0
|
||||||
|
|
||||||
- name: Set node version to 18
|
- name: Set node version to 18
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
|
|
|
@ -15,7 +15,7 @@ jobs:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v2
|
uses: pnpm/action-setup@v3.0.0
|
||||||
|
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
|
|
|
@ -6,6 +6,7 @@ on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
- minor
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read # to fetch code (actions/checkout)
|
contents: read # to fetch code (actions/checkout)
|
||||||
|
@ -20,7 +21,7 @@ jobs:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v2
|
uses: pnpm/action-setup@v3.0.0
|
||||||
|
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
|
@ -42,7 +43,7 @@ jobs:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v2
|
uses: pnpm/action-setup@v3.0.0
|
||||||
|
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
|
@ -71,7 +72,7 @@ jobs:
|
||||||
key: chromium-${{ hashFiles('pnpm-lock.yaml') }}
|
key: chromium-${{ hashFiles('pnpm-lock.yaml') }}
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v2
|
uses: pnpm/action-setup@v3.0.0
|
||||||
|
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
|
@ -97,7 +98,7 @@ jobs:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v2
|
uses: pnpm/action-setup@v3.0.0
|
||||||
|
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
|
@ -125,7 +126,7 @@ jobs:
|
||||||
# - uses: actions/checkout@v4
|
# - uses: actions/checkout@v4
|
||||||
|
|
||||||
# - name: Install pnpm
|
# - name: Install pnpm
|
||||||
# uses: pnpm/action-setup@v2
|
# uses: pnpm/action-setup@v3.0.0
|
||||||
|
|
||||||
# - name: Install Node.js
|
# - name: Install Node.js
|
||||||
# uses: actions/setup-node@v4
|
# uses: actions/setup-node@v4
|
||||||
|
|
|
@ -7,6 +7,7 @@ on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
- minor
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
@ -22,7 +23,7 @@ jobs:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v2
|
uses: pnpm/action-setup@v3.0.0
|
||||||
|
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
|
|
|
@ -24,7 +24,7 @@ jobs:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v2
|
uses: pnpm/action-setup@v3.0.0
|
||||||
|
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
|
|
|
@ -10,3 +10,4 @@ TODOs.md
|
||||||
.eslintcache
|
.eslintcache
|
||||||
dts-build/packages
|
dts-build/packages
|
||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
|
*.tgz
|
||||||
|
|
|
@ -5,24 +5,15 @@
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "Jest",
|
|
||||||
"type": "node",
|
"type": "node",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceFolder}/node_modules/.bin/jest",
|
"name": "Vitest - Debug Current Test File",
|
||||||
"stopOnEntry": false,
|
"autoAttachChildProcesses": true,
|
||||||
"args": ["${fileBasename}", "--runInBand", "--detectOpenHandles"],
|
"skipFiles": ["<node_internals>/**", "**/node_modules/**"],
|
||||||
"cwd": "${workspaceFolder}",
|
"program": "${workspaceRoot}/node_modules/vitest/vitest.mjs",
|
||||||
"preLaunchTask": null,
|
"args": ["run", "${relativeFile}"],
|
||||||
"runtimeExecutable": null,
|
"smartStep": true,
|
||||||
"runtimeArgs": ["--nolazy"],
|
"console": "integratedTerminal"
|
||||||
"env": {
|
|
||||||
"NODE_ENV": "development"
|
|
||||||
},
|
|
||||||
"console": "integratedTerminal",
|
|
||||||
"sourceMaps": true,
|
|
||||||
"windows": {
|
|
||||||
"program": "${workspaceFolder}/node_modules/jest/bin/jest"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
52
CHANGELOG.md
52
CHANGELOG.md
|
@ -1,3 +1,55 @@
|
||||||
|
## [3.4.22](https://github.com/vuejs/core/compare/v3.4.21...v3.4.22) (2024-04-15)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compat:** fix $options mutation + adjust private API initialization ([d58d133](https://github.com/vuejs/core/commit/d58d133b1cde5085cc5ab0012d544cafd62a6ee6)), closes [#10626](https://github.com/vuejs/core/issues/10626) [#10636](https://github.com/vuejs/core/issues/10636)
|
||||||
|
* **compile-sfc:** analyze v-bind shorthand usage in template ([#10518](https://github.com/vuejs/core/issues/10518)) ([e5919d4](https://github.com/vuejs/core/commit/e5919d4658cfe0bb18c76611dd3c3432c57f94ab)), closes [#10515](https://github.com/vuejs/core/issues/10515)
|
||||||
|
* **compiler-core:** fix loc.source for end tags with whitespace before > ([16174da](https://github.com/vuejs/core/commit/16174da21d6c8ac0aae027dd964fc35e221ded0a)), closes [#10694](https://github.com/vuejs/core/issues/10694) [#10695](https://github.com/vuejs/core/issues/10695)
|
||||||
|
* **compiler-core:** fix v-bind shorthand for component :is ([04af950](https://github.com/vuejs/core/commit/04af9504a720c8e6de26c04b1282cf14fa1bcee3)), closes [#10469](https://github.com/vuejs/core/issues/10469) [#10471](https://github.com/vuejs/core/issues/10471)
|
||||||
|
* **compiler-sfc:** :is() and :where() in compound selectors ([#10522](https://github.com/vuejs/core/issues/10522)) ([660cadc](https://github.com/vuejs/core/commit/660cadc7aadb909ef33a6055c4374902a82607a4)), closes [#10511](https://github.com/vuejs/core/issues/10511)
|
||||||
|
* **compiler-sfc:** also search for `.tsx` when type import's extension is omitted ([#10637](https://github.com/vuejs/core/issues/10637)) ([34106bc](https://github.com/vuejs/core/commit/34106bc9c715247211273bb9c64712f04bd4879d)), closes [#10635](https://github.com/vuejs/core/issues/10635)
|
||||||
|
* **compiler-sfc:** fix defineModel coercion for boolean + string union types ([#9603](https://github.com/vuejs/core/issues/9603)) ([0cef65c](https://github.com/vuejs/core/commit/0cef65cee411356e721bbc90d731fc52fc8fce94)), closes [#9587](https://github.com/vuejs/core/issues/9587) [#10676](https://github.com/vuejs/core/issues/10676)
|
||||||
|
* **compiler-sfc:** fix universal selector scope ([#10551](https://github.com/vuejs/core/issues/10551)) ([54a6afa](https://github.com/vuejs/core/commit/54a6afa75a546078e901ce0882da53b97420fe94)), closes [#10548](https://github.com/vuejs/core/issues/10548)
|
||||||
|
* **compiler-sfc:** use options module name if options provide runtimeModuleName options ([#10457](https://github.com/vuejs/core/issues/10457)) ([e76d743](https://github.com/vuejs/core/commit/e76d7430aa7470342f3fe263145a0fa92f5898ca)), closes [#10454](https://github.com/vuejs/core/issues/10454)
|
||||||
|
* **custom-element:** avoid setting attr to null if it is removed ([#9012](https://github.com/vuejs/core/issues/9012)) ([b49306a](https://github.com/vuejs/core/commit/b49306adff4572d90a42ccd231387f16eb966bbe)), closes [#9006](https://github.com/vuejs/core/issues/9006) [#10324](https://github.com/vuejs/core/issues/10324)
|
||||||
|
* **hydration:** properly handle optimized mode during hydrate node ([#10638](https://github.com/vuejs/core/issues/10638)) ([2ec06fd](https://github.com/vuejs/core/commit/2ec06fd6c8383e11cdf4efcab1707f973bd6a54c)), closes [#10607](https://github.com/vuejs/core/issues/10607)
|
||||||
|
* **reactivity:** computed should not be detected as true by isProxy ([#10401](https://github.com/vuejs/core/issues/10401)) ([9da34d7](https://github.com/vuejs/core/commit/9da34d7af81607fddd1f32f21b3b4002402ff1cc))
|
||||||
|
* **reactivity:** fix hasOwnProperty key coercion edge cases ([969c5fb](https://github.com/vuejs/core/commit/969c5fb30f4c725757c7385abfc74772514eae4b))
|
||||||
|
* **reactivity:** fix tracking when hasOwnProperty is called with non-string value ([c3c5dc9](https://github.com/vuejs/core/commit/c3c5dc93fbccc196771458f0b43cd5b7ad1863f4)), closes [#10455](https://github.com/vuejs/core/issues/10455) [#10464](https://github.com/vuejs/core/issues/10464)
|
||||||
|
* **runtime-core:** fix errorHandler causes an infinite loop during execution ([#9575](https://github.com/vuejs/core/issues/9575)) ([ab59bed](https://github.com/vuejs/core/commit/ab59bedae4e5e40b28804d88a51305b236d4a873))
|
||||||
|
* **runtime-core:** handle invalid values in callWithAsyncErrorHandling ([53d15d3](https://github.com/vuejs/core/commit/53d15d3f76184eed67a18d35e43d9a2062f8e121))
|
||||||
|
* **runtime-core:** show hydration mismatch details for non-rectified mismatches too when __PROD_HYDRATION_MISMATCH_DETAILS__ is set ([#10599](https://github.com/vuejs/core/issues/10599)) ([0dea7f9](https://github.com/vuejs/core/commit/0dea7f9a260d93eb6c39aabac8c94c2c9b2042dd))
|
||||||
|
* **runtime-dom:** `v-model` string/number coercion for multiselect options ([#10576](https://github.com/vuejs/core/issues/10576)) ([db374e5](https://github.com/vuejs/core/commit/db374e54c9f5e07324728b85c74eca84e28dd352))
|
||||||
|
* **runtime-dom:** fix css v-bind for suspensed components ([#8523](https://github.com/vuejs/core/issues/8523)) ([67722ba](https://github.com/vuejs/core/commit/67722ba23b7c36ab8f3fa2d2b4df08e4ddc322e1)), closes [#8520](https://github.com/vuejs/core/issues/8520)
|
||||||
|
* **runtime-dom:** force update v-model number with leading 0 ([#10506](https://github.com/vuejs/core/issues/10506)) ([15ffe8f](https://github.com/vuejs/core/commit/15ffe8f2c954359770c57e4d9e589b0b622e4a60)), closes [#10503](https://github.com/vuejs/core/issues/10503) [#10615](https://github.com/vuejs/core/issues/10615)
|
||||||
|
* **runtime-dom:** sanitize wrongly passed string value as event handler ([#8953](https://github.com/vuejs/core/issues/8953)) ([7ccd453](https://github.com/vuejs/core/commit/7ccd453dd004076cad49ec9f56cd5fe97b7b6ed8)), closes [#8818](https://github.com/vuejs/core/issues/8818)
|
||||||
|
* **ssr:** don't render v-if comments in TransitionGroup ([#6732](https://github.com/vuejs/core/issues/6732)) ([5a96267](https://github.com/vuejs/core/commit/5a9626708e970c6fc0b6f786e3c80c22273d126f)), closes [#6715](https://github.com/vuejs/core/issues/6715)
|
||||||
|
* **Transition:** ensure the KeepAlive children unmount w/ out-in mode ([#10632](https://github.com/vuejs/core/issues/10632)) ([fc99e4d](https://github.com/vuejs/core/commit/fc99e4d3f01b190ef9fd3c218a668ba9124a32bc)), closes [#10620](https://github.com/vuejs/core/issues/10620)
|
||||||
|
* **TransitionGroup:** avoid set transition hooks for comment nodes and text nodes ([#9421](https://github.com/vuejs/core/issues/9421)) ([140a768](https://github.com/vuejs/core/commit/140a7681cc3bba22f55d97fd85a5eafe97a1230f)), closes [#4621](https://github.com/vuejs/core/issues/4621) [#4622](https://github.com/vuejs/core/issues/4622) [#5153](https://github.com/vuejs/core/issues/5153) [#5168](https://github.com/vuejs/core/issues/5168) [#7898](https://github.com/vuejs/core/issues/7898) [#9067](https://github.com/vuejs/core/issues/9067)
|
||||||
|
* **types:** avoid merging object union types when using withDefaults ([#10596](https://github.com/vuejs/core/issues/10596)) ([37ba93c](https://github.com/vuejs/core/commit/37ba93c213a81f99a68a99ef5d4065d61b150ba3)), closes [#10594](https://github.com/vuejs/core/issues/10594)
|
||||||
|
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* add `__NO_SIDE_EFFECTS__` comments ([#9053](https://github.com/vuejs/core/issues/9053)) ([d46df6b](https://github.com/vuejs/core/commit/d46df6bdb14b0509eb2134b3f85297a306821c61))
|
||||||
|
* optimize component props/slots internal object checks ([6af733d](https://github.com/vuejs/core/commit/6af733d68eb400a3d2c5ef5f465fff32b72a324e))
|
||||||
|
* **ssr:** avoid calling markRaw on component instance proxy ([4bc9f39](https://github.com/vuejs/core/commit/4bc9f39f028af7313e5cf24c16915a1985d27bf8))
|
||||||
|
* **ssr:** optimize setup context creation for ssr in v8 ([ca84316](https://github.com/vuejs/core/commit/ca84316bfb3410efe21333670a6ad5cd21857396))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.4.21](https://github.com/vuejs/core/compare/v3.4.20...v3.4.21) (2024-02-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **runtime-dom:** avoid unset option's value ([#10416](https://github.com/vuejs/core/issues/10416)) ([b3f8b5a](https://github.com/vuejs/core/commit/b3f8b5a4e700d4c47a146b6040882287d180f6cb)), closes [#10412](https://github.com/vuejs/core/issues/10412) [#10396](https://github.com/vuejs/core/issues/10396)
|
||||||
|
* **suspense:** ensure nested suspense patching if in fallback state ([#10417](https://github.com/vuejs/core/issues/10417)) ([7c97778](https://github.com/vuejs/core/commit/7c97778aec1e3513035e5df265e1b8a7801f6106)), closes [#10415](https://github.com/vuejs/core/issues/10415)
|
||||||
|
* **warning:** stringify args in warn handler ([#10414](https://github.com/vuejs/core/issues/10414)) ([bc37258](https://github.com/vuejs/core/commit/bc37258caa2f6f67f4554ab8587aca3798d92124)), closes [#10409](https://github.com/vuejs/core/issues/10409)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [3.4.20](https://github.com/vuejs/core/compare/v3.4.19...v3.4.20) (2024-02-26)
|
## [3.4.20](https://github.com/vuejs/core/compare/v3.4.19...v3.4.20) (2024-02-26)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"drips": {
|
||||||
|
"ethereum": {
|
||||||
|
"ownedBy": "0x5393BdeA2a020769256d9f337B0fc81a2F64850A"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
# vuejs/core [](https://www.npmjs.com/package/vue) [](https://github.com/vuejs/core/actions/workflows/ci.yml)
|
# vuejs/core [](https://www.npmjs.com/package/vue) [](https://github.com/vuejs/core/actions/workflows/ci.yml) [](https://www.npmjs.com/package/vue)
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
|
|
44
package.json
44
package.json
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "3.4.20",
|
"version": "3.4.22",
|
||||||
"packageManager": "pnpm@8.15.4",
|
"packageManager": "pnpm@8.15.6",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "node scripts/dev.js",
|
"dev": "node scripts/dev.js",
|
||||||
"build": "node scripts/build.js",
|
"build": "node scripts/build.js",
|
||||||
"build-dts": "tsc -p tsconfig.build.json && rollup -c rollup.dts.config.js",
|
"build-dts": "tsc -p tsconfig.build-browser.json && tsc -p tsconfig.build-node.json && rollup -c rollup.dts.config.js",
|
||||||
"clean": "rimraf packages/*/dist temp .eslintcache",
|
"clean": "rimraf packages/*/dist temp .eslintcache",
|
||||||
"size": "run-s \"size-*\" && tsx scripts/usage-size.ts",
|
"size": "run-s \"size-*\" && tsx scripts/usage-size.ts",
|
||||||
"size-global": "node scripts/build.js vue runtime-dom -f global -p --size",
|
"size-global": "node scripts/build.js vue runtime-dom -f global -p --size",
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
"test-unit": "vitest -c vitest.unit.config.ts",
|
"test-unit": "vitest -c vitest.unit.config.ts",
|
||||||
"test-e2e": "node scripts/build.js vue -f global -d && vitest -c vitest.e2e.config.ts",
|
"test-e2e": "node scripts/build.js vue -f global -d && vitest -c vitest.e2e.config.ts",
|
||||||
"test-dts": "run-s build-dts test-dts-only",
|
"test-dts": "run-s build-dts test-dts-only",
|
||||||
"test-dts-only": "tsc -p ./packages/dts-test/tsconfig.test.json",
|
"test-dts-only": "tsc -p packages/dts-built-test/tsconfig.json && tsc -p ./packages/dts-test/tsconfig.test.json",
|
||||||
"test-coverage": "vitest -c vitest.unit.config.ts --coverage",
|
"test-coverage": "vitest -c vitest.unit.config.ts --coverage",
|
||||||
"test-bench": "vitest bench",
|
"test-bench": "vitest bench",
|
||||||
"release": "node scripts/release.js",
|
"release": "node scripts/release.js",
|
||||||
|
@ -59,9 +59,9 @@
|
||||||
"node": ">=18.12.0"
|
"node": ">=18.12.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/parser": "^7.23.9",
|
"@babel/parser": "^7.24.1",
|
||||||
"@babel/types": "^7.23.9",
|
"@babel/types": "^7.24.0",
|
||||||
"@codspeed/vitest-plugin": "^2.3.1",
|
"@codspeed/vitest-plugin": "^3.1.0",
|
||||||
"@rollup/plugin-alias": "^5.1.0",
|
"@rollup/plugin-alias": "^5.1.0",
|
||||||
"@rollup/plugin-commonjs": "^25.0.7",
|
"@rollup/plugin-commonjs": "^25.0.7",
|
||||||
"@rollup/plugin-json": "^6.1.0",
|
"@rollup/plugin-json": "^6.1.0",
|
||||||
|
@ -70,15 +70,15 @@
|
||||||
"@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.11.20",
|
"@types/node": "^20.12.5",
|
||||||
"@types/semver": "^7.5.8",
|
"@types/semver": "^7.5.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.0.2",
|
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
||||||
"@typescript-eslint/parser": "^7.0.2",
|
"@typescript-eslint/parser": "^7.4.0",
|
||||||
"@vitest/coverage-istanbul": "^1.3.1",
|
"@vitest/coverage-istanbul": "^1.4.0",
|
||||||
"@vue/consolidate": "1.0.0",
|
"@vue/consolidate": "1.0.0",
|
||||||
"conventional-changelog-cli": "^4.1.0",
|
"conventional-changelog-cli": "^4.1.0",
|
||||||
"enquirer": "^2.4.1",
|
"enquirer": "^2.4.1",
|
||||||
"esbuild": "^0.20.1",
|
"esbuild": "^0.20.2",
|
||||||
"esbuild-plugin-polyfill-node": "^0.3.0",
|
"esbuild-plugin-polyfill-node": "^0.3.0",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-define-config": "^2.1.0",
|
"eslint-define-config": "^2.1.0",
|
||||||
|
@ -89,30 +89,30 @@
|
||||||
"jsdom": "^24.0.0",
|
"jsdom": "^24.0.0",
|
||||||
"lint-staged": "^15.2.2",
|
"lint-staged": "^15.2.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"magic-string": "^0.30.7",
|
"magic-string": "^0.30.8",
|
||||||
"markdown-table": "^3.0.3",
|
"markdown-table": "^3.0.3",
|
||||||
"marked": "^12.0.0",
|
"marked": "^12.0.1",
|
||||||
"minimist": "^1.2.8",
|
"minimist": "^1.2.8",
|
||||||
"npm-run-all2": "^6.1.2",
|
"npm-run-all2": "^6.1.2",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"pretty-bytes": "^6.1.1",
|
"pretty-bytes": "^6.1.1",
|
||||||
"pug": "^3.0.2",
|
"pug": "^3.0.2",
|
||||||
"puppeteer": "~22.2.0",
|
"puppeteer": "~22.6.3",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
"rollup": "^4.12.0",
|
"rollup": "^4.13.2",
|
||||||
"rollup-plugin-dts": "^6.1.0",
|
"rollup-plugin-dts": "^6.1.0",
|
||||||
"rollup-plugin-esbuild": "^6.1.1",
|
"rollup-plugin-esbuild": "^6.1.1",
|
||||||
"rollup-plugin-polyfill-node": "^0.13.0",
|
"rollup-plugin-polyfill-node": "^0.13.0",
|
||||||
"semver": "^7.6.0",
|
"semver": "^7.6.0",
|
||||||
"serve": "^14.2.1",
|
"serve": "^14.2.1",
|
||||||
"simple-git-hooks": "^2.9.0",
|
"simple-git-hooks": "^2.11.1",
|
||||||
"terser": "^5.28.1",
|
"terser": "^5.30.1",
|
||||||
"todomvc-app-css": "^2.4.3",
|
"todomvc-app-css": "^2.4.3",
|
||||||
"tslib": "^2.6.2",
|
"tslib": "^2.6.2",
|
||||||
"tsx": "^4.7.1",
|
"tsx": "^4.7.2",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "~5.4.5",
|
||||||
"vite": "^5.1.4",
|
"vite": "^5.2.7",
|
||||||
"vitest": "^1.3.1"
|
"vitest": "^1.4.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2070,6 +2070,16 @@ describe('compiler: parse', () => {
|
||||||
baseParse(`<Foo>`, { parseMode: 'sfc', onError() {} })
|
baseParse(`<Foo>`, { parseMode: 'sfc', onError() {} })
|
||||||
expect(() => baseParse(`{ foo }`)).not.toThrow()
|
expect(() => baseParse(`{ foo }`)).not.toThrow()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('correct loc when the closing > is foarmatted', () => {
|
||||||
|
const [span] = baseParse(`<span></span
|
||||||
|
|
||||||
|
>`).children
|
||||||
|
|
||||||
|
expect(span.loc.source).toBe('<span></span\n \n >')
|
||||||
|
expect(span.loc.start.offset).toBe(0)
|
||||||
|
expect(span.loc.end.offset).toBe(27)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('decodeEntities option', () => {
|
describe('decodeEntities option', () => {
|
||||||
|
@ -2166,7 +2176,7 @@ describe('compiler: parse', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should remove leading newline character immediately following the pre element start tag', () => {
|
test('should remove leading newline character immediately following the pre element start tag', () => {
|
||||||
const ast = baseParse(`<pre>\n foo bar </pre>`, {
|
const ast = parse(`<pre>\n foo bar </pre>`, {
|
||||||
isPreTag: tag => tag === 'pre',
|
isPreTag: tag => tag === 'pre',
|
||||||
})
|
})
|
||||||
expect(ast.children).toHaveLength(1)
|
expect(ast.children).toHaveLength(1)
|
||||||
|
@ -2176,7 +2186,7 @@ describe('compiler: parse', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should NOT remove leading newline character immediately following child-tag of pre element', () => {
|
test('should NOT remove leading newline character immediately following child-tag of pre element', () => {
|
||||||
const ast = baseParse(`<pre><span></span>\n foo bar </pre>`, {
|
const ast = parse(`<pre><span></span>\n foo bar </pre>`, {
|
||||||
isPreTag: tag => tag === 'pre',
|
isPreTag: tag => tag === 'pre',
|
||||||
})
|
})
|
||||||
const preElement = ast.children[0] as ElementNode
|
const preElement = ast.children[0] as ElementNode
|
||||||
|
@ -2187,7 +2197,7 @@ describe('compiler: parse', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test('self-closing pre tag', () => {
|
test('self-closing pre tag', () => {
|
||||||
const ast = baseParse(`<pre/><span>\n foo bar</span>`, {
|
const ast = parse(`<pre/><span>\n foo bar</span>`, {
|
||||||
isPreTag: tag => tag === 'pre',
|
isPreTag: tag => tag === 'pre',
|
||||||
})
|
})
|
||||||
const elementAfterPre = ast.children[1] as ElementNode
|
const elementAfterPre = ast.children[1] as ElementNode
|
||||||
|
@ -2196,7 +2206,7 @@ describe('compiler: parse', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should NOT condense whitespaces in RCDATA text mode', () => {
|
test('should NOT condense whitespaces in RCDATA text mode', () => {
|
||||||
const ast = baseParse(`<textarea>Text:\n foo</textarea>`, {
|
const ast = parse(`<textarea>Text:\n foo</textarea>`, {
|
||||||
parseMode: 'html',
|
parseMode: 'html',
|
||||||
})
|
})
|
||||||
const preElement = ast.children[0] as ElementNode
|
const preElement = ast.children[0] as ElementNode
|
||||||
|
|
|
@ -1231,6 +1231,24 @@ describe('compiler: element transform', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('dynamic binding shorthand', () => {
|
||||||
|
const { node, root } = parseWithBind(`<component :is />`)
|
||||||
|
expect(root.helpers).toContain(RESOLVE_DYNAMIC_COMPONENT)
|
||||||
|
expect(node).toMatchObject({
|
||||||
|
isBlock: true,
|
||||||
|
tag: {
|
||||||
|
callee: RESOLVE_DYNAMIC_COMPONENT,
|
||||||
|
arguments: [
|
||||||
|
{
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'is',
|
||||||
|
isStatic: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
test('is casting', () => {
|
test('is casting', () => {
|
||||||
const { node, root } = parseWithBind(`<div is="vue:foo" />`)
|
const { node, root } = parseWithBind(`<div is="vue:foo" />`)
|
||||||
expect(root.helpers).toContain(RESOLVE_COMPONENT)
|
expect(root.helpers).toContain(RESOLVE_COMPONENT)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vue/compiler-core",
|
"name": "@vue/compiler-core",
|
||||||
"version": "3.4.20",
|
"version": "3.4.22",
|
||||||
"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",
|
||||||
|
@ -46,13 +46,13 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/vuejs/core/tree/main/packages/compiler-core#readme",
|
"homepage": "https://github.com/vuejs/core/tree/main/packages/compiler-core#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": "^7.23.9",
|
"@babel/parser": "^7.24.1",
|
||||||
"@vue/shared": "workspace:*",
|
"@vue/shared": "workspace:*",
|
||||||
"entities": "^4.5.0",
|
"entities": "^4.5.0",
|
||||||
"estree-walker": "^2.0.2",
|
"estree-walker": "^2.0.2",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/types": "^7.23.9"
|
"@babel/types": "^7.24.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ import {
|
||||||
getVNodeHelper,
|
getVNodeHelper,
|
||||||
locStub,
|
locStub,
|
||||||
} from './ast'
|
} from './ast'
|
||||||
import { type RawSourceMap, SourceMapGenerator } from 'source-map-js'
|
import { SourceMapGenerator } from 'source-map-js'
|
||||||
import {
|
import {
|
||||||
advancePositionWithMutation,
|
advancePositionWithMutation,
|
||||||
assert,
|
assert,
|
||||||
|
@ -56,6 +56,45 @@ import {
|
||||||
} from './runtimeHelpers'
|
} from './runtimeHelpers'
|
||||||
import type { ImportItem } from './transform'
|
import type { ImportItem } from './transform'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `SourceMapGenerator` type from `source-map-js` is a bit incomplete as it
|
||||||
|
* misses `toJSON()`. We also need to add types for internal properties which we
|
||||||
|
* need to access for better performance.
|
||||||
|
*
|
||||||
|
* Since TS 5.3, dts generation starts to strangely include broken triple slash
|
||||||
|
* references for source-map-js, so we are inlining all source map related types
|
||||||
|
* here to to workaround that.
|
||||||
|
*/
|
||||||
|
export interface CodegenSourceMapGenerator {
|
||||||
|
setSourceContent(sourceFile: string, sourceContent: string): void
|
||||||
|
// SourceMapGenerator has this method but the types do not include it
|
||||||
|
toJSON(): RawSourceMap
|
||||||
|
_sources: Set<string>
|
||||||
|
_names: Set<string>
|
||||||
|
_mappings: {
|
||||||
|
add(mapping: MappingItem): void
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RawSourceMap {
|
||||||
|
file?: string
|
||||||
|
sourceRoot?: string
|
||||||
|
version: string
|
||||||
|
sources: string[]
|
||||||
|
names: string[]
|
||||||
|
sourcesContent?: string[]
|
||||||
|
mappings: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MappingItem {
|
||||||
|
source: string
|
||||||
|
generatedLine: number
|
||||||
|
generatedColumn: number
|
||||||
|
originalLine: number
|
||||||
|
originalColumn: number
|
||||||
|
name: string | null
|
||||||
|
}
|
||||||
|
|
||||||
const PURE_ANNOTATION = `/*#__PURE__*/`
|
const PURE_ANNOTATION = `/*#__PURE__*/`
|
||||||
|
|
||||||
const aliasHelper = (s: symbol) => `${helperNameMap[s]}: _${helperNameMap[s]}`
|
const aliasHelper = (s: symbol) => `${helperNameMap[s]}: _${helperNameMap[s]}`
|
||||||
|
@ -85,7 +124,7 @@ export interface CodegenContext
|
||||||
offset: number
|
offset: number
|
||||||
indentLevel: number
|
indentLevel: number
|
||||||
pure: boolean
|
pure: boolean
|
||||||
map?: SourceMapGenerator
|
map?: CodegenSourceMapGenerator
|
||||||
helper(key: symbol): string
|
helper(key: symbol): string
|
||||||
push(code: string, newlineIndex?: number, node?: CodegenNode): void
|
push(code: string, newlineIndex?: number, node?: CodegenNode): void
|
||||||
indent(): void
|
indent(): void
|
||||||
|
@ -218,14 +257,14 @@ function createCodegenContext(
|
||||||
generatedLine: context.line,
|
generatedLine: context.line,
|
||||||
generatedColumn: context.column - 1,
|
generatedColumn: context.column - 1,
|
||||||
source: filename,
|
source: filename,
|
||||||
// @ts-expect-error it is possible to be null
|
|
||||||
name,
|
name,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!__BROWSER__ && sourceMap) {
|
if (!__BROWSER__ && sourceMap) {
|
||||||
// lazy require source-map implementation, only in non-browser builds
|
// lazy require source-map implementation, only in non-browser builds
|
||||||
context.map = new SourceMapGenerator()
|
context.map =
|
||||||
|
new SourceMapGenerator() as unknown as CodegenSourceMapGenerator
|
||||||
context.map.setSourceContent(filename, context.source)
|
context.map.setSourceContent(filename, context.source)
|
||||||
context.map._sources.add(filename)
|
context.map._sources.add(filename)
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,13 @@ export {
|
||||||
type StructuralDirectiveTransform,
|
type StructuralDirectiveTransform,
|
||||||
type DirectiveTransform,
|
type DirectiveTransform,
|
||||||
} from './transform'
|
} from './transform'
|
||||||
export { generate, type CodegenContext, type CodegenResult } from './codegen'
|
export {
|
||||||
|
generate,
|
||||||
|
type CodegenContext,
|
||||||
|
type CodegenResult,
|
||||||
|
type CodegenSourceMapGenerator,
|
||||||
|
type RawSourceMap,
|
||||||
|
} from './codegen'
|
||||||
export {
|
export {
|
||||||
ErrorCodes,
|
ErrorCodes,
|
||||||
errorMessages,
|
errorMessages,
|
||||||
|
|
|
@ -74,6 +74,7 @@ export interface ParserOptions
|
||||||
delimiters?: [string, string]
|
delimiters?: [string, string]
|
||||||
/**
|
/**
|
||||||
* Whitespace handling strategy
|
* Whitespace handling strategy
|
||||||
|
* @default 'condense'
|
||||||
*/
|
*/
|
||||||
whitespace?: 'preserve' | 'condense'
|
whitespace?: 'preserve' | 'condense'
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -613,7 +613,7 @@ function onCloseTag(el: ElementNode, end: number, isImplied = false) {
|
||||||
// implied close, end should be backtracked to close
|
// implied close, end should be backtracked to close
|
||||||
setLocEnd(el.loc, backTrack(end, CharCodes.Lt))
|
setLocEnd(el.loc, backTrack(end, CharCodes.Lt))
|
||||||
} else {
|
} else {
|
||||||
setLocEnd(el.loc, end + 1)
|
setLocEnd(el.loc, lookAhead(end, CharCodes.Gt) + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tokenizer.inSFCRoot) {
|
if (tokenizer.inSFCRoot) {
|
||||||
|
@ -736,6 +736,12 @@ function onCloseTag(el: ElementNode, end: number, isImplied = false) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function lookAhead(index: number, c: number) {
|
||||||
|
let i = index
|
||||||
|
while (currentInput.charCodeAt(i) !== c && i < currentInput.length - 1) i++
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
function backTrack(index: number, c: number) {
|
function backTrack(index: number, c: number) {
|
||||||
let i = index
|
let i = index
|
||||||
while (currentInput.charCodeAt(i) !== c && i >= 0) i--
|
while (currentInput.charCodeAt(i) !== c && i >= 0) i--
|
||||||
|
|
|
@ -64,6 +64,7 @@ import {
|
||||||
checkCompatEnabled,
|
checkCompatEnabled,
|
||||||
isCompatEnabled,
|
isCompatEnabled,
|
||||||
} from '../compat/compatConfig'
|
} from '../compat/compatConfig'
|
||||||
|
import { processExpression } from './transformExpression'
|
||||||
|
|
||||||
// some directive transforms (e.g. v-model) may return a symbol for runtime
|
// some directive transforms (e.g. v-model) may return a symbol for runtime
|
||||||
// import, which should be used instead of a resolveDirective call.
|
// import, which should be used instead of a resolveDirective call.
|
||||||
|
@ -253,7 +254,7 @@ export function resolveComponentType(
|
||||||
|
|
||||||
// 1. dynamic component
|
// 1. dynamic component
|
||||||
const isExplicitDynamic = isComponentTag(tag)
|
const isExplicitDynamic = isComponentTag(tag)
|
||||||
const isProp = findProp(node, 'is')
|
const isProp = findProp(node, 'is', false, true /* allow empty */)
|
||||||
if (isProp) {
|
if (isProp) {
|
||||||
if (
|
if (
|
||||||
isExplicitDynamic ||
|
isExplicitDynamic ||
|
||||||
|
@ -263,10 +264,19 @@ export function resolveComponentType(
|
||||||
context,
|
context,
|
||||||
))
|
))
|
||||||
) {
|
) {
|
||||||
const exp =
|
let exp: ExpressionNode | undefined
|
||||||
isProp.type === NodeTypes.ATTRIBUTE
|
if (isProp.type === NodeTypes.ATTRIBUTE) {
|
||||||
? isProp.value && createSimpleExpression(isProp.value.content, true)
|
exp = isProp.value && createSimpleExpression(isProp.value.content, true)
|
||||||
: isProp.exp
|
} else {
|
||||||
|
exp = isProp.exp
|
||||||
|
if (!exp) {
|
||||||
|
// #10469 handle :is shorthand
|
||||||
|
exp = createSimpleExpression(`is`, false, isProp.loc)
|
||||||
|
if (!__BROWSER__) {
|
||||||
|
exp = isProp.exp = processExpression(exp, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (exp) {
|
if (exp) {
|
||||||
return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [
|
return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [
|
||||||
exp,
|
exp,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vue/compiler-dom",
|
"name": "@vue/compiler-dom",
|
||||||
"version": "3.4.20",
|
"version": "3.4.22",
|
||||||
"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",
|
||||||
|
|
|
@ -1362,3 +1362,24 @@ return { get foo() { return foo } }
|
||||||
|
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`compileScript > should care about runtimeModuleName 1`] = `
|
||||||
|
"import { withAsyncContext as _withAsyncContext } from "npm:vue"
|
||||||
|
|
||||||
|
export default {
|
||||||
|
async setup(__props, { expose: __expose }) {
|
||||||
|
__expose();
|
||||||
|
|
||||||
|
let __temp, __restore
|
||||||
|
|
||||||
|
;(
|
||||||
|
([__temp,__restore] = _withAsyncContext(() => Promise.resolve(1))),
|
||||||
|
await __temp,
|
||||||
|
__restore()
|
||||||
|
)
|
||||||
|
|
||||||
|
return { }
|
||||||
|
}
|
||||||
|
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
|
@ -1472,3 +1472,26 @@ describe('SFC genDefaultAs', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('compileScript', () => {
|
||||||
|
test('should care about runtimeModuleName', () => {
|
||||||
|
const { content } = compile(
|
||||||
|
`
|
||||||
|
<script setup>
|
||||||
|
await Promise.resolve(1)
|
||||||
|
</script>
|
||||||
|
`,
|
||||||
|
{
|
||||||
|
templateOptions: {
|
||||||
|
compilerOptions: {
|
||||||
|
runtimeModuleName: 'npm:vue',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
expect(content).toMatch(
|
||||||
|
`import { withAsyncContext as _withAsyncContext } from "npm:vue"\n`,
|
||||||
|
)
|
||||||
|
assertCode(content)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
|
@ -103,6 +103,26 @@ return { modelValue }
|
||||||
})"
|
})"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`defineModel() > w/ Boolean And Function types, production mode 1`] = `
|
||||||
|
"import { useModel as _useModel, defineComponent as _defineComponent } from 'vue'
|
||||||
|
|
||||||
|
export default /*#__PURE__*/_defineComponent({
|
||||||
|
props: {
|
||||||
|
"modelValue": { type: [Boolean, String] },
|
||||||
|
"modelModifiers": {},
|
||||||
|
},
|
||||||
|
emits: ["update:modelValue"],
|
||||||
|
setup(__props, { expose: __expose }) {
|
||||||
|
__expose();
|
||||||
|
|
||||||
|
const modelValue = _useModel<boolean | string>(__props, "modelValue")
|
||||||
|
|
||||||
|
return { modelValue }
|
||||||
|
}
|
||||||
|
|
||||||
|
})"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`defineModel() > w/ array props 1`] = `
|
exports[`defineModel() > w/ array props 1`] = `
|
||||||
"import { useModel as _useModel, mergeModels as _mergeModels } from 'vue'
|
"import { useModel as _useModel, mergeModels as _mergeModels } from 'vue'
|
||||||
|
|
||||||
|
|
|
@ -66,29 +66,14 @@ return { get vMyDir() { return vMyDir } }
|
||||||
|
|
||||||
exports[`dynamic arguments 1`] = `
|
exports[`dynamic arguments 1`] = `
|
||||||
"import { defineComponent as _defineComponent } from 'vue'
|
"import { defineComponent as _defineComponent } from 'vue'
|
||||||
import { FooBar, foo, bar, unused, baz } from './x'
|
import { FooBar, foo, bar, unused, baz, msg } from './x'
|
||||||
|
|
||||||
export default /*#__PURE__*/_defineComponent({
|
export default /*#__PURE__*/_defineComponent({
|
||||||
setup(__props, { expose: __expose }) {
|
setup(__props, { expose: __expose }) {
|
||||||
__expose();
|
__expose();
|
||||||
|
|
||||||
|
|
||||||
return { get FooBar() { return FooBar }, get foo() { return foo }, get bar() { return bar }, get baz() { return baz } }
|
return { get FooBar() { return FooBar }, get foo() { return foo }, get bar() { return bar }, get baz() { return baz }, get msg() { return msg } }
|
||||||
}
|
|
||||||
|
|
||||||
})"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`import namespace 1`] = `
|
|
||||||
"import { defineComponent as _defineComponent } from 'vue'
|
|
||||||
import * as Foo from './foo'
|
|
||||||
|
|
||||||
export default /*#__PURE__*/_defineComponent({
|
|
||||||
setup(__props, { expose: __expose }) {
|
|
||||||
__expose();
|
|
||||||
|
|
||||||
|
|
||||||
return { get Foo() { return Foo } }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
})"
|
})"
|
||||||
|
|
|
@ -221,4 +221,24 @@ describe('defineModel()', () => {
|
||||||
assertCode(content)
|
assertCode(content)
|
||||||
expect(content).toMatch(`set: (v) => { return v + __props.x }`)
|
expect(content).toMatch(`set: (v) => { return v + __props.x }`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('w/ Boolean And Function types, production mode', () => {
|
||||||
|
const { content, bindings } = compile(
|
||||||
|
`
|
||||||
|
<script setup lang="ts">
|
||||||
|
const modelValue = defineModel<boolean | string>()
|
||||||
|
</script>
|
||||||
|
`,
|
||||||
|
{ isProd: true },
|
||||||
|
)
|
||||||
|
assertCode(content)
|
||||||
|
expect(content).toMatch('"modelValue": { type: [Boolean, String] }')
|
||||||
|
expect(content).toMatch('emits: ["update:modelValue"]')
|
||||||
|
expect(content).toMatch(
|
||||||
|
`const modelValue = _useModel<boolean | string>(__props, "modelValue")`,
|
||||||
|
)
|
||||||
|
expect(bindings).toStrictEqual({
|
||||||
|
modelValue: BindingTypes.SETUP_REF,
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -45,7 +45,7 @@ test('directive', () => {
|
||||||
test('dynamic arguments', () => {
|
test('dynamic arguments', () => {
|
||||||
const { content } = compile(`
|
const { content } = compile(`
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { FooBar, foo, bar, unused, baz } from './x'
|
import { FooBar, foo, bar, unused, baz, msg } from './x'
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<FooBar #[foo.slotName] />
|
<FooBar #[foo.slotName] />
|
||||||
|
@ -53,11 +53,12 @@ test('dynamic arguments', () => {
|
||||||
<div :[bar.attrName]="15"></div>
|
<div :[bar.attrName]="15"></div>
|
||||||
<div unused="unused"></div>
|
<div unused="unused"></div>
|
||||||
<div #[\`item:\${baz.key}\`]="{ value }"></div>
|
<div #[\`item:\${baz.key}\`]="{ value }"></div>
|
||||||
|
<FooBar :msg />
|
||||||
</template>
|
</template>
|
||||||
`)
|
`)
|
||||||
expect(content).toMatch(
|
expect(content).toMatch(
|
||||||
`return { get FooBar() { return FooBar }, get foo() { return foo }, ` +
|
`return { get FooBar() { return FooBar }, get foo() { return foo }, ` +
|
||||||
`get bar() { return bar }, get baz() { return baz } }`,
|
`get bar() { return bar }, get baz() { return baz }, get msg() { return msg } }`,
|
||||||
)
|
)
|
||||||
assertCode(content)
|
assertCode(content)
|
||||||
})
|
})
|
||||||
|
|
|
@ -561,6 +561,27 @@ describe('resolveType', () => {
|
||||||
expect(deps && [...deps]).toStrictEqual(Object.keys(files))
|
expect(deps && [...deps]).toStrictEqual(Object.keys(files))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #10635
|
||||||
|
test('relative tsx', () => {
|
||||||
|
const files = {
|
||||||
|
'/foo.tsx': 'export type P = { foo: number }',
|
||||||
|
'/bar/index.tsx': 'export type PP = { bar: string }',
|
||||||
|
}
|
||||||
|
const { props, deps } = resolve(
|
||||||
|
`
|
||||||
|
import { P } from './foo'
|
||||||
|
import { PP } from './bar'
|
||||||
|
defineProps<P & PP>()
|
||||||
|
`,
|
||||||
|
files,
|
||||||
|
)
|
||||||
|
expect(props).toStrictEqual({
|
||||||
|
foo: ['Number'],
|
||||||
|
bar: ['String'],
|
||||||
|
})
|
||||||
|
expect(deps && [...deps]).toStrictEqual(Object.keys(files))
|
||||||
|
})
|
||||||
|
|
||||||
test.runIf(process.platform === 'win32')('relative ts on Windows', () => {
|
test.runIf(process.platform === 'win32')('relative ts on Windows', () => {
|
||||||
const files = {
|
const files = {
|
||||||
'C:\\Test\\FolderA\\foo.ts': 'export type P = { foo: number }',
|
'C:\\Test\\FolderA\\foo.ts': 'export type P = { foo: number }',
|
||||||
|
|
|
@ -161,6 +161,45 @@ describe('SFC scoped CSS', () => {
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #10511
|
||||||
|
test(':is() and :where() in compound selectors', () => {
|
||||||
|
expect(
|
||||||
|
compileScoped(`.div { color: red; } .div:where(:hover) { color: blue; }`),
|
||||||
|
).toMatchInlineSnapshot(`
|
||||||
|
".div[data-v-test] { color: red;
|
||||||
|
}
|
||||||
|
.div[data-v-test]:where(:hover) { color: blue;
|
||||||
|
}"`)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
compileScoped(`.div { color: red; } .div:is(:hover) { color: blue; }`),
|
||||||
|
).toMatchInlineSnapshot(`
|
||||||
|
".div[data-v-test] { color: red;
|
||||||
|
}
|
||||||
|
.div[data-v-test]:is(:hover) { color: blue;
|
||||||
|
}"`)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
compileScoped(
|
||||||
|
`.div { color: red; } .div:where(.foo:hover) { color: blue; }`,
|
||||||
|
),
|
||||||
|
).toMatchInlineSnapshot(`
|
||||||
|
".div[data-v-test] { color: red;
|
||||||
|
}
|
||||||
|
.div[data-v-test]:where(.foo:hover) { color: blue;
|
||||||
|
}"`)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
compileScoped(
|
||||||
|
`.div { color: red; } .div:is(.foo:hover) { color: blue; }`,
|
||||||
|
),
|
||||||
|
).toMatchInlineSnapshot(`
|
||||||
|
".div[data-v-test] { color: red;
|
||||||
|
}
|
||||||
|
.div[data-v-test]:is(.foo:hover) { color: blue;
|
||||||
|
}"`)
|
||||||
|
})
|
||||||
|
|
||||||
test('media query', () => {
|
test('media query', () => {
|
||||||
expect(compileScoped(`@media print { .foo { color: red }}`))
|
expect(compileScoped(`@media print { .foo { color: red }}`))
|
||||||
.toMatchInlineSnapshot(`
|
.toMatchInlineSnapshot(`
|
||||||
|
@ -390,4 +429,23 @@ describe('SFC style preprocessors', () => {
|
||||||
|
|
||||||
expect(res.errors.length).toBe(0)
|
expect(res.errors.length).toBe(0)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('should mount scope on correct selector when have universal selector', () => {
|
||||||
|
expect(compileScoped(`* { color: red; }`)).toMatchInlineSnapshot(`
|
||||||
|
"[data-v-test] { color: red;
|
||||||
|
}"
|
||||||
|
`)
|
||||||
|
expect(compileScoped('* .foo { color: red; }')).toMatchInlineSnapshot(`
|
||||||
|
".foo[data-v-test] { color: red;
|
||||||
|
}"
|
||||||
|
`)
|
||||||
|
expect(compileScoped(`*.foo { color: red; }`)).toMatchInlineSnapshot(`
|
||||||
|
".foo[data-v-test] { color: red;
|
||||||
|
}"
|
||||||
|
`)
|
||||||
|
expect(compileScoped(`.foo * { color: red; }`)).toMatchInlineSnapshot(`
|
||||||
|
".foo[data-v-test] * { color: red;
|
||||||
|
}"
|
||||||
|
`)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vue/compiler-sfc",
|
"name": "@vue/compiler-sfc",
|
||||||
"version": "3.4.20",
|
"version": "3.4.22",
|
||||||
"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",
|
||||||
|
@ -42,26 +42,26 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/vuejs/core/tree/main/packages/compiler-sfc#readme",
|
"homepage": "https://github.com/vuejs/core/tree/main/packages/compiler-sfc#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": "^7.23.9",
|
"@babel/parser": "^7.24.1",
|
||||||
"@vue/compiler-core": "workspace:*",
|
"@vue/compiler-core": "workspace:*",
|
||||||
"@vue/compiler-dom": "workspace:*",
|
"@vue/compiler-dom": "workspace:*",
|
||||||
"@vue/compiler-ssr": "workspace:*",
|
"@vue/compiler-ssr": "workspace:*",
|
||||||
"@vue/shared": "workspace:*",
|
"@vue/shared": "workspace:*",
|
||||||
"estree-walker": "^2.0.2",
|
"estree-walker": "^2.0.2",
|
||||||
"magic-string": "^0.30.7",
|
"magic-string": "^0.30.8",
|
||||||
"postcss": "^8.4.35",
|
"postcss": "^8.4.38",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/types": "^7.23.9",
|
"@babel/types": "^7.24.0",
|
||||||
"@vue/consolidate": "^1.0.0",
|
"@vue/consolidate": "^1.0.0",
|
||||||
"hash-sum": "^2.0.0",
|
"hash-sum": "^2.0.0",
|
||||||
"lru-cache": "10.1.0",
|
"lru-cache": "10.1.0",
|
||||||
"merge-source-map": "^1.1.0",
|
"merge-source-map": "^1.1.0",
|
||||||
"minimatch": "^9.0.3",
|
"minimatch": "^9.0.4",
|
||||||
"postcss-modules": "^6.0.0",
|
"postcss-modules": "^6.0.0",
|
||||||
"postcss-selector-parser": "^6.0.15",
|
"postcss-selector-parser": "^6.0.16",
|
||||||
"pug": "^3.0.2",
|
"pug": "^3.0.2",
|
||||||
"sass": "^1.71.1"
|
"sass": "^1.74.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -989,10 +989,15 @@ export function compileScript(
|
||||||
|
|
||||||
// 11. finalize Vue helper imports
|
// 11. finalize Vue helper imports
|
||||||
if (ctx.helperImports.size > 0) {
|
if (ctx.helperImports.size > 0) {
|
||||||
|
const runtimeModuleName =
|
||||||
|
options.templateOptions?.compilerOptions?.runtimeModuleName
|
||||||
|
const importSrc = runtimeModuleName
|
||||||
|
? JSON.stringify(runtimeModuleName)
|
||||||
|
: `'vue'`
|
||||||
ctx.s.prepend(
|
ctx.s.prepend(
|
||||||
`import { ${[...ctx.helperImports]
|
`import { ${[...ctx.helperImports]
|
||||||
.map(h => `${h} as _${h}`)
|
.map(h => `${h} as _${h}`)
|
||||||
.join(', ')} } from 'vue'\n`,
|
.join(', ')} } from ${importSrc}\n`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {
|
||||||
type StylePreprocessorResults,
|
type StylePreprocessorResults,
|
||||||
processors,
|
processors,
|
||||||
} from './style/preprocessors'
|
} from './style/preprocessors'
|
||||||
import type { RawSourceMap } from 'source-map-js'
|
import type { RawSourceMap } from '@vue/compiler-core'
|
||||||
import { cssVarsPlugin } from './style/cssVars'
|
import { cssVarsPlugin } from './style/cssVars'
|
||||||
import postcssModules from 'postcss-modules'
|
import postcssModules from 'postcss-modules'
|
||||||
|
|
||||||
|
|
|
@ -6,14 +6,11 @@ import {
|
||||||
type NodeTransform,
|
type NodeTransform,
|
||||||
NodeTypes,
|
NodeTypes,
|
||||||
type ParserOptions,
|
type ParserOptions,
|
||||||
|
type RawSourceMap,
|
||||||
type RootNode,
|
type RootNode,
|
||||||
createRoot,
|
createRoot,
|
||||||
} from '@vue/compiler-core'
|
} from '@vue/compiler-core'
|
||||||
import {
|
import { SourceMapConsumer, SourceMapGenerator } from 'source-map-js'
|
||||||
type RawSourceMap,
|
|
||||||
SourceMapConsumer,
|
|
||||||
SourceMapGenerator,
|
|
||||||
} from 'source-map-js'
|
|
||||||
import {
|
import {
|
||||||
type AssetURLOptions,
|
type AssetURLOptions,
|
||||||
type AssetURLTagConfig,
|
type AssetURLTagConfig,
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
import {
|
import {
|
||||||
type BindingMetadata,
|
type BindingMetadata,
|
||||||
|
type CodegenSourceMapGenerator,
|
||||||
type CompilerError,
|
type CompilerError,
|
||||||
type ElementNode,
|
type ElementNode,
|
||||||
NodeTypes,
|
NodeTypes,
|
||||||
type ParserOptions,
|
type ParserOptions,
|
||||||
|
type RawSourceMap,
|
||||||
type RootNode,
|
type RootNode,
|
||||||
type SourceLocation,
|
type SourceLocation,
|
||||||
createRoot,
|
createRoot,
|
||||||
} from '@vue/compiler-core'
|
} from '@vue/compiler-core'
|
||||||
import * as CompilerDOM from '@vue/compiler-dom'
|
import * as CompilerDOM from '@vue/compiler-dom'
|
||||||
import { type RawSourceMap, SourceMapGenerator } from 'source-map-js'
|
import { SourceMapGenerator } from 'source-map-js'
|
||||||
import type { TemplateCompiler } from './compileTemplate'
|
import type { TemplateCompiler } from './compileTemplate'
|
||||||
import { parseCssVars } from './style/cssVars'
|
import { parseCssVars } from './style/cssVars'
|
||||||
import { createCache } from './cache'
|
import { createCache } from './cache'
|
||||||
|
@ -375,7 +377,7 @@ function generateSourceMap(
|
||||||
const map = new SourceMapGenerator({
|
const map = new SourceMapGenerator({
|
||||||
file: filename.replace(/\\/g, '/'),
|
file: filename.replace(/\\/g, '/'),
|
||||||
sourceRoot: sourceRoot.replace(/\\/g, '/'),
|
sourceRoot: sourceRoot.replace(/\\/g, '/'),
|
||||||
})
|
}) as unknown as CodegenSourceMapGenerator
|
||||||
map.setSourceContent(filename, source)
|
map.setSourceContent(filename, source)
|
||||||
map._sources.add(filename)
|
map._sources.add(filename)
|
||||||
generated.split(splitRE).forEach((line, index) => {
|
generated.split(splitRE).forEach((line, index) => {
|
||||||
|
@ -390,7 +392,6 @@ function generateSourceMap(
|
||||||
generatedLine,
|
generatedLine,
|
||||||
generatedColumn: i,
|
generatedColumn: i,
|
||||||
source: filename,
|
source: filename,
|
||||||
// @ts-expect-error
|
|
||||||
name: null,
|
name: null,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,15 +129,19 @@ export function genModelProps(ctx: ScriptCompileContext) {
|
||||||
|
|
||||||
let runtimeTypes = type && inferRuntimeType(ctx, type)
|
let runtimeTypes = type && inferRuntimeType(ctx, type)
|
||||||
if (runtimeTypes) {
|
if (runtimeTypes) {
|
||||||
|
const hasBoolean = runtimeTypes.includes('Boolean')
|
||||||
const hasUnknownType = runtimeTypes.includes(UNKNOWN_TYPE)
|
const hasUnknownType = runtimeTypes.includes(UNKNOWN_TYPE)
|
||||||
|
|
||||||
runtimeTypes = runtimeTypes.filter(el => {
|
if (isProd || hasUnknownType) {
|
||||||
if (el === UNKNOWN_TYPE) return false
|
runtimeTypes = runtimeTypes.filter(
|
||||||
return isProd
|
t =>
|
||||||
? el === 'Boolean' || (el === 'Function' && options)
|
t === 'Boolean' ||
|
||||||
: true
|
(hasBoolean && t === 'String') ||
|
||||||
})
|
(t === 'Function' && options),
|
||||||
skipCheck = !isProd && hasUnknownType && runtimeTypes.length > 0
|
)
|
||||||
|
|
||||||
|
skipCheck = !isProd && hasUnknownType && runtimeTypes.length > 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let runtimeType =
|
let runtimeType =
|
||||||
|
|
|
@ -60,6 +60,9 @@ function resolveTemplateUsedIdentifiers(sfc: SFCDescriptor): Set<string> {
|
||||||
extractIdentifiers(ids, prop.forParseResult!.source)
|
extractIdentifiers(ids, prop.forParseResult!.source)
|
||||||
} else if (prop.exp) {
|
} else if (prop.exp) {
|
||||||
extractIdentifiers(ids, prop.exp)
|
extractIdentifiers(ids, prop.exp)
|
||||||
|
} else if (prop.name === 'bind' && !prop.exp) {
|
||||||
|
// v-bind shorthand name as identifier
|
||||||
|
ids.add((prop.arg as SimpleExpressionNode).content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -956,8 +956,10 @@ function resolveExt(filename: string, fs: FS) {
|
||||||
return (
|
return (
|
||||||
tryResolve(filename) ||
|
tryResolve(filename) ||
|
||||||
tryResolve(filename + `.ts`) ||
|
tryResolve(filename + `.ts`) ||
|
||||||
|
tryResolve(filename + `.tsx`) ||
|
||||||
tryResolve(filename + `.d.ts`) ||
|
tryResolve(filename + `.d.ts`) ||
|
||||||
tryResolve(joinPaths(filename, `index.ts`)) ||
|
tryResolve(joinPaths(filename, `index.ts`)) ||
|
||||||
|
tryResolve(joinPaths(filename, `index.tsx`)) ||
|
||||||
tryResolve(joinPaths(filename, `index.d.ts`))
|
tryResolve(joinPaths(filename, `index.d.ts`))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,9 +170,37 @@ function rewriteSelector(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (n.type === 'universal') {
|
||||||
|
const prev = selector.at(selector.index(n) - 1)
|
||||||
|
const next = selector.at(selector.index(n) + 1)
|
||||||
|
// * ... {}
|
||||||
|
if (!prev) {
|
||||||
|
// * .foo {} -> .foo[xxxxxxx] {}
|
||||||
|
if (next) {
|
||||||
|
if (next.type === 'combinator' && next.value === ' ') {
|
||||||
|
selector.removeChild(next)
|
||||||
|
}
|
||||||
|
selector.removeChild(n)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
// * {} -> [xxxxxxx] {}
|
||||||
|
node = selectorParser.combinator({
|
||||||
|
value: '',
|
||||||
|
})
|
||||||
|
selector.insertBefore(n, node)
|
||||||
|
selector.removeChild(n)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// .foo * -> .foo[xxxxxxx] *
|
||||||
|
if (node) return
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(n.type !== 'pseudo' && n.type !== 'combinator') ||
|
(n.type !== 'pseudo' && n.type !== 'combinator') ||
|
||||||
(n.type === 'pseudo' && (n.value === ':is' || n.value === ':where'))
|
(n.type === 'pseudo' &&
|
||||||
|
(n.value === ':is' || n.value === ':where') &&
|
||||||
|
!node)
|
||||||
) {
|
) {
|
||||||
node = n
|
node = n
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import merge from 'merge-source-map'
|
import merge from 'merge-source-map'
|
||||||
import type { RawSourceMap } from 'source-map-js'
|
import type { RawSourceMap } from '@vue/compiler-core'
|
||||||
import type { SFCStyleCompileOptions } from '../compileStyle'
|
import type { SFCStyleCompileOptions } from '../compileStyle'
|
||||||
import { isFunction } from '@vue/shared'
|
import { isFunction } from '@vue/shared'
|
||||||
|
|
||||||
|
|
|
@ -82,8 +82,6 @@ describe('transition-group', () => {
|
||||||
})
|
})
|
||||||
if (_ctx.ok) {
|
if (_ctx.ok) {
|
||||||
_push(\`<div>ok</div>\`)
|
_push(\`<div>ok</div>\`)
|
||||||
} else {
|
|
||||||
_push(\`<!---->\`)
|
|
||||||
}
|
}
|
||||||
_push(\`<!--]-->\`)
|
_push(\`<!--]-->\`)
|
||||||
}"
|
}"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vue/compiler-ssr",
|
"name": "@vue/compiler-ssr",
|
||||||
"version": "3.4.20",
|
"version": "3.4.22",
|
||||||
"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",
|
||||||
|
|
|
@ -141,6 +141,7 @@ export function processChildren(
|
||||||
context: SSRTransformContext,
|
context: SSRTransformContext,
|
||||||
asFragment = false,
|
asFragment = false,
|
||||||
disableNestedFragments = false,
|
disableNestedFragments = false,
|
||||||
|
disableCommentAsIfAlternate = false,
|
||||||
) {
|
) {
|
||||||
if (asFragment) {
|
if (asFragment) {
|
||||||
context.pushStringPart(`<!--[-->`)
|
context.pushStringPart(`<!--[-->`)
|
||||||
|
@ -191,7 +192,12 @@ export function processChildren(
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
case NodeTypes.IF:
|
case NodeTypes.IF:
|
||||||
ssrProcessIf(child, context, disableNestedFragments)
|
ssrProcessIf(
|
||||||
|
child,
|
||||||
|
context,
|
||||||
|
disableNestedFragments,
|
||||||
|
disableCommentAsIfAlternate,
|
||||||
|
)
|
||||||
break
|
break
|
||||||
case NodeTypes.FOR:
|
case NodeTypes.FOR:
|
||||||
ssrProcessFor(child, context, disableNestedFragments)
|
ssrProcessFor(child, context, disableNestedFragments)
|
||||||
|
|
|
@ -87,6 +87,13 @@ export function ssrProcessTransitionGroup(
|
||||||
* by disabling nested fragment wrappers from being generated.
|
* by disabling nested fragment wrappers from being generated.
|
||||||
*/
|
*/
|
||||||
true,
|
true,
|
||||||
|
/**
|
||||||
|
* TransitionGroup filters out comment children at runtime and thus
|
||||||
|
* doesn't expect comments to be present during hydration. We need to
|
||||||
|
* account for that by disabling the empty comment that is otherwise
|
||||||
|
* rendered for a falsy v-if that has no v-else specified. (#6715)
|
||||||
|
*/
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
context.pushStringPart(`</`)
|
context.pushStringPart(`</`)
|
||||||
context.pushStringPart(tag.exp!)
|
context.pushStringPart(tag.exp!)
|
||||||
|
@ -106,6 +113,6 @@ export function ssrProcessTransitionGroup(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// fragment
|
// fragment
|
||||||
processChildren(node, context, true, true)
|
processChildren(node, context, true, true, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ export function ssrProcessIf(
|
||||||
node: IfNode,
|
node: IfNode,
|
||||||
context: SSRTransformContext,
|
context: SSRTransformContext,
|
||||||
disableNestedFragments = false,
|
disableNestedFragments = false,
|
||||||
|
disableCommentAsIfAlternate = false,
|
||||||
) {
|
) {
|
||||||
const [rootBranch] = node.branches
|
const [rootBranch] = node.branches
|
||||||
const ifStatement = createIfStatement(
|
const ifStatement = createIfStatement(
|
||||||
|
@ -54,7 +55,7 @@ export function ssrProcessIf(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!currentIf.alternate) {
|
if (!currentIf.alternate && !disableCommentAsIfAlternate) {
|
||||||
currentIf.alternate = createBlockStatement([
|
currentIf.alternate = createBlockStatement([
|
||||||
createCallExpression(`_push`, ['`<!---->`']),
|
createCallExpression(`_push`, ['`<!---->`']),
|
||||||
])
|
])
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "@vue/dts-built-test",
|
"name": "@vue/dts-built-test",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"types": "dist/dts-built-test.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/shared": "workspace:*",
|
"@vue/shared": "workspace:*",
|
||||||
"@vue/reactivity": "workspace:*",
|
"@vue/reactivity": "workspace:*",
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"outDir": "dist",
|
||||||
|
"jsx": "preserve",
|
||||||
|
"module": "esnext",
|
||||||
|
"strict": true,
|
||||||
|
"moduleResolution": "Bundler",
|
||||||
|
"lib": ["esnext", "dom"],
|
||||||
|
"declaration": true,
|
||||||
|
"emitDeclarationOnly": true
|
||||||
|
},
|
||||||
|
"include": ["./src"]
|
||||||
|
}
|
|
@ -102,6 +102,41 @@ describe('defineProps w/ union type declaration + withDefaults', () => {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('defineProps w/ object union + withDefaults', () => {
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<
|
||||||
|
{
|
||||||
|
foo: string
|
||||||
|
} & (
|
||||||
|
| {
|
||||||
|
type: 'hello'
|
||||||
|
bar: string
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'world'
|
||||||
|
bar: number
|
||||||
|
}
|
||||||
|
)
|
||||||
|
>(),
|
||||||
|
{
|
||||||
|
foo: 'default value!',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
expectType<
|
||||||
|
| {
|
||||||
|
readonly type: 'hello'
|
||||||
|
readonly bar: string
|
||||||
|
readonly foo: string
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
readonly type: 'world'
|
||||||
|
readonly bar: number
|
||||||
|
readonly foo: string
|
||||||
|
}
|
||||||
|
>(props)
|
||||||
|
})
|
||||||
|
|
||||||
describe('defineProps w/ generic type declaration + withDefaults', <T extends
|
describe('defineProps w/ generic type declaration + withDefaults', <T extends
|
||||||
number, TA extends {
|
number, TA extends {
|
||||||
a: string
|
a: string
|
||||||
|
|
|
@ -45,18 +45,6 @@ declare module 'estree-walker' {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module 'source-map-js' {
|
|
||||||
export interface SourceMapGenerator {
|
|
||||||
// SourceMapGenerator has this method but the types do not include it
|
|
||||||
toJSON(): RawSourceMap
|
|
||||||
_sources: Set<string>
|
|
||||||
_names: Set<string>
|
|
||||||
_mappings: {
|
|
||||||
add(mapping: MappingItem): void
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare interface String {
|
declare interface String {
|
||||||
/**
|
/**
|
||||||
* @deprecated Please use String.prototype.slice instead of String.prototype.substring in the repository.
|
* @deprecated Please use String.prototype.slice instead of String.prototype.substring in the repository.
|
||||||
|
|
|
@ -4,6 +4,7 @@ import {
|
||||||
EffectScope,
|
EffectScope,
|
||||||
computed,
|
computed,
|
||||||
effect,
|
effect,
|
||||||
|
effectScope,
|
||||||
getCurrentScope,
|
getCurrentScope,
|
||||||
onScopeDispose,
|
onScopeDispose,
|
||||||
reactive,
|
reactive,
|
||||||
|
@ -13,21 +14,21 @@ import {
|
||||||
describe('reactivity/effect/scope', () => {
|
describe('reactivity/effect/scope', () => {
|
||||||
it('should run', () => {
|
it('should run', () => {
|
||||||
const fnSpy = vi.fn(() => {})
|
const fnSpy = vi.fn(() => {})
|
||||||
new EffectScope().run(fnSpy)
|
effectScope().run(fnSpy)
|
||||||
expect(fnSpy).toHaveBeenCalledTimes(1)
|
expect(fnSpy).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should accept zero argument', () => {
|
it('should accept zero argument', () => {
|
||||||
const scope = new EffectScope()
|
const scope = effectScope()
|
||||||
expect(scope.effects.length).toBe(0)
|
expect(scope.effects.length).toBe(0)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should return run value', () => {
|
it('should return run value', () => {
|
||||||
expect(new EffectScope().run(() => 1)).toBe(1)
|
expect(effectScope().run(() => 1)).toBe(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should work w/ active property', () => {
|
it('should work w/ active property', () => {
|
||||||
const scope = new EffectScope()
|
const scope = effectScope()
|
||||||
scope.run(() => 1)
|
scope.run(() => 1)
|
||||||
expect(scope.active).toBe(true)
|
expect(scope.active).toBe(true)
|
||||||
scope.stop()
|
scope.stop()
|
||||||
|
@ -35,7 +36,7 @@ describe('reactivity/effect/scope', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should collect the effects', () => {
|
it('should collect the effects', () => {
|
||||||
const scope = new EffectScope()
|
const scope = effectScope()
|
||||||
scope.run(() => {
|
scope.run(() => {
|
||||||
let dummy
|
let dummy
|
||||||
const counter = reactive({ num: 0 })
|
const counter = reactive({ num: 0 })
|
||||||
|
@ -53,7 +54,7 @@ describe('reactivity/effect/scope', () => {
|
||||||
let dummy, doubled
|
let dummy, doubled
|
||||||
const counter = reactive({ num: 0 })
|
const counter = reactive({ num: 0 })
|
||||||
|
|
||||||
const scope = new EffectScope()
|
const scope = effectScope()
|
||||||
scope.run(() => {
|
scope.run(() => {
|
||||||
effect(() => (dummy = counter.num))
|
effect(() => (dummy = counter.num))
|
||||||
effect(() => (doubled = counter.num * 2))
|
effect(() => (doubled = counter.num * 2))
|
||||||
|
@ -77,11 +78,11 @@ describe('reactivity/effect/scope', () => {
|
||||||
let dummy, doubled
|
let dummy, doubled
|
||||||
const counter = reactive({ num: 0 })
|
const counter = reactive({ num: 0 })
|
||||||
|
|
||||||
const scope = new EffectScope()
|
const scope = effectScope()
|
||||||
scope.run(() => {
|
scope.run(() => {
|
||||||
effect(() => (dummy = counter.num))
|
effect(() => (dummy = counter.num))
|
||||||
// nested scope
|
// nested scope
|
||||||
new EffectScope().run(() => {
|
effectScope().run(() => {
|
||||||
effect(() => (doubled = counter.num * 2))
|
effect(() => (doubled = counter.num * 2))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -107,11 +108,11 @@ describe('reactivity/effect/scope', () => {
|
||||||
let dummy, doubled
|
let dummy, doubled
|
||||||
const counter = reactive({ num: 0 })
|
const counter = reactive({ num: 0 })
|
||||||
|
|
||||||
const scope = new EffectScope()
|
const scope = effectScope()
|
||||||
scope.run(() => {
|
scope.run(() => {
|
||||||
effect(() => (dummy = counter.num))
|
effect(() => (dummy = counter.num))
|
||||||
// nested scope
|
// nested scope
|
||||||
new EffectScope(true).run(() => {
|
effectScope(true).run(() => {
|
||||||
effect(() => (doubled = counter.num * 2))
|
effect(() => (doubled = counter.num * 2))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -136,7 +137,7 @@ describe('reactivity/effect/scope', () => {
|
||||||
let dummy, doubled
|
let dummy, doubled
|
||||||
const counter = reactive({ num: 0 })
|
const counter = reactive({ num: 0 })
|
||||||
|
|
||||||
const scope = new EffectScope()
|
const scope = effectScope()
|
||||||
scope.run(() => {
|
scope.run(() => {
|
||||||
effect(() => (dummy = counter.num))
|
effect(() => (dummy = counter.num))
|
||||||
})
|
})
|
||||||
|
@ -160,7 +161,7 @@ describe('reactivity/effect/scope', () => {
|
||||||
let dummy, doubled
|
let dummy, doubled
|
||||||
const counter = reactive({ num: 0 })
|
const counter = reactive({ num: 0 })
|
||||||
|
|
||||||
const scope = new EffectScope()
|
const scope = effectScope()
|
||||||
scope.run(() => {
|
scope.run(() => {
|
||||||
effect(() => (dummy = counter.num))
|
effect(() => (dummy = counter.num))
|
||||||
})
|
})
|
||||||
|
@ -185,7 +186,7 @@ describe('reactivity/effect/scope', () => {
|
||||||
it('should fire onScopeDispose hook', () => {
|
it('should fire onScopeDispose hook', () => {
|
||||||
let dummy = 0
|
let dummy = 0
|
||||||
|
|
||||||
const scope = new EffectScope()
|
const scope = effectScope()
|
||||||
scope.run(() => {
|
scope.run(() => {
|
||||||
onScopeDispose(() => (dummy += 1))
|
onScopeDispose(() => (dummy += 1))
|
||||||
onScopeDispose(() => (dummy += 2))
|
onScopeDispose(() => (dummy += 2))
|
||||||
|
@ -203,7 +204,7 @@ describe('reactivity/effect/scope', () => {
|
||||||
|
|
||||||
it('should warn onScopeDispose() is called when there is no active effect scope', () => {
|
it('should warn onScopeDispose() is called when there is no active effect scope', () => {
|
||||||
const spy = vi.fn()
|
const spy = vi.fn()
|
||||||
const scope = new EffectScope()
|
const scope = effectScope()
|
||||||
scope.run(() => {
|
scope.run(() => {
|
||||||
onScopeDispose(spy)
|
onScopeDispose(spy)
|
||||||
})
|
})
|
||||||
|
@ -221,8 +222,8 @@ describe('reactivity/effect/scope', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should dereference child scope from parent scope after stopping child scope (no memleaks)', () => {
|
it('should dereference child scope from parent scope after stopping child scope (no memleaks)', () => {
|
||||||
const parent = new EffectScope()
|
const parent = effectScope()
|
||||||
const child = parent.run(() => new EffectScope())!
|
const child = parent.run(() => effectScope())!
|
||||||
expect(parent.scopes!.includes(child)).toBe(true)
|
expect(parent.scopes!.includes(child)).toBe(true)
|
||||||
child.stop()
|
child.stop()
|
||||||
expect(parent.scopes!.includes(child)).toBe(false)
|
expect(parent.scopes!.includes(child)).toBe(false)
|
||||||
|
@ -236,7 +237,7 @@ describe('reactivity/effect/scope', () => {
|
||||||
const watchEffectSpy = vi.fn()
|
const watchEffectSpy = vi.fn()
|
||||||
|
|
||||||
let c: ComputedRef
|
let c: ComputedRef
|
||||||
const scope = new EffectScope()
|
const scope = effectScope()
|
||||||
scope.run(() => {
|
scope.run(() => {
|
||||||
c = computed(() => {
|
c = computed(() => {
|
||||||
computedSpy()
|
computedSpy()
|
||||||
|
@ -272,12 +273,12 @@ describe('reactivity/effect/scope', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('getCurrentScope() stays valid when running a detached nested EffectScope', () => {
|
it('getCurrentScope() stays valid when running a detached nested EffectScope', () => {
|
||||||
const parentScope = new EffectScope()
|
const parentScope = effectScope()
|
||||||
|
|
||||||
parentScope.run(() => {
|
parentScope.run(() => {
|
||||||
const currentScope = getCurrentScope()
|
const currentScope = getCurrentScope()
|
||||||
expect(currentScope).toBeDefined()
|
expect(currentScope).toBeDefined()
|
||||||
const detachedScope = new EffectScope(true)
|
const detachedScope = effectScope(true)
|
||||||
detachedScope.run(() => {})
|
detachedScope.run(() => {})
|
||||||
|
|
||||||
expect(getCurrentScope()).toBe(currentScope)
|
expect(getCurrentScope()).toBe(currentScope)
|
||||||
|
@ -285,10 +286,10 @@ describe('reactivity/effect/scope', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('calling .off() of a detached scope inside an active scope should not break currentScope', () => {
|
it('calling .off() of a detached scope inside an active scope should not break currentScope', () => {
|
||||||
const parentScope = new EffectScope()
|
const parentScope = effectScope()
|
||||||
|
|
||||||
parentScope.run(() => {
|
parentScope.run(() => {
|
||||||
const childScope = new EffectScope(true)
|
const childScope = effectScope(true)
|
||||||
childScope.on()
|
childScope.on()
|
||||||
childScope.off()
|
childScope.off()
|
||||||
expect(getCurrentScope()).toBe(parentScope)
|
expect(getCurrentScope()).toBe(parentScope)
|
||||||
|
|
|
@ -1,5 +1,14 @@
|
||||||
import { isRef, ref } from '../src/ref'
|
import { isRef, ref } from '../src/ref'
|
||||||
import { isReactive, markRaw, reactive, toRaw } from '../src/reactive'
|
import {
|
||||||
|
isProxy,
|
||||||
|
isReactive,
|
||||||
|
markRaw,
|
||||||
|
reactive,
|
||||||
|
readonly,
|
||||||
|
shallowReactive,
|
||||||
|
shallowReadonly,
|
||||||
|
toRaw,
|
||||||
|
} from '../src/reactive'
|
||||||
import { computed } from '../src/computed'
|
import { computed } from '../src/computed'
|
||||||
import { effect } from '../src/effect'
|
import { effect } from '../src/effect'
|
||||||
|
|
||||||
|
@ -302,4 +311,52 @@ describe('reactivity/reactive', () => {
|
||||||
const observed = reactive(original)
|
const observed = reactive(original)
|
||||||
expect(isReactive(observed)).toBe(false)
|
expect(isReactive(observed)).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('hasOwnProperty edge case: Symbol values', () => {
|
||||||
|
const key = Symbol()
|
||||||
|
const obj = reactive({ [key]: 1 }) as { [key]?: 1 }
|
||||||
|
let dummy
|
||||||
|
effect(() => {
|
||||||
|
dummy = obj.hasOwnProperty(key)
|
||||||
|
})
|
||||||
|
expect(dummy).toBe(true)
|
||||||
|
|
||||||
|
delete obj[key]
|
||||||
|
expect(dummy).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('hasOwnProperty edge case: non-string values', () => {
|
||||||
|
const key = {}
|
||||||
|
const obj = reactive({ '[object Object]': 1 }) as { '[object Object]'?: 1 }
|
||||||
|
let dummy
|
||||||
|
effect(() => {
|
||||||
|
// @ts-expect-error
|
||||||
|
dummy = obj.hasOwnProperty(key)
|
||||||
|
})
|
||||||
|
expect(dummy).toBe(true)
|
||||||
|
|
||||||
|
// @ts-expect-error
|
||||||
|
delete obj[key]
|
||||||
|
expect(dummy).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('isProxy', () => {
|
||||||
|
const foo = {}
|
||||||
|
expect(isProxy(foo)).toBe(false)
|
||||||
|
|
||||||
|
const fooRe = reactive(foo)
|
||||||
|
expect(isProxy(fooRe)).toBe(true)
|
||||||
|
|
||||||
|
const fooSRe = shallowReactive(foo)
|
||||||
|
expect(isProxy(fooSRe)).toBe(true)
|
||||||
|
|
||||||
|
const barRl = readonly(foo)
|
||||||
|
expect(isProxy(barRl)).toBe(true)
|
||||||
|
|
||||||
|
const barSRl = shallowReadonly(foo)
|
||||||
|
expect(isProxy(barSRl)).toBe(true)
|
||||||
|
|
||||||
|
const c = computed(() => {})
|
||||||
|
expect(isProxy(c)).toBe(false)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -100,6 +100,21 @@ describe('reactivity/reactive/Array', () => {
|
||||||
expect(fn).toHaveBeenCalledTimes(1)
|
expect(fn).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('should track hasOwnProperty call with index', () => {
|
||||||
|
const original = [1, 2, 3]
|
||||||
|
const observed = reactive(original)
|
||||||
|
|
||||||
|
let dummy
|
||||||
|
effect(() => {
|
||||||
|
dummy = observed.hasOwnProperty(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(dummy).toBe(true)
|
||||||
|
|
||||||
|
delete observed[0]
|
||||||
|
expect(dummy).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
test('shift on Array should trigger dependency once', () => {
|
test('shift on Array should trigger dependency once', () => {
|
||||||
const arr = reactive([1, 2, 3])
|
const arr = reactive([1, 2, 3])
|
||||||
const fn = vi.fn()
|
const fn = vi.fn()
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vue/reactivity",
|
"name": "@vue/reactivity",
|
||||||
"version": "3.4.20",
|
"version": "3.4.22",
|
||||||
"description": "@vue/reactivity",
|
"description": "@vue/reactivity",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"module": "dist/reactivity.esm-bundler.js",
|
"module": "dist/reactivity.esm-bundler.js",
|
||||||
|
|
|
@ -38,10 +38,12 @@ const builtInSymbols = new Set(
|
||||||
.filter(isSymbol),
|
.filter(isSymbol),
|
||||||
)
|
)
|
||||||
|
|
||||||
function hasOwnProperty(this: object, key: string) {
|
function hasOwnProperty(this: object, key: unknown) {
|
||||||
|
// #10455 hasOwnProperty may be called with non-string values
|
||||||
|
if (!isSymbol(key)) key = String(key)
|
||||||
const obj = toRaw(this)
|
const obj = toRaw(this)
|
||||||
track(obj, TrackOpTypes.HAS, key)
|
track(obj, TrackOpTypes.HAS, key)
|
||||||
return obj.hasOwnProperty(key)
|
return obj.hasOwnProperty(key as string)
|
||||||
}
|
}
|
||||||
|
|
||||||
class BaseReactiveHandler implements ProxyHandler<Target> {
|
class BaseReactiveHandler implements ProxyHandler<Target> {
|
||||||
|
|
|
@ -232,8 +232,10 @@ function createReadonlyMethod(type: TriggerOpTypes): Function {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Instrumentations = Record<string | symbol, Function | number>
|
||||||
|
|
||||||
function createInstrumentations() {
|
function createInstrumentations() {
|
||||||
const mutableInstrumentations: Record<string, Function | number> = {
|
const mutableInstrumentations: Instrumentations = {
|
||||||
get(this: MapTypes, key: unknown) {
|
get(this: MapTypes, key: unknown) {
|
||||||
return get(this, key)
|
return get(this, key)
|
||||||
},
|
},
|
||||||
|
@ -248,7 +250,7 @@ function createInstrumentations() {
|
||||||
forEach: createForEach(false, false),
|
forEach: createForEach(false, false),
|
||||||
}
|
}
|
||||||
|
|
||||||
const shallowInstrumentations: Record<string, Function | number> = {
|
const shallowInstrumentations: Instrumentations = {
|
||||||
get(this: MapTypes, key: unknown) {
|
get(this: MapTypes, key: unknown) {
|
||||||
return get(this, key, false, true)
|
return get(this, key, false, true)
|
||||||
},
|
},
|
||||||
|
@ -263,7 +265,7 @@ function createInstrumentations() {
|
||||||
forEach: createForEach(false, true),
|
forEach: createForEach(false, true),
|
||||||
}
|
}
|
||||||
|
|
||||||
const readonlyInstrumentations: Record<string, Function | number> = {
|
const readonlyInstrumentations: Instrumentations = {
|
||||||
get(this: MapTypes, key: unknown) {
|
get(this: MapTypes, key: unknown) {
|
||||||
return get(this, key, true)
|
return get(this, key, true)
|
||||||
},
|
},
|
||||||
|
@ -280,7 +282,7 @@ function createInstrumentations() {
|
||||||
forEach: createForEach(true, false),
|
forEach: createForEach(true, false),
|
||||||
}
|
}
|
||||||
|
|
||||||
const shallowReadonlyInstrumentations: Record<string, Function | number> = {
|
const shallowReadonlyInstrumentations: Instrumentations = {
|
||||||
get(this: MapTypes, key: unknown) {
|
get(this: MapTypes, key: unknown) {
|
||||||
return get(this, key, true, true)
|
return get(this, key, true, true)
|
||||||
},
|
},
|
||||||
|
@ -297,24 +299,18 @@ function createInstrumentations() {
|
||||||
forEach: createForEach(true, true),
|
forEach: createForEach(true, true),
|
||||||
}
|
}
|
||||||
|
|
||||||
const iteratorMethods = ['keys', 'values', 'entries', Symbol.iterator]
|
const iteratorMethods = [
|
||||||
|
'keys',
|
||||||
|
'values',
|
||||||
|
'entries',
|
||||||
|
Symbol.iterator,
|
||||||
|
] as const
|
||||||
|
|
||||||
iteratorMethods.forEach(method => {
|
iteratorMethods.forEach(method => {
|
||||||
mutableInstrumentations[method as string] = createIterableMethod(
|
mutableInstrumentations[method] = createIterableMethod(method, false, false)
|
||||||
method,
|
readonlyInstrumentations[method] = createIterableMethod(method, true, false)
|
||||||
false,
|
shallowInstrumentations[method] = createIterableMethod(method, false, true)
|
||||||
false,
|
shallowReadonlyInstrumentations[method] = createIterableMethod(
|
||||||
)
|
|
||||||
readonlyInstrumentations[method as string] = createIterableMethod(
|
|
||||||
method,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
shallowInstrumentations[method as string] = createIterableMethod(
|
|
||||||
method,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
shallowReadonlyInstrumentations[method as string] = createIterableMethod(
|
|
||||||
method,
|
method,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
|
|
@ -329,8 +329,8 @@ export function isShallow(value: unknown): boolean {
|
||||||
* @param value - The value to check.
|
* @param value - The value to check.
|
||||||
* @see {@link https://vuejs.org/api/reactivity-utilities.html#isproxy}
|
* @see {@link https://vuejs.org/api/reactivity-utilities.html#isproxy}
|
||||||
*/
|
*/
|
||||||
export function isProxy(value: unknown): boolean {
|
export function isProxy(value: any): boolean {
|
||||||
return isReactive(value) || isReadonly(value)
|
return value ? !!value[ReactiveFlags.RAW] : false
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -409,5 +409,5 @@ export const toReactive = <T extends unknown>(value: T): T =>
|
||||||
*
|
*
|
||||||
* @param value - The value for which a readonly proxy shall be created.
|
* @param value - The value for which a readonly proxy shall be created.
|
||||||
*/
|
*/
|
||||||
export const toReadonly = <T extends unknown>(value: T): T =>
|
export const toReadonly = <T extends unknown>(value: T): DeepReadonly<T> =>
|
||||||
isObject(value) ? readonly(value) : value
|
isObject(value) ? readonly(value) : (value as DeepReadonly<T>)
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {
|
||||||
h,
|
h,
|
||||||
nextTick,
|
nextTick,
|
||||||
nodeOps,
|
nodeOps,
|
||||||
|
onUnmounted,
|
||||||
ref,
|
ref,
|
||||||
render,
|
render,
|
||||||
serialize,
|
serialize,
|
||||||
|
@ -768,6 +769,42 @@ describe('BaseTransition', () => {
|
||||||
test('w/ KeepAlive', async () => {
|
test('w/ KeepAlive', async () => {
|
||||||
await runTestWithKeepAlive(testOutIn)
|
await runTestWithKeepAlive(testOutIn)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('w/ KeepAlive + unmount innerChild', async () => {
|
||||||
|
const unmountSpy = vi.fn()
|
||||||
|
const includeRef = ref(['TrueBranch'])
|
||||||
|
const trueComp = {
|
||||||
|
name: 'TrueBranch',
|
||||||
|
setup() {
|
||||||
|
onUnmounted(unmountSpy)
|
||||||
|
const count = ref(0)
|
||||||
|
return () => h('div', count.value)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggle = ref(true)
|
||||||
|
const { props } = mockProps({ mode: 'out-in' }, true /*withKeepAlive*/)
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
const App = {
|
||||||
|
render() {
|
||||||
|
return h(BaseTransition, props, () => {
|
||||||
|
return h(
|
||||||
|
KeepAlive,
|
||||||
|
{ include: includeRef.value },
|
||||||
|
toggle.value ? h(trueComp) : h('div'),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
render(h(App), root)
|
||||||
|
|
||||||
|
// trigger toggle
|
||||||
|
toggle.value = false
|
||||||
|
includeRef.value = []
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
expect(unmountSpy).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// #6835
|
// #6835
|
||||||
|
|
|
@ -54,6 +54,18 @@ describe('Suspense', () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const RouterView = {
|
||||||
|
setup(_: any, { slots }: any) {
|
||||||
|
const route = inject('route') as any
|
||||||
|
const depth = inject('depth', 0)
|
||||||
|
provide('depth', depth + 1)
|
||||||
|
return () => {
|
||||||
|
const current = route.value[depth]
|
||||||
|
return slots.default({ Component: current })[0]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
test('fallback content', async () => {
|
test('fallback content', async () => {
|
||||||
const Async = defineAsyncComponent({
|
const Async = defineAsyncComponent({
|
||||||
render() {
|
render() {
|
||||||
|
@ -1041,18 +1053,6 @@ describe('Suspense', () => {
|
||||||
|
|
||||||
// #10098
|
// #10098
|
||||||
test('switching branches w/ nested suspense', async () => {
|
test('switching branches w/ nested suspense', async () => {
|
||||||
const RouterView = {
|
|
||||||
setup(_: any, { slots }: any) {
|
|
||||||
const route = inject('route') as any
|
|
||||||
const depth = inject('depth', 0)
|
|
||||||
provide('depth', depth + 1)
|
|
||||||
return () => {
|
|
||||||
const current = route.value[depth]
|
|
||||||
return slots.default({ Component: current })[0]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const OuterB = defineAsyncComponent({
|
const OuterB = defineAsyncComponent({
|
||||||
setup: () => {
|
setup: () => {
|
||||||
return () =>
|
return () =>
|
||||||
|
@ -1132,6 +1132,121 @@ describe('Suspense', () => {
|
||||||
expect(serializeInner(root)).toBe(`<div>innerA</div>`)
|
expect(serializeInner(root)).toBe(`<div>innerA</div>`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #10415
|
||||||
|
test('nested suspense (w/ suspensible) switch several times before parent suspense resolve', async () => {
|
||||||
|
const OuterA = defineAsyncComponent({
|
||||||
|
setup: () => {
|
||||||
|
return () =>
|
||||||
|
h(RouterView, null, {
|
||||||
|
default: ({ Component }: any) => [
|
||||||
|
h(Suspense, null, {
|
||||||
|
default: () => h(Component),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const InnerA = defineAsyncComponent({
|
||||||
|
setup: () => {
|
||||||
|
return () => h('div', 'innerA')
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const route = shallowRef([OuterA, InnerA])
|
||||||
|
const InnerB = defineAsyncComponent(
|
||||||
|
{
|
||||||
|
setup: () => {
|
||||||
|
return () => h('div', 'innerB')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
5,
|
||||||
|
)
|
||||||
|
|
||||||
|
const InnerB1 = defineAsyncComponent(
|
||||||
|
{
|
||||||
|
setup: () => {
|
||||||
|
return () => h('div', 'innerB1')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
5,
|
||||||
|
)
|
||||||
|
|
||||||
|
const InnerB2 = defineAsyncComponent(
|
||||||
|
{
|
||||||
|
setup: () => {
|
||||||
|
return () => h('div', 'innerB2')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
5,
|
||||||
|
)
|
||||||
|
|
||||||
|
const OuterB = defineAsyncComponent(
|
||||||
|
{
|
||||||
|
setup() {
|
||||||
|
nextTick(async () => {
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1))
|
||||||
|
route.value = [OuterB, InnerB1]
|
||||||
|
})
|
||||||
|
|
||||||
|
nextTick(async () => {
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1))
|
||||||
|
route.value = [OuterB, InnerB2]
|
||||||
|
})
|
||||||
|
|
||||||
|
return () =>
|
||||||
|
h(RouterView, null, {
|
||||||
|
default: ({ Component }: any) => [
|
||||||
|
h(
|
||||||
|
Suspense,
|
||||||
|
{ suspensible: true },
|
||||||
|
{
|
||||||
|
default: () => h(Component),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
5,
|
||||||
|
)
|
||||||
|
|
||||||
|
const Comp = {
|
||||||
|
setup() {
|
||||||
|
provide('route', route)
|
||||||
|
return () =>
|
||||||
|
h(RouterView, null, {
|
||||||
|
default: ({ Component }: any) => [
|
||||||
|
h(Suspense, null, {
|
||||||
|
default: () => h(Component),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
render(h(Comp), root)
|
||||||
|
await Promise.all(deps)
|
||||||
|
await nextTick()
|
||||||
|
expect(serializeInner(root)).toBe(`<!---->`)
|
||||||
|
|
||||||
|
await Promise.all(deps)
|
||||||
|
await nextTick()
|
||||||
|
expect(serializeInner(root)).toBe(`<div>innerA</div>`)
|
||||||
|
|
||||||
|
deps.length = 0
|
||||||
|
|
||||||
|
route.value = [OuterB, InnerB]
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
|
await Promise.all(deps)
|
||||||
|
await Promise.all(deps)
|
||||||
|
await Promise.all(deps)
|
||||||
|
await nextTick()
|
||||||
|
expect(serializeInner(root)).toBe(`<div>innerB2</div>`)
|
||||||
|
})
|
||||||
|
|
||||||
test('branch switch to 3rd branch before resolve', async () => {
|
test('branch switch to 3rd branch before resolve', async () => {
|
||||||
const calls: string[] = []
|
const calls: string[] = []
|
||||||
|
|
||||||
|
|
|
@ -583,5 +583,31 @@ describe('error handling', () => {
|
||||||
expect(handler).toHaveBeenCalledTimes(4)
|
expect(handler).toHaveBeenCalledTimes(4)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #9574
|
||||||
|
test('should pause tracking in error handler', async () => {
|
||||||
|
const error = new Error('error')
|
||||||
|
const x = ref(Math.random())
|
||||||
|
|
||||||
|
const handler = vi.fn(() => {
|
||||||
|
x.value
|
||||||
|
x.value = Math.random()
|
||||||
|
})
|
||||||
|
|
||||||
|
const app = createApp({
|
||||||
|
setup() {
|
||||||
|
return () => {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
app.config.errorHandler = handler
|
||||||
|
app.mount(nodeOps.createElement('div'))
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
expect(handler).toHaveBeenCalledWith(error, {}, 'render function')
|
||||||
|
expect(handler).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
|
|
||||||
// native event handler handling should be tested in respective renderers
|
// native event handler handling should be tested in respective renderers
|
||||||
})
|
})
|
||||||
|
|
|
@ -7,7 +7,10 @@ import {
|
||||||
Teleport,
|
Teleport,
|
||||||
Transition,
|
Transition,
|
||||||
type VNode,
|
type VNode,
|
||||||
|
createBlock,
|
||||||
createCommentVNode,
|
createCommentVNode,
|
||||||
|
createElementBlock,
|
||||||
|
createElementVNode,
|
||||||
createSSRApp,
|
createSSRApp,
|
||||||
createStaticVNode,
|
createStaticVNode,
|
||||||
createTextVNode,
|
createTextVNode,
|
||||||
|
@ -17,16 +20,19 @@ import {
|
||||||
h,
|
h,
|
||||||
nextTick,
|
nextTick,
|
||||||
onMounted,
|
onMounted,
|
||||||
|
openBlock,
|
||||||
ref,
|
ref,
|
||||||
renderSlot,
|
renderSlot,
|
||||||
useCssVars,
|
useCssVars,
|
||||||
vModelCheckbox,
|
vModelCheckbox,
|
||||||
vShow,
|
vShow,
|
||||||
|
withCtx,
|
||||||
withDirectives,
|
withDirectives,
|
||||||
} from '@vue/runtime-dom'
|
} from '@vue/runtime-dom'
|
||||||
import { type SSRContext, renderToString } from '@vue/server-renderer'
|
import { type SSRContext, renderToString } from '@vue/server-renderer'
|
||||||
import { PatchFlags } from '@vue/shared'
|
import { PatchFlags } from '@vue/shared'
|
||||||
import { vShowOriginalDisplay } from '../../runtime-dom/src/directives/vShow'
|
import { vShowOriginalDisplay } from '../../runtime-dom/src/directives/vShow'
|
||||||
|
import { expect } from 'vitest'
|
||||||
|
|
||||||
function mountWithHydration(html: string, render: () => any) {
|
function mountWithHydration(html: string, render: () => any) {
|
||||||
const container = document.createElement('div')
|
const container = document.createElement('div')
|
||||||
|
@ -1292,6 +1298,81 @@ describe('SSR hydration', () => {
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #10607
|
||||||
|
test('update component stable slot (prod + optimized mode)', async () => {
|
||||||
|
__DEV__ = false
|
||||||
|
const container = document.createElement('div')
|
||||||
|
container.innerHTML = `<template><div show="false"><!--[--><div><div><!----></div></div><div>0</div><!--]--></div></template>`
|
||||||
|
const Comp = {
|
||||||
|
render(this: any) {
|
||||||
|
return (
|
||||||
|
openBlock(),
|
||||||
|
createElementBlock('div', null, [renderSlot(this.$slots, 'default')])
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const show = ref(false)
|
||||||
|
const clicked = ref(false)
|
||||||
|
|
||||||
|
const Wrapper = {
|
||||||
|
setup() {
|
||||||
|
const items = ref<number[]>([])
|
||||||
|
onMounted(() => {
|
||||||
|
items.value = [1]
|
||||||
|
})
|
||||||
|
return () => {
|
||||||
|
return (
|
||||||
|
openBlock(),
|
||||||
|
createBlock(Comp, null, {
|
||||||
|
default: withCtx(() => [
|
||||||
|
createElementVNode('div', null, [
|
||||||
|
createElementVNode('div', null, [
|
||||||
|
clicked.value
|
||||||
|
? (openBlock(),
|
||||||
|
createElementBlock('div', { key: 0 }, 'foo'))
|
||||||
|
: createCommentVNode('v-if', true),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
createElementVNode(
|
||||||
|
'div',
|
||||||
|
null,
|
||||||
|
items.value.length,
|
||||||
|
1 /* TEXT */,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
_: 1 /* STABLE */,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
createSSRApp({
|
||||||
|
components: { Wrapper },
|
||||||
|
data() {
|
||||||
|
return { show }
|
||||||
|
},
|
||||||
|
template: `<Wrapper :show="show"/>`,
|
||||||
|
}).mount(container)
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
expect(container.innerHTML).toBe(
|
||||||
|
`<div show="false"><!--[--><div><div><!----></div></div><div>1</div><!--]--></div>`,
|
||||||
|
)
|
||||||
|
|
||||||
|
show.value = true
|
||||||
|
await nextTick()
|
||||||
|
expect(async () => {
|
||||||
|
clicked.value = true
|
||||||
|
await nextTick()
|
||||||
|
}).not.toThrow("Cannot read properties of null (reading 'insertBefore')")
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
expect(container.innerHTML).toBe(
|
||||||
|
`<div show="true"><!--[--><div><div><div>foo</div></div></div><div>1</div><!--]--></div>`,
|
||||||
|
)
|
||||||
|
__DEV__ = true
|
||||||
|
})
|
||||||
|
|
||||||
describe('mismatch handling', () => {
|
describe('mismatch handling', () => {
|
||||||
test('text node', () => {
|
test('text node', () => {
|
||||||
const { container } = mountWithHydration(`foo`, () => 'bar')
|
const { container } = mountWithHydration(`foo`, () => 'bar')
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vue/runtime-core",
|
"name": "@vue/runtime-core",
|
||||||
"version": "3.4.20",
|
"version": "3.4.22",
|
||||||
"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",
|
||||||
|
|
|
@ -233,7 +233,7 @@ export type DefineModelOptions<T = any> = {
|
||||||
* Otherwise the prop name will default to "modelValue". In both cases, you
|
* Otherwise the prop name will default to "modelValue". In both cases, you
|
||||||
* can also pass an additional object which will be used as the prop's options.
|
* can also pass an additional object which will be used as the prop's options.
|
||||||
*
|
*
|
||||||
* The the returned ref behaves differently depending on whether the parent
|
* The returned ref behaves differently depending on whether the parent
|
||||||
* provided the corresponding v-model props or not:
|
* provided the corresponding v-model props or not:
|
||||||
* - If yes, the returned ref's value will always be in sync with the parent
|
* - If yes, the returned ref's value will always be in sync with the parent
|
||||||
* prop.
|
* prop.
|
||||||
|
@ -284,6 +284,9 @@ export function defineModel(): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
type NotUndefined<T> = T extends undefined ? never : T
|
type NotUndefined<T> = T extends undefined ? never : T
|
||||||
|
type MappedOmit<T, K extends keyof any> = {
|
||||||
|
[P in keyof T as P extends K ? never : P]: T[P]
|
||||||
|
}
|
||||||
|
|
||||||
type InferDefaults<T> = {
|
type InferDefaults<T> = {
|
||||||
[K in keyof T]?: InferDefault<T, T[K]>
|
[K in keyof T]?: InferDefault<T, T[K]>
|
||||||
|
@ -299,7 +302,7 @@ type PropsWithDefaults<
|
||||||
T,
|
T,
|
||||||
Defaults extends InferDefaults<T>,
|
Defaults extends InferDefaults<T>,
|
||||||
BKeys extends keyof T,
|
BKeys extends keyof T,
|
||||||
> = Readonly<Omit<T, keyof Defaults>> & {
|
> = Readonly<MappedOmit<T, keyof Defaults>> & {
|
||||||
readonly [K in keyof Defaults]-?: K extends keyof T
|
readonly [K in keyof Defaults]-?: K extends keyof T
|
||||||
? Defaults[K] extends undefined
|
? Defaults[K] extends undefined
|
||||||
? T[K]
|
? T[K]
|
||||||
|
|
|
@ -427,15 +427,14 @@ function applySingletonPrototype(app: App, Ctor: Function) {
|
||||||
app.config.globalProperties = Object.create(Ctor.prototype)
|
app.config.globalProperties = Object.create(Ctor.prototype)
|
||||||
}
|
}
|
||||||
let hasPrototypeAugmentations = false
|
let hasPrototypeAugmentations = false
|
||||||
const descriptors = Object.getOwnPropertyDescriptors(Ctor.prototype)
|
for (const key of Object.getOwnPropertyNames(Ctor.prototype)) {
|
||||||
for (const key in descriptors) {
|
|
||||||
if (key !== 'constructor') {
|
if (key !== 'constructor') {
|
||||||
hasPrototypeAugmentations = true
|
hasPrototypeAugmentations = true
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
Object.defineProperty(
|
Object.defineProperty(
|
||||||
app.config.globalProperties,
|
app.config.globalProperties,
|
||||||
key,
|
key,
|
||||||
descriptors[key],
|
Object.getOwnPropertyDescriptor(Ctor.prototype, key)!,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import {
|
||||||
DeprecationTypes,
|
DeprecationTypes,
|
||||||
assertCompatEnabled,
|
assertCompatEnabled,
|
||||||
isCompatEnabled,
|
isCompatEnabled,
|
||||||
|
warnDeprecation,
|
||||||
} from './compatConfig'
|
} from './compatConfig'
|
||||||
import { off, on, once } from './instanceEventEmitter'
|
import { off, on, once } from './instanceEventEmitter'
|
||||||
import { getCompatListeners } from './instanceListeners'
|
import { getCompatListeners } from './instanceListeners'
|
||||||
|
@ -121,50 +122,77 @@ export function installCompatInstanceProperties(map: PublicPropertiesMap) {
|
||||||
|
|
||||||
$children: getCompatChildren,
|
$children: getCompatChildren,
|
||||||
$listeners: getCompatListeners,
|
$listeners: getCompatListeners,
|
||||||
|
|
||||||
|
// inject additional properties into $options for compat
|
||||||
|
// e.g. vuex needs this.$options.parent
|
||||||
|
$options: i => {
|
||||||
|
if (!isCompatEnabled(DeprecationTypes.PRIVATE_APIS, i)) {
|
||||||
|
return resolveMergedOptions(i)
|
||||||
|
}
|
||||||
|
if (i.resolvedOptions) {
|
||||||
|
return i.resolvedOptions
|
||||||
|
}
|
||||||
|
const res = (i.resolvedOptions = extend({}, resolveMergedOptions(i)))
|
||||||
|
Object.defineProperties(res, {
|
||||||
|
parent: {
|
||||||
|
get() {
|
||||||
|
warnDeprecation(DeprecationTypes.PRIVATE_APIS, i, '$options.parent')
|
||||||
|
return i.proxy!.$parent
|
||||||
|
},
|
||||||
|
},
|
||||||
|
propsData: {
|
||||||
|
get() {
|
||||||
|
warnDeprecation(
|
||||||
|
DeprecationTypes.PRIVATE_APIS,
|
||||||
|
i,
|
||||||
|
'$options.propsData',
|
||||||
|
)
|
||||||
|
return i.vnode.props
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
},
|
||||||
} as PublicPropertiesMap)
|
} as PublicPropertiesMap)
|
||||||
|
|
||||||
/* istanbul ignore if */
|
const privateAPIs = {
|
||||||
if (isCompatEnabled(DeprecationTypes.PRIVATE_APIS, null)) {
|
// needed by many libs / render fns
|
||||||
extend(map, {
|
$vnode: i => i.vnode,
|
||||||
// needed by many libs / render fns
|
|
||||||
$vnode: i => i.vnode,
|
|
||||||
|
|
||||||
// inject additional properties into $options for compat
|
// some private properties that are likely accessed...
|
||||||
// e.g. vuex needs this.$options.parent
|
_self: i => i.proxy,
|
||||||
$options: i => {
|
_uid: i => i.uid,
|
||||||
const res = extend({}, resolveMergedOptions(i))
|
_data: i => i.data,
|
||||||
res.parent = i.proxy!.$parent
|
_isMounted: i => i.isMounted,
|
||||||
res.propsData = i.vnode.props
|
_isDestroyed: i => i.isUnmounted,
|
||||||
return res
|
|
||||||
},
|
|
||||||
|
|
||||||
// some private properties that are likely accessed...
|
// v2 render helpers
|
||||||
_self: i => i.proxy,
|
$createElement: () => compatH,
|
||||||
_uid: i => i.uid,
|
_c: () => compatH,
|
||||||
_data: i => i.data,
|
_o: () => legacyMarkOnce,
|
||||||
_isMounted: i => i.isMounted,
|
_n: () => looseToNumber,
|
||||||
_isDestroyed: i => i.isUnmounted,
|
_s: () => toDisplayString,
|
||||||
|
_l: () => renderList,
|
||||||
|
_t: i => legacyRenderSlot.bind(null, i),
|
||||||
|
_q: () => looseEqual,
|
||||||
|
_i: () => looseIndexOf,
|
||||||
|
_m: i => legacyRenderStatic.bind(null, i),
|
||||||
|
_f: () => resolveFilter,
|
||||||
|
_k: i => legacyCheckKeyCodes.bind(null, i),
|
||||||
|
_b: () => legacyBindObjectProps,
|
||||||
|
_v: () => createTextVNode,
|
||||||
|
_e: () => createCommentVNode,
|
||||||
|
_u: () => legacyresolveScopedSlots,
|
||||||
|
_g: () => legacyBindObjectListeners,
|
||||||
|
_d: () => legacyBindDynamicKeys,
|
||||||
|
_p: () => legacyPrependModifier,
|
||||||
|
} as PublicPropertiesMap
|
||||||
|
|
||||||
// v2 render helpers
|
for (const key in privateAPIs) {
|
||||||
$createElement: () => compatH,
|
map[key] = i => {
|
||||||
_c: () => compatH,
|
if (isCompatEnabled(DeprecationTypes.PRIVATE_APIS, i)) {
|
||||||
_o: () => legacyMarkOnce,
|
return privateAPIs[key](i)
|
||||||
_n: () => looseToNumber,
|
}
|
||||||
_s: () => toDisplayString,
|
}
|
||||||
_l: () => renderList,
|
|
||||||
_t: i => legacyRenderSlot.bind(null, i),
|
|
||||||
_q: () => looseEqual,
|
|
||||||
_i: () => looseIndexOf,
|
|
||||||
_m: i => legacyRenderStatic.bind(null, i),
|
|
||||||
_f: () => resolveFilter,
|
|
||||||
_k: i => legacyCheckKeyCodes.bind(null, i),
|
|
||||||
_b: () => legacyBindObjectProps,
|
|
||||||
_v: () => createTextVNode,
|
|
||||||
_e: () => createCommentVNode,
|
|
||||||
_u: () => legacyresolveScopedSlots,
|
|
||||||
_g: () => legacyBindObjectListeners,
|
|
||||||
_d: () => legacyBindDynamicKeys,
|
|
||||||
_p: () => legacyPrependModifier,
|
|
||||||
} as PublicPropertiesMap)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ import { type Directive, validateDirectiveName } from './directives'
|
||||||
import {
|
import {
|
||||||
type ComponentOptions,
|
type ComponentOptions,
|
||||||
type ComputedOptions,
|
type ComputedOptions,
|
||||||
|
type MergedComponentOptions,
|
||||||
type MethodOptions,
|
type MethodOptions,
|
||||||
applyOptions,
|
applyOptions,
|
||||||
resolveMergedOptions,
|
resolveMergedOptions,
|
||||||
|
@ -528,6 +529,12 @@ export interface ComponentInternalInstance {
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
getCssVars?: () => Record<string, string>
|
getCssVars?: () => Record<string, string>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* v2 compat only, for caching mutated $options
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
resolvedOptions?: MergedComponentOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
const emptyAppContext = createAppContext()
|
const emptyAppContext = createAppContext()
|
||||||
|
@ -780,8 +787,7 @@ function setupStatefulComponent(
|
||||||
// 0. create render proxy property access cache
|
// 0. create render proxy property access cache
|
||||||
instance.accessCache = Object.create(null)
|
instance.accessCache = Object.create(null)
|
||||||
// 1. create public instance / render proxy
|
// 1. create public instance / render proxy
|
||||||
// also mark it raw so it's never observed
|
instance.proxy = new Proxy(instance.ctx, PublicInstanceProxyHandlers)
|
||||||
instance.proxy = markRaw(new Proxy(instance.ctx, PublicInstanceProxyHandlers))
|
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
exposePropsOnRenderContext(instance)
|
exposePropsOnRenderContext(instance)
|
||||||
}
|
}
|
||||||
|
@ -1010,36 +1016,28 @@ export function finishComponentSetup(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAttrsProxy(instance: ComponentInternalInstance): Data {
|
const attrsProxyHandlers = __DEV__
|
||||||
return (
|
? {
|
||||||
instance.attrsProxy ||
|
get(target: Data, key: string) {
|
||||||
(instance.attrsProxy = new Proxy(
|
markAttrsAccessed()
|
||||||
instance.attrs,
|
track(target, TrackOpTypes.GET, '')
|
||||||
__DEV__
|
return target[key]
|
||||||
? {
|
},
|
||||||
get(target, key: string) {
|
set() {
|
||||||
markAttrsAccessed()
|
warn(`setupContext.attrs is readonly.`)
|
||||||
track(instance, TrackOpTypes.GET, '$attrs')
|
return false
|
||||||
return target[key]
|
},
|
||||||
},
|
deleteProperty() {
|
||||||
set() {
|
warn(`setupContext.attrs is readonly.`)
|
||||||
warn(`setupContext.attrs is readonly.`)
|
return false
|
||||||
return false
|
},
|
||||||
},
|
}
|
||||||
deleteProperty() {
|
: {
|
||||||
warn(`setupContext.attrs is readonly.`)
|
get(target: Data, key: string) {
|
||||||
return false
|
track(target, TrackOpTypes.GET, '')
|
||||||
},
|
return target[key]
|
||||||
}
|
},
|
||||||
: {
|
}
|
||||||
get(target, key: string) {
|
|
||||||
track(instance, TrackOpTypes.GET, '$attrs')
|
|
||||||
return target[key]
|
|
||||||
},
|
|
||||||
},
|
|
||||||
))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dev-only
|
* Dev-only
|
||||||
|
@ -1086,9 +1084,13 @@ export function createSetupContext(
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
// We use getters in dev in case libs like test-utils overwrite instance
|
// We use getters in dev in case libs like test-utils overwrite instance
|
||||||
// properties (overwrites should not be done in prod)
|
// properties (overwrites should not be done in prod)
|
||||||
|
let attrsProxy: Data
|
||||||
return Object.freeze({
|
return Object.freeze({
|
||||||
get attrs() {
|
get attrs() {
|
||||||
return getAttrsProxy(instance)
|
return (
|
||||||
|
attrsProxy ||
|
||||||
|
(attrsProxy = new Proxy(instance.attrs, attrsProxyHandlers))
|
||||||
|
)
|
||||||
},
|
},
|
||||||
get slots() {
|
get slots() {
|
||||||
return getSlotsProxy(instance)
|
return getSlotsProxy(instance)
|
||||||
|
@ -1100,9 +1102,7 @@ export function createSetupContext(
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
get attrs() {
|
attrs: new Proxy(instance.attrs, attrsProxyHandlers),
|
||||||
return getAttrsProxy(instance)
|
|
||||||
},
|
|
||||||
slots: instance.slots,
|
slots: instance.slots,
|
||||||
emit: instance.emit,
|
emit: instance.emit,
|
||||||
expose,
|
expose,
|
||||||
|
|
|
@ -12,7 +12,6 @@ import {
|
||||||
PatchFlags,
|
PatchFlags,
|
||||||
camelize,
|
camelize,
|
||||||
capitalize,
|
capitalize,
|
||||||
def,
|
|
||||||
extend,
|
extend,
|
||||||
hasOwn,
|
hasOwn,
|
||||||
hyphenate,
|
hyphenate,
|
||||||
|
@ -34,7 +33,6 @@ import {
|
||||||
setCurrentInstance,
|
setCurrentInstance,
|
||||||
} from './component'
|
} from './component'
|
||||||
import { isEmitListener } from './componentEmits'
|
import { isEmitListener } from './componentEmits'
|
||||||
import { InternalObjectKey } from './vnode'
|
|
||||||
import type { AppContext } from './apiCreateApp'
|
import type { AppContext } from './apiCreateApp'
|
||||||
import { createPropsDefaultThis } from './compat/props'
|
import { createPropsDefaultThis } from './compat/props'
|
||||||
import { isCompatEnabled, softAssertCompatEnabled } from './compat/compatConfig'
|
import { isCompatEnabled, softAssertCompatEnabled } from './compat/compatConfig'
|
||||||
|
@ -187,6 +185,13 @@ type NormalizedProp =
|
||||||
export type NormalizedProps = Record<string, NormalizedProp>
|
export type NormalizedProps = Record<string, NormalizedProp>
|
||||||
export type NormalizedPropsOptions = [NormalizedProps, string[]] | []
|
export type NormalizedPropsOptions = [NormalizedProps, string[]] | []
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used during vnode props normalization to check if the vnode props is the
|
||||||
|
* attrs object of a component via `Object.getPrototypeOf`. This is more
|
||||||
|
* performant than defining a non-enumerable property.
|
||||||
|
*/
|
||||||
|
export const attrsProto = {}
|
||||||
|
|
||||||
export function initProps(
|
export function initProps(
|
||||||
instance: ComponentInternalInstance,
|
instance: ComponentInternalInstance,
|
||||||
rawProps: Data | null,
|
rawProps: Data | null,
|
||||||
|
@ -194,8 +199,7 @@ export function initProps(
|
||||||
isSSR = false,
|
isSSR = false,
|
||||||
) {
|
) {
|
||||||
const props: Data = {}
|
const props: Data = {}
|
||||||
const attrs: Data = {}
|
const attrs: Data = Object.create(attrsProto)
|
||||||
def(attrs, InternalObjectKey, 1)
|
|
||||||
|
|
||||||
instance.propsDefaults = Object.create(null)
|
instance.propsDefaults = Object.create(null)
|
||||||
|
|
||||||
|
@ -361,7 +365,7 @@ export function updateProps(
|
||||||
|
|
||||||
// trigger updates for $attrs in case it's used in component slots
|
// trigger updates for $attrs in case it's used in component slots
|
||||||
if (hasAttrsChanged) {
|
if (hasAttrsChanged) {
|
||||||
trigger(instance, TriggerOpTypes.SET, '$attrs')
|
trigger(instance.attrs, TriggerOpTypes.SET, '')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import {
|
||||||
isString,
|
isString,
|
||||||
} from '@vue/shared'
|
} from '@vue/shared'
|
||||||
import {
|
import {
|
||||||
|
ReactiveFlags,
|
||||||
type ShallowUnwrapRef,
|
type ShallowUnwrapRef,
|
||||||
TrackOpTypes,
|
TrackOpTypes,
|
||||||
type UnwrapNestedRefs,
|
type UnwrapNestedRefs,
|
||||||
|
@ -306,6 +307,10 @@ const hasSetupBinding = (state: Data, key: string) =>
|
||||||
|
|
||||||
export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
|
export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
|
||||||
get({ _: instance }: ComponentRenderContext, key: string) {
|
get({ _: instance }: ComponentRenderContext, key: string) {
|
||||||
|
if (key === ReactiveFlags.SKIP) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
const { ctx, setupState, data, props, accessCache, type, appContext } =
|
const { ctx, setupState, data, props, accessCache, type, appContext } =
|
||||||
instance
|
instance
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { type ComponentInternalInstance, currentInstance } from './component'
|
import { type ComponentInternalInstance, currentInstance } from './component'
|
||||||
import {
|
import {
|
||||||
InternalObjectKey,
|
|
||||||
type VNode,
|
type VNode,
|
||||||
type VNodeChild,
|
type VNodeChild,
|
||||||
type VNodeNormalizedChildren,
|
type VNodeNormalizedChildren,
|
||||||
|
@ -174,7 +173,7 @@ export const initSlots = (
|
||||||
// we should avoid the proxy object polluting the slots of the internal instance
|
// we should avoid the proxy object polluting the slots of the internal instance
|
||||||
instance.slots = toRaw(children as InternalSlots)
|
instance.slots = toRaw(children as InternalSlots)
|
||||||
// make compiler marker non-enumerable
|
// make compiler marker non-enumerable
|
||||||
def(children as InternalSlots, '_', type)
|
def(instance.slots, '_', type)
|
||||||
} else {
|
} else {
|
||||||
normalizeObjectSlots(
|
normalizeObjectSlots(
|
||||||
children as RawSlots,
|
children as RawSlots,
|
||||||
|
@ -188,7 +187,6 @@ export const initSlots = (
|
||||||
normalizeVNodeSlots(instance, children)
|
normalizeVNodeSlots(instance, children)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def(instance.slots, InternalObjectKey, 1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateSlots = (
|
export const updateSlots = (
|
||||||
|
|
|
@ -254,7 +254,7 @@ const KeepAliveImpl: ComponentOptions = {
|
||||||
pendingCacheKey = null
|
pendingCacheKey = null
|
||||||
|
|
||||||
if (!slots.default) {
|
if (!slots.default) {
|
||||||
return null
|
return (current = null)
|
||||||
}
|
}
|
||||||
|
|
||||||
const children = slots.default()
|
const children = slots.default()
|
||||||
|
|
|
@ -99,7 +99,11 @@ export const SuspenseImpl = {
|
||||||
// 2. mounting along with the pendingBranch of parentSuspense
|
// 2. mounting along with the pendingBranch of parentSuspense
|
||||||
// it is necessary to skip the current patch to avoid multiple mounts
|
// it is necessary to skip the current patch to avoid multiple mounts
|
||||||
// of inner components.
|
// of inner components.
|
||||||
if (parentSuspense && parentSuspense.deps > 0) {
|
if (
|
||||||
|
parentSuspense &&
|
||||||
|
parentSuspense.deps > 0 &&
|
||||||
|
!n1.suspense!.isInFallback
|
||||||
|
) {
|
||||||
n2.suspense = n1.suspense!
|
n2.suspense = n1.suspense!
|
||||||
n2.suspense.vnode = n2
|
n2.suspense.vnode = n2
|
||||||
n2.el = n1.el
|
n2.el = n1.el
|
||||||
|
|
|
@ -123,6 +123,7 @@ export const devtoolsComponentRemoved = (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! #__NO_SIDE_EFFECTS__ */
|
||||||
function createDevtoolsComponentHook(hook: DevtoolsHooks) {
|
function createDevtoolsComponentHook(hook: DevtoolsHooks) {
|
||||||
return (component: ComponentInternalInstance) => {
|
return (component: ComponentInternalInstance) => {
|
||||||
emit(
|
emit(
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
|
import { pauseTracking, resetTracking } from '@vue/reactivity'
|
||||||
import type { VNode } from './vnode'
|
import type { VNode } from './vnode'
|
||||||
import type { ComponentInternalInstance } from './component'
|
import type { ComponentInternalInstance } from './component'
|
||||||
import { popWarningContext, pushWarningContext, warn } from './warning'
|
import { popWarningContext, pushWarningContext, warn } from './warning'
|
||||||
import { isFunction, isPromise } from '@vue/shared'
|
import { isArray, isFunction, isPromise } from '@vue/shared'
|
||||||
import { LifecycleHooks } from './enums'
|
import { LifecycleHooks } from './enums'
|
||||||
|
|
||||||
// contexts where user provided function may be executed, in addition to
|
// contexts where user provided function may be executed, in addition to
|
||||||
|
@ -78,7 +79,7 @@ export function callWithAsyncErrorHandling(
|
||||||
instance: ComponentInternalInstance | null,
|
instance: ComponentInternalInstance | null,
|
||||||
type: ErrorTypes,
|
type: ErrorTypes,
|
||||||
args?: unknown[],
|
args?: unknown[],
|
||||||
): any[] {
|
): any {
|
||||||
if (isFunction(fn)) {
|
if (isFunction(fn)) {
|
||||||
const res = callWithErrorHandling(fn, instance, type, args)
|
const res = callWithErrorHandling(fn, instance, type, args)
|
||||||
if (res && isPromise(res)) {
|
if (res && isPromise(res)) {
|
||||||
|
@ -89,11 +90,17 @@ export function callWithAsyncErrorHandling(
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
const values = []
|
if (isArray(fn)) {
|
||||||
for (let i = 0; i < fn.length; i++) {
|
const values = []
|
||||||
values.push(callWithAsyncErrorHandling(fn[i], instance, type, args))
|
for (let i = 0; i < fn.length; i++) {
|
||||||
|
values.push(callWithAsyncErrorHandling(fn[i], instance, type, args))
|
||||||
|
}
|
||||||
|
return values
|
||||||
|
} else if (__DEV__) {
|
||||||
|
warn(
|
||||||
|
`Invalid value type passed to callWithAsyncErrorHandling(): ${typeof fn}`,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return values
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handleError(
|
export function handleError(
|
||||||
|
@ -127,12 +134,14 @@ export function handleError(
|
||||||
// app-level handling
|
// app-level handling
|
||||||
const appErrorHandler = instance.appContext.config.errorHandler
|
const appErrorHandler = instance.appContext.config.errorHandler
|
||||||
if (appErrorHandler) {
|
if (appErrorHandler) {
|
||||||
|
pauseTracking()
|
||||||
callWithErrorHandling(
|
callWithErrorHandling(
|
||||||
appErrorHandler,
|
appErrorHandler,
|
||||||
null,
|
null,
|
||||||
ErrorCodes.APP_ERROR_HANDLER,
|
ErrorCodes.APP_ERROR_HANDLER,
|
||||||
[err, exposedInstance, errorInfo],
|
[err, exposedInstance, errorInfo],
|
||||||
)
|
)
|
||||||
|
resetTracking()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,6 +120,7 @@ export function createHydrationFunctions(
|
||||||
slotScopeIds: string[] | null,
|
slotScopeIds: string[] | null,
|
||||||
optimized = false,
|
optimized = false,
|
||||||
): Node | null => {
|
): Node | null => {
|
||||||
|
optimized = optimized || !!vnode.dynamicChildren
|
||||||
const isFragmentStart = isComment(node) && node.data === '['
|
const isFragmentStart = isComment(node) && node.data === '['
|
||||||
const onMismatch = () =>
|
const onMismatch = () =>
|
||||||
handleMismatch(
|
handleMismatch(
|
||||||
|
@ -443,6 +444,7 @@ export function createHydrationFunctions(
|
||||||
if (props) {
|
if (props) {
|
||||||
if (
|
if (
|
||||||
__DEV__ ||
|
__DEV__ ||
|
||||||
|
__FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ||
|
||||||
forcePatch ||
|
forcePatch ||
|
||||||
!optimized ||
|
!optimized ||
|
||||||
patchFlag & (PatchFlags.FULL_PROPS | PatchFlags.NEED_HYDRATION)
|
patchFlag & (PatchFlags.FULL_PROPS | PatchFlags.NEED_HYDRATION)
|
||||||
|
@ -450,7 +452,7 @@ export function createHydrationFunctions(
|
||||||
for (const key in props) {
|
for (const key in props) {
|
||||||
// check hydration mismatch
|
// check hydration mismatch
|
||||||
if (
|
if (
|
||||||
__DEV__ &&
|
(__DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__) &&
|
||||||
propHasMismatch(el, key, props[key], vnode, parentComponent)
|
propHasMismatch(el, key, props[key], vnode, parentComponent)
|
||||||
) {
|
) {
|
||||||
hasMismatch = true
|
hasMismatch = true
|
||||||
|
|
|
@ -55,6 +55,7 @@ import { convertLegacyVModelProps } from './compat/componentVModel'
|
||||||
import { defineLegacyVNodeProperties } from './compat/renderFn'
|
import { defineLegacyVNodeProperties } from './compat/renderFn'
|
||||||
import { ErrorCodes, callWithAsyncErrorHandling } from './errorHandling'
|
import { ErrorCodes, callWithAsyncErrorHandling } from './errorHandling'
|
||||||
import type { ComponentPublicInstance } from './componentPublicInstance'
|
import type { ComponentPublicInstance } from './componentPublicInstance'
|
||||||
|
import { attrsProto } from './componentProps'
|
||||||
|
|
||||||
export const Fragment = Symbol.for('v-fgt') as any as {
|
export const Fragment = Symbol.for('v-fgt') as any as {
|
||||||
__isFragment: true
|
__isFragment: true
|
||||||
|
@ -404,8 +405,6 @@ const createVNodeWithArgsTransform = (
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const InternalObjectKey = `__vInternal`
|
|
||||||
|
|
||||||
const normalizeKey = ({ key }: VNodeProps): VNode['key'] =>
|
const normalizeKey = ({ key }: VNodeProps): VNode['key'] =>
|
||||||
key != null ? key : null
|
key != null ? key : null
|
||||||
|
|
||||||
|
@ -618,7 +617,7 @@ function _createVNode(
|
||||||
|
|
||||||
export function guardReactiveProps(props: (Data & VNodeProps) | null) {
|
export function guardReactiveProps(props: (Data & VNodeProps) | null) {
|
||||||
if (!props) return null
|
if (!props) return null
|
||||||
return isProxy(props) || InternalObjectKey in props
|
return isProxy(props) || Object.getPrototypeOf(props) === attrsProto
|
||||||
? extend({}, props)
|
? extend({}, props)
|
||||||
: props
|
: props
|
||||||
}
|
}
|
||||||
|
@ -792,7 +791,7 @@ export function normalizeChildren(vnode: VNode, children: unknown) {
|
||||||
} else {
|
} else {
|
||||||
type = ShapeFlags.SLOTS_CHILDREN
|
type = ShapeFlags.SLOTS_CHILDREN
|
||||||
const slotFlag = (children as RawSlots)._
|
const slotFlag = (children as RawSlots)._
|
||||||
if (!slotFlag && !(InternalObjectKey in children!)) {
|
if (!slotFlag) {
|
||||||
// if slots are not normalized, attach context instance
|
// if slots are not normalized, attach context instance
|
||||||
// (compiled / normalized slots already have context)
|
// (compiled / normalized slots already have context)
|
||||||
;(children as RawSlots)._ctx = currentRenderingInstance
|
;(children as RawSlots)._ctx = currentRenderingInstance
|
||||||
|
|
|
@ -45,7 +45,7 @@ export function warn(msg: string, ...args: any[]) {
|
||||||
instance,
|
instance,
|
||||||
ErrorCodes.APP_WARN_HANDLER,
|
ErrorCodes.APP_WARN_HANDLER,
|
||||||
[
|
[
|
||||||
msg + args.join(''),
|
msg + args.map(a => a.toString?.() ?? JSON.stringify(a)).join(''),
|
||||||
instance && instance.proxy,
|
instance && instance.proxy,
|
||||||
trace
|
trace
|
||||||
.map(
|
.map(
|
||||||
|
|
|
@ -139,6 +139,12 @@ describe('defineCustomElement', () => {
|
||||||
expect(e.shadowRoot!.innerHTML).toBe('<div></div><div>two</div>')
|
expect(e.shadowRoot!.innerHTML).toBe('<div></div><div>two</div>')
|
||||||
expect(e.hasAttribute('foo')).toBe(false)
|
expect(e.hasAttribute('foo')).toBe(false)
|
||||||
|
|
||||||
|
e.foo = undefined
|
||||||
|
await nextTick()
|
||||||
|
expect(e.shadowRoot!.innerHTML).toBe('<div></div><div>two</div>')
|
||||||
|
expect(e.hasAttribute('foo')).toBe(false)
|
||||||
|
expect(e.foo).toBe(undefined)
|
||||||
|
|
||||||
e.bazQux = 'four'
|
e.bazQux = 'four'
|
||||||
await nextTick()
|
await nextTick()
|
||||||
expect(e.shadowRoot!.innerHTML).toBe('<div></div><div>four</div>')
|
expect(e.shadowRoot!.innerHTML).toBe('<div></div><div>four</div>')
|
||||||
|
|
|
@ -1237,4 +1237,73 @@ describe('vModel', () => {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
expect(data.value).toEqual('使用拼音输入')
|
expect(data.value).toEqual('使用拼音输入')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('multiple select (model is number, option value is string)', async () => {
|
||||||
|
const component = defineComponent({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
value: [1, 2],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render() {
|
||||||
|
return [
|
||||||
|
withVModel(
|
||||||
|
h(
|
||||||
|
'select',
|
||||||
|
{
|
||||||
|
multiple: true,
|
||||||
|
'onUpdate:modelValue': setValue.bind(this),
|
||||||
|
},
|
||||||
|
[h('option', { value: '1' }), h('option', { value: '2' })],
|
||||||
|
),
|
||||||
|
this.value,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
})
|
||||||
|
render(h(component), root)
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
const [foo, bar] = root.querySelectorAll('option')
|
||||||
|
|
||||||
|
expect(foo.selected).toEqual(true)
|
||||||
|
expect(bar.selected).toEqual(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
// #10503
|
||||||
|
test('equal value with a leading 0 should trigger update.', async () => {
|
||||||
|
const setNum = function (this: any, value: any) {
|
||||||
|
this.num = value
|
||||||
|
}
|
||||||
|
const component = defineComponent({
|
||||||
|
data() {
|
||||||
|
return { num: 0 }
|
||||||
|
},
|
||||||
|
render() {
|
||||||
|
return [
|
||||||
|
withVModel(
|
||||||
|
h('input', {
|
||||||
|
id: 'input_num1',
|
||||||
|
type: 'number',
|
||||||
|
'onUpdate:modelValue': setNum.bind(this),
|
||||||
|
}),
|
||||||
|
this.num,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
render(h(component), root)
|
||||||
|
const data = root._vnode.component.data
|
||||||
|
|
||||||
|
const inputNum1 = root.querySelector('#input_num1')!
|
||||||
|
expect(inputNum1.value).toBe('0')
|
||||||
|
|
||||||
|
inputNum1.value = '01'
|
||||||
|
triggerEvent('input', inputNum1)
|
||||||
|
await nextTick()
|
||||||
|
expect(data.num).toBe(1)
|
||||||
|
|
||||||
|
expect(inputNum1.value).toBe('1')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -118,6 +118,63 @@ describe('useCssVars', () => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('with v-if & async component & suspense', async () => {
|
||||||
|
const state = reactive({ color: 'red' })
|
||||||
|
const root = document.createElement('div')
|
||||||
|
const show = ref(false)
|
||||||
|
let resolveAsync: any
|
||||||
|
let asyncPromise: any
|
||||||
|
|
||||||
|
const AsyncComp = {
|
||||||
|
setup() {
|
||||||
|
useCssVars(() => state)
|
||||||
|
asyncPromise = new Promise(r => {
|
||||||
|
resolveAsync = () => {
|
||||||
|
r(() => h('p', 'default'))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return asyncPromise
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const App = {
|
||||||
|
setup() {
|
||||||
|
return () =>
|
||||||
|
h(Suspense, null, {
|
||||||
|
default: h('div', {}, show.value ? h(AsyncComp) : h('p')),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
render(h(App), root)
|
||||||
|
await nextTick()
|
||||||
|
// AsyncComp resolve
|
||||||
|
show.value = true
|
||||||
|
await nextTick()
|
||||||
|
resolveAsync()
|
||||||
|
await asyncPromise.then(() => {})
|
||||||
|
// Suspense effects flush
|
||||||
|
await nextTick()
|
||||||
|
// css vars use with default tree
|
||||||
|
for (const c of [].slice.call(root.children as any)) {
|
||||||
|
expect(
|
||||||
|
((c as any).children[0] as HTMLElement).style.getPropertyValue(
|
||||||
|
`--color`,
|
||||||
|
),
|
||||||
|
).toBe(`red`)
|
||||||
|
}
|
||||||
|
|
||||||
|
state.color = 'green'
|
||||||
|
await nextTick()
|
||||||
|
for (const c of [].slice.call(root.children as any)) {
|
||||||
|
expect(
|
||||||
|
((c as any).children[0] as HTMLElement).style.getPropertyValue(
|
||||||
|
`--color`,
|
||||||
|
),
|
||||||
|
).toBe('green')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
test('with subTree changed', async () => {
|
test('with subTree changed', async () => {
|
||||||
const state = reactive({ color: 'red' })
|
const state = reactive({ color: 'red' })
|
||||||
const value = ref(true)
|
const value = ref(true)
|
||||||
|
|
|
@ -192,4 +192,14 @@ describe(`runtime-dom: events patching`, () => {
|
||||||
testElement.dispatchEvent(new CustomEvent('foobar'))
|
testElement.dispatchEvent(new CustomEvent('foobar'))
|
||||||
expect(fn2).toHaveBeenCalledTimes(1)
|
expect(fn2).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('handles an unknown type', () => {
|
||||||
|
const el = document.createElement('div')
|
||||||
|
patchProp(el, 'onClick', null, 'test')
|
||||||
|
el.dispatchEvent(new Event('click'))
|
||||||
|
expect(
|
||||||
|
`Wrong type passed as event handler to onClick - did you forget @ or : ` +
|
||||||
|
`in front of your prop?\nExpected function or array of functions, received type string.`,
|
||||||
|
).toHaveBeenWarned()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -291,6 +291,18 @@ describe('runtime-dom: props patching', () => {
|
||||||
expect(el.value).toBe('baz')
|
expect(el.value).toBe('baz')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('init empty value for option', () => {
|
||||||
|
const root = document.createElement('div')
|
||||||
|
render(
|
||||||
|
h('select', { value: 'foo' }, [h('option', { value: '' }, 'foo')]),
|
||||||
|
root,
|
||||||
|
)
|
||||||
|
const select = root.children[0] as HTMLSelectElement
|
||||||
|
const option = select.children[0] as HTMLOptionElement
|
||||||
|
expect(select.value).toBe('')
|
||||||
|
expect(option.value).toBe('')
|
||||||
|
})
|
||||||
|
|
||||||
// #8780
|
// #8780
|
||||||
test('embedded tag with width and height', () => {
|
test('embedded tag with width and height', () => {
|
||||||
// Width and height of some embedded element such as img、video、source、canvas
|
// Width and height of some embedded element such as img、video、source、canvas
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vue/runtime-dom",
|
"name": "@vue/runtime-dom",
|
||||||
"version": "3.4.20",
|
"version": "3.4.22",
|
||||||
"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",
|
||||||
|
|
|
@ -313,7 +313,7 @@ export class VueElement extends BaseClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected _setAttr(key: string) {
|
protected _setAttr(key: string) {
|
||||||
let value = this.getAttribute(key)
|
let value = this.hasAttribute(key) ? this.getAttribute(key) : undefined
|
||||||
const camelKey = camelize(key)
|
const camelKey = camelize(key)
|
||||||
if (this._numberProps && this._numberProps[camelKey]) {
|
if (this._numberProps && this._numberProps[camelKey]) {
|
||||||
value = toNumber(value)
|
value = toNumber(value)
|
||||||
|
|
|
@ -112,7 +112,29 @@ const TransitionGroupImpl: ComponentOptions = {
|
||||||
tag = 'span'
|
tag = 'span'
|
||||||
}
|
}
|
||||||
|
|
||||||
prevChildren = children
|
prevChildren = []
|
||||||
|
if (children) {
|
||||||
|
for (let i = 0; i < children.length; i++) {
|
||||||
|
const child = children[i]
|
||||||
|
if (child.el && child.el instanceof Element) {
|
||||||
|
prevChildren.push(child)
|
||||||
|
setTransitionHooks(
|
||||||
|
child,
|
||||||
|
resolveTransitionHooks(
|
||||||
|
child,
|
||||||
|
cssTransitionProps,
|
||||||
|
state,
|
||||||
|
instance,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
positionMap.set(
|
||||||
|
child,
|
||||||
|
(child.el as Element).getBoundingClientRect(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
children = slots.default ? getTransitionRawChildren(slots.default()) : []
|
children = slots.default ? getTransitionRawChildren(slots.default()) : []
|
||||||
|
|
||||||
for (let i = 0; i < children.length; i++) {
|
for (let i = 0; i < children.length; i++) {
|
||||||
|
@ -127,17 +149,6 @@ const TransitionGroupImpl: ComponentOptions = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prevChildren) {
|
|
||||||
for (let i = 0; i < prevChildren.length; i++) {
|
|
||||||
const child = prevChildren[i]
|
|
||||||
setTransitionHooks(
|
|
||||||
child,
|
|
||||||
resolveTransitionHooks(child, cssTransitionProps, state, instance),
|
|
||||||
)
|
|
||||||
positionMap.set(child, (child.el as Element).getBoundingClientRect())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return createVNode(tag, null, children)
|
return createVNode(tag, null, children)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -86,9 +86,10 @@ export const vModelText: ModelDirective<
|
||||||
el[assignKey] = getModelAssigner(vnode)
|
el[assignKey] = getModelAssigner(vnode)
|
||||||
// avoid clearing unresolved text. #2302
|
// avoid clearing unresolved text. #2302
|
||||||
if ((el as any).composing) return
|
if ((el as any).composing) return
|
||||||
|
|
||||||
const elValue =
|
const elValue =
|
||||||
number || el.type === 'number' ? looseToNumber(el.value) : el.value
|
(number || el.type === 'number') && !/^0\d/.test(el.value)
|
||||||
|
? looseToNumber(el.value)
|
||||||
|
: el.value
|
||||||
const newValue = value == null ? '' : value
|
const newValue = value == null ? '' : value
|
||||||
|
|
||||||
if (elValue === newValue) {
|
if (elValue === newValue) {
|
||||||
|
@ -242,9 +243,7 @@ function setSelected(el: HTMLSelectElement, value: any, number: boolean) {
|
||||||
const optionType = typeof optionValue
|
const optionType = typeof optionValue
|
||||||
// fast path for string / number values
|
// fast path for string / number values
|
||||||
if (optionType === 'string' || optionType === 'number') {
|
if (optionType === 'string' || optionType === 'number') {
|
||||||
option.selected = value.includes(
|
option.selected = value.some(v => String(v) === String(optionValue))
|
||||||
number ? looseToNumber(optionValue) : optionValue,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
option.selected = looseIndexOf(value, optionValue) > -1
|
option.selected = looseIndexOf(value, optionValue) > -1
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,9 +42,8 @@ export function useCssVars(getter: (ctx: any) => Record<string, string>) {
|
||||||
updateTeleports(vars)
|
updateTeleports(vars)
|
||||||
}
|
}
|
||||||
|
|
||||||
watchPostEffect(setVars)
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
watchPostEffect(setVars)
|
||||||
const ob = new MutationObserver(setVars)
|
const ob = new MutationObserver(setVars)
|
||||||
ob.observe(instance.subTree.el!.parentNode, { childList: true })
|
ob.observe(instance.subTree.el!.parentNode, { childList: true })
|
||||||
onUnmounted(() => ob.disconnect())
|
onUnmounted(() => ob.disconnect())
|
||||||
|
|
|
@ -1348,8 +1348,9 @@ export interface Events {
|
||||||
// selection events
|
// selection events
|
||||||
onSelect: Event
|
onSelect: Event
|
||||||
|
|
||||||
// UI events
|
// scroll events
|
||||||
onScroll: UIEvent
|
onScroll: Event
|
||||||
|
onScrollend: Event
|
||||||
|
|
||||||
// touch events
|
// touch events
|
||||||
onTouchcancel: TouchEvent
|
onTouchcancel: TouchEvent
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import { hyphenate, isArray } from '@vue/shared'
|
import { NOOP, hyphenate, isArray, isFunction } from '@vue/shared'
|
||||||
import {
|
import {
|
||||||
type ComponentInternalInstance,
|
type ComponentInternalInstance,
|
||||||
ErrorCodes,
|
ErrorCodes,
|
||||||
callWithAsyncErrorHandling,
|
callWithAsyncErrorHandling,
|
||||||
|
warn,
|
||||||
} from '@vue/runtime-core'
|
} from '@vue/runtime-core'
|
||||||
|
|
||||||
interface Invoker extends EventListener {
|
interface Invoker extends EventListener {
|
||||||
|
@ -36,7 +37,7 @@ export function patchEvent(
|
||||||
el: Element & { [veiKey]?: Record<string, Invoker | undefined> },
|
el: Element & { [veiKey]?: Record<string, Invoker | undefined> },
|
||||||
rawName: string,
|
rawName: string,
|
||||||
prevValue: EventValue | null,
|
prevValue: EventValue | null,
|
||||||
nextValue: EventValue | null,
|
nextValue: EventValue | unknown,
|
||||||
instance: ComponentInternalInstance | null = null,
|
instance: ComponentInternalInstance | null = null,
|
||||||
) {
|
) {
|
||||||
// vei = vue event invokers
|
// vei = vue event invokers
|
||||||
|
@ -44,12 +45,19 @@ export function patchEvent(
|
||||||
const existingInvoker = invokers[rawName]
|
const existingInvoker = invokers[rawName]
|
||||||
if (nextValue && existingInvoker) {
|
if (nextValue && existingInvoker) {
|
||||||
// patch
|
// patch
|
||||||
existingInvoker.value = nextValue
|
existingInvoker.value = __DEV__
|
||||||
|
? sanitizeEventValue(nextValue, rawName)
|
||||||
|
: (nextValue as EventValue)
|
||||||
} else {
|
} else {
|
||||||
const [name, options] = parseName(rawName)
|
const [name, options] = parseName(rawName)
|
||||||
if (nextValue) {
|
if (nextValue) {
|
||||||
// add
|
// add
|
||||||
const invoker = (invokers[rawName] = createInvoker(nextValue, instance))
|
const invoker = (invokers[rawName] = createInvoker(
|
||||||
|
__DEV__
|
||||||
|
? sanitizeEventValue(nextValue, rawName)
|
||||||
|
: (nextValue as EventValue),
|
||||||
|
instance,
|
||||||
|
))
|
||||||
addEventListener(el, name, invoker, options)
|
addEventListener(el, name, invoker, options)
|
||||||
} else if (existingInvoker) {
|
} else if (existingInvoker) {
|
||||||
// remove
|
// remove
|
||||||
|
@ -116,6 +124,17 @@ function createInvoker(
|
||||||
return invoker
|
return invoker
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sanitizeEventValue(value: unknown, propName: string): EventValue {
|
||||||
|
if (isFunction(value) || isArray(value)) {
|
||||||
|
return value as EventValue
|
||||||
|
}
|
||||||
|
warn(
|
||||||
|
`Wrong type passed as event handler to ${propName} - did you forget @ or : ` +
|
||||||
|
`in front of your prop?\nExpected function or array of functions, received type ${typeof value}.`,
|
||||||
|
)
|
||||||
|
return NOOP
|
||||||
|
}
|
||||||
|
|
||||||
function patchStopImmediatePropagation(
|
function patchStopImmediatePropagation(
|
||||||
e: Event,
|
e: Event,
|
||||||
value: EventValue,
|
value: EventValue,
|
||||||
|
@ -126,7 +145,9 @@ function patchStopImmediatePropagation(
|
||||||
originalStop.call(e)
|
originalStop.call(e)
|
||||||
;(e as any)._stopped = true
|
;(e as any)._stopped = true
|
||||||
}
|
}
|
||||||
return value.map(fn => (e: Event) => !(e as any)._stopped && fn && fn(e))
|
return (value as Function[]).map(
|
||||||
|
fn => (e: Event) => !(e as any)._stopped && fn && fn(e),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,20 +34,20 @@ export function patchDOMProp(
|
||||||
// custom elements may use _value internally
|
// custom elements may use _value internally
|
||||||
!tag.includes('-')
|
!tag.includes('-')
|
||||||
) {
|
) {
|
||||||
// store value as _value as well since
|
|
||||||
// non-string values will be stringified.
|
|
||||||
el._value = value
|
|
||||||
// #4956: <option> value will fallback to its text content so we need to
|
// #4956: <option> value will fallback to its text content so we need to
|
||||||
// compare against its attribute value instead.
|
// compare against its attribute value instead.
|
||||||
const oldValue =
|
const oldValue =
|
||||||
tag === 'OPTION' ? el.getAttribute('value') || '' : el.value
|
tag === 'OPTION' ? el.getAttribute('value') || '' : el.value
|
||||||
const newValue = value == null ? '' : value
|
const newValue = value == null ? '' : value
|
||||||
if (oldValue !== newValue) {
|
if (oldValue !== newValue || !('_value' in el)) {
|
||||||
el.value = newValue
|
el.value = newValue
|
||||||
}
|
}
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
el.removeAttribute(key)
|
el.removeAttribute(key)
|
||||||
}
|
}
|
||||||
|
// store value as _value as well since
|
||||||
|
// non-string values will be stringified.
|
||||||
|
el._value = value
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vue/server-renderer",
|
"name": "@vue/server-renderer",
|
||||||
"version": "3.4.20",
|
"version": "3.4.22",
|
||||||
"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,7 +17,7 @@ import {
|
||||||
} from '@vue/shared'
|
} from '@vue/shared'
|
||||||
|
|
||||||
// leading comma for empty string ""
|
// leading comma for empty string ""
|
||||||
const shouldIgnoreProp = makeMap(
|
const shouldIgnoreProp = /*#__PURE__*/ makeMap(
|
||||||
`,key,ref,innerHTML,textContent,ref_key,ref_for`,
|
`,key,ref,innerHTML,textContent,ref_key,ref_for`,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^5.0.4",
|
"@vitejs/plugin-vue": "^5.0.4",
|
||||||
"vite": "^5.1.4"
|
"vite": "^5.2.7"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/repl": "^4.1.1",
|
"@vue/repl": "^4.1.1",
|
||||||
|
|
|
@ -27,7 +27,7 @@ export async function downloadProject(store: ReplStore) {
|
||||||
|
|
||||||
const files = store.getFiles()
|
const files = store.getFiles()
|
||||||
for (const file in files) {
|
for (const file in files) {
|
||||||
if (file !== 'import-map.json') {
|
if (file !== 'import-map.json' && file !== 'tsconfig.json') {
|
||||||
src.file(file, files[file])
|
src.file(file, files[file])
|
||||||
} else {
|
} else {
|
||||||
zip.file(file, files[file])
|
zip.file(file, files[file])
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Vite Vue Starter
|
# Vite Vue Starter
|
||||||
|
|
||||||
This is a project template using [Vite](https://vitejs.dev/). It requires [Node.js](https://nodejs.org) v12+.
|
This is a project template using [Vite](https://vitejs.dev/). It requires [Node.js](https://nodejs.org) version 18+, 20+.
|
||||||
|
|
||||||
To start:
|
To start:
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,6 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^5.0.4",
|
"@vitejs/plugin-vue": "^5.0.4",
|
||||||
"vite": "^5.1.4"
|
"vite": "^5.2.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,2 @@
|
||||||
// serve vue to the iframe sandbox during dev.
|
// serve vue to the iframe sandbox during dev.
|
||||||
// @ts-expect-error
|
|
||||||
export * from 'vue/dist/vue.runtime.esm-browser.prod.js'
|
export * from 'vue/dist/vue.runtime.esm-browser.prod.js'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vue/shared",
|
"name": "@vue/shared",
|
||||||
"version": "3.4.20",
|
"version": "3.4.22",
|
||||||
"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",
|
||||||
|
|
|
@ -165,6 +165,9 @@ export const toNumber = (val: any): any => {
|
||||||
return isNaN(n) ? val : n
|
return isNaN(n) ? val : n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for typeof global checks without @types/node
|
||||||
|
declare var global: {}
|
||||||
|
|
||||||
let _globalThis: any
|
let _globalThis: any
|
||||||
export const getGlobalThis = (): any => {
|
export const getGlobalThis = (): any => {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
* \/\*#\_\_PURE\_\_\*\/
|
* \/\*#\_\_PURE\_\_\*\/
|
||||||
* So that rollup can tree-shake them if necessary.
|
* So that rollup can tree-shake them if necessary.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*! #__NO_SIDE_EFFECTS__ */
|
||||||
export function makeMap(
|
export function makeMap(
|
||||||
str: string,
|
str: string,
|
||||||
expectsLowerCase?: boolean,
|
expectsLowerCase?: boolean,
|
||||||
|
|
|
@ -54,4 +54,6 @@ const replacer = (_key: string, val: any): any => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const stringifySymbol = (v: unknown, i: number | string = ''): any =>
|
const stringifySymbol = (v: unknown, i: number | string = ''): any =>
|
||||||
isSymbol(v) ? `Symbol(${v.description ?? i})` : v
|
// Symbol.description in es2019+ so we need to cast here to pass
|
||||||
|
// the lib: es2016 check
|
||||||
|
isSymbol(v) ? `Symbol(${(v as any).description ?? i})` : v
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
"enableNonBrowserBranches": true
|
"enableNonBrowserBranches": true
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"monaco-editor": "^0.46.0",
|
"monaco-editor": "^0.47.0",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue