Compare commits

...

291 Commits
v3.5.9 ... main

Author SHA1 Message Date
pengbo cdffaf6b9e
chore(compile-core): removed the optional tag parameter from condenseWhitespace's signature (#13437)
ci / test (push) Has been cancelled Details
ci / continuous-release (push) Has been cancelled Details
size data / upload (push) Has been cancelled Details
2025-06-06 08:25:02 +08:00
renovate[bot] a47832e75e
chore(deps): update dependency esbuild to ^0.25.5 (#13427)
ci / test (push) Waiting to run Details
ci / continuous-release (push) Waiting to run Details
size data / upload (push) Waiting to run Details
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-05 10:39:31 +08:00
renovate[bot] e416f84d74
chore(deps): update all non-major dependencies (#13426)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-05 10:38:49 +08:00
daiwei 1b98aafa05 chore: update snap 2025-06-05 10:26:52 +08:00
Alex Snezhko 55dad625ac
fix(compiler-core): prevent comments from blocking static node hoisting (#13345)
close #13344
2025-06-05 10:23:00 +08:00
inottn 47ddf98602
fix(runtime-core): unset old ref during patching when new ref is absent (#12900)
fix #12898
2025-06-05 10:19:48 +08:00
SerKo e8d8f5f604
fix(reactivity): add `__v_skip` flag to `Dep` to prevent reactive conversion (#12804)
close #12803
2025-06-05 10:19:16 +08:00
edison 5ba1afba09
fix(custom-element): ensure configureApp is applied to async component (#12607)
close #12448
2025-06-05 10:10:52 +08:00
edison 73055d8d95
fix(custom-element): prevent injecting child styles if shadowRoot is false (#12769)
close #12630
2025-06-05 10:02:26 +08:00
Arman Tang 4aa7a4aba3
chore(shared): update patch flag name (#12831) 2025-06-05 10:01:51 +08:00
edison 4eb46e443f
fix(compile-sfc): handle mapped types work with omit and pick (#12648)
close #12647
2025-06-05 10:01:22 +08:00
edison 10ebcef8c8
fix(compiler-core): ignore whitespace when matching adjacent v-if (#12321)
close #9173
2025-06-05 09:44:25 +08:00
山吹色御守 f05a8d613b
fix(compiler-core): do not increase newlines in `InEntity` state (#13362) 2025-06-05 09:39:05 +08:00
山吹色御守 762fae4b57
fix(types): typo of `vOnce` and `vSlot` (#13343) 2025-06-05 09:36:47 +08:00
skirtle e53a4ffbe0
chore(hydration): reuse existing variable (#13412)
ci / test (push) Has been cancelled Details
ci / continuous-release (push) Has been cancelled Details
size data / upload (push) Has been cancelled Details
canary release / canary (push) Has been cancelled Details
canary minor release / canary (push) Has been cancelled Details
2025-05-30 14:43:23 +08:00
btea 62f2aa11a2
test(compiler-sfc): direct descendant wildcard rule selector (#13411)
add test case for #13387
2025-05-30 10:35:27 +08:00
daiwei a60f2bd371 chore: update changelog
ci / test (push) Has been cancelled Details
ci / continuous-release (push) Has been cancelled Details
size data / upload (push) Has been cancelled Details
2025-05-29 09:04:53 +08:00
daiwei e7381761cc release: v3.5.16 2025-05-29 08:24:16 +08:00
edison 19f23b180b
Revert "fix(compiler-sfc): add scoping tag to trailing universal selector (#1…" (#13406)
This reverts commit 949df80880.
2025-05-29 08:21:19 +08:00
Arpit Jain d9bd436b1a
chore: fix typos
ci / test (push) Waiting to run Details
ci / continuous-release (push) Waiting to run Details
size data / upload (push) Waiting to run Details
2025-05-28 08:26:28 +08:00
edison 42f879fcab
Revert "fix(compiler-sfc): add error handling for defineModel() without varia…" (#13390)
ci / test (push) Waiting to run Details
ci / continuous-release (push) Waiting to run Details
size data / upload (push) Waiting to run Details
This reverts commit 00734afef5.
2025-05-27 18:49:34 +08:00
daiwei d5ada3d235 release: v3.5.15
ci / test (push) Waiting to run Details
ci / continuous-release (push) Waiting to run Details
size data / upload (push) Waiting to run Details
2025-05-26 20:38:56 +08:00
renovate[bot] c017c7b8d3
chore(deps): update dependency lint-staged to v16 (#13381)
ci / test (push) Waiting to run Details
ci / continuous-release (push) Waiting to run Details
size data / upload (push) Waiting to run Details
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-26 09:45:16 +08:00
renovate[bot] 004f488a67
chore(deps): update dependency eslint-plugin-import-x to ^4.13.1 (#13380)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-26 09:41:35 +08:00
renovate[bot] 1ee3fcf929
chore(deps): update dependency @vitest/eslint-plugin to ^1.2.1 (#13379)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-26 09:28:23 +08:00
renovate[bot] c46d9f37ae
chore(deps): update build (#13378)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-26 09:27:29 +08:00
edison 9fa787cfd2
chore(workflow): add TypeScript type checking step to CI pipeline (#13367)
ci / test (push) Has been cancelled Details
ci / continuous-release (push) Has been cancelled Details
size data / upload (push) Has been cancelled Details
Lock Closed Issues / action (push) Has been cancelled Details
Auto close issues with "can't reproduce" label / close-issues (push) Has been cancelled Details
2025-05-22 15:48:20 +08:00
edison 2c6c0794a1
chore: fix type check error (#13366)
ci / test (push) Waiting to run Details
ci / continuous-release (push) Waiting to run Details
size data / upload (push) Waiting to run Details
2025-05-22 11:38:58 +08:00
yangxiuxiu 93949e6587
fix(compat): should not warn COMPILER_V_BIND_OBJECT_ORDER when using v-bind together with v-for (#12993)
fix #12992
2025-05-22 08:44:34 +08:00
thecodewarrior 949df80880
fix(compiler-sfc): add scoping tag to trailing universal selector (#12918)
close #12906
2025-05-22 08:41:27 +08:00
edison a683c80cf4
fix(custom-element): properly resolve props for sync component defs (#12855)
close #12854
2025-05-22 08:38:27 +08:00
edison 1d41d4de7f
fix(custom-element): ensure proper remount and prevent redundant slot parsing with shadowRoot false (#13201)
close #13199
2025-05-22 08:05:39 +08:00
Tycho 5179d328d9
fix(types): exclude `undefined` from inferred prop types with default values (#13007)
close #13006
2025-05-22 08:03:33 +08:00
renovate[bot] d53daf1f29
chore(deps): update all non-major dependencies (#13353)
ci / test (push) Waiting to run Details
ci / continuous-release (push) Waiting to run Details
size data / upload (push) Waiting to run Details
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-21 09:20:45 +08:00
renovate[bot] 2b894746bd
chore(deps): update test (#13354)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-21 09:17:42 +08:00
renovate[bot] 64d2ba9f47
chore(deps): update dependency rollup to ^4.41.0 (#13356)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-21 09:07:01 +08:00
renovate[bot] dc18a159e8
chore(deps): update lint (#13357)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-21 09:06:37 +08:00
Runyasak Chaengnaimuang 00734afef5
fix(compiler-sfc): add error handling for defineModel() without variable assignment (#13352)
close #13280
2025-05-21 09:06:05 +08:00
edison 89edc6cdcb
fix(compile-sfc): handle inline template source map in prod build (#12701)
ci / test (push) Waiting to run Details
ci / continuous-release (push) Waiting to run Details
size data / upload (push) Waiting to run Details
close #12682
close vitejs/vite-plugin-vue#500
2025-05-20 08:46:01 +08:00
Tycho f44feed6fa
fix(types): avoid merging component instance into `$props` in `ComponentInstance` (#12870)
close #12751
2025-05-20 08:44:35 +08:00
Tycho c69c4bb59c
fix(watch): update `oldValue` before running `cb` to prevent stale value (#12296)
close #12294
2025-05-20 08:44:13 +08:00
edison 1a664749d4
fix(compat): ensure false value on input retains value attribute (#13216)
close #13205
2025-05-20 08:43:51 +08:00
edison 013749e75e
fix(custom-element): preserve appContext during update (#12455)
close #12453
2025-05-20 08:34:36 +08:00
edison 35aeae7fa3
fix(hydration): handle transition appear hydration edge case (#13339)
close #13335
2025-05-20 08:28:43 +08:00
edison d15dce3142
fix(teleport): handle deferred teleport updates before and after mount (#13350)
close #13349
2025-05-20 08:27:54 +08:00
edison 163b3651d1
fix(compiler-dom): improve HTML nesting validation to allow any child element within template tag (#13320)
ci / test (push) Has been cancelled Details
ci / continuous-release (push) Has been cancelled Details
size data / upload (push) Has been cancelled Details
Lock Closed Issues / action (push) Has been cancelled Details
Auto close issues with "can't reproduce" label / close-issues (push) Has been cancelled Details
close #13318
2025-05-16 09:05:31 +08:00
Teages f7ce5ae666
fix(compiler-sfc): simulate `allowArbitraryExtensions` on resolving type (#13301)
close #13295
2025-05-16 08:38:47 +08:00
edison 772b0087cb
fix(suspense): handle edge case in patching list nodes within Suspense (#13306)
close #13305
2025-05-16 08:32:55 +08:00
linzhe cf5a5e0edf
fix(compiler-sfc): improve type inference for TSTypeAliasDeclaration with better runtime type detection (#13245)
close #13240
2025-05-16 08:32:13 +08:00
edison d37a2ac59d
fix(compiler-core): ensure mapping is added only if node source is available (#13285)
close #13261
close vitejs/vite-plugin-vue#368
2025-05-16 08:22:37 +08:00
edison 80055fddfb
fix(hydration): skip lazy hydration for patched components (#13283)
close #13255
2025-05-16 08:22:01 +08:00
Adrian Cerbaro b9910755a5
fix(custom-element): allow injecting values ​​from app context in nested elements (#13219)
close #13212)
2025-05-16 08:07:32 +08:00
daiwei d0253a0b7e release: v3.5.14
ci / test (push) Waiting to run Details
ci / continuous-release (push) Waiting to run Details
size data / upload (push) Waiting to run Details
2025-05-15 11:13:02 +08:00
edison 1f98a9c493
fix(hmr): avoid hydration for hmr root reload (#12450)
ci / test (push) Has been cancelled Details
ci / continuous-release (push) Has been cancelled Details
size data / upload (push) Has been cancelled Details
close vitejs/vite-plugin-vue#146
close vitejs/vite-plugin-vue#477
2025-05-13 22:23:23 +08:00
tonicli 626450590d
fix(runtime-core): inherit comment nodes during block patch in production build (#10748)
close #10747
close #12650
2025-05-13 22:18:28 +08:00
edison 8e3435779a
fix(compiler-sfc): fix scope handling for props destructure in function parameters and catch clauses
close #12790
2025-05-13 22:17:24 +08:00
yangxiuxiu 343c891224
fix(transition): fix KeepAlive with transition out-in mode behavior in production (#12468)
close #12465
2025-05-13 22:16:45 +08:00
edison 9c4dbbc518
fix(hmr): avoid hydration for hmr updating (#12262)
close #7706
close #8170
2025-05-13 22:15:50 +08:00
renovate[bot] f7dad6da2f
chore(deps): update dependency @babel/parser to ^7.27.2 (#13310)
ci / test (push) Waiting to run Details
ci / continuous-release (push) Waiting to run Details
size data / upload (push) Waiting to run Details
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-13 15:29:08 +08:00
renovate[bot] 258f78b643
chore(deps): update test (#13311)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-13 11:44:59 +08:00
btea 3cb4db21ef
chore: add pnpm setting to pnpm-workspace (#13268)
ci / test (push) Has been cancelled Details
ci / continuous-release (push) Has been cancelled Details
size data / upload (push) Has been cancelled Details
Lock Closed Issues / action (push) Has been cancelled Details
Auto close issues with "can't reproduce" label / close-issues (push) Has been cancelled Details
2025-05-10 22:19:53 +08:00
renovate[bot] d79aa70c61
chore(deps): update build (#13276)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-10 16:07:50 +08:00
edison f556c925ac
chore: fix typo (#13290) [ci skip]
ci / test (push) Has been cancelled Details
ci / continuous-release (push) Has been cancelled Details
size data / upload (push) Has been cancelled Details
2025-05-07 20:35:45 +08:00
renovate[bot] 56be3dd4db
chore(deps): update compiler to ^7.27.1 (#13277)
ci / test (push) Has been cancelled Details
ci / continuous-release (push) Has been cancelled Details
size data / upload (push) Has been cancelled Details
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-05 20:53:19 +08:00
Tycho 3f27c58ffb
fix(runtime-core): respect immutability for readonly reactive arrays in `v-for` (#13091)
ci / test (push) Has been cancelled Details
ci / continuous-release (push) Has been cancelled Details
size data / upload (push) Has been cancelled Details
close #13087
2025-05-02 02:55:24 -07:00
yangxiuxiu 9196222ae1
fix(slots): properly warn if slot invoked in setup (#12195)
close #12194
2025-05-02 02:53:14 -07:00
edison 2206cd235a
fix(ssr): properly init slots during ssr rendering (#12441)
close #12438
2025-05-02 02:48:03 -07:00
edison 5e37dd0095
fix(hmr/teleport): adjust static children traversal for HMR in dev mode (#12819)
close #12816
2025-05-02 02:18:01 -07:00
edison 0b23fd2383
fix(reactivity): should not recompute if computed does not track reactive data (#12341)
ci / test (push) Waiting to run Details
ci / continuous-release (push) Waiting to run Details
size data / upload (push) Waiting to run Details
close #12337
2025-05-01 07:02:17 -07:00
edison 8b848cbbd2
fix(TransitionGroup): reset prevChildren to prevent memory leak (#13183)
ci / test (push) Waiting to run Details
ci / continuous-release (push) Waiting to run Details
size data / upload (push) Waiting to run Details
close #13181
2025-05-01 02:58:07 -07:00
dopamine 016c472bd2
fix(runtime-core): stop tracking deps in setRef during unmount (#13210) 2025-05-01 02:56:42 -07:00
edison 5d166f3796
fix(compiler-core): remove slot cache from parent renderCache during unmounting (#13215)
* fix(compiler-core): remove slot cache from parent renderCache during unmounting

* chore: update
2025-05-01 02:55:36 -07:00
dopamine b3ecee3da8
fix(runtime-core): update __vnode of static nodes when patching along the optimized path (#13223)
* fix(runtime-core):  update __vnode of static nodes when patching along the optimized path

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-05-01 02:54:40 -07:00
renovate[bot] e4d9e7ee52
chore(deps): update lint (#13250)
ci / test (push) Has been cancelled Details
ci / continuous-release (push) Has been cancelled Details
size data / upload (push) Has been cancelled Details
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-29 16:27:44 +08:00
renovate[bot] bfc458f7bf
chore(deps): update build (#13249)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-29 16:27:30 +08:00
renovate[bot] d9923c3503
chore(deps): update dependency vite to v5.4.18 [security] (#13237)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-29 15:59:20 +08:00
renovate[bot] a23fb59e83
chore(deps): update dependency vite to v5.4.18 [security] (#13235)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-24 08:11:14 +08:00
renovate[bot] c3e3396475
chore(deps): update dependency vite to v5.4.18 [security] (#13229)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: edison <daiwei521@126.com>
2025-04-23 08:31:15 +08:00
Jasper Kisro b92ae84ce5
chore: update CHANGELOG.md (#13230) 2025-04-23 07:58:31 +08:00
renovate[bot] b782cd6c3c
chore(deps): update dependency vite to ^6.3.2 (#13225)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-22 08:15:50 +08:00
renovate[bot] 4085ed9052
chore(deps): update pnpm to v10.9.0 (#13224)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-22 08:15:32 +08:00
renovate[bot] 4f792535e2
chore(deps): update build (#13195)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-15 08:17:57 +08:00
renovate[bot] c15ed52030
chore(deps): update dependency vite to v5.4.18 [security] (#13198)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-15 08:17:42 +08:00
renovate[bot] 9d84d64fee
chore(deps): update dependency @types/node to ^22.14.1 (#13196)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-14 17:08:59 +08:00
山吹色御守 8ae11226e8
fix(compiler-sfc): treat the return value of `useTemplateRef` as a definite ref (#13197) 2025-04-14 17:08:06 +08:00
renovate[bot] 32bc647fab
chore(deps): update build (#13165)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-10 15:51:53 +08:00
renovate[bot] 4f6ef92ad9
chore(deps): update dependency vite to v5.4.17 [security] (#13173)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-09 08:10:43 +08:00
bornkiss 347c7849ad
chore: add bsky link (#13175) 2025-04-08 20:47:02 +08:00
renovate[bot] 1faca599cd
chore(deps): update all non-major dependencies (#13166)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-08 15:11:17 +08:00
linzhe 466b30f404
fix(compat): correct deprecation message for v-bind.sync usage (#13137)
close #13133
2025-04-02 11:12:29 +08:00
renovate[bot] f6e84af30a
chore(deps): update all non-major dependencies (#13120)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-31 15:10:54 +08:00
renovate[bot] 5f14669d29
chore(deps): update lint (#13122)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-31 15:02:15 +08:00
renovate[bot] 25e803773a
chore(deps): update compiler to ^7.27.0 (#13123)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-31 15:01:57 +08:00
Ecco 1499135c22
fix(runtime-dom): always treat autocorrect as attribute (#13001)
close #5705
2025-03-31 14:31:11 +08:00
renovate[bot] 733e266cdd
chore(deps): update build (#13121)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-31 11:13:43 +08:00
Leedom c97cc4cdb0
chore: fix typo (#13117) 2025-03-29 22:00:36 +08:00
renovate[bot] 93d663a046
chore(deps): update dawidd6/action-download-artifact action to v9 (#13098)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-25 08:14:10 +08:00
renovate[bot] 60b7bf50e6
fix(deps): update dependency @vue/repl to ^4.5.1 (#13097)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-25 08:13:07 +08:00
renovate[bot] 40fd95ffd3
chore(deps): update all non-major dependencies (#13092)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-25 08:12:49 +08:00
renovate[bot] d65b25cdda
chore(deps): update build (#13093)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-24 10:59:40 +08:00
renovate[bot] 07064f3522
chore(deps): update lint (#13096)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-24 10:59:05 +08:00
renovate[bot] c65b8d1519
chore(deps): update test (#13095)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-24 10:54:07 +08:00
Eduardo San Martin Morote 7278d35213
docs(tsdoc): remove extra () in link tag (#13086) 2025-03-24 08:20:35 +08:00
Tycho de7959ea47
chore(sfc-playground): dynamically set Vue version in downloaded project (#13074) 2025-03-20 16:09:51 +08:00
edison 021f8f3b69
fix(readme): update contributors image (#13068)
The current image is too large to load.
see github.com/orgs/community/discussions/116471
2025-03-19 15:14:12 +08:00
Tycho f6f64befb8
types: enhance plugin type inference for better IDE support (#13063)
* types: enhance plugin type inference for better JSDoc and IDE support

* test: clean up

* chore: tweaks
2025-03-19 11:44:32 +08:00
Buer Yang 10e54dcc86
fix(types): the directive's modifiers should be optional (#12605)
* fix(types): the directive's modifiers should be optional

* fix: test

---------

Co-authored-by: edison <daiwei521@126.com>
2025-03-19 11:38:59 +08:00
renovate[bot] 4fea167b57
fix(deps): update compiler (#13051)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-17 13:27:17 +08:00
renovate[bot] fbf88b6062
chore(deps): update dependency @vitejs/plugin-vue to ^5.2.2 (#13050)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-17 13:27:00 +08:00
renovate[bot] 1722090022
chore(deps): update test (#13048)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-17 11:01:54 +08:00
renovate[bot] 36509d8561
chore(deps): update lint (#13049)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-17 09:29:53 +08:00
renovate[bot] 4eba2c53bb
chore(deps): update pnpm to v10.6.3 (#13047)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-17 09:03:00 +08:00
renovate[bot] d2c8c19ae8
chore(deps): update build (#13046)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-17 09:02:37 +08:00
Bald-M 388295b27f
fix(compiler): fix spelling error in domTagConfig (#13043) 2025-03-17 08:18:09 +08:00
edison fdbd026583
fix(customFormatter): properly accessing ref value during debugger (#12948) 2025-03-14 08:19:06 +08:00
Shinigami 636a8619f0
feat(types): add type TemplateRef (#12645)
* feat(types): add type TemplateRef

* chore: simplify

Co-authored-by: jh-leong <jh.leong@outlook.com>

---------

Co-authored-by: jh-leong <jh.leong@outlook.com>
2025-03-14 08:17:49 +08:00
@beer d48937fb95
chore: update node v22 on netlify (#12613) 2025-03-12 08:30:29 +08:00
renovate[bot] fb0c3ca519
chore(deps): update all non-major dependencies (#13014)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-10 15:46:47 +08:00
renovate[bot] 87e0cd71c2
chore(deps): update build (#13015)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-10 15:46:31 +08:00
renovate[bot] 4b1931cf89
chore(deps): update all non-major dependencies (#12983)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-04 20:15:44 +08:00
renovate[bot] 9b708cf5f7
chore(deps): update test (#12984)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-04 08:26:16 +08:00
edison 8bd9cdb77e
Revert "ci(pkg-pr-new): add 'vapor' branch for pull-request" (#12943)
This reverts commit d18c248691.
2025-02-25 20:39:50 +08:00
zhiyuanzmj d18c248691
ci(pkg-pr-new): add 'vapor' branch for pull-request (#12941) 2025-02-25 15:24:18 +08:00
renovate[bot] 2dd2feab9c
chore(deps): update dependency @types/node to ^22.13.5 (#12932)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-24 09:37:17 +08:00
renovate[bot] 79d5d6cf4d
chore(deps): update build (#12931)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-24 09:36:45 +08:00
Sunny 604d08760e
test(reactivity): add tests for reactive and non-reactive objects (#12576) 2025-02-20 17:00:31 +08:00
btea 5e776ae97e
chore: add `onlyBuiltDependencies` list (#12912) 2025-02-19 20:49:51 +08:00
FatRadish 295b5ec19b
fix(reactivity): ensure markRaw objects are not reactive (#12824)
close #12807
2025-02-19 14:25:30 +08:00
inottn 0c8dd94ef9
fix(ci): use `with` instead of `assert` syntax (#12901) 2025-02-18 08:18:34 +08:00
renovate[bot] efed3ebee6
chore(deps): update pnpm to v10 (#12892)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: edison <daiwei521@126.com>
2025-02-17 16:58:53 +08:00
edison 2785d70382
chore(deps): upgrade node to 22.14.0 (#12895)
to fix Netlify deploy error, see https://github.com/pnpm/pnpm/issues/9029#issuecomment-2650658230
2025-02-17 16:50:47 +08:00
edison cbf5821028
chore(deps): fix MappingItem type (#12891) 2025-02-17 15:07:10 +08:00
renovate[bot] 4a1884f8dc
chore(deps): update all non-major dependencies (#12886)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-17 14:50:22 +08:00
renovate[bot] ce0554fc2c
chore(deps): update test (#12885)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-17 14:42:37 +08:00
renovate[bot] 633327e14d
chore(deps): update build (#12884)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-17 14:27:25 +08:00
renovate[bot] 4f4425e0df
chore(deps): update lint (#12887)
* chore(deps): update lint

* [autofix.ci] apply automated fixes

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-02-17 14:26:56 +08:00
edison d6a6ec13ce
fix(runtime-core): prevent unmounted vnode from being inserted during transition leave (#12862)
close #12860
2025-02-12 15:30:08 +08:00
Bob 263f63f735
chore(tsconfig): remove repeated global.d.ts (#12850)
Co-authored-by: zhangqihui <zhangqihui@gigacloudtech.com>
2025-02-11 15:44:54 +08:00
Aaron-zon 99551e387a
chore(compiler-sfc): change `let start` to `const start` (#12849) 2025-02-11 15:18:09 +08:00
renovate[bot] 2ab70c202f
chore(deps): update build (#12834)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-10 09:43:09 +08:00
renovate[bot] de0bf335cb
chore(deps): update test (#12835)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-10 09:38:39 +08:00
renovate[bot] 119f18c773
chore(deps): update test (#12806)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-05 08:31:25 +08:00
renovate[bot] a117a7a84b
chore(deps): update build (#12805)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-05 08:27:54 +08:00
renovate[bot] 992a05dd48
chore(deps): update dependency vitest to v3.0.5 [security] (#12812)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-05 08:25:10 +08:00
renovate[bot] 22f359bdbe
chore(deps): update dependency vite to v5.4.12 [security] (#12793)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-31 21:12:38 +08:00
Jeff Muizelaar 7ecd2a22c7
test(e2e): Replace deprecated 'clickCount' property with 'count' (#12778)
This fixes double clicks when using WebDriver BiDi.
See https://github.com/puppeteer/puppeteer/issues/13550
2025-01-29 20:22:20 +08:00
renovate[bot] 4650715197
chore(deps): update build (#12783)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-29 20:18:58 +08:00
renovate[bot] a63679f2ef
chore(deps): update dependency @types/node to ^22.12.0 (#12784)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-29 20:18:26 +08:00
Tycho 29216853d4
chore(compiler-sfc): remove unused variable (#12750) 2025-01-21 09:28:04 +08:00
renovate[bot] 0f12fb7ea9
fix(deps): update dependency postcss to ^8.5.1 (#12747)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-20 09:43:23 +08:00
renovate[bot] 08e153c48c
chore(deps): update lint (#12746)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-20 09:43:06 +08:00
renovate[bot] f2263229ff
chore(deps): update dependency puppeteer to ~24.1.0 (#12745)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-20 09:42:48 +08:00
renovate[bot] 50b7aa17e9
chore(deps): update all non-major dependencies (#12742)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-20 08:41:00 +08:00
renovate[bot] 26162b4999
chore(deps): update build (#12743)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-20 08:31:16 +08:00
renovate[bot] c48a00d85e
chore(deps): update test to v3 (major) (#12744)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-20 08:31:00 +08:00
edison 82da43d167
fix(test): use LaunchOptions instead of PuppeteerLaunchOptions (#12734)
ref puppeteer/puppeteer#13426
2025-01-17 09:26:12 +08:00
renovate[bot] 2e6ec39811
chore(deps): update test (major) (#12692)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-14 10:15:44 +08:00
edison c950b4c0c4
chore(deps): manually update puppeteer + @vitest/eslint-plugin (#12706) 2025-01-14 10:09:08 +08:00
renovate[bot] f399dd3588
chore(deps): update autofix-ci/action digest to 551dded (#12696)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-13 08:33:14 +08:00
renovate[bot] 2d6bcc4537
chore(deps): update all non-major dependencies (#12685)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-12 09:57:53 +08:00
renovate[bot] 4170dec5a1
chore(deps): update dawidd6/action-download-artifact action to v7 (#12690)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-12 09:39:39 +08:00
renovate[bot] 18555fa7b2
chore(deps): update build (#12686)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-12 09:39:06 +08:00
renovate[bot] 23d2f453d1
chore(deps): update dependency minimatch to v10 (#12691)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-12 09:38:25 +08:00
renovate[bot] fbdd084acc
chore(deps): update lint (#12689)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-12 09:38:06 +08:00
renovate[bot] db57d21c17
fix(deps): update dependency @vue/repl to ^4.4.3 (#12688)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-12 09:37:55 +08:00
Evan You 22dcbf3e20
fix(reactivity): ensure multiple effectScope on() and off() calls maintains correct active scope
close #12631
close #12632

This is a combination of changes from both 8dec243 and #12641
2025-01-08 18:07:44 +08:00
我想静静 e8e842241a
chore: remove unused `configDefaults` (#12643) 2025-01-03 15:20:25 +08:00
renovate[bot] 5a6e98ca32
chore(deps): update pnpm to v9.15.2 (#12628)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-30 09:57:28 +08:00
renovate[bot] eb618fd889
chore(deps): update build (#12627)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-30 09:57:12 +08:00
edison 21f8d9dba9
chore(deps): update test (#12600) 2024-12-23 11:25:58 +08:00
renovate[bot] 3faa0a3a9e
chore(deps): update build (major) (#12562)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-23 11:17:34 +08:00
renovate[bot] b7085a85f1
chore(deps): update dependency magic-string to ^0.30.17 (#12597)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-23 11:15:11 +08:00
renovate[bot] 289f4bd94f
chore(deps): update lint (#12598)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-23 11:14:51 +08:00
renovate[bot] 234b6cbb74
chore(deps): update build (#12595)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-23 11:08:56 +08:00
renovate[bot] 6da11a7d22
chore(deps): update all non-major dependencies (#12594)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-23 11:05:25 +08:00
Marc Bernard bc688434af
docs: remove 3.3 info from 3.4 changelog (#12565)[ci-skip]
Some clean-up. All removed info is already included in [3.3 changelog](https://github.com/vuejs/core/blob/main/changelogs/CHANGELOG-3.3.md)
2024-12-19 14:58:05 +08:00
renovate[bot] 833f9ea1f7
chore(deps): update lint (#12561)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-16 11:26:37 +08:00
renovate[bot] ec22b79fd4
chore(deps): update build (#12558)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-16 10:49:38 +08:00
renovate[bot] 76bdd78f17
chore(deps): update dependency magic-string to ^0.30.15 (#12559)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-16 10:49:21 +08:00
renovate[bot] f74146f40e
fix(deps): update dependency monaco-editor to ^0.52.2 (#12560)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-16 10:49:05 +08:00
renovate[bot] d07cdead2c
chore(deps): update all non-major dependencies (#12557)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-16 10:48:44 +08:00
LiquidAssContainer 11c053a542
fix(typos): fix comments referencing transformElement.ts (#12551)[ci-skip] 2024-12-16 10:43:01 +08:00
renovate[bot] 201936f9a3
chore(deps): update build (#12512)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-09 09:30:58 +08:00
renovate[bot] 11f76741fb
chore(deps): update dependency magic-string to ^0.30.14 (#12493)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-05 09:23:28 +08:00
renovate[bot] c86a08b946
chore(deps): update all non-major dependencies (#12492)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-05 09:22:52 +08:00
renovate[bot] 5a5406d002
chore(deps): update all non-major dependencies (#12463)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-27 08:49:07 +08:00
renovate[bot] d82fb465a6
chore(deps): update build (#12464)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-27 08:42:42 +08:00
renovate[bot] fc4bbf95c1
chore(deps): update test (#12002)
* chore(deps): update test

* chore: pin puppeteer

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: daiwei <daiwei521@126.com>
2024-11-22 14:51:15 +08:00
Liu Bo 06310e82f5
fix(types): allow return any for Options API lifecycle hooks (#5914)
Co-authored-by: edison <daiwei521@126.com>
2024-11-19 20:29:08 +08:00
renovate[bot] 14f6917c3c
chore(deps): update all non-major dependencies (#12423)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-18 11:30:02 +08:00
renovate[bot] 01057fc74c
chore(deps): update build (#12421)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-18 11:29:29 +08:00
renovate[bot] fdaff720d7
fix(deps): update compiler (#12422)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-18 10:31:14 +08:00
renovate[bot] c028aeafa9
chore(deps): update lint (#12424)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-18 10:28:12 +08:00
Evan You 6eb29d345a
release: v3.5.13 2024-11-15 22:45:28 +08:00
edison 4f8d807822
fix(ssr): handle initial selected state for select with v-model + v-for option (#12399)
close #12395
2024-11-15 22:32:39 +08:00
edison 983eb50a17
fix(templateRef): set ref on cached async component which wrapped in KeepAlive (#12290)
close #4999
close #5004
2024-11-15 22:32:22 +08:00
edison da7ad5e3d2
fix(ssr): avoid updating subtree of async component if it is resolved (#12363)
close #12362
2024-11-15 22:11:21 +08:00
Bulat Aikaev 1f75d4e6df
fix(ssr): ensure v-text updates correctly with custom directives in SSR output (#12311)
close #12309
2024-11-15 22:02:50 +08:00
Tadas 4b479db61d
fix(transition): reflow before leave-active class after leave-from (#12288)
re-fix #2593
2024-11-15 21:36:21 +08:00
linzhe a20a4cb36a
fix(hydration): the component vnode's el should be updated when a mismatch occurs. (#12255)
close #12253
2024-11-15 18:18:58 +08:00
Evan You 352bc88c1b
fix(custom-element): avoid triggering mutationObserver when relecting props
close #12214
close #12215
2024-11-15 17:21:49 +08:00
Evan You 10ab8c0e7b
chore(playground): reset version when opening local playground from reproduction 2024-11-15 17:04:25 +08:00
zhangenming d637bd6c01
perf(reactivity): do not track inner key `__v_skip`` (#11690) 2024-11-15 11:00:24 +08:00
edison 2d78539da3
fix(compiler-dom): properly stringify template string style (#12392)
close #12391
2024-11-15 10:56:08 +08:00
Evan You 54812eacaa
test: add test case for transition memory leaks
from https://github.com/vuejs/core/pull/12190
2024-11-15 10:50:26 +08:00
edison 1022eabaa1
fix(types): defineEmits w/ interface declaration (#12343)
close #8457
2024-11-15 10:46:59 +08:00
edison 660132df6c
fix(Transition): fix transition memory leak edge case (#12182)
close #12181
2024-11-15 10:40:26 +08:00
edison 4aeff318bd
chore(deps): update dependency postcss-selector-parser to v7 (#12289) 2024-11-15 10:37:55 +08:00
edison 70b44ca835
chore(reactivity): remove unecessary array copy (#12400) 2024-11-15 10:37:24 +08:00
Evan You a49858f3ee
build: strip pure comments in minified builds 2024-11-14 23:33:58 +08:00
edison 8bff142f99
fix(teleport): handle deferred teleport update before mounted (#12168)
close #12161
2024-11-14 20:55:18 +08:00
linzhe c4312f9c71
fix(runtime-dom): set css vars on update to handle child forcing reflow in onMount (#11561) 2024-11-14 15:58:28 +08:00
Evan You 2d5c5e25e9
fix(runtime-dom): set css vars before user onMounted hooks
close #11533
2024-11-14 15:50:19 +08:00
linzhe 99009eee0e
fix(compiler-core): handle v-memo + v-for with functional key (#12014)
close #12013
2024-11-14 15:14:29 +08:00
edison 37300fc261
fix(v-once): setting hasOnce to current block only when in v-once (#12374)
close #12371
2024-11-14 14:53:55 +08:00
edison bee2f5ee62
fix(reactivity): release nested effects/scopes on effect scope stop (#12373)
close #12370
2024-11-14 14:24:22 +08:00
Evan You 21932840ea
fix(reactiivty): avoid unnecessary watcher effect removal from inactive scope
close #5783
close #5806
2024-11-14 14:12:41 +08:00
Evan You e9f3e6b546
workflow: bench against bundled dist file to avoid import access overhead
ref https://github.com/vitest-dev/vitest/issues/6903
2024-11-14 08:38:48 +08:00
Evan You 3656364b06
chore: add well-known funding manifest urls [ci skip] 2024-11-14 00:22:44 +08:00
Evan You 506ed4e75f
chore: enable format on save in workspace settings 2024-11-13 15:31:17 +08:00
Evan You 83430a35f4
workflow: improve bench scripts 2024-11-13 14:13:32 +08:00
renovate[bot] b5ff930089
fix(deps): update dependency postcss to ^8.4.48 (#12356)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-11 10:20:54 +08:00
renovate[bot] 852642729a
chore(deps): update build (#12357)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-11 10:17:49 +08:00
renovate[bot] a0901756da
chore: migrate renovate config (#12354)
* chore(config): migrate config .github/renovate.json5

* chore: fix lint

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
2024-11-11 03:17:52 +08:00
renovate[bot] 76c43c6040
chore(deps): update dependency @types/node to v22 (#12320)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-04 14:38:05 +08:00
renovate[bot] e81ecc9a9d
chore(deps): update lint (#12319)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-04 14:19:14 +08:00
renovate[bot] 7d0dc7394f
chore(deps): update all non-major dependencies (#12316)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-04 09:25:09 +08:00
renovate[bot] 394902c2e9
chore(deps): update build (#12317)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-04 09:09:02 +08:00
renovate[bot] 664d2e553d
chore(deps): update pnpm to v9.12.3 (#12278)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-28 13:44:08 +08:00
renovate[bot] 3a043e8c16
chore(deps): update dependency typescript-eslint to ^8.11.0 (#12276)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-28 09:23:54 +08:00
renovate[bot] 6c0f4741ed
chore(deps): update dependency npm-run-all2 to v7 (#12277)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-28 09:23:14 +08:00
renovate[bot] ad247b3323
chore(deps): update all non-major dependencies (#12275)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-28 09:17:49 +08:00
renovate[bot] 5652c5ad83
chore(deps): update build (#12274)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-28 09:17:21 +08:00
renovate[bot] ed01d92571
chore(deps): update all non-major dependencies (#12222)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-22 09:53:31 +08:00
renovate[bot] 1222437ec2
chore(deps): update lint (#12226)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-21 10:31:21 +08:00
renovate[bot] 536d600199
chore(deps): update build (#12223)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-21 10:25:22 +08:00
Tycho 657603d7b7
docs: update package name to `@vue/compiler-core` (#12192)[ci skip] 2024-10-17 12:00:03 +08:00
renovate[bot] 2442c3b061
chore(deps): update dependency typescript-eslint to ^8.8.1 (#12167)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: edison <daiwei521@126.com>
2024-10-14 15:14:41 +08:00
renovate[bot] 5b17afa89d
chore(deps): update dependency magic-string to ^0.30.12 (#12166)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: edison <daiwei521@126.com>
2024-10-14 15:14:27 +08:00
edison 828d4a4439
fix(test): update snapshot (#12169) 2024-10-14 11:24:13 +08:00
btea a038505c65
chore: improve `renderComponentRoot` warn message (#10914) 2024-10-14 10:14:32 +08:00
远方os 4e19a99461
test(shared): improve test coverage (#8456)
Co-authored-by: edison <daiwei521@126.com>
2024-10-14 10:10:27 +08:00
zr 3b5d8d2511
test(defineProps): add intersection type test (#8684)
Co-authored-by: daiwei <daiwei521@126.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2024-10-14 10:09:13 +08:00
renovate[bot] aa6879f987
chore(deps): update dependency @swc/core to ^1.7.35 (#12165)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-14 10:07:11 +08:00
renovate[bot] be9eed2593
chore(deps): update all non-major dependencies (#12164)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-14 10:06:33 +08:00
skirtle 1755ac0a10
perf(runtime-core): use feature flag for call to resolveMergedOptions (#12163)
Reduce bundle size when using `__VUE_OPTIONS_API__: false`
2024-10-14 08:18:18 +08:00
Evan You 770ea67a9c
release: v3.5.12 2024-10-11 21:12:32 +08:00
skirtle c82b66214b
refactor(reactivity): reduce size of collectionHandlers (#12152) 2024-10-11 21:10:09 +08:00
Tycho ea943afe40
fix(runtime-dom): prevent unnecessary updates in v-model checkbox when value is unchanged (#12146)
close #12144
2024-10-11 21:00:08 +08:00
Evan You d82fa611e8
chore: format 2024-10-11 11:25:48 +08:00
KevinXi d96883cf7d
test(reactivity): test for verifying no unnecessary calls of reactive array identity methods (#11328)
related: #9511
2024-10-11 11:24:03 +08:00
Michael Brevard 1ae545a378
fix(hydration): provide compat fallback for idle callback hydration strategy (#11935) 2024-10-11 11:22:01 +08:00
edison 05685a9d7c
fix(types): retain union type narrowing with defaults applied (#12108)
close #12106
2024-10-11 11:17:48 +08:00
山吹色御守 cde2c0671b
fix(compiler): clone loc to `ifNode` (#12131)
fix vuejs/language-tools#4911
2024-10-11 11:07:07 +08:00
山吹色御守 4474c113d1
fix(compiler-sfc): use sass modern api if available and avoid deprecation warning (#11992) 2024-10-11 11:05:54 +08:00
YangLGggggggggg 9da1ac1565
fix(runtime-core): fix required prop check false positive for kebab-case edge cases (#12034)
close #12011
2024-10-11 11:02:58 +08:00
edison 10a46f43c0
chore(runtime-core): warn if use a non-ref to hold the element reference in DEV (#12051)
close #12029
2024-10-11 10:53:45 +08:00
linzhe d3ecde8a69
fix(compiler-sfc): do not skip TSInstantiationExpression when transforming props destructure (#12064) 2024-10-11 10:51:57 +08:00
linzhe 76a8223199
fix(teleport): handle disabled teleport with updateCssVars (#12113)
close #12112
2024-10-11 10:50:36 +08:00
yangxiuxiu b4d35349d8
fix(useId): ensure useId consistency when using serverPrefetch (#12128)
close #12102
2024-10-11 10:49:14 +08:00
skirtle ec917cfdb9
perf(reactivity): avoid unnecessary recursion in removeSub (#12135) 2024-10-11 10:48:54 +08:00
edison f6d9926236
fix(compiler-dom): avoid stringify option with null value (#12096)
close #12093
2024-10-11 10:41:55 +08:00
Tycho 7ad289e1e7
fix(reactivity): trigger reactivity for Map key `undefined` (#12055)
close #12054
2024-10-11 10:39:08 +08:00
山吹色御守 c0418a3b8f
fix(defineModel): handle kebab-case model correctly (#12063)
close #12060
2024-10-11 10:35:57 +08:00
edison f1a4f67aed
fix(transition/ssr): make transition appear work with Suspense in SSR (#12047)
close #12046
2024-10-11 10:34:28 +08:00
w2xi e0a591e1cd
chore(sfc-playground): adjust the tooltip text for toggling the theme (#12116)
* chore(sfc-playground): adjust the tooltip text for toggling the theme

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2024-10-11 10:31:01 +08:00
Tycho 704173e242
fix(types): ensure `this.$props` type does not include `string` (#12123)
close #12122
2024-10-11 10:30:09 +08:00
Tycho d9d4d4e158
fix(runtime-core): allow symbol values for slot prop key (#12069)
close #12068
2024-10-11 10:28:54 +08:00
edison e16e9a7341
fix(custom-element): properly remove hyphenated attribute (#12143)
close #12139
2024-10-11 09:52:06 +08:00
renovate[bot] 35785f3cd7
chore(deps): update lint (#12118)
* chore(deps): update lint

* chore: update package name

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: daiwei <daiwei521@126.com>
2024-10-07 10:45:41 +08:00
dependabot[bot] 723f588716
chore(deps-dev): bump vite from 5.4.0 to 5.4.8 (#12121)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.4.0 to 5.4.8.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v5.4.8/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.4.8/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-07 10:45:08 +08:00
renovate[bot] 73a3666dee
chore(deps): update dependency @rollup/plugin-commonjs to v28 (#12120)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-07 10:42:31 +08:00
renovate[bot] f7cbea2111
fix(deps): update dependency monaco-editor to ^0.52.0 (#12119)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-07 10:33:18 +08:00
skirtle b094c72b3d
fix(watch): watchEffect clean-up with SSR (#12097)
close #11956
2024-10-04 16:09:23 +08:00
Evan You 6e4de8d75e
release: v3.5.11 2024-10-03 23:49:47 +08:00
山吹色御守 6f85894376
fix(type): should not intersect `PublicProps` with `Props` (#12077) 2024-10-03 23:24:09 +08:00
山吹色御守 c97bb84d0b
fix(types): infer the first generic type of `Ref` correctly (#12094) 2024-10-03 23:22:57 +08:00
山吹色御守 57315ab968
fix(types): correctly infer `TypeProps` when it is `any` (#12073)
close #12058
2024-10-03 23:22:27 +08:00
skirtle 577edca8e7
fix(scheduler): job ordering when the post queue is flushing (#12090) 2024-10-03 23:21:31 +08:00
renovate[bot] 3a55c3e421
chore(deps): update dependency rollup to ^4.24.0 (#12081)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-03 23:17:36 +08:00
renovate[bot] 435e4fefad
chore(deps): update all non-major dependencies (#12080)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-03 23:17:22 +08:00
Tycho d3f5e6e531
fix(reactivity): prevent overwriting `next` property during batch processing (#12075)
close #12072
2024-10-03 23:16:52 +08:00
Evan You 29de6f8b0b
chore: remove no longer used property on Dep 2024-09-28 19:25:16 +08:00
山吹色御守 2328b051f4
fix(compiler-sfc): do not skip `TSSatisfiesExpression` when transforming props destructure (#12062)
close #12061
2024-09-28 09:56:09 +08:00
Evan You 4b09ab2074
release: v3.5.10 2024-09-27 23:16:33 +08:00
Evan You 93c95dd4cd
fix(reactivity): fix nested batch edge case 2024-09-27 23:10:20 +08:00
Evan You aa9ef2386a
fix(reactivity): only clear notified flags for computed in first batch iteration
close #12045
2024-09-27 11:25:58 +08:00
Evan You 60c2029f77
test: add test case for #11928 2024-09-27 11:06:34 +08:00
Tycho e2c19c20cf
fix(types/ref): handle nested refs in UnwrapRef (#12049)
close #12044
2024-09-27 10:23:01 +08:00
Evan You ea3efa09e0
fix(custom-element): properly set kebab-case props on Vue custom elements
close #12030
close #12032
2024-09-27 09:25:00 +08:00
Evan You a77b95992a
workflow: link to release workflow in release script [ci skip] 2024-09-26 19:30:19 +08:00
199 changed files with 7006 additions and 2650 deletions

View File

@ -1,18 +1,17 @@
{ {
$schema: 'https://docs.renovatebot.com/renovate-schema.json', $schema: 'https://docs.renovatebot.com/renovate-schema.json',
extends: ['config:base', 'schedule:weekly', 'group:allNonMajor'], extends: ['config:recommended', 'schedule:weekly', 'group:allNonMajor'],
labels: ['dependencies'], labels: ['dependencies'],
ignorePaths: ['**/__tests__/**'], ignorePaths: ['**/__tests__/**'],
rangeStrategy: 'bump', rangeStrategy: 'bump',
packageRules: [ packageRules: [
{ {
depTypeList: ['peerDependencies'], matchDepTypes: ['peerDependencies'],
enabled: false, enabled: false,
}, },
{ {
groupName: 'test', groupName: 'test',
matchPackageNames: ['vitest', 'jsdom', 'puppeteer'], matchPackageNames: ['vitest', 'jsdom', 'puppeteer', '@vitest{/,}**'],
matchPackagePrefixes: ['@vitest'],
}, },
{ {
groupName: 'playground', groupName: 'playground',
@ -23,18 +22,28 @@
}, },
{ {
groupName: 'compiler', groupName: 'compiler',
matchPackageNames: ['magic-string'], matchPackageNames: ['magic-string', '@babel{/,}**', 'postcss{/,}**'],
matchPackagePrefixes: ['@babel', 'postcss'],
}, },
{ {
groupName: 'build', groupName: 'build',
matchPackageNames: ['vite', '@swc/core'], matchPackageNames: [
matchPackagePrefixes: ['rollup', 'esbuild', '@rollup', '@vitejs'], 'vite',
'@swc/core',
'rollup{/,}**',
'esbuild{/,}**',
'@rollup{/,}**',
'@vitejs{/,}**',
],
}, },
{ {
groupName: 'lint', groupName: 'lint',
matchPackageNames: ['simple-git-hooks', 'lint-staged'], matchPackageNames: [
matchPackagePrefixes: ['typescript-eslint', 'eslint', 'prettier'], 'simple-git-hooks',
'lint-staged',
'typescript-eslint{/,}**',
'eslint{/,}**',
'prettier{/,}**',
],
}, },
], ],
ignoreDeps: [ ignoreDeps: [

View File

@ -14,7 +14,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v4.0.0 uses: pnpm/action-setup@v4.1.0
- name: Install Node.js - name: Install Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
@ -31,4 +31,4 @@ jobs:
- name: Run prettier - name: Run prettier
run: pnpm run format run: pnpm run format
- uses: autofix-ci/action@ff86a557419858bb967097bfc916833f5647fa8c - uses: autofix-ci/action@551dded8c6cc8a1054039c8bc0b8b48c51dfc6ef

View File

@ -17,7 +17,7 @@ jobs:
ref: minor ref: minor
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v4.0.0 uses: pnpm/action-setup@v4.1.0
- name: Install Node.js - name: Install Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4

View File

@ -15,7 +15,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v4.0.0 uses: pnpm/action-setup@v4.1.0
- name: Install Node.js - name: Install Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4

View File

@ -25,7 +25,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v4.0.0 uses: pnpm/action-setup@v4.1.0
- name: Install Node.js - name: Install Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4

View File

@ -25,7 +25,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v4.0.0 uses: pnpm/action-setup@v4.1.0
- name: Install Node.js - name: Install Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
@ -37,7 +37,7 @@ jobs:
run: pnpm install run: pnpm install
- name: Download Size Data - name: Download Size Data
uses: dawidd6/action-download-artifact@v6 uses: dawidd6/action-download-artifact@v9
with: with:
name: size-data name: size-data
run_id: ${{ github.event.workflow_run.id }} run_id: ${{ github.event.workflow_run.id }}
@ -56,7 +56,7 @@ jobs:
path: temp/size/base.txt path: temp/size/base.txt
- name: Download Previous Size Data - name: Download Previous Size Data
uses: dawidd6/action-download-artifact@v6 uses: dawidd6/action-download-artifact@v9
with: with:
branch: ${{ steps.pr-base.outputs.content }} branch: ${{ steps.pr-base.outputs.content }}
workflow: size-data.yml workflow: size-data.yml

View File

@ -14,7 +14,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v4.0.0 uses: pnpm/action-setup@v4.1.0
- name: Install Node.js - name: Install Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
@ -35,7 +35,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v4.0.0 uses: pnpm/action-setup@v4.1.0
- name: Install Node.js - name: Install Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
@ -63,7 +63,7 @@ jobs:
key: chromium-${{ hashFiles('pnpm-lock.yaml') }} key: chromium-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v4.0.0 uses: pnpm/action-setup@v4.1.0
- name: Install Node.js - name: Install Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
@ -88,7 +88,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v4.0.0 uses: pnpm/action-setup@v4.1.0
- name: Install Node.js - name: Install Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
@ -104,5 +104,8 @@ jobs:
- name: Run prettier - name: Run prettier
run: pnpm run format-check run: pnpm run format-check
- name: Run tsc
run: pnpm run check
- name: Run type declaration tests - name: Run type declaration tests
run: pnpm run test-dts run: pnpm run test-dts

View File

@ -1 +1 @@
20 22.14.0

View File

@ -13,5 +13,6 @@
}, },
"[json]": { "[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"
} },
"editor.formatOnSave": true
} }

View File

@ -0,0 +1 @@
https://vuejs.org/funding.json

View File

@ -1,3 +1,169 @@
## [3.5.16](https://github.com/vuejs/core/compare/v3.5.15...v3.5.16) (2025-05-29)
### Reverts
* Revert "fix(compiler-sfc): add scoping tag to trailing universal selector" (#13406) ([19f23b1](https://github.com/vuejs/core/commit/19f23b180bb679e38db95d6a10a420abeedc8e1c)), closes [#13406](https://github.com/vuejs/core/issues/13406)
* Revert "fix(compiler-sfc): add error handling for defineModel() without variable" (#13390) ([42f879f](https://github.com/vuejs/core/commit/42f879fcab48e0e1011967a771b4ad9e8838d760)), closes [#13390](https://github.com/vuejs/core/issues/13390)
## [3.5.15](https://github.com/vuejs/core/compare/v3.5.14...v3.5.15) (2025-05-26)
### Bug Fixes
* **compat:** ensure false value on input retains value attribute ([#13216](https://github.com/vuejs/core/issues/13216)) ([1a66474](https://github.com/vuejs/core/commit/1a664749d4d65a345589a6d78106ede7574cb2e1)), closes [#13205](https://github.com/vuejs/core/issues/13205)
* **compat:** should not warn COMPILER_V_BIND_OBJECT_ORDER when using v-bind together with v-for ([#12993](https://github.com/vuejs/core/issues/12993)) ([93949e6](https://github.com/vuejs/core/commit/93949e6587ee019bccd5b8b9d76f0e1ed6ea16fc)), closes [#12992](https://github.com/vuejs/core/issues/12992)
* **compile-sfc:** handle inline template source map in prod build ([#12701](https://github.com/vuejs/core/issues/12701)) ([89edc6c](https://github.com/vuejs/core/commit/89edc6cdcbd34ea6394927ecbfaa61dc4f871de7)), closes [#12682](https://github.com/vuejs/core/issues/12682) [vitejs/vite-plugin-vue#500](https://github.com/vitejs/vite-plugin-vue/issues/500)
* **compiler-core:** ensure mapping is added only if node source is available ([#13285](https://github.com/vuejs/core/issues/13285)) ([d37a2ac](https://github.com/vuejs/core/commit/d37a2ac59d904ac0e3257ba552b6c04920a363f0)), closes [#13261](https://github.com/vuejs/core/issues/13261) [vitejs/vite-plugin-vue#368](https://github.com/vitejs/vite-plugin-vue/issues/368)
* **compiler-dom:** improve HTML nesting validation to allow any child element within template tag ([#13320](https://github.com/vuejs/core/issues/13320)) ([163b365](https://github.com/vuejs/core/commit/163b3651d174321911648a164052effa9249a2aa)), closes [#13318](https://github.com/vuejs/core/issues/13318)
* **compiler-sfc:** add error handling for defineModel() without variable assignment ([#13352](https://github.com/vuejs/core/issues/13352)) ([00734af](https://github.com/vuejs/core/commit/00734afef5f7bddbdaee52aa5359a6ef989f32d3)), closes [#13280](https://github.com/vuejs/core/issues/13280)
* **compiler-sfc:** add scoping tag to trailing universal selector ([#12918](https://github.com/vuejs/core/issues/12918)) ([949df80](https://github.com/vuejs/core/commit/949df808809fd7cccf7718797beab0654aa68302)), closes [#12906](https://github.com/vuejs/core/issues/12906)
* **compiler-sfc:** improve type inference for TSTypeAliasDeclaration with better runtime type detection ([#13245](https://github.com/vuejs/core/issues/13245)) ([cf5a5e0](https://github.com/vuejs/core/commit/cf5a5e0edf0efcab25c27aa2d13eba91f7372d39)), closes [#13240](https://github.com/vuejs/core/issues/13240)
* **compiler-sfc:** simulate `allowArbitraryExtensions` on resolving type ([#13301](https://github.com/vuejs/core/issues/13301)) ([f7ce5ae](https://github.com/vuejs/core/commit/f7ce5ae666129339c006b339437c2dff6bceffe0)), closes [#13295](https://github.com/vuejs/core/issues/13295)
* **custom-element:** allow injecting values from app context in nested elements ([#13219](https://github.com/vuejs/core/issues/13219)) ([b991075](https://github.com/vuejs/core/commit/b9910755a50c7d6c52b28c3aef20cf97810295c9)), closes [#13212](https://github.com/vuejs/core/issues/13212)
* **custom-element:** ensure proper remount and prevent redundant slot parsing with shadowRoot false ([#13201](https://github.com/vuejs/core/issues/13201)) ([1d41d4d](https://github.com/vuejs/core/commit/1d41d4de7f64a37160c8171d0137fd8d35c346c9)), closes [#13199](https://github.com/vuejs/core/issues/13199)
* **custom-element:** preserve appContext during update ([#12455](https://github.com/vuejs/core/issues/12455)) ([013749e](https://github.com/vuejs/core/commit/013749e75ef3b51762a86da379ea4ba4501b54ae)), closes [#12453](https://github.com/vuejs/core/issues/12453)
* **custom-element:** properly resolve props for sync component defs ([#12855](https://github.com/vuejs/core/issues/12855)) ([a683c80](https://github.com/vuejs/core/commit/a683c80cf44ecc482f8ac9c76bf2381443c1b0bb)), closes [#12854](https://github.com/vuejs/core/issues/12854)
* **hydration:** handle transition appear hydration edge case ([#13339](https://github.com/vuejs/core/issues/13339)) ([35aeae7](https://github.com/vuejs/core/commit/35aeae7fa3168adcf9ed95fd35495d17c8b93eeb)), closes [#13335](https://github.com/vuejs/core/issues/13335)
* **hydration:** skip lazy hydration for patched components ([#13283](https://github.com/vuejs/core/issues/13283)) ([80055fd](https://github.com/vuejs/core/commit/80055fddfb3ca1e2a44f19c7f0ffaeba00de5140)), closes [#13255](https://github.com/vuejs/core/issues/13255)
* **suspense:** handle edge case in patching list nodes within Suspense ([#13306](https://github.com/vuejs/core/issues/13306)) ([772b008](https://github.com/vuejs/core/commit/772b0087cb7be151c514a1d30365fb0f61a652ba)), closes [#13305](https://github.com/vuejs/core/issues/13305)
* **teleport:** handle deferred teleport updates before and after mount ([#13350](https://github.com/vuejs/core/issues/13350)) ([d15dce3](https://github.com/vuejs/core/commit/d15dce3142474f2ef9fffed38383acdadcb26c4c)), closes [#13349](https://github.com/vuejs/core/issues/13349)
* **types:** avoid merging component instance into `$props` in `ComponentInstance` ([#12870](https://github.com/vuejs/core/issues/12870)) ([f44feed](https://github.com/vuejs/core/commit/f44feed6fa461a9c4c724e9631c19e9e214c0a20)), closes [#12751](https://github.com/vuejs/core/issues/12751)
* **types:** exclude `undefined` from inferred prop types with default values ([#13007](https://github.com/vuejs/core/issues/13007)) ([5179d32](https://github.com/vuejs/core/commit/5179d328d950015e7fb2a74fe1a8518fd8d2c94e)), closes [#13006](https://github.com/vuejs/core/issues/13006)
* **watch:** update `oldValue` before running `cb` to prevent stale value ([#12296](https://github.com/vuejs/core/issues/12296)) ([c69c4bb](https://github.com/vuejs/core/commit/c69c4bb59c114f2b5e03733b55ef9ace3087b5c3)), closes [#12294](https://github.com/vuejs/core/issues/12294)
## [3.5.14](https://github.com/vuejs/core/compare/v3.5.13...v3.5.14) (2025-05-15)
### Bug Fixes
* **compat:** correct deprecation message for v-bind.sync usage ([#13137](https://github.com/vuejs/core/issues/13137)) ([466b30f](https://github.com/vuejs/core/commit/466b30f4049ec89fb282624ec17d1a93472ab93f)), closes [#13133](https://github.com/vuejs/core/issues/13133)
* **compiler-core:** remove slot cache from parent renderCache during unmounting ([#13215](https://github.com/vuejs/core/issues/13215)) ([5d166f3](https://github.com/vuejs/core/commit/5d166f3796a03a497435fc079c6a83a4e9c6cf52))
* **compiler-sfc:** fix scope handling for props destructure in function parameters and catch clauses ([8e34357](https://github.com/vuejs/core/commit/8e3435779a667de485cf9efd78667d0ca14c5f84)), closes [#12790](https://github.com/vuejs/core/issues/12790)
* **compiler-sfc:** treat the return value of `useTemplateRef` as a definite ref ([#13197](https://github.com/vuejs/core/issues/13197)) ([8ae1122](https://github.com/vuejs/core/commit/8ae11226e8ee938615e17c7b81dc38ae3f7cefb9))
* **compiler:** fix spelling error in domTagConfig ([#13043](https://github.com/vuejs/core/issues/13043)) ([388295b](https://github.com/vuejs/core/commit/388295b27f3cc69eba25d325bbe60a36a3df831a))
* **customFormatter:** properly accessing ref value during debugger ([#12948](https://github.com/vuejs/core/issues/12948)) ([fdbd026](https://github.com/vuejs/core/commit/fdbd02658301dd794fe0c84f0018d080a07fca9f))
* **hmr/teleport:** adjust static children traversal for HMR in dev mode ([#12819](https://github.com/vuejs/core/issues/12819)) ([5e37dd0](https://github.com/vuejs/core/commit/5e37dd009562bcd8080a200c32abde2d6e4f0305)), closes [#12816](https://github.com/vuejs/core/issues/12816)
* **hmr:** avoid hydration for hmr root reload ([#12450](https://github.com/vuejs/core/issues/12450)) ([1f98a9c](https://github.com/vuejs/core/commit/1f98a9c493d01c21befa90107f0593bc92a58932)), closes [vitejs/vite-plugin-vue#146](https://github.com/vitejs/vite-plugin-vue/issues/146) [vitejs/vite-plugin-vue#477](https://github.com/vitejs/vite-plugin-vue/issues/477)
* **hmr:** avoid hydration for hmr updating ([#12262](https://github.com/vuejs/core/issues/12262)) ([9c4dbbc](https://github.com/vuejs/core/commit/9c4dbbc5185125835ad3e49baba303bd54676111)), closes [#7706](https://github.com/vuejs/core/issues/7706) [#8170](https://github.com/vuejs/core/issues/8170)
* **reactivity:** ensure markRaw objects are not reactive ([#12824](https://github.com/vuejs/core/issues/12824)) ([295b5ec](https://github.com/vuejs/core/commit/295b5ec19b6a52c4a56652cc4d6e93a4ea7c14ed)), closes [#12807](https://github.com/vuejs/core/issues/12807)
* **reactivity:** ensure multiple effectScope on() and off() calls maintains correct active scope ([22dcbf3](https://github.com/vuejs/core/commit/22dcbf3e20eb84f69c8952f6f70d9990136a4a68)), closes [#12631](https://github.com/vuejs/core/issues/12631) [#12632](https://github.com/vuejs/core/issues/12632) [#12641](https://github.com/vuejs/core/issues/12641)
* **reactivity:** should not recompute if computed does not track reactive data ([#12341](https://github.com/vuejs/core/issues/12341)) ([0b23fd2](https://github.com/vuejs/core/commit/0b23fd23833cf085e7e112bf4435cfc9b360d072)), closes [#12337](https://github.com/vuejs/core/issues/12337)
* **runtime-core:** stop tracking deps in setRef during unmount ([#13210](https://github.com/vuejs/core/issues/13210)) ([016c472](https://github.com/vuejs/core/commit/016c472bd2e7604b21c69dee1da8545ce26e4d2f))
* **runtime-core:** update __vnode of static nodes when patching along the optimized path ([#13223](https://github.com/vuejs/core/issues/13223)) ([b3ecee3](https://github.com/vuejs/core/commit/b3ecee3da8ed5c55dea89ce6b4b376b2b722b018))
* **runtime-core:** inherit comment nodes during block patch in production build ([#10748](https://github.com/vuejs/core/issues/10748)) ([6264505](https://github.com/vuejs/core/commit/626450590d81f79117b34d2a73073b1dc8f551bd)), closes [#10747](https://github.com/vuejs/core/issues/10747) [#12650](https://github.com/vuejs/core/issues/12650)
* **runtime-core:** prevent unmounted vnode from being inserted during transition leave ([#12862](https://github.com/vuejs/core/issues/12862)) ([d6a6ec1](https://github.com/vuejs/core/commit/d6a6ec13ce521683bfb2a22932778ef7b51f8600)), closes [#12860](https://github.com/vuejs/core/issues/12860)
* **runtime-core:** respect immutability for readonly reactive arrays in `v-for` ([#13091](https://github.com/vuejs/core/issues/13091)) ([3f27c58](https://github.com/vuejs/core/commit/3f27c58ffbd4309df369bc89493fdc284dc540bb)), closes [#13087](https://github.com/vuejs/core/issues/13087)
* **runtime-dom:** always treat autocorrect as attribute ([#13001](https://github.com/vuejs/core/issues/13001)) ([1499135](https://github.com/vuejs/core/commit/1499135c227236e037bb746beeb777941b0b58ff)), closes [#5705](https://github.com/vuejs/core/issues/5705)
* **slots:** properly warn if slot invoked in setup ([#12195](https://github.com/vuejs/core/issues/12195)) ([9196222](https://github.com/vuejs/core/commit/9196222ae1d63b52b35ac5fbf5e71494587ccf05)), closes [#12194](https://github.com/vuejs/core/issues/12194)
* **ssr:** properly init slots during ssr rendering ([#12441](https://github.com/vuejs/core/issues/12441)) ([2206cd2](https://github.com/vuejs/core/commit/2206cd235a1627c540e795e378b7564a55b47313)), closes [#12438](https://github.com/vuejs/core/issues/12438)
* **transition:** fix KeepAlive with transition out-in mode behavior in production ([#12468](https://github.com/vuejs/core/issues/12468)) ([343c891](https://github.com/vuejs/core/commit/343c89122448719bd6ed6bd9de986dfb2721d6bf)), closes [#12465](https://github.com/vuejs/core/issues/12465)
* **TransitionGroup:** reset prevChildren to prevent memory leak ([#13183](https://github.com/vuejs/core/issues/13183)) ([8b848cb](https://github.com/vuejs/core/commit/8b848cbbd2af337d23e19e202f9ab433f8580855)), closes [#13181](https://github.com/vuejs/core/issues/13181)
* **types:** allow return any for Options API lifecycle hooks ([#5914](https://github.com/vuejs/core/issues/5914)) ([06310e8](https://github.com/vuejs/core/commit/06310e82f5bed62d1b9733dcb18cd8d6edc988de))
* **types:** the directive's modifiers should be optional ([#12605](https://github.com/vuejs/core/issues/12605)) ([10e54dc](https://github.com/vuejs/core/commit/10e54dcc86a7967f3196d96200bcbd1d3d42082f))
* **typos:** fix comments referencing transformElement.ts ([#12551](https://github.com/vuejs/core/issues/12551))[ci-skip] ([11c053a](https://github.com/vuejs/core/commit/11c053a5429ad0d27a0e2c78b6b026ea00ace116))
### Features
* **types:** add type TemplateRef ([#12645](https://github.com/vuejs/core/issues/12645)) ([636a861](https://github.com/vuejs/core/commit/636a8619f06c71dfd79f7f6412fd130c4f84226f))
## [3.5.13](https://github.com/vuejs/core/compare/v3.5.12...v3.5.13) (2024-11-15)
### Bug Fixes
* **compiler-core:** handle v-memo + v-for with functional key ([#12014](https://github.com/vuejs/core/issues/12014)) ([99009ee](https://github.com/vuejs/core/commit/99009eee0efc238392daba93792d478525b21afa)), closes [#12013](https://github.com/vuejs/core/issues/12013)
* **compiler-dom:** properly stringify template string style ([#12392](https://github.com/vuejs/core/issues/12392)) ([2d78539](https://github.com/vuejs/core/commit/2d78539da35322aea5f821b3cf9b02d006abac72)), closes [#12391](https://github.com/vuejs/core/issues/12391)
* **custom-element:** avoid triggering mutationObserver when relecting props ([352bc88](https://github.com/vuejs/core/commit/352bc88c1bd2fda09c61ab17ea1a5967ffcd7bc0)), closes [#12214](https://github.com/vuejs/core/issues/12214) [#12215](https://github.com/vuejs/core/issues/12215)
* **deps:** update dependency postcss to ^8.4.48 ([#12356](https://github.com/vuejs/core/issues/12356)) ([b5ff930](https://github.com/vuejs/core/commit/b5ff930089985a58c3553977ef999cec2a6708a4))
* **hydration:** the component vnode's el should be updated when a mismatch occurs. ([#12255](https://github.com/vuejs/core/issues/12255)) ([a20a4cb](https://github.com/vuejs/core/commit/a20a4cb36a3e717d1f8f259d0d59f133f508ff0a)), closes [#12253](https://github.com/vuejs/core/issues/12253)
* **reactivity:** avoid unnecessary watcher effect removal from inactive scope ([2193284](https://github.com/vuejs/core/commit/21932840eae72ffcd357a62ec596aaecc7ec224a)), closes [#5783](https://github.com/vuejs/core/issues/5783) [#5806](https://github.com/vuejs/core/issues/5806)
* **reactivity:** release nested effects/scopes on effect scope stop ([#12373](https://github.com/vuejs/core/issues/12373)) ([bee2f5e](https://github.com/vuejs/core/commit/bee2f5ee62dc0cd04123b737779550726374dd0a)), closes [#12370](https://github.com/vuejs/core/issues/12370)
* **runtime-dom:** set css vars before user onMounted hooks ([2d5c5e2](https://github.com/vuejs/core/commit/2d5c5e25e9b7a56e883674fb434135ac514429b5)), closes [#11533](https://github.com/vuejs/core/issues/11533)
* **runtime-dom:** set css vars on update to handle child forcing reflow in onMount ([#11561](https://github.com/vuejs/core/issues/11561)) ([c4312f9](https://github.com/vuejs/core/commit/c4312f9c715c131a09e552ba46e9beb4b36d55e6))
* **ssr:** avoid updating subtree of async component if it is resolved ([#12363](https://github.com/vuejs/core/issues/12363)) ([da7ad5e](https://github.com/vuejs/core/commit/da7ad5e3d24f3e108401188d909d27a4910da095)), closes [#12362](https://github.com/vuejs/core/issues/12362)
* **ssr:** ensure v-text updates correctly with custom directives in SSR output ([#12311](https://github.com/vuejs/core/issues/12311)) ([1f75d4e](https://github.com/vuejs/core/commit/1f75d4e6dfe18121ebe443cd3e8105d54f727893)), closes [#12309](https://github.com/vuejs/core/issues/12309)
* **ssr:** handle initial selected state for select with v-model + v-for option ([#12399](https://github.com/vuejs/core/issues/12399)) ([4f8d807](https://github.com/vuejs/core/commit/4f8d8078221ee52deed266677a227ad2a6d8dd22)), closes [#12395](https://github.com/vuejs/core/issues/12395)
* **teleport:** handle deferred teleport update before mounted ([#12168](https://github.com/vuejs/core/issues/12168)) ([8bff142](https://github.com/vuejs/core/commit/8bff142f99b646e9dd15897ec75368fbf34f1534)), closes [#12161](https://github.com/vuejs/core/issues/12161)
* **templateRef:** set ref on cached async component which wrapped in KeepAlive ([#12290](https://github.com/vuejs/core/issues/12290)) ([983eb50](https://github.com/vuejs/core/commit/983eb50a17eac76f1bba4394ad0316c62b72191d)), closes [#4999](https://github.com/vuejs/core/issues/4999) [#5004](https://github.com/vuejs/core/issues/5004)
* **test:** update snapshot ([#12169](https://github.com/vuejs/core/issues/12169)) ([828d4a4](https://github.com/vuejs/core/commit/828d4a443919fa2aa4e2e92fbd03a5f04b258eea))
* **Transition:** fix transition memory leak edge case ([#12182](https://github.com/vuejs/core/issues/12182)) ([660132d](https://github.com/vuejs/core/commit/660132df6c6a8c14bf75e593dc47d2fdada30322)), closes [#12181](https://github.com/vuejs/core/issues/12181)
* **transition:** reflow before leave-active class after leave-from ([#12288](https://github.com/vuejs/core/issues/12288)) ([4b479db](https://github.com/vuejs/core/commit/4b479db61d233b054561402ae94ef08550073ea1)), closes [#2593](https://github.com/vuejs/core/issues/2593)
* **types:** defineEmits w/ interface declaration ([#12343](https://github.com/vuejs/core/issues/12343)) ([1022eab](https://github.com/vuejs/core/commit/1022eabaa1aaf8436876f5ec5573cb1e4b3959a6)), closes [#8457](https://github.com/vuejs/core/issues/8457)
* **v-once:** setting hasOnce to current block only when in v-once ([#12374](https://github.com/vuejs/core/issues/12374)) ([37300fc](https://github.com/vuejs/core/commit/37300fc26190a7299efddbf98800ffd96d5cad96)), closes [#12371](https://github.com/vuejs/core/issues/12371)
### Performance Improvements
* **reactivity:** do not track inner key `__v_skip`` ([#11690](https://github.com/vuejs/core/issues/11690)) ([d637bd6](https://github.com/vuejs/core/commit/d637bd6c0164c2883e6eabd3c2f1f8c258dedfb1))
* **runtime-core:** use feature flag for call to resolveMergedOptions ([#12163](https://github.com/vuejs/core/issues/12163)) ([1755ac0](https://github.com/vuejs/core/commit/1755ac0a108ba3486bd8397e56d3bdcd69196594))
## [3.5.12](https://github.com/vuejs/core/compare/v3.5.11...v3.5.12) (2024-10-11)
### Bug Fixes
* **compiler-dom:** avoid stringify option with null value ([#12096](https://github.com/vuejs/core/issues/12096)) ([f6d9926](https://github.com/vuejs/core/commit/f6d99262364b7444ebab8742158599e8cdd79eaa)), closes [#12093](https://github.com/vuejs/core/issues/12093)
* **compiler-sfc:** do not skip TSInstantiationExpression when transforming props destructure ([#12064](https://github.com/vuejs/core/issues/12064)) ([d3ecde8](https://github.com/vuejs/core/commit/d3ecde8a696ff62c8d0ab067fd1d7ee0565b63c5))
* **compiler-sfc:** use sass modern api if available and avoid deprecation warning ([#11992](https://github.com/vuejs/core/issues/11992)) ([4474c11](https://github.com/vuejs/core/commit/4474c113d1fb1c26298dd6794275d5b5c7cc4d93))
* **compiler:** clone loc to `ifNode` ([#12131](https://github.com/vuejs/core/issues/12131)) ([cde2c06](https://github.com/vuejs/core/commit/cde2c0671b00d4f6111fcbd7aa76e45872f20b0c)), closes [vuejs/language-tools#4911](https://github.com/vuejs/language-tools/issues/4911)
* **custom-element:** properly remove hyphenated attribute ([#12143](https://github.com/vuejs/core/issues/12143)) ([e16e9a7](https://github.com/vuejs/core/commit/e16e9a7341e7cfb3c443da4e5e5b06e8158712c3)), closes [#12139](https://github.com/vuejs/core/issues/12139)
* **defineModel:** handle kebab-case model correctly ([#12063](https://github.com/vuejs/core/issues/12063)) ([c0418a3](https://github.com/vuejs/core/commit/c0418a3b8fa96a0b108ab71b7aab5d3388f90557)), closes [#12060](https://github.com/vuejs/core/issues/12060)
* **deps:** update dependency monaco-editor to ^0.52.0 ([#12119](https://github.com/vuejs/core/issues/12119)) ([f7cbea2](https://github.com/vuejs/core/commit/f7cbea2111c7770a180b640f36f6a5d4d6abc698))
* **hydration:** provide compat fallback for idle callback hydration strategy ([#11935](https://github.com/vuejs/core/issues/11935)) ([1ae545a](https://github.com/vuejs/core/commit/1ae545a3786abef983be1c969726489685569c92))
* **reactivity:** trigger reactivity for Map key `undefined` ([#12055](https://github.com/vuejs/core/issues/12055)) ([7ad289e](https://github.com/vuejs/core/commit/7ad289e1e7fea654524008ff91e43a8b8a55ef22)), closes [#12054](https://github.com/vuejs/core/issues/12054)
* **runtime-core:** allow symbol values for slot prop key ([#12069](https://github.com/vuejs/core/issues/12069)) ([d9d4d4e](https://github.com/vuejs/core/commit/d9d4d4e158cd51a9ddda249f29de8467f60b2792)), closes [#12068](https://github.com/vuejs/core/issues/12068)
* **runtime-core:** fix required prop check false positive for kebab-case edge cases ([#12034](https://github.com/vuejs/core/issues/12034)) ([9da1ac1](https://github.com/vuejs/core/commit/9da1ac156552ac449754e1373aac7e349841becb)), closes [#12011](https://github.com/vuejs/core/issues/12011)
* **runtime-dom:** prevent unnecessary updates in v-model checkbox when value is unchanged ([#12146](https://github.com/vuejs/core/issues/12146)) ([ea943af](https://github.com/vuejs/core/commit/ea943afe404c4ca4b729906c5e8daf7aa2ccde9b)), closes [#12144](https://github.com/vuejs/core/issues/12144)
* **teleport:** handle disabled teleport with updateCssVars ([#12113](https://github.com/vuejs/core/issues/12113)) ([76a8223](https://github.com/vuejs/core/commit/76a8223199c148b79a5c0ea19e235164809760cd)), closes [#12112](https://github.com/vuejs/core/issues/12112)
* **transition/ssr:** make transition appear work with Suspense in SSR ([#12047](https://github.com/vuejs/core/issues/12047)) ([f1a4f67](https://github.com/vuejs/core/commit/f1a4f67aedfe83e440c54222213f070774faa421)), closes [#12046](https://github.com/vuejs/core/issues/12046)
* **types:** ensure `this.$props` type does not include `string` ([#12123](https://github.com/vuejs/core/issues/12123)) ([704173e](https://github.com/vuejs/core/commit/704173e24276706de672cca6c9507e4dd9651197)), closes [#12122](https://github.com/vuejs/core/issues/12122)
* **types:** retain union type narrowing with defaults applied ([#12108](https://github.com/vuejs/core/issues/12108)) ([05685a9](https://github.com/vuejs/core/commit/05685a9d7c42d4cd37169b867833776b91154fed)), closes [#12106](https://github.com/vuejs/core/issues/12106)
* **useId:** ensure useId consistency when using serverPrefetch ([#12128](https://github.com/vuejs/core/issues/12128)) ([b4d3534](https://github.com/vuejs/core/commit/b4d35349d8bc39aa15bd3f1094d230e5928b177c)), closes [#12102](https://github.com/vuejs/core/issues/12102)
* **watch:** watchEffect clean-up with SSR ([#12097](https://github.com/vuejs/core/issues/12097)) ([b094c72](https://github.com/vuejs/core/commit/b094c72b3d40c52c7124f145a9db028509a11202)), closes [#11956](https://github.com/vuejs/core/issues/11956)
### Performance Improvements
* **reactivity:** avoid unnecessary recursion in removeSub ([#12135](https://github.com/vuejs/core/issues/12135)) ([ec917cf](https://github.com/vuejs/core/commit/ec917cfdb9d0169cd0835d3a0e28244242657dc9))
## [3.5.11](https://github.com/vuejs/core/compare/v3.5.10...v3.5.11) (2024-10-03)
### Bug Fixes
* **compiler-sfc:** do not skip `TSSatisfiesExpression` when transforming props destructure ([#12062](https://github.com/vuejs/core/issues/12062)) ([2328b05](https://github.com/vuejs/core/commit/2328b051f4efa1f1394b7d4e73b7c3f76e430e7c)), closes [#12061](https://github.com/vuejs/core/issues/12061)
* **reactivity:** prevent overwriting `next` property during batch processing ([#12075](https://github.com/vuejs/core/issues/12075)) ([d3f5e6e](https://github.com/vuejs/core/commit/d3f5e6e5319b4ffaa55ca9a2ea3d95d78e76fa58)), closes [#12072](https://github.com/vuejs/core/issues/12072)
* **scheduler:** job ordering when the post queue is flushing ([#12090](https://github.com/vuejs/core/issues/12090)) ([577edca](https://github.com/vuejs/core/commit/577edca8e7795436efd710d1c289ea8ea2642b0e))
* **types:** correctly infer `TypeProps` when it is `any` ([#12073](https://github.com/vuejs/core/issues/12073)) ([57315ab](https://github.com/vuejs/core/commit/57315ab9688c9741a271d1075bbd28cbe5f71e2f)), closes [#12058](https://github.com/vuejs/core/issues/12058)
* **types:** should not intersect `PublicProps` with `Props` ([#12077](https://github.com/vuejs/core/issues/12077)) ([6f85894](https://github.com/vuejs/core/commit/6f8589437635706f825ccec51800effba1d2bf5f))
* **types:** infer the first generic type of `Ref` correctly ([#12094](https://github.com/vuejs/core/issues/12094)) ([c97bb84](https://github.com/vuejs/core/commit/c97bb84d0b0a16b012f886b6498e924415ed63e5))
## [3.5.10](https://github.com/vuejs/core/compare/v3.5.9...v3.5.10) (2024-09-27)
### Bug Fixes
* **custom-element:** properly set kebab-case props on Vue custom elements ([ea3efa0](https://github.com/vuejs/core/commit/ea3efa09e008918c1d9ba7226833a8b1a7a57244)), closes [#12030](https://github.com/vuejs/core/issues/12030) [#12032](https://github.com/vuejs/core/issues/12032)
* **reactivity:** fix nested batch edge case ([93c95dd](https://github.com/vuejs/core/commit/93c95dd4cd416503f43a98a1455f62658d22b0b2))
* **reactivity:** only clear notified flags for computed in first batch iteration ([aa9ef23](https://github.com/vuejs/core/commit/aa9ef2386a0cd39a174e5a887ec2b1a3525034fc)), closes [#12045](https://github.com/vuejs/core/issues/12045)
* **types/ref:** handle nested refs in UnwrapRef ([#12049](https://github.com/vuejs/core/issues/12049)) ([e2c19c2](https://github.com/vuejs/core/commit/e2c19c20cfee9788519a80c0e53e216b78505994)), closes [#12044](https://github.com/vuejs/core/issues/12044)
## [3.5.9](https://github.com/vuejs/core/compare/v3.5.8...v3.5.9) (2024-09-26) ## [3.5.9](https://github.com/vuejs/core/compare/v3.5.8...v3.5.9) (2024-09-26)

View File

@ -34,7 +34,8 @@ Please make sure to respect issue requirements and use [the new issue helper](ht
## Stay In Touch ## Stay In Touch
- [Twitter](https://twitter.com/vuejs) - [X](https://x.com/vuejs)
- [Bluesky](https://bsky.app/profile/vuejs.org)
- [Blog](https://blog.vuejs.org/) - [Blog](https://blog.vuejs.org/)
- [Job Board](https://vuejobs.com/?ref=vuejs) - [Job Board](https://vuejobs.com/?ref=vuejs)
@ -44,7 +45,9 @@ Please make sure to read the [Contributing Guide](https://github.com/vuejs/core/
Thank you to all the people who already contributed to Vue! Thank you to all the people who already contributed to Vue!
<a href="https://github.com/vuejs/core/graphs/contributors"><img src="https://opencollective.com/vuejs/contributors.svg?width=890" /></a> <a href="https://github.com/vuejs/core/graphs/contributors"><img src="https://opencollective.com/vuejs/contributors.svg?width=890&limit=500" /></a>
<sub>_Note: Showing the first 500 contributors only due to GitHub image size limitations_</sub>
## License ## License

View File

@ -56,13 +56,13 @@
- **hydration:** handle camel-case tag name when performing match assertion ([#3247](https://github.com/vuejs/core/issues/3247)) ([9036f88](https://github.com/vuejs/core/commit/9036f88d8304a3455265f1ecd86ec8f4a5ea4715)), closes [#3243](https://github.com/vuejs/core/issues/3243) - **hydration:** handle camel-case tag name when performing match assertion ([#3247](https://github.com/vuejs/core/issues/3247)) ([9036f88](https://github.com/vuejs/core/commit/9036f88d8304a3455265f1ecd86ec8f4a5ea4715)), closes [#3243](https://github.com/vuejs/core/issues/3243)
- **KeepAlive:** adapt keepalive for ssr ([#3259](https://github.com/vuejs/core/issues/3259)) ([e8e9b00](https://github.com/vuejs/core/commit/e8e9b00f81ed42434afd92f84101e7a14d70a23c)), closes [#3255](https://github.com/vuejs/core/issues/3255) - **KeepAlive:** adapt keepalive for ssr ([#3259](https://github.com/vuejs/core/issues/3259)) ([e8e9b00](https://github.com/vuejs/core/commit/e8e9b00f81ed42434afd92f84101e7a14d70a23c)), closes [#3255](https://github.com/vuejs/core/issues/3255)
- **reactivity:** ensure computed can be wrapped by readonly ([41e02f0](https://github.com/vuejs/core/commit/41e02f0fac069c93c94438741517e713f3c94215)), closes [#3376](https://github.com/vuejs/core/issues/3376) - **reactivity:** ensure computed can be wrapped by readonly ([41e02f0](https://github.com/vuejs/core/commit/41e02f0fac069c93c94438741517e713f3c94215)), closes [#3376](https://github.com/vuejs/core/issues/3376)
- **reactivity:** ensure that shallow and normal proxies are tracked seperately (close [#2843](https://github.com/vuejs/core/issues/2843)) ([#2851](https://github.com/vuejs/core/issues/2851)) ([22cc4a7](https://github.com/vuejs/core/commit/22cc4a76592cfe336e75e2fa0c05232ae1f0f149)) - **reactivity:** ensure that shallow and normal proxies are tracked separately (close [#2843](https://github.com/vuejs/core/issues/2843)) ([#2851](https://github.com/vuejs/core/issues/2851)) ([22cc4a7](https://github.com/vuejs/core/commit/22cc4a76592cfe336e75e2fa0c05232ae1f0f149))
- **reactivity:** fix shallow readonly behavior for collections ([#3003](https://github.com/vuejs/core/issues/3003)) ([68de9f4](https://github.com/vuejs/core/commit/68de9f408a2e61a5726a4a0d03b026cba451c5bd)), closes [#3007](https://github.com/vuejs/core/issues/3007) - **reactivity:** fix shallow readonly behavior for collections ([#3003](https://github.com/vuejs/core/issues/3003)) ([68de9f4](https://github.com/vuejs/core/commit/68de9f408a2e61a5726a4a0d03b026cba451c5bd)), closes [#3007](https://github.com/vuejs/core/issues/3007)
- **rumtime-core:** custom dom props should be cloned when cloning a hoisted DOM ([#3080](https://github.com/vuejs/core/issues/3080)) ([5dbe834](https://github.com/vuejs/core/commit/5dbe8348581dacd7a3594a9b0055ce350ce8e5bf)), closes [#3072](https://github.com/vuejs/core/issues/3072) - **rumtime-core:** custom dom props should be cloned when cloning a hoisted DOM ([#3080](https://github.com/vuejs/core/issues/3080)) ([5dbe834](https://github.com/vuejs/core/commit/5dbe8348581dacd7a3594a9b0055ce350ce8e5bf)), closes [#3072](https://github.com/vuejs/core/issues/3072)
- **runtime-core:** cache props default values to avoid unnecessary watcher trigger ([#3474](https://github.com/vuejs/core/issues/3474)) ([44166b4](https://github.com/vuejs/core/commit/44166b43d9be1062f79612880f71284049bcab0b)), closes [#3471](https://github.com/vuejs/core/issues/3471) - **runtime-core:** cache props default values to avoid unnecessary watcher trigger ([#3474](https://github.com/vuejs/core/issues/3474)) ([44166b4](https://github.com/vuejs/core/commit/44166b43d9be1062f79612880f71284049bcab0b)), closes [#3471](https://github.com/vuejs/core/issues/3471)
- **runtime-core:** ensure only skip unflushed job ([#3406](https://github.com/vuejs/core/issues/3406)) ([bf34e33](https://github.com/vuejs/core/commit/bf34e33c909da89681b9c5004cdf04ab198ec5a7)) - **runtime-core:** ensure only skip unflushed job ([#3406](https://github.com/vuejs/core/issues/3406)) ([bf34e33](https://github.com/vuejs/core/commit/bf34e33c909da89681b9c5004cdf04ab198ec5a7))
- **runtime-core:** fix async component ref handling ([#3191](https://github.com/vuejs/core/issues/3191)) ([7562e72](https://github.com/vuejs/core/commit/7562e72c2b58a5646bd4fbd9adea11eb884fe140)), closes [#3188](https://github.com/vuejs/core/issues/3188) - **runtime-core:** fix async component ref handling ([#3191](https://github.com/vuejs/core/issues/3191)) ([7562e72](https://github.com/vuejs/core/commit/7562e72c2b58a5646bd4fbd9adea11eb884fe140)), closes [#3188](https://github.com/vuejs/core/issues/3188)
- **runtime-core:** fix erraneous emits warnings w/ mixins ([60d777d](https://github.com/vuejs/core/commit/60d777d228414515cc32526ad72a53ef070501be)), closes [#2651](https://github.com/vuejs/core/issues/2651) - **runtime-core:** fix erroneous emits warnings w/ mixins ([60d777d](https://github.com/vuejs/core/commit/60d777d228414515cc32526ad72a53ef070501be)), closes [#2651](https://github.com/vuejs/core/issues/2651)
- **runtime-core:** fix warning for absent props ([#3363](https://github.com/vuejs/core/issues/3363)) ([86ceef4](https://github.com/vuejs/core/commit/86ceef43523bfbbb0a24731d3802ca6849cbefd6)), closes [#3362](https://github.com/vuejs/core/issues/3362) - **runtime-core:** fix warning for absent props ([#3363](https://github.com/vuejs/core/issues/3363)) ([86ceef4](https://github.com/vuejs/core/commit/86ceef43523bfbbb0a24731d3802ca6849cbefd6)), closes [#3362](https://github.com/vuejs/core/issues/3362)
- **runtime-core:** handle error in async setup ([#2881](https://github.com/vuejs/core/issues/2881)) ([d668d48](https://github.com/vuejs/core/commit/d668d48e9e5211a49ee53361ea5b4d67ba16e0a3)) - **runtime-core:** handle error in async setup ([#2881](https://github.com/vuejs/core/issues/2881)) ([d668d48](https://github.com/vuejs/core/commit/d668d48e9e5211a49ee53361ea5b4d67ba16e0a3))
- **runtime-core:** handle error in async watchEffect ([#3129](https://github.com/vuejs/core/issues/3129)) ([eb1fae6](https://github.com/vuejs/core/commit/eb1fae63f926435fb0eef890663d24e09d4c79e1)) - **runtime-core:** handle error in async watchEffect ([#3129](https://github.com/vuejs/core/issues/3129)) ([eb1fae6](https://github.com/vuejs/core/commit/eb1fae63f926435fb0eef890663d24e09d4c79e1))
@ -202,7 +202,7 @@ may cause build issues in projects still using TS 3.x.
- **script-setup:** ensure useContext() return valid context ([73cdb9d](https://github.com/vuejs/core/commit/73cdb9d4208f887fe08349657122e39175d7166c)) - **script-setup:** ensure useContext() return valid context ([73cdb9d](https://github.com/vuejs/core/commit/73cdb9d4208f887fe08349657122e39175d7166c))
- **slots:** dynamically named slots should be keyed by name ([2ab8c41](https://github.com/vuejs/core/commit/2ab8c41a1a43952fb229587a9da48d9a1214ab9e)), closes [#2535](https://github.com/vuejs/core/issues/2535) - **slots:** dynamically named slots should be keyed by name ([2ab8c41](https://github.com/vuejs/core/commit/2ab8c41a1a43952fb229587a9da48d9a1214ab9e)), closes [#2535](https://github.com/vuejs/core/issues/2535)
- **slots:** should render fallback content when slot content contains no valid nodes ([#2485](https://github.com/vuejs/core/issues/2485)) ([ce4915d](https://github.com/vuejs/core/commit/ce4915d8bed12f4cdb5fa8ca39bda98d0d3aabb7)), closes [#2347](https://github.com/vuejs/core/issues/2347) [#2461](https://github.com/vuejs/core/issues/2461) - **slots:** should render fallback content when slot content contains no valid nodes ([#2485](https://github.com/vuejs/core/issues/2485)) ([ce4915d](https://github.com/vuejs/core/commit/ce4915d8bed12f4cdb5fa8ca39bda98d0d3aabb7)), closes [#2347](https://github.com/vuejs/core/issues/2347) [#2461](https://github.com/vuejs/core/issues/2461)
- **suspense:** fix nested async child toggle inside already resovled suspense ([cf7f1db](https://github.com/vuejs/core/commit/cf7f1dbc9be8d50ad220e3630c38f5a9a217d693)), closes [#2215](https://github.com/vuejs/core/issues/2215) - **suspense:** fix nested async child toggle inside already resolved suspense ([cf7f1db](https://github.com/vuejs/core/commit/cf7f1dbc9be8d50ad220e3630c38f5a9a217d693)), closes [#2215](https://github.com/vuejs/core/issues/2215)
- **teleport:** Teleport into SVG elements ([#2648](https://github.com/vuejs/core/issues/2648)) ([cd92836](https://github.com/vuejs/core/commit/cd928362232747a51d1fd4790bb20adcdd59d187)), closes [#2652](https://github.com/vuejs/core/issues/2652) - **teleport:** Teleport into SVG elements ([#2648](https://github.com/vuejs/core/issues/2648)) ([cd92836](https://github.com/vuejs/core/commit/cd928362232747a51d1fd4790bb20adcdd59d187)), closes [#2652](https://github.com/vuejs/core/issues/2652)
- **transition:** avoid invoking stale transition end callbacks ([eaf8a67](https://github.com/vuejs/core/commit/eaf8a67c7219e1b79d6abca44a1d7f1b341b58b0)), closes [#2482](https://github.com/vuejs/core/issues/2482) - **transition:** avoid invoking stale transition end callbacks ([eaf8a67](https://github.com/vuejs/core/commit/eaf8a67c7219e1b79d6abca44a1d7f1b341b58b0)), closes [#2482](https://github.com/vuejs/core/issues/2482)
- **transition:** respect rules in \*-leave-from transition class ([#2597](https://github.com/vuejs/core/issues/2597)) ([e2618a6](https://github.com/vuejs/core/commit/e2618a632d4add2819ffb8b575af0da189dc3204)), closes [#2593](https://github.com/vuejs/core/issues/2593) - **transition:** respect rules in \*-leave-from transition class ([#2597](https://github.com/vuejs/core/issues/2597)) ([e2618a6](https://github.com/vuejs/core/commit/e2618a632d4add2819ffb8b575af0da189dc3204)), closes [#2593](https://github.com/vuejs/core/issues/2593)
@ -236,7 +236,7 @@ may cause build issues in projects still using TS 3.x.
- **compiler-sfc:** compileScript inline render function mode ([886ed76](https://github.com/vuejs/core/commit/886ed7681dd203c07ff3b504538328f43e14d9b0)) - **compiler-sfc:** compileScript inline render function mode ([886ed76](https://github.com/vuejs/core/commit/886ed7681dd203c07ff3b504538328f43e14d9b0))
- **compiler-sfc:** new script setup implementation ([556560f](https://github.com/vuejs/core/commit/556560fae31d9e406cfae656089657b6332686c1)) - **compiler-sfc:** new script setup implementation ([556560f](https://github.com/vuejs/core/commit/556560fae31d9e406cfae656089657b6332686c1))
- **compiler-sfc:** new SFC css varaible injection implementation ([41bb7fa](https://github.com/vuejs/core/commit/41bb7fa330e78c4a354a2e67742bd13bee2f4293)) - **compiler-sfc:** new SFC css variable injection implementation ([41bb7fa](https://github.com/vuejs/core/commit/41bb7fa330e78c4a354a2e67742bd13bee2f4293))
- **compiler-sfc:** support kebab-case components in `<script setup>` sfc template ([3f99e23](https://github.com/vuejs/core/commit/3f99e239e03a8861c462d4ee91feb82066ab3e28)) - **compiler-sfc:** support kebab-case components in `<script setup>` sfc template ([3f99e23](https://github.com/vuejs/core/commit/3f99e239e03a8861c462d4ee91feb82066ab3e28))
- **runtime-core:** explicit expose API ([0e59770](https://github.com/vuejs/core/commit/0e59770b9282992f6a5af4d8fef33dafb948fc8b)) - **runtime-core:** explicit expose API ([0e59770](https://github.com/vuejs/core/commit/0e59770b9282992f6a5af4d8fef33dafb948fc8b))
@ -282,7 +282,7 @@ may cause build issues in projects still using TS 3.x.
- **runtime-core:** fix directive merging on component root ([4d1ebb5](https://github.com/vuejs/core/commit/4d1ebb5deb4c1cb2a02e8482bf8f9cc87197b088)), closes [#2298](https://github.com/vuejs/core/issues/2298) - **runtime-core:** fix directive merging on component root ([4d1ebb5](https://github.com/vuejs/core/commit/4d1ebb5deb4c1cb2a02e8482bf8f9cc87197b088)), closes [#2298](https://github.com/vuejs/core/issues/2298)
- **runtime-core:** fix duplicated unmount traversal in optimized mode ([376883d](https://github.com/vuejs/core/commit/376883d1cfea6ed92807cce1f1209f943a04b625)), closes [#2169](https://github.com/vuejs/core/issues/2169) - **runtime-core:** fix duplicated unmount traversal in optimized mode ([376883d](https://github.com/vuejs/core/commit/376883d1cfea6ed92807cce1f1209f943a04b625)), closes [#2169](https://github.com/vuejs/core/issues/2169)
- **runtime-core:** fix provide function data access in extends/mixins ([f06518a](https://github.com/vuejs/core/commit/f06518a8c9201b4fa2a956595aa9d89a192fcd20)), closes [#2300](https://github.com/vuejs/core/issues/2300) - **runtime-core:** fix provide function data access in extends/mixins ([f06518a](https://github.com/vuejs/core/commit/f06518a8c9201b4fa2a956595aa9d89a192fcd20)), closes [#2300](https://github.com/vuejs/core/issues/2300)
- **runtime-core:** fix SSR memoery leak due to props normalization cache ([a66e53a](https://github.com/vuejs/core/commit/a66e53a24f445b688eef6812ecb872dc53cf2702)), closes [#2225](https://github.com/vuejs/core/issues/2225) - **runtime-core:** fix SSR memory leak due to props normalization cache ([a66e53a](https://github.com/vuejs/core/commit/a66e53a24f445b688eef6812ecb872dc53cf2702)), closes [#2225](https://github.com/vuejs/core/issues/2225)
- **runtime-core:** make errorCaptured return value handling consistent with Vue 2 ([#2289](https://github.com/vuejs/core/issues/2289)) ([4d20ac8](https://github.com/vuejs/core/commit/4d20ac8173f84c87288255dcc03c62a6ee862a23)), closes [#2267](https://github.com/vuejs/core/issues/2267) - **runtime-core:** make errorCaptured return value handling consistent with Vue 2 ([#2289](https://github.com/vuejs/core/issues/2289)) ([4d20ac8](https://github.com/vuejs/core/commit/4d20ac8173f84c87288255dcc03c62a6ee862a23)), closes [#2267](https://github.com/vuejs/core/issues/2267)
- **runtime-core:** use consistent camelCase event casing for render functions ([#2278](https://github.com/vuejs/core/issues/2278)) ([62f2617](https://github.com/vuejs/core/commit/62f26173ba715fd8bf2b131e19d94275106e830d)), closes [#2249](https://github.com/vuejs/core/issues/2249) - **runtime-core:** use consistent camelCase event casing for render functions ([#2278](https://github.com/vuejs/core/issues/2278)) ([62f2617](https://github.com/vuejs/core/commit/62f26173ba715fd8bf2b131e19d94275106e830d)), closes [#2249](https://github.com/vuejs/core/issues/2249)
- **runtime-core:** vnode.el is null in watcher after rerendering ([#2295](https://github.com/vuejs/core/issues/2295)) ([28d5fd7](https://github.com/vuejs/core/commit/28d5fd7a2871c10df3427dfbbe0e203c2a976cb4)), closes [#2170](https://github.com/vuejs/core/issues/2170) - **runtime-core:** vnode.el is null in watcher after rerendering ([#2295](https://github.com/vuejs/core/issues/2295)) ([28d5fd7](https://github.com/vuejs/core/commit/28d5fd7a2871c10df3427dfbbe0e203c2a976cb4)), closes [#2170](https://github.com/vuejs/core/issues/2170)
@ -450,7 +450,7 @@ may cause build issues in projects still using TS 3.x.
- **compiler-core:** should attach key to single element child of `<template v-for>` ([#1910](https://github.com/vuejs/core/issues/1910)) ([69cfed6](https://github.com/vuejs/core/commit/69cfed6b313821d1ae7ecb02b63b0aaccb5599c6)) - **compiler-core:** should attach key to single element child of `<template v-for>` ([#1910](https://github.com/vuejs/core/issues/1910)) ([69cfed6](https://github.com/vuejs/core/commit/69cfed6b313821d1ae7ecb02b63b0aaccb5599c6))
- **reactivity:** unwrap non-index accessed refs on reactive arrays ([#1859](https://github.com/vuejs/core/issues/1859)) ([3c05f8b](https://github.com/vuejs/core/commit/3c05f8bbd6cd0e01bbc5830730852f9a93d8de8a)), closes [#1846](https://github.com/vuejs/core/issues/1846) - **reactivity:** unwrap non-index accessed refs on reactive arrays ([#1859](https://github.com/vuejs/core/issues/1859)) ([3c05f8b](https://github.com/vuejs/core/commit/3c05f8bbd6cd0e01bbc5830730852f9a93d8de8a)), closes [#1846](https://github.com/vuejs/core/issues/1846)
- **runtime-core:** correctly track dynamic nodes in renderSlot ([#1911](https://github.com/vuejs/core/issues/1911)) ([7ffb79c](https://github.com/vuejs/core/commit/7ffb79c56318861075a47bd2357e34cde8a6dad9)) - **runtime-core:** correctly track dynamic nodes in renderSlot ([#1911](https://github.com/vuejs/core/issues/1911)) ([7ffb79c](https://github.com/vuejs/core/commit/7ffb79c56318861075a47bd2357e34cde8a6dad9))
- **runtime-core:** disable block tracking when calling compiled slot function in tempalte expressions ([f02e2f9](https://github.com/vuejs/core/commit/f02e2f99d9c2ca95f4fd984d7bd62178eceaa214)), closes [#1745](https://github.com/vuejs/core/issues/1745) [#1918](https://github.com/vuejs/core/issues/1918) - **runtime-core:** disable block tracking when calling compiled slot function in template expressions ([f02e2f9](https://github.com/vuejs/core/commit/f02e2f99d9c2ca95f4fd984d7bd62178eceaa214)), closes [#1745](https://github.com/vuejs/core/issues/1745) [#1918](https://github.com/vuejs/core/issues/1918)
- **teleport:** only inherit el for non-patched nodes ([d4cc7b2](https://github.com/vuejs/core/commit/d4cc7b2496f9ed21ef6cac426697eac058da76bb)), closes [#1903](https://github.com/vuejs/core/issues/1903) - **teleport:** only inherit el for non-patched nodes ([d4cc7b2](https://github.com/vuejs/core/commit/d4cc7b2496f9ed21ef6cac426697eac058da76bb)), closes [#1903](https://github.com/vuejs/core/issues/1903)
### Performance Improvements ### Performance Improvements
@ -631,7 +631,7 @@ may cause build issues in projects still using TS 3.x.
- **runtime-dom/v-on:** only block event handlers based on attach timestamp ([8b320cc](https://github.com/vuejs/core/commit/8b320cc12f74aafea9ec69f7ce70231d4f0d08fd)), closes [#1565](https://github.com/vuejs/core/issues/1565) - **runtime-dom/v-on:** only block event handlers based on attach timestamp ([8b320cc](https://github.com/vuejs/core/commit/8b320cc12f74aafea9ec69f7ce70231d4f0d08fd)), closes [#1565](https://github.com/vuejs/core/issues/1565)
- **slots:** differentiate dynamic/static compiled slots ([65beba9](https://github.com/vuejs/core/commit/65beba98fe5793133d3218945218b9e3f8d136eb)), closes [#1557](https://github.com/vuejs/core/issues/1557) - **slots:** differentiate dynamic/static compiled slots ([65beba9](https://github.com/vuejs/core/commit/65beba98fe5793133d3218945218b9e3f8d136eb)), closes [#1557](https://github.com/vuejs/core/issues/1557)
- **v-on:** capitalize dynamic event names ([9152a89](https://github.com/vuejs/core/commit/9152a8901653d7cef864a52a3c618afcc70d827d)) - **v-on:** capitalize dynamic event names ([9152a89](https://github.com/vuejs/core/commit/9152a8901653d7cef864a52a3c618afcc70d827d))
- **v-on:** refactor DOM event options modifer handling ([380c679](https://github.com/vuejs/core/commit/380c6792d8899f1a43a9e6400c5df483c63290b6)), closes [#1567](https://github.com/vuejs/core/issues/1567) - **v-on:** refactor DOM event options modifier handling ([380c679](https://github.com/vuejs/core/commit/380c6792d8899f1a43a9e6400c5df483c63290b6)), closes [#1567](https://github.com/vuejs/core/issues/1567)
### Features ### Features
@ -743,7 +743,7 @@ may cause build issues in projects still using TS 3.x.
- **compiler-core:** fix parsing for directive with dynamic argument containing dots ([0d26413](https://github.com/vuejs/core/commit/0d26413433d41389f5525a0ef2c2dd7cfbb454d4)) - **compiler-core:** fix parsing for directive with dynamic argument containing dots ([0d26413](https://github.com/vuejs/core/commit/0d26413433d41389f5525a0ef2c2dd7cfbb454d4))
- **compiler-core:** support static slot names containing dots for 2.x compat ([825ec15](https://github.com/vuejs/core/commit/825ec1500feda8b0c43245e7e92074af7f9dcca2)), closes [#1241](https://github.com/vuejs/core/issues/1241) - **compiler-core:** support static slot names containing dots for 2.x compat ([825ec15](https://github.com/vuejs/core/commit/825ec1500feda8b0c43245e7e92074af7f9dcca2)), closes [#1241](https://github.com/vuejs/core/issues/1241)
- **hmr:** force full update on nested child components ([#1312](https://github.com/vuejs/core/issues/1312)) ([8f2a748](https://github.com/vuejs/core/commit/8f2a7489b7c74f5cfc1844697c60287c37fc0eb8)) - **hmr:** force full update on nested child components ([#1312](https://github.com/vuejs/core/issues/1312)) ([8f2a748](https://github.com/vuejs/core/commit/8f2a7489b7c74f5cfc1844697c60287c37fc0eb8))
- **reactivity:** fix toRaw for objects prototype inherting reactive ([10bb34b](https://github.com/vuejs/core/commit/10bb34bb869a47c37d945f8c80abf723fac9fc1a)), closes [#1246](https://github.com/vuejs/core/issues/1246) - **reactivity:** fix toRaw for objects prototype inheriting reactive ([10bb34b](https://github.com/vuejs/core/commit/10bb34bb869a47c37d945f8c80abf723fac9fc1a)), closes [#1246](https://github.com/vuejs/core/issues/1246)
- **runtime-core:** should pass instance to patchProp on mount for event error handling ([#1337](https://github.com/vuejs/core/issues/1337)) ([aac9b03](https://github.com/vuejs/core/commit/aac9b03c11c9be0c67b924004364a42d04d78195)), closes [#1336](https://github.com/vuejs/core/issues/1336) - **runtime-core:** should pass instance to patchProp on mount for event error handling ([#1337](https://github.com/vuejs/core/issues/1337)) ([aac9b03](https://github.com/vuejs/core/commit/aac9b03c11c9be0c67b924004364a42d04d78195)), closes [#1336](https://github.com/vuejs/core/issues/1336)
- **runtime-core:** track access to $attrs ([6abac87](https://github.com/vuejs/core/commit/6abac87b3d1b7a22df80b7a70a10101a7f3d3732)), closes [#1346](https://github.com/vuejs/core/issues/1346) - **runtime-core:** track access to $attrs ([6abac87](https://github.com/vuejs/core/commit/6abac87b3d1b7a22df80b7a70a10101a7f3d3732)), closes [#1346](https://github.com/vuejs/core/issues/1346)
- always treat spellcheck and draggable as attributes ([4492b88](https://github.com/vuejs/core/commit/4492b88938922a7f1bcc36a608375ad99f16b22e)), closes [#1350](https://github.com/vuejs/core/issues/1350) - always treat spellcheck and draggable as attributes ([4492b88](https://github.com/vuejs/core/commit/4492b88938922a7f1bcc36a608375ad99f16b22e)), closes [#1350](https://github.com/vuejs/core/issues/1350)
@ -863,7 +863,7 @@ may cause build issues in projects still using TS 3.x.
### Bug Fixes ### Bug Fixes
- **compiler:** bail strigification on runtime constant expressions ([f9a3766](https://github.com/vuejs/core/commit/f9a3766fd68dc6996cdbda6475287c4005f55243)) - **compiler:** bail stringification on runtime constant expressions ([f9a3766](https://github.com/vuejs/core/commit/f9a3766fd68dc6996cdbda6475287c4005f55243))
- **transitionGroup:** fix transition children resolving condition ([f05aeea](https://github.com/vuejs/core/commit/f05aeea7aec2e6cd859f40edc6236afd0ce2ea7d)) - **transitionGroup:** fix transition children resolving condition ([f05aeea](https://github.com/vuejs/core/commit/f05aeea7aec2e6cd859f40edc6236afd0ce2ea7d))
### Features ### Features

View File

@ -28,7 +28,7 @@
- **build:** avoid using async/await syntax ([438754a](https://github.com/vuejs/core/commit/438754a0d1428d10e27d1a290beb4b81da5fdaeb)) - **build:** avoid using async/await syntax ([438754a](https://github.com/vuejs/core/commit/438754a0d1428d10e27d1a290beb4b81da5fdaeb))
- **build:** fix generated code containing unprocessed class field syntax ([2788154](https://github.com/vuejs/core/commit/2788154f7707928f1dd3e4d9bd144f758a8c0478)), closes [#4052](https://github.com/vuejs/core/issues/4052) [vuejs/vue-cli#6562](https://github.com/vuejs/vue-cli/issues/6562) - **build:** fix generated code containing unprocessed class field syntax ([2788154](https://github.com/vuejs/core/commit/2788154f7707928f1dd3e4d9bd144f758a8c0478)), closes [#4052](https://github.com/vuejs/core/issues/4052) [vuejs/vue-cli#6562](https://github.com/vuejs/vue-cli/issues/6562)
- **codegen:** ensure valid types in genreated code when using global directives ([a44d528](https://github.com/vuejs/core/commit/a44d528af1227c05dedf610b6ec45504d8e58276)), closes [#4054](https://github.com/vuejs/core/issues/4054) - **codegen:** ensure valid types in generated code when using global directives ([a44d528](https://github.com/vuejs/core/commit/a44d528af1227c05dedf610b6ec45504d8e58276)), closes [#4054](https://github.com/vuejs/core/issues/4054)
- **compiler-sfc:** fix parse-only mode when there is no script setup block ([253ca27](https://github.com/vuejs/core/commit/253ca2729d808fc051215876aa4af986e4caa43c)) - **compiler-sfc:** fix parse-only mode when there is no script setup block ([253ca27](https://github.com/vuejs/core/commit/253ca2729d808fc051215876aa4af986e4caa43c))
- **runtime-core:** add useAttrs and useSlots export ([#4053](https://github.com/vuejs/core/issues/4053)) ([735ada1](https://github.com/vuejs/core/commit/735ada1507623b8d36e80b30a4f67a8af4a45c99)) - **runtime-core:** add useAttrs and useSlots export ([#4053](https://github.com/vuejs/core/issues/4053)) ([735ada1](https://github.com/vuejs/core/commit/735ada1507623b8d36e80b30a4f67a8af4a45c99))
- **runtime-core:** fix instance accessed via $parent chain when using expose() ([#4048](https://github.com/vuejs/core/issues/4048)) ([12cf9f4](https://github.com/vuejs/core/commit/12cf9f4ea148a59fd9002ecf9ea9d365829ce37c)) - **runtime-core:** fix instance accessed via $parent chain when using expose() ([#4048](https://github.com/vuejs/core/issues/4048)) ([12cf9f4](https://github.com/vuejs/core/commit/12cf9f4ea148a59fd9002ecf9ea9d365829ce37c))
@ -114,7 +114,7 @@
### Performance Improvements ### Performance Improvements
- only trigger `$attrs` update when it has actually changed ([5566d39](https://github.com/vuejs/core/commit/5566d39d467ebdd4e4234bc97d62600ff01ea28e)) - only trigger `$attrs` update when it has actually changed ([5566d39](https://github.com/vuejs/core/commit/5566d39d467ebdd4e4234bc97d62600ff01ea28e))
- **compiler:** skip unncessary checks when parsing end tag ([048ac29](https://github.com/vuejs/core/commit/048ac299f35709b25ae1bc1efa67d2abc53dbc3b)) - **compiler:** skip unnecessary checks when parsing end tag ([048ac29](https://github.com/vuejs/core/commit/048ac299f35709b25ae1bc1efa67d2abc53dbc3b))
- avoid deopt for props/emits normalization when global mixins are used ([51d2be2](https://github.com/vuejs/core/commit/51d2be20386d4dc59006d31a1cc96676871027ce)) - avoid deopt for props/emits normalization when global mixins are used ([51d2be2](https://github.com/vuejs/core/commit/51d2be20386d4dc59006d31a1cc96676871027ce))
### Deprecations ### Deprecations
@ -181,7 +181,7 @@
* **compat:** avoid accidentally delete the modelValue prop ([#3772](https://github.com/vuejs/core/issues/3772)) ([4f17be7](https://github.com/vuejs/core/commit/4f17be7b1ce4872ded085a36b95c1897d8c1f299)) * **compat:** avoid accidentally delete the modelValue prop ([#3772](https://github.com/vuejs/core/issues/3772)) ([4f17be7](https://github.com/vuejs/core/commit/4f17be7b1ce4872ded085a36b95c1897d8c1f299))
* **compat:** enum coercion warning ([#3755](https://github.com/vuejs/core/issues/3755)) ([f01aadf](https://github.com/vuejs/core/commit/f01aadf2a16a7bef422eb039d7b157bef9ad32fc)) * **compat:** enum coercion warning ([#3755](https://github.com/vuejs/core/issues/3755)) ([f01aadf](https://github.com/vuejs/core/commit/f01aadf2a16a7bef422eb039d7b157bef9ad32fc))
* **compiler-core:** fix whitespace management for slots with whitespace: 'preserve' ([#3767](https://github.com/vuejs/core/issues/3767)) ([47da921](https://github.com/vuejs/core/commit/47da92146c9fb3fa6b1e250e064ca49b74d815e4)), closes [#3766](https://github.com/vuejs/core/issues/3766) * **compiler-core:** fix whitespace management for slots with whitespace: 'preserve' ([#3767](https://github.com/vuejs/core/issues/3767)) ([47da921](https://github.com/vuejs/core/commit/47da92146c9fb3fa6b1e250e064ca49b74d815e4)), closes [#3766](https://github.com/vuejs/core/issues/3766)
* **compiler-dom:** comments in the v-if branchs should be ignored when used in Transition ([#3622](https://github.com/vuejs/core/issues/3622)) ([7c74feb](https://github.com/vuejs/core/commit/7c74feb3dc6beae7ff3ad22193be3b5a0f4d8aac)), closes [#3619](https://github.com/vuejs/core/issues/3619) * **compiler-dom:** comments in the v-if branches should be ignored when used in Transition ([#3622](https://github.com/vuejs/core/issues/3622)) ([7c74feb](https://github.com/vuejs/core/commit/7c74feb3dc6beae7ff3ad22193be3b5a0f4d8aac)), closes [#3619](https://github.com/vuejs/core/issues/3619)
* **compiler-sfc:** support tsx in setup script ([#3825](https://github.com/vuejs/core/issues/3825)) ([01e8ba8](https://github.com/vuejs/core/commit/01e8ba8f873afe3857a23fb68b44fdc057e31781)), closes [#3808](https://github.com/vuejs/core/issues/3808) * **compiler-sfc:** support tsx in setup script ([#3825](https://github.com/vuejs/core/issues/3825)) ([01e8ba8](https://github.com/vuejs/core/commit/01e8ba8f873afe3857a23fb68b44fdc057e31781)), closes [#3808](https://github.com/vuejs/core/issues/3808)
* **compiler-ssr:** disable hoisting in compiler-ssr ([3ef1fcc](https://github.com/vuejs/core/commit/3ef1fcc8590da186664197a0a82e7856011c1693)), closes [#3536](https://github.com/vuejs/core/issues/3536) * **compiler-ssr:** disable hoisting in compiler-ssr ([3ef1fcc](https://github.com/vuejs/core/commit/3ef1fcc8590da186664197a0a82e7856011c1693)), closes [#3536](https://github.com/vuejs/core/issues/3536)
* **devtools:** send update to component owning the slot ([1355ee2](https://github.com/vuejs/core/commit/1355ee27a65d466bfe8f3a7ba99aa2213e25bc50)) * **devtools:** send update to component owning the slot ([1355ee2](https://github.com/vuejs/core/commit/1355ee27a65d466bfe8f3a7ba99aa2213e25bc50))
@ -265,7 +265,7 @@
- **compat:** avoid accidentally delete the modelValue prop ([#3772](https://github.com/vuejs/core/issues/3772)) ([4f17be7](https://github.com/vuejs/core/commit/4f17be7b1ce4872ded085a36b95c1897d8c1f299)) - **compat:** avoid accidentally delete the modelValue prop ([#3772](https://github.com/vuejs/core/issues/3772)) ([4f17be7](https://github.com/vuejs/core/commit/4f17be7b1ce4872ded085a36b95c1897d8c1f299))
- **compat:** enum coercion warning ([#3755](https://github.com/vuejs/core/issues/3755)) ([f01aadf](https://github.com/vuejs/core/commit/f01aadf2a16a7bef422eb039d7b157bef9ad32fc)) - **compat:** enum coercion warning ([#3755](https://github.com/vuejs/core/issues/3755)) ([f01aadf](https://github.com/vuejs/core/commit/f01aadf2a16a7bef422eb039d7b157bef9ad32fc))
- **compiler-core:** fix whitespace management for slots with whitespace: 'preserve' ([#3767](https://github.com/vuejs/core/issues/3767)) ([47da921](https://github.com/vuejs/core/commit/47da92146c9fb3fa6b1e250e064ca49b74d815e4)), closes [#3766](https://github.com/vuejs/core/issues/3766) - **compiler-core:** fix whitespace management for slots with whitespace: 'preserve' ([#3767](https://github.com/vuejs/core/issues/3767)) ([47da921](https://github.com/vuejs/core/commit/47da92146c9fb3fa6b1e250e064ca49b74d815e4)), closes [#3766](https://github.com/vuejs/core/issues/3766)
- **compiler-dom:** comments in the v-if branchs should be ignored when used in Transition ([#3622](https://github.com/vuejs/core/issues/3622)) ([7c74feb](https://github.com/vuejs/core/commit/7c74feb3dc6beae7ff3ad22193be3b5a0f4d8aac)), closes [#3619](https://github.com/vuejs/core/issues/3619) - **compiler-dom:** comments in the v-if branches should be ignored when used in Transition ([#3622](https://github.com/vuejs/core/issues/3622)) ([7c74feb](https://github.com/vuejs/core/commit/7c74feb3dc6beae7ff3ad22193be3b5a0f4d8aac)), closes [#3619](https://github.com/vuejs/core/issues/3619)
- **compiler-sfc:** support tsx in setup script ([#3825](https://github.com/vuejs/core/issues/3825)) ([01e8ba8](https://github.com/vuejs/core/commit/01e8ba8f873afe3857a23fb68b44fdc057e31781)), closes [#3808](https://github.com/vuejs/core/issues/3808) - **compiler-sfc:** support tsx in setup script ([#3825](https://github.com/vuejs/core/issues/3825)) ([01e8ba8](https://github.com/vuejs/core/commit/01e8ba8f873afe3857a23fb68b44fdc057e31781)), closes [#3808](https://github.com/vuejs/core/issues/3808)
- **compiler-ssr:** disable hoisting in compiler-ssr ([3ef1fcc](https://github.com/vuejs/core/commit/3ef1fcc8590da186664197a0a82e7856011c1693)), closes [#3536](https://github.com/vuejs/core/issues/3536) - **compiler-ssr:** disable hoisting in compiler-ssr ([3ef1fcc](https://github.com/vuejs/core/commit/3ef1fcc8590da186664197a0a82e7856011c1693)), closes [#3536](https://github.com/vuejs/core/issues/3536)
- **devtools:** send update to component owning the slot ([1355ee2](https://github.com/vuejs/core/commit/1355ee27a65d466bfe8f3a7ba99aa2213e25bc50)) - **devtools:** send update to component owning the slot ([1355ee2](https://github.com/vuejs/core/commit/1355ee27a65d466bfe8f3a7ba99aa2213e25bc50))
@ -317,4 +317,4 @@
### Performance Improvements ### Performance Improvements
- only trigger $attrs update when it has actually changed ([5566d39](https://github.com/vuejs/core/commit/5566d39d467ebdd4e4234bc97d62600ff01ea28e)) - only trigger $attrs update when it has actually changed ([5566d39](https://github.com/vuejs/core/commit/5566d39d467ebdd4e4234bc97d62600ff01ea28e))
- **compiler:** skip unncessary checks when parsing end tag ([048ac29](https://github.com/vuejs/core/commit/048ac299f35709b25ae1bc1efa67d2abc53dbc3b)) - **compiler:** skip unnecessary checks when parsing end tag ([048ac29](https://github.com/vuejs/core/commit/048ac299f35709b25ae1bc1efa67d2abc53dbc3b))

View File

@ -26,7 +26,7 @@
* **reactivity-transform:** fix $$ escape edge cases ([e06d3b6](https://github.com/vuejs/core/commit/e06d3b614ea518e9cdf83fca9200fc816eb4e5a1)), closes [#6312](https://github.com/vuejs/core/issues/6312) [#6944](https://github.com/vuejs/core/issues/6944) * **reactivity-transform:** fix $$ escape edge cases ([e06d3b6](https://github.com/vuejs/core/commit/e06d3b614ea518e9cdf83fca9200fc816eb4e5a1)), closes [#6312](https://github.com/vuejs/core/issues/6312) [#6944](https://github.com/vuejs/core/issues/6944)
* **reactivity-transform:** prohibit const assignment at compile time ([#6993](https://github.com/vuejs/core/issues/6993)) ([3427052](https://github.com/vuejs/core/commit/3427052229db3448252d938292a40e960a0f4b9c)), closes [#6992](https://github.com/vuejs/core/issues/6992) * **reactivity-transform:** prohibit const assignment at compile time ([#6993](https://github.com/vuejs/core/issues/6993)) ([3427052](https://github.com/vuejs/core/commit/3427052229db3448252d938292a40e960a0f4b9c)), closes [#6992](https://github.com/vuejs/core/issues/6992)
* **reactivity:** `triggerRef` working with `toRef` from reactive ([#7507](https://github.com/vuejs/core/issues/7507)) ([e64c9ae](https://github.com/vuejs/core/commit/e64c9ae957aa2606b55e8652bbde30a6ada59fb0)) * **reactivity:** `triggerRef` working with `toRef` from reactive ([#7507](https://github.com/vuejs/core/issues/7507)) ([e64c9ae](https://github.com/vuejs/core/commit/e64c9ae957aa2606b55e8652bbde30a6ada59fb0))
* **reactivity:** ensure watch(Effect) can run independent of unmounted instance if created in a detatched effectScope (fix [#7319](https://github.com/vuejs/core/issues/7319)) ([#7330](https://github.com/vuejs/core/issues/7330)) ([cd7c887](https://github.com/vuejs/core/commit/cd7c887b755810aedf83f3d458cb956d5b147f6f)) * **reactivity:** ensure watch(Effect) can run independent of unmounted instance if created in a detached effectScope (fix [#7319](https://github.com/vuejs/core/issues/7319)) ([#7330](https://github.com/vuejs/core/issues/7330)) ([cd7c887](https://github.com/vuejs/core/commit/cd7c887b755810aedf83f3d458cb956d5b147f6f))
* **reactivity:** track hasOwnProperty ([588bd44](https://github.com/vuejs/core/commit/588bd44f036b79d7dee5d23661aa7244f70e6beb)), closes [#2619](https://github.com/vuejs/core/issues/2619) [#2621](https://github.com/vuejs/core/issues/2621) * **reactivity:** track hasOwnProperty ([588bd44](https://github.com/vuejs/core/commit/588bd44f036b79d7dee5d23661aa7244f70e6beb)), closes [#2619](https://github.com/vuejs/core/issues/2619) [#2621](https://github.com/vuejs/core/issues/2621)
* **runtime-core:** ensure prop type validation warning shows custom class names ([#7198](https://github.com/vuejs/core/issues/7198)) ([620327d](https://github.com/vuejs/core/commit/620327d527593c6263a21500baddbae1ebc30db8)) * **runtime-core:** ensure prop type validation warning shows custom class names ([#7198](https://github.com/vuejs/core/issues/7198)) ([620327d](https://github.com/vuejs/core/commit/620327d527593c6263a21500baddbae1ebc30db8))
* **runtime-core:** fix keep-alive cache prune logic on vnodes with same type but different keys ([#7510](https://github.com/vuejs/core/issues/7510)) ([1fde49c](https://github.com/vuejs/core/commit/1fde49c0f57cc50fedf91366a274c9759d1d9a39)), closes [#7355](https://github.com/vuejs/core/issues/7355) * **runtime-core:** fix keep-alive cache prune logic on vnodes with same type but different keys ([#7510](https://github.com/vuejs/core/issues/7510)) ([1fde49c](https://github.com/vuejs/core/commit/1fde49c0f57cc50fedf91366a274c9759d1d9a39)), closes [#7355](https://github.com/vuejs/core/issues/7355)
@ -126,7 +126,7 @@
* **transition/keep-alive:** fix unmount bug for component with out-in transition ([#6839](https://github.com/vuejs/core/issues/6839)) ([64e6d92](https://github.com/vuejs/core/commit/64e6d9221d353598b5f61c158c978d80e3b4628c)), closes [#6835](https://github.com/vuejs/core/issues/6835) * **transition/keep-alive:** fix unmount bug for component with out-in transition ([#6839](https://github.com/vuejs/core/issues/6839)) ([64e6d92](https://github.com/vuejs/core/commit/64e6d9221d353598b5f61c158c978d80e3b4628c)), closes [#6835](https://github.com/vuejs/core/issues/6835)
* **types/reactivity-transform:** fix type when initial value is not used ([#6821](https://github.com/vuejs/core/issues/6821)) ([fdc5902](https://github.com/vuejs/core/commit/fdc5902cce0d077c722dfd422850ca69fd51be8e)), closes [#6820](https://github.com/vuejs/core/issues/6820) * **types/reactivity-transform:** fix type when initial value is not used ([#6821](https://github.com/vuejs/core/issues/6821)) ([fdc5902](https://github.com/vuejs/core/commit/fdc5902cce0d077c722dfd422850ca69fd51be8e)), closes [#6820](https://github.com/vuejs/core/issues/6820)
* **types:** `$watch` callback parameters type ([#6136](https://github.com/vuejs/core/issues/6136)) ([41d9c47](https://github.com/vuejs/core/commit/41d9c47300888fce9d4ff6a02f69d8a912cded8f)), closes [#6135](https://github.com/vuejs/core/issues/6135) * **types:** `$watch` callback parameters type ([#6136](https://github.com/vuejs/core/issues/6136)) ([41d9c47](https://github.com/vuejs/core/commit/41d9c47300888fce9d4ff6a02f69d8a912cded8f)), closes [#6135](https://github.com/vuejs/core/issues/6135)
* **types:** ensure createBlock() helper accepts Teleport and Supsense types (fix: [#2855](https://github.com/vuejs/core/issues/2855)) ([#5458](https://github.com/vuejs/core/issues/5458)) ([e5fc7dc](https://github.com/vuejs/core/commit/e5fc7dcc02f2dd3fa8172958259049031626375f)) * **types:** ensure createBlock() helper accepts Teleport and Suspense types (fix: [#2855](https://github.com/vuejs/core/issues/2855)) ([#5458](https://github.com/vuejs/core/issues/5458)) ([e5fc7dc](https://github.com/vuejs/core/commit/e5fc7dcc02f2dd3fa8172958259049031626375f))
* **types:** export `Raw` type ([#6380](https://github.com/vuejs/core/issues/6380)) ([e9172db](https://github.com/vuejs/core/commit/e9172db68b86fad2e0bb1de9e5d0dddbe3c2a25e)), closes [#7048](https://github.com/vuejs/core/issues/7048) * **types:** export `Raw` type ([#6380](https://github.com/vuejs/core/issues/6380)) ([e9172db](https://github.com/vuejs/core/commit/e9172db68b86fad2e0bb1de9e5d0dddbe3c2a25e)), closes [#7048](https://github.com/vuejs/core/issues/7048)
* **types:** should unwrap tuple correctly ([#3820](https://github.com/vuejs/core/issues/3820)) ([e816812](https://github.com/vuejs/core/commit/e816812f10b9e3a375eef8dffd617d7f08b23c00)), closes [#3819](https://github.com/vuejs/core/issues/3819) * **types:** should unwrap tuple correctly ([#3820](https://github.com/vuejs/core/issues/3820)) ([e816812](https://github.com/vuejs/core/commit/e816812f10b9e3a375eef8dffd617d7f08b23c00)), closes [#3819](https://github.com/vuejs/core/issues/3819)
* **types:** stricter type condition for `EventHandlers` ([#6855](https://github.com/vuejs/core/issues/6855)) ([bad3f3c](https://github.com/vuejs/core/commit/bad3f3ce46aad1f5fec47d1d02aee26af393bcff)), closes [#6899](https://github.com/vuejs/core/issues/6899) * **types:** stricter type condition for `EventHandlers` ([#6855](https://github.com/vuejs/core/issues/6855)) ([bad3f3c](https://github.com/vuejs/core/commit/bad3f3ce46aad1f5fec47d1d02aee26af393bcff)), closes [#6899](https://github.com/vuejs/core/issues/6899)
@ -714,7 +714,7 @@
* **compiler-core:** avoid runtime dependency on @babel/types ([1045590](https://github.com/vuejs/core/commit/1045590d4bbaf4a2b05311f11b22a0b3d22cf609)), closes [#4531](https://github.com/vuejs/core/issues/4531) * **compiler-core:** avoid runtime dependency on @babel/types ([1045590](https://github.com/vuejs/core/commit/1045590d4bbaf4a2b05311f11b22a0b3d22cf609)), closes [#4531](https://github.com/vuejs/core/issues/4531)
* **compiler-core:** pick last char when dynamic directive doesn't close ([#4507](https://github.com/vuejs/core/issues/4507)) ([5d262e0](https://github.com/vuejs/core/commit/5d262e08d5d5fb29f48ba5fa5b97a9a3e34b9d4b)) * **compiler-core:** pick last char when dynamic directive doesn't close ([#4507](https://github.com/vuejs/core/issues/4507)) ([5d262e0](https://github.com/vuejs/core/commit/5d262e08d5d5fb29f48ba5fa5b97a9a3e34b9d4b))
* **compiler:** condense whitespaces in static class attributes ([#4432](https://github.com/vuejs/core/issues/4432)) ([b8653d3](https://github.com/vuejs/core/commit/b8653d390a555e1ee3f92a1c49cfd8800c67e46a)), closes [#4251](https://github.com/vuejs/core/issues/4251) * **compiler:** condense whitespaces in static class attributes ([#4432](https://github.com/vuejs/core/issues/4432)) ([b8653d3](https://github.com/vuejs/core/commit/b8653d390a555e1ee3f92a1c49cfd8800c67e46a)), closes [#4251](https://github.com/vuejs/core/issues/4251)
* **runtime-dom:** style patching shoud always preserve v-show display property ([d534515](https://github.com/vuejs/core/commit/d53451583684c37bda7d30bff912216e1a58126f)), closes [#4424](https://github.com/vuejs/core/issues/4424) * **runtime-dom:** style patching should always preserve v-show display property ([d534515](https://github.com/vuejs/core/commit/d53451583684c37bda7d30bff912216e1a58126f)), closes [#4424](https://github.com/vuejs/core/issues/4424)
* **type:** fix prop type infer ([#4530](https://github.com/vuejs/core/issues/4530)) ([4178d5d](https://github.com/vuejs/core/commit/4178d5d7d9549a0a1d19663bc2f92c8ac6a731b2)), closes [#4525](https://github.com/vuejs/core/issues/4525) * **type:** fix prop type infer ([#4530](https://github.com/vuejs/core/issues/4530)) ([4178d5d](https://github.com/vuejs/core/commit/4178d5d7d9549a0a1d19663bc2f92c8ac6a731b2)), closes [#4525](https://github.com/vuejs/core/issues/4525)
@ -741,7 +741,7 @@
* **compiler-sfc:** ensure script setup generates type-valid ts output ([bacb201](https://github.com/vuejs/core/commit/bacb2012acb4045a2db6988ba4545a7655d6ca14)), closes [#4455](https://github.com/vuejs/core/issues/4455) * **compiler-sfc:** ensure script setup generates type-valid ts output ([bacb201](https://github.com/vuejs/core/commit/bacb2012acb4045a2db6988ba4545a7655d6ca14)), closes [#4455](https://github.com/vuejs/core/issues/4455)
* **compiler-sfc:** generate matching prop types when withDefaults is used ([#4466](https://github.com/vuejs/core/issues/4466)) ([8580796](https://github.com/vuejs/core/commit/85807967dc874e6ea6b20f341875beda938e3058)), closes [#4455](https://github.com/vuejs/core/issues/4455) * **compiler-sfc:** generate matching prop types when withDefaults is used ([#4466](https://github.com/vuejs/core/issues/4466)) ([8580796](https://github.com/vuejs/core/commit/85807967dc874e6ea6b20f341875beda938e3058)), closes [#4455](https://github.com/vuejs/core/issues/4455)
* **compiler:** generate function ref for script setup if inline is ture. ([#4492](https://github.com/vuejs/core/issues/4492)) ([4cd282b](https://github.com/vuejs/core/commit/4cd282b0a17589ef9ca2649e7beb0bdee4a73c57)) * **compiler:** generate function ref for script setup if inline is true. ([#4492](https://github.com/vuejs/core/issues/4492)) ([4cd282b](https://github.com/vuejs/core/commit/4cd282b0a17589ef9ca2649e7beb0bdee4a73c57))
* **compiler:** report invalid directive name error ([#4494](https://github.com/vuejs/core/issues/4494)) ([#4495](https://github.com/vuejs/core/issues/4495)) ([c00925e](https://github.com/vuejs/core/commit/c00925ed5c409b57a1540b79c595b7f8117e2d4c)) * **compiler:** report invalid directive name error ([#4494](https://github.com/vuejs/core/issues/4494)) ([#4495](https://github.com/vuejs/core/issues/4495)) ([c00925e](https://github.com/vuejs/core/commit/c00925ed5c409b57a1540b79c595b7f8117e2d4c))
* **types:** include ref-macros.d.ts in npm dist files ([d7f1b77](https://github.com/vuejs/core/commit/d7f1b771f80ab9014a4701913b50458fd251a117)), closes [#4433](https://github.com/vuejs/core/issues/4433) * **types:** include ref-macros.d.ts in npm dist files ([d7f1b77](https://github.com/vuejs/core/commit/d7f1b771f80ab9014a4701913b50458fd251a117)), closes [#4433](https://github.com/vuejs/core/issues/4433)
@ -798,7 +798,7 @@
### Bug Fixes ### Bug Fixes
* **compiler-sfc:** fix import usage check for lowercase imported components ([57f1081](https://github.com/vuejs/core/commit/57f10812cc7f1e9f6c92736c36aba577943996fd)), closes [#4358](https://github.com/vuejs/core/issues/4358) * **compiler-sfc:** fix import usage check for lowercase imported components ([57f1081](https://github.com/vuejs/core/commit/57f10812cc7f1e9f6c92736c36aba577943996fd)), closes [#4358](https://github.com/vuejs/core/issues/4358)
* **runtime-core:** ensure consistent arguments for tempalte and render funtion slot usage ([644971e](https://github.com/vuejs/core/commit/644971ec06642817cf7e720ad4980182d2140f53)), closes [#4367](https://github.com/vuejs/core/issues/4367) * **runtime-core:** ensure consistent arguments for template and render function slot usage ([644971e](https://github.com/vuejs/core/commit/644971ec06642817cf7e720ad4980182d2140f53)), closes [#4367](https://github.com/vuejs/core/issues/4367)
* **runtime-core:** fix child component double update on props change ([c1f564e](https://github.com/vuejs/core/commit/c1f564e1dc40eda9af657c30cd787a8d770dde0f)), closes [#4365](https://github.com/vuejs/core/issues/4365) * **runtime-core:** fix child component double update on props change ([c1f564e](https://github.com/vuejs/core/commit/c1f564e1dc40eda9af657c30cd787a8d770dde0f)), closes [#4365](https://github.com/vuejs/core/issues/4365)

View File

@ -259,7 +259,7 @@
* **sfc:** support imported types in SFC macros ([#8083](https://github.com/vuejs/core/pull/8083)) * **sfc:** support imported types in SFC macros ([#8083](https://github.com/vuejs/core/pull/8083))
* **types/slots:** support slot presence / props type checks via `defineSlots` macro and `slots` option ([#7982](https://github.com/vuejs/core/issues/7982)) ([5a2f5d5](https://github.com/vuejs/core/commit/5a2f5d59cffa36a99e6f2feab6b3ba7958b7362f)) * **types/slots:** support slot presence / props type checks via `defineSlots` macro and `slots` option ([#7982](https://github.com/vuejs/core/issues/7982)) ([5a2f5d5](https://github.com/vuejs/core/commit/5a2f5d59cffa36a99e6f2feab6b3ba7958b7362f))
* **sfc:** support more ergnomic defineEmits type syntax ([#7992](https://github.com/vuejs/core/issues/7992)) ([8876dcc](https://github.com/vuejs/core/commit/8876dccf42a7f05375d97cb18c1afdfd0fc51c94)) * **sfc:** support more ergonomic defineEmits type syntax ([#7992](https://github.com/vuejs/core/issues/7992)) ([8876dcc](https://github.com/vuejs/core/commit/8876dccf42a7f05375d97cb18c1afdfd0fc51c94))
* **sfc:** introduce `defineModel` macro and `useModel` helper ([#8018](https://github.com/vuejs/core/issues/8018)) ([14f3d74](https://github.com/vuejs/core/commit/14f3d747a34d45415b0036b274517d70a27ec0d3)) * **sfc:** introduce `defineModel` macro and `useModel` helper ([#8018](https://github.com/vuejs/core/issues/8018)) ([14f3d74](https://github.com/vuejs/core/commit/14f3d747a34d45415b0036b274517d70a27ec0d3))
* **reactivity:** improve support of getter usage in reactivity APIs ([#7997](https://github.com/vuejs/core/issues/7997)) ([59e8284](https://github.com/vuejs/core/commit/59e828448e7f37643cd0eaea924a764e9d314448)) * **reactivity:** improve support of getter usage in reactivity APIs ([#7997](https://github.com/vuejs/core/issues/7997)) ([59e8284](https://github.com/vuejs/core/commit/59e828448e7f37643cd0eaea924a764e9d314448))
* **compiler-sfc:** add defineOptions macro ([#5738](https://github.com/vuejs/core/issues/5738)) ([bcf5841](https://github.com/vuejs/core/commit/bcf5841ddecc64d0bdbd56ce1463eb8ebf01bb9d)) * **compiler-sfc:** add defineOptions macro ([#5738](https://github.com/vuejs/core/issues/5738)) ([bcf5841](https://github.com/vuejs/core/commit/bcf5841ddecc64d0bdbd56ce1463eb8ebf01bb9d))
@ -483,7 +483,7 @@
* **compiler-sfc:** support arbitrary expression as withDefaults argument ([fe61944](https://github.com/vuejs/core/commit/fe619443d2e99301975de120685dbae8d66c03a6)), closes [#6459](https://github.com/vuejs/core/issues/6459) * **compiler-sfc:** support arbitrary expression as withDefaults argument ([fe61944](https://github.com/vuejs/core/commit/fe619443d2e99301975de120685dbae8d66c03a6)), closes [#6459](https://github.com/vuejs/core/issues/6459)
* **reactivity:** improve support of getter usage in reactivity APIs ([#7997](https://github.com/vuejs/core/issues/7997)) ([59e8284](https://github.com/vuejs/core/commit/59e828448e7f37643cd0eaea924a764e9d314448)) * **reactivity:** improve support of getter usage in reactivity APIs ([#7997](https://github.com/vuejs/core/issues/7997)) ([59e8284](https://github.com/vuejs/core/commit/59e828448e7f37643cd0eaea924a764e9d314448))
* **sfc:** revert withDefaults() deprecation ([4af5d1b](https://github.com/vuejs/core/commit/4af5d1b0754035058436f9e4e5c12aedef199177)) * **sfc:** revert withDefaults() deprecation ([4af5d1b](https://github.com/vuejs/core/commit/4af5d1b0754035058436f9e4e5c12aedef199177))
* **sfc:** support more ergnomic defineEmits type syntax ([#7992](https://github.com/vuejs/core/issues/7992)) ([8876dcc](https://github.com/vuejs/core/commit/8876dccf42a7f05375d97cb18c1afdfd0fc51c94)) * **sfc:** support more ergonomic defineEmits type syntax ([#7992](https://github.com/vuejs/core/issues/7992)) ([8876dcc](https://github.com/vuejs/core/commit/8876dccf42a7f05375d97cb18c1afdfd0fc51c94))
* **types/slots:** support slot presence / props type checks via `defineSlots` macro and `slots` option ([#7982](https://github.com/vuejs/core/issues/7982)) ([5a2f5d5](https://github.com/vuejs/core/commit/5a2f5d59cffa36a99e6f2feab6b3ba7958b7362f)) * **types/slots:** support slot presence / props type checks via `defineSlots` macro and `slots` option ([#7982](https://github.com/vuejs/core/issues/7982)) ([5a2f5d5](https://github.com/vuejs/core/commit/5a2f5d59cffa36a99e6f2feab6b3ba7958b7362f))
@ -544,7 +544,7 @@
### Bug Fixes ### Bug Fixes
* **runtime-core:** support `getCurrentInstance` across mutiple builds of Vue ([8d2d5bf](https://github.com/vuejs/core/commit/8d2d5bf48a24dab44e5b03cb8fa0c5faa4b696e3)) * **runtime-core:** support `getCurrentInstance` across multiple builds of Vue ([8d2d5bf](https://github.com/vuejs/core/commit/8d2d5bf48a24dab44e5b03cb8fa0c5faa4b696e3))
* **types:** ensure defineProps with generics return correct types ([c288c7b](https://github.com/vuejs/core/commit/c288c7b0bd6077d690f42153c3fc49a45454a66a)) * **types:** ensure defineProps with generics return correct types ([c288c7b](https://github.com/vuejs/core/commit/c288c7b0bd6077d690f42153c3fc49a45454a66a))

View File

@ -167,7 +167,7 @@
### Bug Fixes ### Bug Fixes
* **compat:** correctly transform non-identifier expressions in legacy filter syntax ([#10896](https://github.com/vuejs/core/issues/10896)) ([07b3c4b](https://github.com/vuejs/core/commit/07b3c4b7860009e19446f3d78571556c5737d82a)), closes [#10852](https://github.com/vuejs/core/issues/10852) * **compat:** correctly transform non-identifier expressions in legacy filter syntax ([#10896](https://github.com/vuejs/core/issues/10896)) ([07b3c4b](https://github.com/vuejs/core/commit/07b3c4b7860009e19446f3d78571556c5737d82a)), closes [#10852](https://github.com/vuejs/core/issues/10852)
* **compat:** ensure proper handling of render fuction from SFC using Vue.extend ([#7781](https://github.com/vuejs/core/issues/7781)) ([c73847f](https://github.com/vuejs/core/commit/c73847f2becc20f03cb9c68748eea92455e688ee)), closes [#7766](https://github.com/vuejs/core/issues/7766) * **compat:** ensure proper handling of render function from SFC using Vue.extend ([#7781](https://github.com/vuejs/core/issues/7781)) ([c73847f](https://github.com/vuejs/core/commit/c73847f2becc20f03cb9c68748eea92455e688ee)), closes [#7766](https://github.com/vuejs/core/issues/7766)
* **compat:** only warn ATTR_FALSE_VALUE when enabled ([04729ba](https://github.com/vuejs/core/commit/04729ba2163d840f0ca7866bc964696eb5557804)), closes [#11126](https://github.com/vuejs/core/issues/11126) * **compat:** only warn ATTR_FALSE_VALUE when enabled ([04729ba](https://github.com/vuejs/core/commit/04729ba2163d840f0ca7866bc964696eb5557804)), closes [#11126](https://github.com/vuejs/core/issues/11126)
* **compile-sfc:** register props destructure rest id as setup bindings ([#10888](https://github.com/vuejs/core/issues/10888)) ([b2b5f57](https://github.com/vuejs/core/commit/b2b5f57c2c945edd0eebc1b545ec1b7568e51484)), closes [#10885](https://github.com/vuejs/core/issues/10885) * **compile-sfc:** register props destructure rest id as setup bindings ([#10888](https://github.com/vuejs/core/issues/10888)) ([b2b5f57](https://github.com/vuejs/core/commit/b2b5f57c2c945edd0eebc1b545ec1b7568e51484)), closes [#10885](https://github.com/vuejs/core/issues/10885)
* **compile-sfc:** Support project reference with folder, ([#10908](https://github.com/vuejs/core/issues/10908)) ([bdeac37](https://github.com/vuejs/core/commit/bdeac377c7b85888193b49ac187e927636cc40bc)), closes [#10907](https://github.com/vuejs/core/issues/10907) * **compile-sfc:** Support project reference with folder, ([#10908](https://github.com/vuejs/core/issues/10908)) ([bdeac37](https://github.com/vuejs/core/commit/bdeac377c7b85888193b49ac187e927636cc40bc)), closes [#10907](https://github.com/vuejs/core/issues/10907)
@ -218,7 +218,7 @@
### Bug Fixes ### Bug Fixes
* **compat:** include legacy scoped slots ([#10868](https://github.com/vuejs/core/issues/10868)) ([8366126](https://github.com/vuejs/core/commit/83661264a4ced3cb2ff6800904a86dd9e82bbfe2)), closes [#8869](https://github.com/vuejs/core/issues/8869) * **compat:** include legacy scoped slots ([#10868](https://github.com/vuejs/core/issues/10868)) ([8366126](https://github.com/vuejs/core/commit/83661264a4ced3cb2ff6800904a86dd9e82bbfe2)), closes [#8869](https://github.com/vuejs/core/issues/8869)
* **compiler-core:** add support for arrow aysnc function with unbracketed ([#5789](https://github.com/vuejs/core/issues/5789)) ([ca7d421](https://github.com/vuejs/core/commit/ca7d421e8775f6813f8943d32ab485e0c542f98b)), closes [#5788](https://github.com/vuejs/core/issues/5788) * **compiler-core:** add support for arrow async function with unbracketed ([#5789](https://github.com/vuejs/core/issues/5789)) ([ca7d421](https://github.com/vuejs/core/commit/ca7d421e8775f6813f8943d32ab485e0c542f98b)), closes [#5788](https://github.com/vuejs/core/issues/5788)
* **compiler-dom:** restrict createStaticVNode usage with option elements ([#10846](https://github.com/vuejs/core/issues/10846)) ([0e3d617](https://github.com/vuejs/core/commit/0e3d6178b02d0386d779720ae2cc4eac1d1ec990)), closes [#6568](https://github.com/vuejs/core/issues/6568) [#7434](https://github.com/vuejs/core/issues/7434) * **compiler-dom:** restrict createStaticVNode usage with option elements ([#10846](https://github.com/vuejs/core/issues/10846)) ([0e3d617](https://github.com/vuejs/core/commit/0e3d6178b02d0386d779720ae2cc4eac1d1ec990)), closes [#6568](https://github.com/vuejs/core/issues/6568) [#7434](https://github.com/vuejs/core/issues/7434)
* **compiler-sfc:** handle keyof operator ([#10874](https://github.com/vuejs/core/issues/10874)) ([10d34a5](https://github.com/vuejs/core/commit/10d34a5624775f20437ccad074a97270ef74c3fb)), closes [#10871](https://github.com/vuejs/core/issues/10871) * **compiler-sfc:** handle keyof operator ([#10874](https://github.com/vuejs/core/issues/10874)) ([10d34a5](https://github.com/vuejs/core/commit/10d34a5624775f20437ccad074a97270ef74c3fb)), closes [#10871](https://github.com/vuejs/core/issues/10871)
* **hydration:** handle edge case of style mismatch without style attribute ([f2c1412](https://github.com/vuejs/core/commit/f2c1412e46a8fad3e13403bfa78335c4f704f21c)), closes [#10786](https://github.com/vuejs/core/issues/10786) * **hydration:** handle edge case of style mismatch without style attribute ([f2c1412](https://github.com/vuejs/core/commit/f2c1412e46a8fad3e13403bfa78335c4f704f21c)), closes [#10786](https://github.com/vuejs/core/issues/10786)
@ -417,7 +417,7 @@
* **compiler-sfc:** fix type resolution for symlinked node_modules structure w/ pnpm ([75e866b](https://github.com/vuejs/core/commit/75e866bd4ef368b4e037a4933dbaf188920dc683)), closes [#10121](https://github.com/vuejs/core/issues/10121) * **compiler-sfc:** fix type resolution for symlinked node_modules structure w/ pnpm ([75e866b](https://github.com/vuejs/core/commit/75e866bd4ef368b4e037a4933dbaf188920dc683)), closes [#10121](https://github.com/vuejs/core/issues/10121)
* correct url for production error reference links ([c3087ff](https://github.com/vuejs/core/commit/c3087ff2cce7d96c60a870f8233441311ab4dfb4)) * correct url for production error reference links ([c3087ff](https://github.com/vuejs/core/commit/c3087ff2cce7d96c60a870f8233441311ab4dfb4))
* **hydration:** fix incorect mismatch warning for option with non-string value and inner text ([d16a213](https://github.com/vuejs/core/commit/d16a2138a33b106b9e1499bbb9e1c67790370c97)) * **hydration:** fix incorrect mismatch warning for option with non-string value and inner text ([d16a213](https://github.com/vuejs/core/commit/d16a2138a33b106b9e1499bbb9e1c67790370c97))
* **reactivity:** re-fix [#10114](https://github.com/vuejs/core/issues/10114) ([#10123](https://github.com/vuejs/core/issues/10123)) ([c2b274a](https://github.com/vuejs/core/commit/c2b274a887f61deb7e0185d1bef3b77d31e991cc)) * **reactivity:** re-fix [#10114](https://github.com/vuejs/core/issues/10114) ([#10123](https://github.com/vuejs/core/issues/10123)) ([c2b274a](https://github.com/vuejs/core/commit/c2b274a887f61deb7e0185d1bef3b77d31e991cc))
* **runtime-core:** should not warn out-of-render slot fn usage when mounting another app in setup ([#10125](https://github.com/vuejs/core/issues/10125)) ([6fa33e6](https://github.com/vuejs/core/commit/6fa33e67ec42af140a86fbdb86939032c3a1f345)), closes [#10124](https://github.com/vuejs/core/issues/10124) * **runtime-core:** should not warn out-of-render slot fn usage when mounting another app in setup ([#10125](https://github.com/vuejs/core/issues/10125)) ([6fa33e6](https://github.com/vuejs/core/commit/6fa33e67ec42af140a86fbdb86939032c3a1f345)), closes [#10124](https://github.com/vuejs/core/issues/10124)
@ -741,17 +741,6 @@ Note that this is a type-only breaking change in a minor release, which adheres
## [3.3.13](https://github.com/vuejs/core/compare/v3.3.12...v3.3.13) (2023-12-19)
### Bug Fixes
* **compiler-core:** fix v-on with modifiers on inline expression of undefined ([#9866](https://github.com/vuejs/core/issues/9866)) ([bae79dd](https://github.com/vuejs/core/commit/bae79ddf8564a2da4a5365cfeb8d811990f42335)), closes [#9865](https://github.com/vuejs/core/issues/9865)
* **runtime-dom:** cache event handlers by key/modifiers ([#9851](https://github.com/vuejs/core/issues/9851)) ([04d2c05](https://github.com/vuejs/core/commit/04d2c05054c26b02fbc1d84839b0ed5cd36455b6)), closes [#9849](https://github.com/vuejs/core/issues/9849)
* **types:** extract properties from extended collections ([#9854](https://github.com/vuejs/core/issues/9854)) ([24b1c1d](https://github.com/vuejs/core/commit/24b1c1dd57fd55d998aa231a147500e010b10219)), closes [#9852](https://github.com/vuejs/core/issues/9852)
# [3.4.0-beta.3](https://github.com/vuejs/core/compare/v3.3.12...v3.4.0-beta.3) (2023-12-16) # [3.4.0-beta.3](https://github.com/vuejs/core/compare/v3.3.12...v3.4.0-beta.3) (2023-12-16)
@ -764,19 +753,6 @@ Note that this is a type-only breaking change in a minor release, which adheres
## [3.3.12](https://github.com/vuejs/core/compare/v3.3.11...v3.3.12) (2023-12-16)
### Bug Fixes
* **hydration:** handle appear transition before patch props ([#9837](https://github.com/vuejs/core/issues/9837)) ([e70f4c4](https://github.com/vuejs/core/commit/e70f4c47c553b6e16d8fad70743271ca23802fe7)), closes [#9832](https://github.com/vuejs/core/issues/9832)
* **sfc/cssVars:** fix loss of CSS v-bind variables when setting inline style with string value ([#9824](https://github.com/vuejs/core/issues/9824)) ([0a387df](https://github.com/vuejs/core/commit/0a387dfb1d04afb6eae4296b6da76dfdaca77af4)), closes [#9821](https://github.com/vuejs/core/issues/9821)
* **ssr:** fix suspense hydration of fallback content ([#7188](https://github.com/vuejs/core/issues/7188)) ([60415b5](https://github.com/vuejs/core/commit/60415b5d67df55f1fd6b176615299c08640fa142))
* **types:** add `xmlns:xlink` to `SVGAttributes` ([#9300](https://github.com/vuejs/core/issues/9300)) ([0d61b42](https://github.com/vuejs/core/commit/0d61b429ecf63591d31e09702058fa4c7132e1a7)), closes [#9299](https://github.com/vuejs/core/issues/9299)
* **types:** fix `shallowRef` type error ([#9839](https://github.com/vuejs/core/issues/9839)) ([9a57158](https://github.com/vuejs/core/commit/9a571582b53220270e498d8712ea59312c0bef3a))
* **types:** support for generic keyof slots ([#8374](https://github.com/vuejs/core/issues/8374)) ([213eba4](https://github.com/vuejs/core/commit/213eba479ce080efc1053fe636f6be4a4c889b44))
# [3.4.0-beta.2](https://github.com/vuejs/core/compare/v3.4.0-beta.1...v3.4.0-beta.2) (2023-12-14) # [3.4.0-beta.2](https://github.com/vuejs/core/compare/v3.4.0-beta.1...v3.4.0-beta.2) (2023-12-14)
@ -836,22 +812,6 @@ default.
## [3.3.11](https://github.com/vuejs/core/compare/v3.3.10...v3.3.11) (2023-12-08)
### Bug Fixes
* **custom-element:** correctly handle number type props in prod ([#8989](https://github.com/vuejs/core/issues/8989)) ([d74d364](https://github.com/vuejs/core/commit/d74d364d62db8e48881af6b5a75ce4fb5f36cc35))
* **reactivity:** fix mutation on user proxy of reactive Array ([6ecbd5c](https://github.com/vuejs/core/commit/6ecbd5ce2a7f59314a8326a1d193874b87f4d8c8)), closes [#9742](https://github.com/vuejs/core/issues/9742) [#9751](https://github.com/vuejs/core/issues/9751) [#9750](https://github.com/vuejs/core/issues/9750)
* **runtime-dom:** fix width and height prop check condition ([5b00286](https://github.com/vuejs/core/commit/5b002869c533220706f9788b496b8ca8d8e98609)), closes [#9762](https://github.com/vuejs/core/issues/9762)
* **shared:** handle Map with symbol keys in toDisplayString ([#9731](https://github.com/vuejs/core/issues/9731)) ([364821d](https://github.com/vuejs/core/commit/364821d6bdb1775e2f55a69bcfb9f40f7acf1506)), closes [#9727](https://github.com/vuejs/core/issues/9727)
* **shared:** handle more Symbol cases in toDisplayString ([983d45d](https://github.com/vuejs/core/commit/983d45d4f8eb766b5a16b7ea93b86d3c51618fa6))
* **Suspense:** properly get anchor when mount fallback vnode ([#9770](https://github.com/vuejs/core/issues/9770)) ([b700328](https://github.com/vuejs/core/commit/b700328342e17dc16b19316c2e134a26107139d2)), closes [#9769](https://github.com/vuejs/core/issues/9769)
* **types:** ref() return type should not be any when initial value is any ([#9768](https://github.com/vuejs/core/issues/9768)) ([cdac121](https://github.com/vuejs/core/commit/cdac12161ec27b45ded48854c3d749664b6d4a6d))
* **watch:** should not fire pre watcher on child component unmount ([#7181](https://github.com/vuejs/core/issues/7181)) ([6784f0b](https://github.com/vuejs/core/commit/6784f0b1f8501746ea70d87d18ed63a62cf6b76d)), closes [#7030](https://github.com/vuejs/core/issues/7030)
# [3.4.0-alpha.4](https://github.com/vuejs/core/compare/v3.3.10...v3.4.0-alpha.4) (2023-12-04) # [3.4.0-alpha.4](https://github.com/vuejs/core/compare/v3.3.10...v3.4.0-alpha.4) (2023-12-04)
@ -873,37 +833,6 @@ default.
## [3.3.10](https://github.com/vuejs/core/compare/v3.3.9...v3.3.10) (2023-12-04)
### Bug Fixes
* **app:** prevent template from being cached between apps with different options ([#9724](https://github.com/vuejs/core/issues/9724)) ([ec71585](https://github.com/vuejs/core/commit/ec715854ca12520b2afc9e9b3981cbae05ae5206)), closes [#9618](https://github.com/vuejs/core/issues/9618)
* **compiler-sfc:** avoid passing forEach index to genMap ([f12db7f](https://github.com/vuejs/core/commit/f12db7fb564a534cef2e5805cc9f54afe5d72fbf))
* **compiler-sfc:** deindent pug/jade templates ([6345197](https://github.com/vuejs/core/commit/634519720a21fb5a6871454e1cadad7053a568b8)), closes [#3231](https://github.com/vuejs/core/issues/3231) [#3842](https://github.com/vuejs/core/issues/3842) [#7723](https://github.com/vuejs/core/issues/7723)
* **compiler-sfc:** fix :where and :is selector in scoped mode with multiple selectors ([#9735](https://github.com/vuejs/core/issues/9735)) ([c3e2c55](https://github.com/vuejs/core/commit/c3e2c556b532656b50b8ab5cd2d9eabc26622d63)), closes [#9707](https://github.com/vuejs/core/issues/9707)
* **compiler-sfc:** generate more treeshaking friendly code ([#9507](https://github.com/vuejs/core/issues/9507)) ([8d74ca0](https://github.com/vuejs/core/commit/8d74ca0e6fa2738ca6854b7e879ff59419f948c7)), closes [#9500](https://github.com/vuejs/core/issues/9500)
* **compiler-sfc:** support inferring generic types ([#8511](https://github.com/vuejs/core/issues/8511)) ([eb5e307](https://github.com/vuejs/core/commit/eb5e307c0be62002e62c4c800d0dfacb39b0d4ca)), closes [#8482](https://github.com/vuejs/core/issues/8482)
* **compiler-sfc:** support resolving components from props ([#8785](https://github.com/vuejs/core/issues/8785)) ([7cbcee3](https://github.com/vuejs/core/commit/7cbcee3d831241a8bd3588ae92d3f27e3641e25f))
* **compiler-sfc:** throw error when failing to load TS during type resolution ([#8883](https://github.com/vuejs/core/issues/8883)) ([4936d2e](https://github.com/vuejs/core/commit/4936d2e11a8d0ca3704bfe408548cb26bb3fd5e9))
* **cssVars:** cssVar names should be double-escaped when generating code for ssr ([#8824](https://github.com/vuejs/core/issues/8824)) ([5199a12](https://github.com/vuejs/core/commit/5199a12f8855cd06f24bf355708b5a2134f63176)), closes [#7823](https://github.com/vuejs/core/issues/7823)
* **deps:** update compiler to ^7.23.4 ([#9681](https://github.com/vuejs/core/issues/9681)) ([31f6ebc](https://github.com/vuejs/core/commit/31f6ebc4df84490ed29fb75e7bf4259200eb51f0))
* **runtime-core:** Suspense get anchor properly in Transition ([#9309](https://github.com/vuejs/core/issues/9309)) ([65f3fe2](https://github.com/vuejs/core/commit/65f3fe273127a8b68e1222fbb306d28d85f01757)), closes [#8105](https://github.com/vuejs/core/issues/8105)
* **runtime-dom:** set width/height with units as attribute ([#8781](https://github.com/vuejs/core/issues/8781)) ([bfc1838](https://github.com/vuejs/core/commit/bfc1838f31199de3f189198a3c234fa7bae91386))
* **ssr:** avoid computed being accidentally cached before server render ([#9688](https://github.com/vuejs/core/issues/9688)) ([30d5d93](https://github.com/vuejs/core/commit/30d5d93a92b2154406ec04f8aca6b217fa01177c)), closes [#5300](https://github.com/vuejs/core/issues/5300)
* **types:** expose emits as props in functional components ([#9234](https://github.com/vuejs/core/issues/9234)) ([887e54c](https://github.com/vuejs/core/commit/887e54c347ea9eac4c721b5e2288f054873d1d30))
* **types:** fix reactive collection types ([#8960](https://github.com/vuejs/core/issues/8960)) ([ad27473](https://github.com/vuejs/core/commit/ad274737015c36906d76f3189203093fa3a2e4e7)), closes [#8904](https://github.com/vuejs/core/issues/8904)
* **types:** improve return type withKeys and withModifiers ([#9734](https://github.com/vuejs/core/issues/9734)) ([43c3cfd](https://github.com/vuejs/core/commit/43c3cfdec5ae5d70fa2a21e857abc2d73f1a0d07))
### Performance Improvements
* optimize on* prop check ([38aaa8c](https://github.com/vuejs/core/commit/38aaa8c88648c54fe2616ad9c0961288092fcb44))
* **runtime-dom:** cache modifier wrapper functions ([da4a4fb](https://github.com/vuejs/core/commit/da4a4fb5e8eee3c6d31f24ebd79a9d0feca56cb2)), closes [#8882](https://github.com/vuejs/core/issues/8882)
* **v-on:** constant handlers with modifiers should not be treated as dynamic ([4d94ebf](https://github.com/vuejs/core/commit/4d94ebfe75174b340d2b794e699cad1add3600a9))
# [3.4.0-alpha.3](https://github.com/vuejs/core/compare/v3.4.0-alpha.2...v3.4.0-alpha.3) (2023-11-28) # [3.4.0-alpha.3](https://github.com/vuejs/core/compare/v3.4.0-alpha.2...v3.4.0-alpha.3) (2023-11-28)
@ -960,55 +889,6 @@ default.
## [3.3.9](https://github.com/vuejs/core/compare/v3.3.8...v3.3.9) (2023-11-25)
### Bug Fixes
* **compiler-core:** avoid rewriting scope variables in inline for loops ([#7245](https://github.com/vuejs/core/issues/7245)) ([a2d810e](https://github.com/vuejs/core/commit/a2d810eb40cef631f61991ca68b426ee9546aba0)), closes [#7238](https://github.com/vuejs/core/issues/7238)
* **compiler-core:** fix `resolveParserPlugins` decorators check ([#9566](https://github.com/vuejs/core/issues/9566)) ([9d0eba9](https://github.com/vuejs/core/commit/9d0eba916f3bf6fb5c03222400edae1a2db7444f)), closes [#9560](https://github.com/vuejs/core/issues/9560)
* **compiler-sfc:** consistently escape type-only prop names ([#8654](https://github.com/vuejs/core/issues/8654)) ([3e08d24](https://github.com/vuejs/core/commit/3e08d246dfd8523c54fb8e7a4a6fd5506ffb1bcc)), closes [#8635](https://github.com/vuejs/core/issues/8635) [#8910](https://github.com/vuejs/core/issues/8910) [vitejs/vite-plugin-vue#184](https://github.com/vitejs/vite-plugin-vue/issues/184)
* **compiler-sfc:** malformed filename on windows using path.posix.join() ([#9478](https://github.com/vuejs/core/issues/9478)) ([f18a174](https://github.com/vuejs/core/commit/f18a174979626b3429db93c5d5b7ae5448917c70)), closes [#8671](https://github.com/vuejs/core/issues/8671) [#9583](https://github.com/vuejs/core/issues/9583) [#9446](https://github.com/vuejs/core/issues/9446) [#9473](https://github.com/vuejs/core/issues/9473)
* **compiler-sfc:** support `:is` and `:where` selector in scoped css rewrite ([#8929](https://github.com/vuejs/core/issues/8929)) ([3227e50](https://github.com/vuejs/core/commit/3227e50b32105f8893f7dff2f29278c5b3a9f621))
* **compiler-sfc:** support resolve extends interface for defineEmits ([#8470](https://github.com/vuejs/core/issues/8470)) ([9e1b74b](https://github.com/vuejs/core/commit/9e1b74bcd5fa4151f5d1bc02c69fbbfa4762f577)), closes [#8465](https://github.com/vuejs/core/issues/8465)
* **hmr/transition:** fix kept-alive component inside transition disappearing after hmr ([#7126](https://github.com/vuejs/core/issues/7126)) ([d11e978](https://github.com/vuejs/core/commit/d11e978fc98dcc83526c167e603b8308f317f786)), closes [#7121](https://github.com/vuejs/core/issues/7121)
* **hydration:** force hydration for v-bind with .prop modifier ([364f319](https://github.com/vuejs/core/commit/364f319d214226770d97c98d8fcada80c9e8dde3)), closes [#7490](https://github.com/vuejs/core/issues/7490)
* **hydration:** properly hydrate indeterminate prop ([34b5a5d](https://github.com/vuejs/core/commit/34b5a5da4ae9c9faccac237acd7acc8e7e017571)), closes [#7476](https://github.com/vuejs/core/issues/7476)
* **reactivity:** clear method on readonly collections should return undefined ([#7316](https://github.com/vuejs/core/issues/7316)) ([657476d](https://github.com/vuejs/core/commit/657476dcdb964be4fbb1277c215c073f3275728e))
* **reactivity:** onCleanup also needs to be cleaned ([#8655](https://github.com/vuejs/core/issues/8655)) ([73fd810](https://github.com/vuejs/core/commit/73fd810eebdd383a2b4629f67736c4db1f428abd)), closes [#5151](https://github.com/vuejs/core/issues/5151) [#7695](https://github.com/vuejs/core/issues/7695)
* **ssr:** hydration `__vnode` missing for devtools ([#9328](https://github.com/vuejs/core/issues/9328)) ([5156ac5](https://github.com/vuejs/core/commit/5156ac5b38cfa80d3db26f2c9bf40cb22a7521cb))
* **types:** allow falsy value types in `StyleValue` ([#7954](https://github.com/vuejs/core/issues/7954)) ([17aa92b](https://github.com/vuejs/core/commit/17aa92b79b31d8bb8b5873ddc599420cb9806db8)), closes [#7955](https://github.com/vuejs/core/issues/7955)
* **types:** defineCustomElement using defineComponent return type with emits ([#7937](https://github.com/vuejs/core/issues/7937)) ([5d932a8](https://github.com/vuejs/core/commit/5d932a8e6d14343c9d7fc7c2ecb58ac618b2f938)), closes [#7782](https://github.com/vuejs/core/issues/7782)
* **types:** fix `unref` and `toValue` when input union type contains ComputedRef ([#8748](https://github.com/vuejs/core/issues/8748)) ([176d476](https://github.com/vuejs/core/commit/176d47671271b1abc21b1508e9a493c7efca6451)), closes [#8747](https://github.com/vuejs/core/issues/8747) [#8857](https://github.com/vuejs/core/issues/8857)
* **types:** fix instance type when props type is incompatible with setup returned type ([#7338](https://github.com/vuejs/core/issues/7338)) ([0e1e8f9](https://github.com/vuejs/core/commit/0e1e8f919e5a74cdaadf9c80ee135088b25e7fa3)), closes [#5885](https://github.com/vuejs/core/issues/5885)
* **types:** fix shallowRef return type with union value type ([#7853](https://github.com/vuejs/core/issues/7853)) ([7c44800](https://github.com/vuejs/core/commit/7c448000b0def910c2cfabfdf7ff20a3d6bc844f)), closes [#7852](https://github.com/vuejs/core/issues/7852)
* **types:** more precise types for class bindings ([#8012](https://github.com/vuejs/core/issues/8012)) ([46e3374](https://github.com/vuejs/core/commit/46e33744c890bd49482c5e5c5cdea44e00ec84d5))
* **types:** remove optional properties from defineProps return type ([#6421](https://github.com/vuejs/core/issues/6421)) ([94c049d](https://github.com/vuejs/core/commit/94c049d930d922069e38ea8700d7ff0970f71e61)), closes [#6420](https://github.com/vuejs/core/issues/6420)
* **types:** return type of withDefaults should be readonly ([#8601](https://github.com/vuejs/core/issues/8601)) ([f15debc](https://github.com/vuejs/core/commit/f15debc01acb22d23f5acee97e6f02db88cef11a))
* **types:** revert class type restrictions ([5d077c8](https://github.com/vuejs/core/commit/5d077c8754cc14f85d2d6d386df70cf8c0d93842)), closes [#8012](https://github.com/vuejs/core/issues/8012)
* **types:** update jsx type definitions ([#8607](https://github.com/vuejs/core/issues/8607)) ([58e2a94](https://github.com/vuejs/core/commit/58e2a94871ae06a909c5f8bad07fb401193e6a38))
* **types:** widen ClassValue type ([2424013](https://github.com/vuejs/core/commit/242401305944422d0c361b16101a4d18908927af))
* **v-model:** avoid overwriting number input with same value ([#7004](https://github.com/vuejs/core/issues/7004)) ([40f4b77](https://github.com/vuejs/core/commit/40f4b77bb570868cb6e47791078767797e465989)), closes [#7003](https://github.com/vuejs/core/issues/7003)
* **v-model:** unnecessary value binding error should apply to dynamic instead of static binding ([2859b65](https://github.com/vuejs/core/commit/2859b653c9a22460e60233cac10fe139e359b046)), closes [#3596](https://github.com/vuejs/core/issues/3596)
## [3.3.8](https://github.com/vuejs/core/compare/v3.3.7...v3.3.8) (2023-11-06)
### Bug Fixes
* **compile-sfc:** support `Error` type in `defineProps` ([#5955](https://github.com/vuejs/core/issues/5955)) ([a989345](https://github.com/vuejs/core/commit/a9893458ec519aae442e1b99e64e6d74685cd22c))
* **compiler-core:** known global should be shadowed by local variables in expression rewrite ([#9492](https://github.com/vuejs/core/issues/9492)) ([a75d1c5](https://github.com/vuejs/core/commit/a75d1c5c6242e91a73cc5ba01e6da620dea0b3d9)), closes [#9482](https://github.com/vuejs/core/issues/9482)
* **compiler-sfc:** fix dynamic directive arguments usage check for slots ([#9495](https://github.com/vuejs/core/issues/9495)) ([b39fa1f](https://github.com/vuejs/core/commit/b39fa1f8157647859331ce439c42ae016a49b415)), closes [#9493](https://github.com/vuejs/core/issues/9493)
* **deps:** update dependency @vue/repl to ^2.6.2 ([#9536](https://github.com/vuejs/core/issues/9536)) ([5cef325](https://github.com/vuejs/core/commit/5cef325f41e3b38657c72fa1a38dedeee1c7a60a))
* **deps:** update dependency @vue/repl to ^2.6.3 ([#9540](https://github.com/vuejs/core/issues/9540)) ([176d590](https://github.com/vuejs/core/commit/176d59058c9aecffe9da4d4311e98496684f06d4))
* **hydration:** fix tagName access error on comment/text node hydration mismatch ([dd8a0cf](https://github.com/vuejs/core/commit/dd8a0cf5dcde13d2cbd899262a0e07f16e14e489)), closes [#9531](https://github.com/vuejs/core/issues/9531)
* **types:** avoid exposing lru-cache types in generated dts ([462aeb3](https://github.com/vuejs/core/commit/462aeb3b600765e219ded2ee9a0ed1e74df61de0)), closes [#9521](https://github.com/vuejs/core/issues/9521)
* **warn:** avoid warning on empty children with Suspense ([#3962](https://github.com/vuejs/core/issues/3962)) ([405f345](https://github.com/vuejs/core/commit/405f34587a63a5f1e3d147b9848219ea98acc22d))
# [3.4.0-alpha.1](https://github.com/vuejs/core/compare/v3.3.7...v3.4.0-alpha.1) (2023-10-28) # [3.4.0-alpha.1](https://github.com/vuejs/core/compare/v3.3.7...v3.4.0-alpha.1) (2023-10-28)

View File

@ -1,6 +1,6 @@
import importX from 'eslint-plugin-import-x' import importX from 'eslint-plugin-import-x'
import tseslint from 'typescript-eslint' import tseslint from 'typescript-eslint'
import vitest from 'eslint-plugin-vitest' import vitest from '@vitest/eslint-plugin'
import { builtinModules } from 'node:module' import { builtinModules } from 'node:module'
const DOMGlobals = ['window', 'document'] const DOMGlobals = ['window', 'document']

View File

@ -1,3 +1,3 @@
[build.environment] [build.environment]
NODE_VERSION = "18" NODE_VERSION = "22"
NPM_FLAGS = "--version" # prevent Netlify npm install NPM_FLAGS = "--version" # prevent Netlify npm install

View File

@ -1,7 +1,7 @@
{ {
"private": true, "private": true,
"version": "3.5.9", "version": "3.5.16",
"packageManager": "pnpm@9.10.0", "packageManager": "pnpm@10.11.1",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "node scripts/dev.js", "dev": "node scripts/dev.js",
@ -22,7 +22,10 @@
"test-dts": "run-s build-dts test-dts-only", "test-dts": "run-s build-dts test-dts-only",
"test-dts-only": "tsc -p packages-private/dts-built-test/tsconfig.json && tsc -p ./packages-private/dts-test/tsconfig.test.json", "test-dts-only": "tsc -p packages-private/dts-built-test/tsconfig.json && tsc -p ./packages-private/dts-test/tsconfig.test.json",
"test-coverage": "vitest run --project unit --coverage", "test-coverage": "vitest run --project unit --coverage",
"test-bench": "vitest bench", "prebench": "node scripts/build.js -pf esm-browser reactivity",
"prebench-compare": "node scripts/build.js -pf esm-browser reactivity",
"bench": "vitest bench --project=unit --outputJson=temp/bench.json",
"bench-compare": "vitest bench --project=unit --compare=temp/bench.json",
"release": "node scripts/release.js", "release": "node scripts/release.js",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s", "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
"dev-esm": "node scripts/dev.js -if esm-bundler-runtime", "dev-esm": "node scripts/dev.js -if esm-bundler-runtime",
@ -62,62 +65,51 @@
"@babel/parser": "catalog:", "@babel/parser": "catalog:",
"@babel/types": "catalog:", "@babel/types": "catalog:",
"@rollup/plugin-alias": "^5.1.1", "@rollup/plugin-alias": "^5.1.1",
"@rollup/plugin-commonjs": "^26.0.3", "@rollup/plugin-commonjs": "^28.0.3",
"@rollup/plugin-json": "^6.1.0", "@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0", "@rollup/plugin-node-resolve": "^16.0.1",
"@rollup/plugin-replace": "5.0.4", "@rollup/plugin-replace": "5.0.4",
"@swc/core": "^1.7.28", "@swc/core": "^1.11.29",
"@types/hash-sum": "^1.0.2", "@types/hash-sum": "^1.0.2",
"@types/node": "^20.16.5", "@types/node": "^22.15.29",
"@types/semver": "^7.5.8", "@types/semver": "^7.7.0",
"@types/serve-handler": "^6.1.4", "@types/serve-handler": "^6.1.4",
"@vitest/coverage-v8": "^2.1.1", "@vitest/coverage-v8": "^3.1.4",
"@vitest/eslint-plugin": "^1.2.1",
"@vue/consolidate": "1.0.0", "@vue/consolidate": "1.0.0",
"conventional-changelog-cli": "^5.0.0", "conventional-changelog-cli": "^5.0.0",
"enquirer": "^2.4.1", "enquirer": "^2.4.1",
"esbuild": "^0.24.0", "esbuild": "^0.25.5",
"esbuild-plugin-polyfill-node": "^0.3.0", "esbuild-plugin-polyfill-node": "^0.3.0",
"eslint": "^9.10.0", "eslint": "^9.27.0",
"eslint-plugin-import-x": "^4.2.1", "eslint-plugin-import-x": "^4.13.1",
"eslint-plugin-vitest": "^0.5.4",
"estree-walker": "catalog:", "estree-walker": "catalog:",
"jsdom": "^25.0.0", "jsdom": "^26.1.0",
"lint-staged": "^15.2.10", "lint-staged": "^16.0.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"magic-string": "^0.30.11", "magic-string": "^0.30.17",
"markdown-table": "^3.0.3", "markdown-table": "^3.0.4",
"marked": "13.0.3", "marked": "13.0.3",
"npm-run-all2": "^6.2.3", "npm-run-all2": "^7.0.2",
"picocolors": "^1.1.0", "picocolors": "^1.1.1",
"prettier": "^3.3.3", "prettier": "^3.5.3",
"pretty-bytes": "^6.1.1", "pretty-bytes": "^6.1.1",
"pug": "^3.0.3", "pug": "^3.0.3",
"puppeteer": "~23.3.0", "puppeteer": "~24.9.0",
"rimraf": "^6.0.1", "rimraf": "^6.0.1",
"rollup": "^4.22.4", "rollup": "^4.41.1",
"rollup-plugin-dts": "^6.1.1", "rollup-plugin-dts": "^6.2.1",
"rollup-plugin-esbuild": "^6.1.1", "rollup-plugin-esbuild": "^6.2.1",
"rollup-plugin-polyfill-node": "^0.13.0", "rollup-plugin-polyfill-node": "^0.13.0",
"semver": "^7.6.3", "semver": "^7.7.2",
"serve": "^14.2.3", "serve": "^14.2.4",
"serve-handler": "^6.1.5", "serve-handler": "^6.1.6",
"simple-git-hooks": "^2.11.1", "simple-git-hooks": "^2.13.0",
"todomvc-app-css": "^2.4.3", "todomvc-app-css": "^2.4.3",
"tslib": "^2.7.0", "tslib": "^2.8.1",
"typescript": "~5.6.2", "typescript": "~5.6.2",
"typescript-eslint": "^8.5.0", "typescript-eslint": "^8.32.1",
"vite": "catalog:", "vite": "catalog:",
"vitest": "^2.1.1" "vitest": "^3.1.4"
},
"pnpm": {
"peerDependencyRules": {
"allowedVersions": {
"typescript-eslint>eslint": "^9.0.0",
"@typescript-eslint/eslint-plugin>eslint": "^9.0.0",
"@typescript-eslint/parser>eslint": "^9.0.0",
"@typescript-eslint/type-utils>eslint": "^9.0.0",
"@typescript-eslint/utils>eslint": "^9.0.0"
}
}
} }
} }

View File

@ -9,7 +9,7 @@ app.directive<HTMLElement, string, 'prevent' | 'stop', 'arg1' | 'arg2'>(
mounted(el, binding) { mounted(el, binding) {
expectType<HTMLElement>(el) expectType<HTMLElement>(el)
expectType<string>(binding.value) expectType<string>(binding.value)
expectType<{ prevent: boolean; stop: boolean }>(binding.modifiers) expectType<{ prevent?: boolean; stop?: boolean }>(binding.modifiers)
expectType<'arg1' | 'arg2'>(binding.arg!) expectType<'arg1' | 'arg2'>(binding.arg!)
// @ts-expect-error not any // @ts-expect-error not any

View File

@ -12,8 +12,11 @@ app.use(PluginWithoutType, 2)
app.use(PluginWithoutType, { anything: 'goes' }, true) app.use(PluginWithoutType, { anything: 'goes' }, true)
type PluginOptions = { type PluginOptions = {
/** option1 */
option1?: string option1?: string
/** option2 */
option2: number option2: number
/** option3 */
option3: boolean option3: boolean
} }
@ -25,6 +28,20 @@ const PluginWithObjectOptions = {
}, },
} }
const objectPluginOptional = {
install(app: App, options?: PluginOptions) {},
}
app.use(objectPluginOptional)
app.use(
objectPluginOptional,
// Test JSDoc and `go to definition` for options
{
option1: 'foo',
option2: 1,
option3: true,
},
)
for (const Plugin of [ for (const Plugin of [
PluginWithObjectOptions, PluginWithObjectOptions,
PluginWithObjectOptions.install, PluginWithObjectOptions.install,
@ -92,7 +109,27 @@ const PluginTyped: Plugin<PluginOptions> = (app, options) => {}
// @ts-expect-error: needs options // @ts-expect-error: needs options
app.use(PluginTyped) app.use(PluginTyped)
app.use(PluginTyped, { option2: 2, option3: true }) app.use(
PluginTyped,
// Test autocomplete for options
{
option1: '',
option2: 2,
option3: true,
},
)
const functionPluginOptional = (app: App, options?: PluginOptions) => {}
app.use(functionPluginOptional)
app.use(functionPluginOptional, { option2: 2, option3: true })
// type optional params
const functionPluginOptional2: Plugin<[options?: PluginOptions]> = (
app,
options,
) => {}
app.use(functionPluginOptional2)
app.use(functionPluginOptional2, { option2: 2, option3: true })
// vuetify usage // vuetify usage
const key: string = '' const key: string = ''

View File

@ -137,3 +137,18 @@ describe('Generic component', () => {
expectType<string | number>(comp.msg) expectType<string | number>(comp.msg)
expectType<Array<string | number>>(comp.list) expectType<Array<string | number>>(comp.list)
}) })
// #12751
{
const Comp = defineComponent({
__typeEmits: {} as {
'update:visible': [value?: boolean]
},
})
const comp: ComponentInstance<typeof Comp> = {} as any
expectType<((value?: boolean) => any) | undefined>(comp['onUpdate:visible'])
expectType<{ 'onUpdate:visible'?: (value?: boolean) => any }>(comp['$props'])
// @ts-expect-error
comp['$props']['$props']
}

View File

@ -20,6 +20,9 @@ import { type IsAny, type IsUnion, describe, expectType } from './utils'
describe('with object props', () => { describe('with object props', () => {
interface ExpectedProps { interface ExpectedProps {
a?: number | undefined a?: number | undefined
aa: number
aaa: number | null
aaaa: number | undefined
b: string b: string
e?: Function e?: Function
h: boolean h: boolean
@ -53,6 +56,19 @@ describe('with object props', () => {
const props = { const props = {
a: Number, a: Number,
aa: {
type: Number as PropType<number | undefined>,
default: 1,
},
aaa: {
type: Number as PropType<number | null>,
default: 1,
},
aaaa: {
type: Number as PropType<number | undefined>,
// `as const` prevents widening to `boolean` (keeps literal `true` type)
required: true as const,
},
// required should make property non-void // required should make property non-void
b: { b: {
type: String, type: String,
@ -146,6 +162,13 @@ describe('with object props', () => {
setup(props) { setup(props) {
// type assertion. See https://github.com/SamVerschueren/tsd // type assertion. See https://github.com/SamVerschueren/tsd
expectType<ExpectedProps['a']>(props.a) expectType<ExpectedProps['a']>(props.a)
expectType<ExpectedProps['aa']>(props.aa)
expectType<ExpectedProps['aaa']>(props.aaa)
// @ts-expect-error should included `undefined`
expectType<number>(props.aaaa)
expectType<ExpectedProps['aaaa']>(props.aaaa)
expectType<ExpectedProps['b']>(props.b) expectType<ExpectedProps['b']>(props.b)
expectType<ExpectedProps['e']>(props.e) expectType<ExpectedProps['e']>(props.e)
expectType<ExpectedProps['h']>(props.h) expectType<ExpectedProps['h']>(props.h)
@ -198,6 +221,8 @@ describe('with object props', () => {
render() { render() {
const props = this.$props const props = this.$props
expectType<ExpectedProps['a']>(props.a) expectType<ExpectedProps['a']>(props.a)
expectType<ExpectedProps['aa']>(props.aa)
expectType<ExpectedProps['aaa']>(props.aaa)
expectType<ExpectedProps['b']>(props.b) expectType<ExpectedProps['b']>(props.b)
expectType<ExpectedProps['e']>(props.e) expectType<ExpectedProps['e']>(props.e)
expectType<ExpectedProps['h']>(props.h) expectType<ExpectedProps['h']>(props.h)
@ -225,6 +250,8 @@ describe('with object props', () => {
// should also expose declared props on `this` // should also expose declared props on `this`
expectType<ExpectedProps['a']>(this.a) expectType<ExpectedProps['a']>(this.a)
expectType<ExpectedProps['aa']>(this.aa)
expectType<ExpectedProps['aaa']>(this.aaa)
expectType<ExpectedProps['b']>(this.b) expectType<ExpectedProps['b']>(this.b)
expectType<ExpectedProps['e']>(this.e) expectType<ExpectedProps['e']>(this.e)
expectType<ExpectedProps['h']>(this.h) expectType<ExpectedProps['h']>(this.h)
@ -269,6 +296,7 @@ describe('with object props', () => {
expectType<JSX.Element>( expectType<JSX.Element>(
<MyComponent <MyComponent
a={1} a={1}
aaaa={1}
b="b" b="b"
bb="bb" bb="bb"
e={() => {}} e={() => {}}
@ -295,6 +323,7 @@ describe('with object props', () => {
expectType<Component>( expectType<Component>(
<MyComponent <MyComponent
aaaa={1}
b="b" b="b"
dd={{ n: 1 }} dd={{ n: 1 }}
ddd={['ddd']} ddd={['ddd']}
@ -2068,3 +2097,13 @@ expectString(instance.actionText)
// public prop on $props should be optional // public prop on $props should be optional
// @ts-expect-error // @ts-expect-error
expectString(instance.$props.actionText) expectString(instance.$props.actionText)
// #12122
defineComponent({
props: { foo: String },
render() {
expectType<{ readonly foo?: string }>(this.$props)
// @ts-expect-error
expectType<string>(this.$props)
},
})

View File

@ -29,7 +29,7 @@ describe('custom', () => {
value: number value: number
oldValue: number | null oldValue: number | null
arg?: 'Arg' arg?: 'Arg'
modifiers: Record<'a' | 'b', boolean> modifiers: Partial<Record<'a' | 'b', boolean>>
}>(testDirective<number, 'a' | 'b', 'Arg'>()) }>(testDirective<number, 'a' | 'b', 'Arg'>())
expectType<{ expectType<{

View File

@ -4,6 +4,7 @@ import {
type MaybeRefOrGetter, type MaybeRefOrGetter,
type Ref, type Ref,
type ShallowRef, type ShallowRef,
type TemplateRef,
type ToRefs, type ToRefs,
type WritableComputedRef, type WritableComputedRef,
computed, computed,
@ -189,6 +190,24 @@ describe('allow getter and setter types to be unrelated', <T>() => {
f.value = ref(1) f.value = ref(1)
}) })
describe('correctly unwraps nested refs', () => {
const obj = {
n: 24,
ref: ref(24),
nestedRef: ref({ n: ref(0) }),
}
const a = ref(obj)
expectType<number>(a.value.n)
expectType<number>(a.value.ref)
expectType<number>(a.value.nestedRef.n)
const b = reactive({ a })
expectType<number>(b.a.n)
expectType<number>(b.a.ref)
expectType<number>(b.a.nestedRef.n)
})
// computed // computed
describe('allow computed getter and setter types to be unrelated', () => { describe('allow computed getter and setter types to be unrelated', () => {
const obj = ref({ const obj = ref({
@ -517,7 +536,7 @@ expectType<string>(toValue(unref2))
// useTemplateRef // useTemplateRef
const tRef = useTemplateRef('foo') const tRef = useTemplateRef('foo')
expectType<Readonly<ShallowRef<unknown>>>(tRef) expectType<TemplateRef>(tRef)
const tRef2 = useTemplateRef<HTMLElement>('bar') const tRef2 = useTemplateRef<HTMLElement>('bar')
expectType<Readonly<ShallowRef<HTMLElement | null>>>(tRef2) expectType<TemplateRef<HTMLElement>>(tRef2)

View File

@ -240,6 +240,23 @@ describe('withDefaults w/ defineProp type is different from the defaults type',
res1.value res1.value
}) })
describe('withDefaults w/ defineProp discriminate union type', () => {
const props = withDefaults(
defineProps<
{ type: 'button'; buttonType?: 'submit' } | { type: 'link'; href: string }
>(),
{
type: 'button',
},
)
if (props.type === 'button') {
expectType<'submit' | undefined>(props.buttonType)
}
if (props.type === 'link') {
expectType<string>(props.href)
}
})
describe('defineProps w/ runtime declaration', () => { describe('defineProps w/ runtime declaration', () => {
// runtime declaration // runtime declaration
const props = defineProps({ const props = defineProps({
@ -289,6 +306,14 @@ describe('defineEmits w/ type declaration', () => {
emit2('baz') emit2('baz')
}) })
describe('defineEmits w/ interface declaration', () => {
interface Emits {
foo: [value: string]
}
const emit = defineEmits<Emits>()
emit('foo', 'hi')
})
describe('defineEmits w/ alt type declaration', () => { describe('defineEmits w/ alt type declaration', () => {
const emit = defineEmits<{ const emit = defineEmits<{
foo: [id: string] foo: [id: string]

View File

@ -13,7 +13,7 @@
"vite": "catalog:" "vite": "catalog:"
}, },
"dependencies": { "dependencies": {
"@vue/repl": "^4.4.2", "@vue/repl": "^4.5.1",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"jszip": "^3.10.1", "jszip": "^3.10.1",
"vue": "workspace:*" "vue": "workspace:*"

View File

@ -123,6 +123,7 @@ onMounted(() => {
:prod="productionMode" :prod="productionMode"
:ssr="useSSRMode" :ssr="useSSRMode"
:autoSave="autoSave" :autoSave="autoSave"
:theme="theme"
@toggle-theme="toggleTheme" @toggle-theme="toggleTheme"
@toggle-prod="toggleProdMode" @toggle-prod="toggleProdMode"
@toggle-ssr="toggleSSR" @toggle-ssr="toggleSSR"
@ -164,8 +165,9 @@ onMounted(() => {
body { body {
font-size: 13px; font-size: 13px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, font-family:
Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
margin: 0; margin: 0;
--base: #444; --base: #444;
--nav-height: 50px; --nav-height: 50px;

View File

@ -15,6 +15,7 @@ const props = defineProps<{
prod: boolean prod: boolean
ssr: boolean ssr: boolean
autoSave: boolean autoSave: boolean
theme: 'dark' | 'light'
}>() }>()
const emit = defineEmits([ const emit = defineEmits([
'toggle-theme', 'toggle-theme',
@ -45,6 +46,7 @@ function resetVueVersion() {
async function copyLink(e: MouseEvent) { async function copyLink(e: MouseEvent) {
if (e.metaKey) { if (e.metaKey) {
resetVueVersion()
// hidden logic for going to local debug from play.vuejs.org // hidden logic for going to local debug from play.vuejs.org
window.location.href = 'http://localhost:5173/' + window.location.hash window.location.href = 'http://localhost:5173/' + window.location.hash
return return
@ -117,7 +119,11 @@ function toggleDark() {
> >
<span>{{ autoSave ? 'AutoSave ON' : 'AutoSave OFF' }}</span> <span>{{ autoSave ? 'AutoSave ON' : 'AutoSave OFF' }}</span>
</button> </button>
<button title="Toggle dark mode" class="toggle-dark" @click="toggleDark"> <button
:title="`Switch to ${theme === 'dark' ? 'light' : 'dark'} theme`"
class="toggle-dark"
@click="toggleDark"
>
<Sun class="light" /> <Sun class="light" />
<Moon class="dark" /> <Moon class="dark" />
</button> </button>

View File

@ -17,7 +17,10 @@ export async function downloadProject(store: ReplStore) {
// basic structure // basic structure
zip.file('index.html', index) zip.file('index.html', index)
zip.file('package.json', pkg) zip.file(
'package.json',
pkg.replace(`"vue": "latest"`, `"vue": "${store.vueVersion || 'latest'}"`),
)
zip.file('vite.config.js', config) zip.file('vite.config.js', config)
zip.file('README.md', readme) zip.file('README.md', readme)

View File

@ -8,10 +8,10 @@
"serve": "vite preview" "serve": "vite preview"
}, },
"dependencies": { "dependencies": {
"vue": "^3.4.0" "vue": "latest"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^5.1.4", "@vitejs/plugin-vue": "^5.2.4",
"vite": "^5.4.8" "vite": "^6.3.5"
} }
} }

View File

@ -11,7 +11,7 @@
"enableNonBrowserBranches": true "enableNonBrowserBranches": true
}, },
"dependencies": { "dependencies": {
"monaco-editor": "^0.51.0", "monaco-editor": "^0.52.2",
"source-map-js": "^1.2.1" "source-map-js": "^1.2.1"
} }
} }

View File

@ -1,8 +1,9 @@
body { body {
margin: 0; margin: 0;
overflow: hidden; overflow: hidden;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, font-family:
Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
--bg: #1d1f21; --bg: #1d1f21;
--border: #333; --border: #333;
} }

View File

@ -2271,6 +2271,11 @@ describe('compiler: parse', () => {
expect(span.loc.start.offset).toBe(0) expect(span.loc.start.offset).toBe(0)
expect(span.loc.end.offset).toBe(27) expect(span.loc.end.offset).toBe(27)
}) })
test('correct loc when a line in attribute value ends with &', () => {
const [span] = baseParse(`<span v-if="foo &&\nbar"></span>`).children
expect(span.loc.end.line).toBe(2)
})
}) })
describe('decodeEntities option', () => { describe('decodeEntities option', () => {

View File

@ -8,7 +8,7 @@ return function render(_ctx, _cache) {
const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [ return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
_createElementVNode("div", { key: "foo" }, null, -1 /* HOISTED */) _createElementVNode("div", { key: "foo" }, null, -1 /* CACHED */)
]))) ])))
} }
}" }"
@ -25,11 +25,11 @@ return function render(_ctx, _cache) {
_createElementVNode("p", null, [ _createElementVNode("p", null, [
_createElementVNode("span"), _createElementVNode("span"),
_createElementVNode("span") _createElementVNode("span")
], -1 /* HOISTED */), ], -1 /* CACHED */),
_createElementVNode("p", null, [ _createElementVNode("p", null, [
_createElementVNode("span"), _createElementVNode("span"),
_createElementVNode("span") _createElementVNode("span")
], -1 /* HOISTED */) ], -1 /* CACHED */)
]))) ])))
} }
}" }"
@ -45,7 +45,7 @@ return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [ return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
_createElementVNode("div", null, [ _createElementVNode("div", null, [
_createCommentVNode("comment") _createCommentVNode("comment")
], -1 /* HOISTED */) ], -1 /* CACHED */)
]))) ])))
} }
}" }"
@ -59,9 +59,9 @@ return function render(_ctx, _cache) {
const { createElementVNode: _createElementVNode, createTextVNode: _createTextVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue const { createElementVNode: _createElementVNode, createTextVNode: _createTextVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [ return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
_createElementVNode("span", null, null, -1 /* HOISTED */), _createElementVNode("span", null, null, -1 /* CACHED */),
_createTextVNode("foo"), _createTextVNode("foo"),
_createElementVNode("div", null, null, -1 /* HOISTED */) _createElementVNode("div", null, null, -1 /* CACHED */)
]))) ])))
} }
}" }"
@ -75,7 +75,7 @@ return function render(_ctx, _cache) {
const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [ return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
_createElementVNode("span", { class: "inline" }, "hello", -1 /* HOISTED */) _createElementVNode("span", { class: "inline" }, "hello", -1 /* CACHED */)
]))) ])))
} }
}" }"
@ -148,7 +148,7 @@ return function render(_ctx, _cache) {
const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [ return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
_createElementVNode("span", null, "foo " + _toDisplayString(1) + " " + _toDisplayString(true), -1 /* HOISTED */) _createElementVNode("span", null, "foo " + _toDisplayString(1) + " " + _toDisplayString(true), -1 /* CACHED */)
]))) ])))
} }
}" }"
@ -162,7 +162,7 @@ return function render(_ctx, _cache) {
const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [ return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
_createElementVNode("span", { foo: 0 }, _toDisplayString(1), -1 /* HOISTED */) _createElementVNode("span", { foo: 0 }, _toDisplayString(1), -1 /* CACHED */)
]))) ])))
} }
}" }"
@ -178,7 +178,7 @@ return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("div", null, [ return (_openBlock(), _createElementBlock("div", null, [
(_openBlock(true), _createElementBlock(_Fragment, null, _renderList(1, (i) => { (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(1, (i) => {
return (_openBlock(), _createElementBlock("div", null, [...(_cache[0] || (_cache[0] = [ return (_openBlock(), _createElementBlock("div", null, [...(_cache[0] || (_cache[0] = [
_createElementVNode("span", { class: "hi" }, null, -1 /* HOISTED */) _createElementVNode("span", { class: "hi" }, null, -1 /* CACHED */)
]))])) ]))]))
}), 256 /* UNKEYED_FRAGMENT */)) }), 256 /* UNKEYED_FRAGMENT */))
])) ]))
@ -216,7 +216,7 @@ return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("div", null, [ return (_openBlock(), _createElementBlock("div", null, [
_withDirectives((_openBlock(), _createElementBlock("svg", null, _cache[0] || (_cache[0] = [ _withDirectives((_openBlock(), _createElementBlock("svg", null, _cache[0] || (_cache[0] = [
_createElementVNode("path", { d: "M2,3H5.5L12" }, null, -1 /* HOISTED */) _createElementVNode("path", { d: "M2,3H5.5L12" }, null, -1 /* CACHED */)
]))), [ ]))), [
[_directive_foo] [_directive_foo]
]) ])
@ -402,7 +402,7 @@ return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("div", null, [ return (_openBlock(), _createElementBlock("div", null, [
ok ok
? (_openBlock(), _createElementBlock("div", _hoisted_1, _cache[0] || (_cache[0] = [ ? (_openBlock(), _createElementBlock("div", _hoisted_1, _cache[0] || (_cache[0] = [
_createElementVNode("span", null, null, -1 /* HOISTED */) _createElementVNode("span", null, null, -1 /* CACHED */)
]))) ])))
: _createCommentVNode("v-if", true) : _createCommentVNode("v-if", true)
])) ]))
@ -410,6 +410,32 @@ return function render(_ctx, _cache) {
}" }"
`; `;
exports[`compiler: cacheStatic transform > should hoist props for root with single element excluding comments 1`] = `
"const _Vue = Vue
const { createElementVNode: _createElementVNode, createCommentVNode: _createCommentVNode } = _Vue
const _hoisted_1 = { id: "a" }
return function render(_ctx, _cache) {
with (_ctx) {
const { createCommentVNode: _createCommentVNode, createElementVNode: _createElementVNode, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
return (_openBlock(), _createElementBlock(_Fragment, null, [
_createCommentVNode("comment"),
_createElementVNode("div", _hoisted_1, _cache[0] || (_cache[0] = [
_createElementVNode("div", { id: "b" }, [
_createElementVNode("div", { id: "c" }, [
_createElementVNode("div", { id: "d" }, [
_createElementVNode("div", { id: "e" }, "hello")
])
])
], -1 /* CACHED */)
]))
], 2112 /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */))
}
}"
`;
exports[`compiler: cacheStatic transform > should hoist v-for children if static 1`] = ` exports[`compiler: cacheStatic transform > should hoist v-for children if static 1`] = `
"const _Vue = Vue "const _Vue = Vue
const { createElementVNode: _createElementVNode } = _Vue const { createElementVNode: _createElementVNode } = _Vue
@ -423,7 +449,7 @@ return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("div", null, [ return (_openBlock(), _createElementBlock("div", null, [
(_openBlock(true), _createElementBlock(_Fragment, null, _renderList(list, (i) => { (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(list, (i) => {
return (_openBlock(), _createElementBlock("div", _hoisted_1, _cache[0] || (_cache[0] = [ return (_openBlock(), _createElementBlock("div", _hoisted_1, _cache[0] || (_cache[0] = [
_createElementVNode("span", null, null, -1 /* HOISTED */) _createElementVNode("span", null, null, -1 /* CACHED */)
]))) ])))
}), 256 /* UNKEYED_FRAGMENT */)) }), 256 /* UNKEYED_FRAGMENT */))
])) ]))

View File

@ -1,5 +1,23 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`compiler: v-memo transform > element v-for key expression prefixing + v-memo 1`] = `
"import { renderList as _renderList, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock, isMemoSame as _isMemoSame, withMemo as _withMemo } from "vue"
export function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("div", null, [
(_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.tableData, (data, __, ___, _cached) => {
const _memo = (_ctx.getLetter(data))
if (_cached && _cached.key === _ctx.getId(data) && _isMemoSame(_cached, _memo)) return _cached
const _item = (_openBlock(), _createElementBlock("span", {
key: _ctx.getId(data)
}))
_item.memo = _memo
return _item
}, _cache, 0), 128 /* KEYED_FRAGMENT */))
]))
}"
`;
exports[`compiler: v-memo transform > on component 1`] = ` exports[`compiler: v-memo transform > on component 1`] = `
"import { resolveComponent as _resolveComponent, createVNode as _createVNode, withMemo as _withMemo, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue" "import { resolveComponent as _resolveComponent, createVNode as _createVNode, withMemo as _withMemo, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"

View File

@ -8,7 +8,7 @@ return function render(_ctx, _cache) {
const { setBlockTracking: _setBlockTracking, createElementVNode: _createElementVNode } = _Vue const { setBlockTracking: _setBlockTracking, createElementVNode: _createElementVNode } = _Vue
return _cache[0] || ( return _cache[0] || (
_setBlockTracking(-1), _setBlockTracking(-1, true),
(_cache[0] = _createElementVNode("div", { id: foo }, null, 8 /* PROPS */, ["id"])).cacheIndex = 0, (_cache[0] = _createElementVNode("div", { id: foo }, null, 8 /* PROPS */, ["id"])).cacheIndex = 0,
_setBlockTracking(1), _setBlockTracking(1),
_cache[0] _cache[0]
@ -28,7 +28,7 @@ return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("div", null, [ return (_openBlock(), _createElementBlock("div", null, [
_cache[0] || ( _cache[0] || (
_setBlockTracking(-1), _setBlockTracking(-1, true),
(_cache[0] = _createVNode(_component_Comp, { id: foo }, null, 8 /* PROPS */, ["id"])).cacheIndex = 0, (_cache[0] = _createVNode(_component_Comp, { id: foo }, null, 8 /* PROPS */, ["id"])).cacheIndex = 0,
_setBlockTracking(1), _setBlockTracking(1),
_cache[0] _cache[0]
@ -47,7 +47,7 @@ return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("div", null, [ return (_openBlock(), _createElementBlock("div", null, [
_cache[0] || ( _cache[0] || (
_setBlockTracking(-1), _setBlockTracking(-1, true),
(_cache[0] = _createElementVNode("div", { id: foo }, null, 8 /* PROPS */, ["id"])).cacheIndex = 0, (_cache[0] = _createElementVNode("div", { id: foo }, null, 8 /* PROPS */, ["id"])).cacheIndex = 0,
_setBlockTracking(1), _setBlockTracking(1),
_cache[0] _cache[0]
@ -66,7 +66,7 @@ return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("div", null, [ return (_openBlock(), _createElementBlock("div", null, [
_cache[0] || ( _cache[0] || (
_setBlockTracking(-1), _setBlockTracking(-1, true),
(_cache[0] = _renderSlot($slots, "default")).cacheIndex = 0, (_cache[0] = _renderSlot($slots, "default")).cacheIndex = 0,
_setBlockTracking(1), _setBlockTracking(1),
_cache[0] _cache[0]
@ -85,7 +85,7 @@ return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("div", null, [ return (_openBlock(), _createElementBlock("div", null, [
_cache[0] || ( _cache[0] || (
_setBlockTracking(-1), _setBlockTracking(-1, true),
(_cache[0] = _createElementVNode("div")).cacheIndex = 0, (_cache[0] = _createElementVNode("div")).cacheIndex = 0,
_setBlockTracking(1), _setBlockTracking(1),
_cache[0] _cache[0]

View File

@ -246,6 +246,28 @@ return function render(_ctx, _cache) {
}" }"
`; `;
exports[`compiler: transform component slots > with whitespace: 'preserve' > named slot with v-if + v-else 1`] = `
"const { resolveComponent: _resolveComponent, withCtx: _withCtx, createSlots: _createSlots, openBlock: _openBlock, createBlock: _createBlock } = Vue
return function render(_ctx, _cache) {
const _component_Comp = _resolveComponent("Comp")
return (_openBlock(), _createBlock(_component_Comp, null, _createSlots({ _: 2 /* DYNAMIC */ }, [
ok
? {
name: "one",
fn: _withCtx(() => ["foo"]),
key: "0"
}
: {
name: "two",
fn: _withCtx(() => ["baz"]),
key: "1"
}
]), 1024 /* DYNAMIC_SLOTS */))
}"
`;
exports[`compiler: transform component slots > with whitespace: 'preserve' > should not generate whitespace only default slot 1`] = ` exports[`compiler: transform component slots > with whitespace: 'preserve' > should not generate whitespace only default slot 1`] = `
"const { resolveComponent: _resolveComponent, withCtx: _withCtx, openBlock: _openBlock, createBlock: _createBlock } = Vue "const { resolveComponent: _resolveComponent, withCtx: _withCtx, openBlock: _openBlock, createBlock: _createBlock } = Vue

View File

@ -170,6 +170,11 @@ describe('compiler: cacheStatic transform', () => {
{ {
/* _ slot flag */ /* _ slot flag */
}, },
{
type: NodeTypes.JS_PROPERTY,
key: { content: '__' },
value: { content: '[0]' },
},
], ],
}) })
}) })
@ -197,6 +202,11 @@ describe('compiler: cacheStatic transform', () => {
{ {
/* _ slot flag */ /* _ slot flag */
}, },
{
type: NodeTypes.JS_PROPERTY,
key: { content: '__' },
value: { content: '[0]' },
},
], ],
}) })
}) })
@ -533,6 +543,32 @@ describe('compiler: cacheStatic transform', () => {
expect(generate(root).code).toMatchSnapshot() expect(generate(root).code).toMatchSnapshot()
}) })
test('should hoist props for root with single element excluding comments', () => {
// deeply nested div to trigger stringification condition
const root = transformWithCache(
`<!--comment--><div id="a"><div id="b"><div id="c"><div id="d"><div id="e">hello</div></div></div></div></div>`,
)
expect(root.cached.length).toBe(1)
expect(root.hoists).toMatchObject([createObjectMatcher({ id: 'a' })])
expect((root.codegenNode as VNodeCall).children).toMatchObject([
{
type: NodeTypes.COMMENT,
content: 'comment',
},
{
type: NodeTypes.ELEMENT,
codegenNode: {
type: NodeTypes.VNODE_CALL,
tag: `"div"`,
props: { content: `_hoisted_1` },
children: { type: NodeTypes.JS_CACHE_EXPRESSION },
},
},
])
expect(generate(root).code).toMatchSnapshot()
})
describe('prefixIdentifiers', () => { describe('prefixIdentifiers', () => {
test('cache nested static tree with static interpolation', () => { test('cache nested static tree with static interpolation', () => {
const root = transformWithCache( const root = transformWithCache(

View File

@ -53,4 +53,12 @@ describe('compiler: v-memo transform', () => {
), ),
).toMatchSnapshot() ).toMatchSnapshot()
}) })
test('element v-for key expression prefixing + v-memo', () => {
expect(
compile(
`<span v-for="data of tableData" :key="getId(data)" v-memo="getLetter(data)"></span>`,
),
).toMatchSnapshot()
})
}) })

View File

@ -988,5 +988,19 @@ describe('compiler: transform component slots', () => {
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot() expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
}) })
test('named slot with v-if + v-else', () => {
const source = `
<Comp>
<template #one v-if="ok">foo</template>
<template #two v-else>baz</template>
</Comp>
`
const { root } = parseWithSlots(source, {
whitespace: 'preserve',
})
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
})
}) })
}) })

View File

@ -1,6 +1,6 @@
{ {
"name": "@vue/compiler-core", "name": "@vue/compiler-core",
"version": "3.5.9", "version": "3.5.16",
"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",

View File

@ -418,6 +418,7 @@ export interface CacheExpression extends Node {
index: number index: number
value: JSChildNode value: JSChildNode
needPauseTracking: boolean needPauseTracking: boolean
inVOnce: boolean
needArraySpread: boolean needArraySpread: boolean
} }
@ -774,12 +775,14 @@ export function createCacheExpression(
index: number, index: number,
value: JSChildNode, value: JSChildNode,
needPauseTracking: boolean = false, needPauseTracking: boolean = false,
inVOnce: boolean = false,
): CacheExpression { ): CacheExpression {
return { return {
type: NodeTypes.JS_CACHE_EXPRESSION, type: NodeTypes.JS_CACHE_EXPRESSION,
index, index,
value, value,
needPauseTracking: needPauseTracking, needPauseTracking: needPauseTracking,
inVOnce,
needArraySpread: false, needArraySpread: false,
loc: locStub, loc: locStub,
} }

View File

@ -188,8 +188,10 @@ function createCodegenContext(
name = content name = content
} }
} }
if (node.loc.source) {
addMapping(node.loc.start, name) addMapping(node.loc.start, name)
} }
}
if (newlineIndex === NewlineType.Unknown) { if (newlineIndex === NewlineType.Unknown) {
// multiple newlines, full iteration // multiple newlines, full iteration
advancePositionWithMutation(context, code) advancePositionWithMutation(context, code)
@ -225,7 +227,7 @@ function createCodegenContext(
context.column = code.length - newlineIndex context.column = code.length - newlineIndex
} }
} }
if (node && node.loc !== locStub) { if (node && node.loc !== locStub && node.loc.source) {
addMapping(node.loc.end) addMapping(node.loc.end)
} }
} }
@ -1017,7 +1019,9 @@ function genCacheExpression(node: CacheExpression, context: CodegenContext) {
push(`_cache[${node.index}] || (`) push(`_cache[${node.index}] || (`)
if (needPauseTracking) { if (needPauseTracking) {
indent() indent()
push(`${helper(SET_BLOCK_TRACKING)}(-1),`) push(`${helper(SET_BLOCK_TRACKING)}(-1`)
if (node.inVOnce) push(`, true`)
push(`),`)
newline() newline()
push(`(`) push(`(`)
} }

View File

@ -388,7 +388,7 @@ const tokenizer = new Tokenizer(stack, {
CompilerDeprecationTypes.COMPILER_V_BIND_SYNC, CompilerDeprecationTypes.COMPILER_V_BIND_SYNC,
currentOptions, currentOptions,
currentProp.loc, currentProp.loc,
currentProp.rawName, currentProp.arg!.loc.source,
) )
) { ) {
currentProp.name = 'model' currentProp.name = 'model'
@ -647,7 +647,7 @@ function onCloseTag(el: ElementNode, end: number, isImplied = false) {
// whitespace management // whitespace management
if (!tokenizer.inRCDATA) { if (!tokenizer.inRCDATA) {
el.children = condenseWhitespace(children, tag) el.children = condenseWhitespace(children)
} }
if (ns === Namespaces.HTML && currentOptions.isIgnoreNewlineTag(tag)) { if (ns === Namespaces.HTML && currentOptions.isIgnoreNewlineTag(tag)) {
@ -832,10 +832,7 @@ function isUpperCase(c: number) {
} }
const windowsNewlineRE = /\r\n/g const windowsNewlineRE = /\r\n/g
function condenseWhitespace( function condenseWhitespace(nodes: TemplateChildNode[]): TemplateChildNode[] {
nodes: TemplateChildNode[],
tag?: string,
): TemplateChildNode[] {
const shouldCondense = currentOptions.whitespace !== 'preserve' const shouldCondense = currentOptions.whitespace !== 'preserve'
let removedWhitespace = false let removedWhitespace = false
for (let i = 0; i < nodes.length; i++) { for (let i = 0; i < nodes.length; i++) {
@ -933,6 +930,10 @@ function getLoc(start: number, end?: number): SourceLocation {
} }
} }
export function cloneLoc(loc: SourceLocation): SourceLocation {
return getLoc(loc.start.offset, loc.end.offset)
}
function setLocEnd(loc: SourceLocation, end: number) { function setLocEnd(loc: SourceLocation, end: number) {
loc.end = tokenizer.getPos(end) loc.end = tokenizer.getPos(end)
loc.source = getSlice(loc.start.offset, end) loc.source = getSlice(loc.start.offset, end)

View File

@ -929,7 +929,7 @@ export default class Tokenizer {
this.buffer = input this.buffer = input
while (this.index < this.buffer.length) { while (this.index < this.buffer.length) {
const c = this.buffer.charCodeAt(this.index) const c = this.buffer.charCodeAt(this.index)
if (c === CharCodes.NewLine) { if (c === CharCodes.NewLine && this.state !== State.InEntity) {
this.newlines.push(this.index) this.newlines.push(this.index)
} }
switch (this.state) { switch (this.state) {

View File

@ -37,7 +37,7 @@ import {
helperNameMap, helperNameMap,
} from './runtimeHelpers' } from './runtimeHelpers'
import { isVSlot } from './utils' import { isVSlot } from './utils'
import { cacheStatic, isSingleElementRoot } from './transforms/cacheStatic' import { cacheStatic, getSingleElementRoot } from './transforms/cacheStatic'
import type { CompilerCompatOptions } from './compat/compatConfig' import type { CompilerCompatOptions } from './compat/compatConfig'
// There are two types of transforms: // There are two types of transforms:
@ -116,7 +116,7 @@ export interface TransformContext
addIdentifiers(exp: ExpressionNode | string): void addIdentifiers(exp: ExpressionNode | string): void
removeIdentifiers(exp: ExpressionNode | string): void removeIdentifiers(exp: ExpressionNode | string): void
hoist(exp: string | JSChildNode | ArrayExpression): SimpleExpressionNode hoist(exp: string | JSChildNode | ArrayExpression): SimpleExpressionNode
cache(exp: JSChildNode, isVNode?: boolean): CacheExpression cache(exp: JSChildNode, isVNode?: boolean, inVOnce?: boolean): CacheExpression
constantCache: WeakMap<TemplateChildNode, ConstantTypes> constantCache: WeakMap<TemplateChildNode, ConstantTypes>
// 2.x Compat only // 2.x Compat only
@ -297,11 +297,12 @@ export function createTransformContext(
identifier.hoisted = exp identifier.hoisted = exp
return identifier return identifier
}, },
cache(exp, isVNode = false) { cache(exp, isVNode = false, inVOnce = false) {
const cacheExp = createCacheExpression( const cacheExp = createCacheExpression(
context.cached.length, context.cached.length,
exp, exp,
isVNode, isVNode,
inVOnce,
) )
context.cached.push(cacheExp) context.cached.push(cacheExp)
return cacheExp return cacheExp
@ -355,12 +356,12 @@ function createRootCodegen(root: RootNode, context: TransformContext) {
const { helper } = context const { helper } = context
const { children } = root const { children } = root
if (children.length === 1) { if (children.length === 1) {
const child = children[0] const singleElementRootChild = getSingleElementRoot(root)
// if the single child is an element, turn it into a block. // if the single child is an element, turn it into a block.
if (isSingleElementRoot(root, child) && child.codegenNode) { if (singleElementRootChild && singleElementRootChild.codegenNode) {
// single element root is never hoisted so codegenNode will never be // single element root is never hoisted so codegenNode will never be
// SimpleExpressionNode // SimpleExpressionNode
const codegenNode = child.codegenNode const codegenNode = singleElementRootChild.codegenNode
if (codegenNode.type === NodeTypes.VNODE_CALL) { if (codegenNode.type === NodeTypes.VNODE_CALL) {
convertToBlock(codegenNode, context) convertToBlock(codegenNode, context)
} }
@ -369,7 +370,7 @@ function createRootCodegen(root: RootNode, context: TransformContext) {
// - single <slot/>, IfNode, ForNode: already blocks. // - single <slot/>, IfNode, ForNode: already blocks.
// - single text node: always patched. // - single text node: always patched.
// root codegen falls through via genNode() // root codegen falls through via genNode()
root.codegenNode = child root.codegenNode = children[0]
} }
} else if (children.length > 1) { } else if (children.length > 1) {
// root has multiple nodes - return a fragment block. // root has multiple nodes - return a fragment block.

View File

@ -12,11 +12,14 @@ import {
type RootNode, type RootNode,
type SimpleExpressionNode, type SimpleExpressionNode,
type SlotFunctionExpression, type SlotFunctionExpression,
type SlotsObjectProperty,
type TemplateChildNode, type TemplateChildNode,
type TemplateNode, type TemplateNode,
type TextCallNode, type TextCallNode,
type VNodeCall, type VNodeCall,
createArrayExpression, createArrayExpression,
createObjectProperty,
createSimpleExpression,
getVNodeBlockHelper, getVNodeBlockHelper,
getVNodeHelper, getVNodeHelper,
} from '../ast' } from '../ast'
@ -38,20 +41,19 @@ export function cacheStatic(root: RootNode, context: TransformContext): void {
context, context,
// Root node is unfortunately non-hoistable due to potential parent // Root node is unfortunately non-hoistable due to potential parent
// fallthrough attributes. // fallthrough attributes.
isSingleElementRoot(root, root.children[0]), !!getSingleElementRoot(root),
) )
} }
export function isSingleElementRoot( export function getSingleElementRoot(
root: RootNode, root: RootNode,
child: TemplateChildNode, ): PlainElementNode | ComponentNode | TemplateNode | null {
): child is PlainElementNode | ComponentNode | TemplateNode { const children = root.children.filter(x => x.type !== NodeTypes.COMMENT)
const { children } = root return children.length === 1 &&
return ( children[0].type === NodeTypes.ELEMENT &&
children.length === 1 && !isSlotOutlet(children[0])
child.type === NodeTypes.ELEMENT && ? children[0]
!isSlotOutlet(child) : null
)
} }
function walk( function walk(
@ -140,6 +142,7 @@ function walk(
} }
let cachedAsArray = false let cachedAsArray = false
const slotCacheKeys = []
if (toCache.length === children.length && node.type === NodeTypes.ELEMENT) { if (toCache.length === children.length && node.type === NodeTypes.ELEMENT) {
if ( if (
node.tagType === ElementTypes.ELEMENT && node.tagType === ElementTypes.ELEMENT &&
@ -163,6 +166,7 @@ function walk(
// default slot // default slot
const slot = getSlotNode(node.codegenNode, 'default') const slot = getSlotNode(node.codegenNode, 'default')
if (slot) { if (slot) {
slotCacheKeys.push(context.cached.length)
slot.returns = getCacheExpression( slot.returns = getCacheExpression(
createArrayExpression(slot.returns as TemplateChildNode[]), createArrayExpression(slot.returns as TemplateChildNode[]),
) )
@ -186,6 +190,7 @@ function walk(
slotName.arg && slotName.arg &&
getSlotNode(parent.codegenNode, slotName.arg) getSlotNode(parent.codegenNode, slotName.arg)
if (slot) { if (slot) {
slotCacheKeys.push(context.cached.length)
slot.returns = getCacheExpression( slot.returns = getCacheExpression(
createArrayExpression(slot.returns as TemplateChildNode[]), createArrayExpression(slot.returns as TemplateChildNode[]),
) )
@ -196,10 +201,31 @@ function walk(
if (!cachedAsArray) { if (!cachedAsArray) {
for (const child of toCache) { for (const child of toCache) {
slotCacheKeys.push(context.cached.length)
child.codegenNode = context.cache(child.codegenNode!) child.codegenNode = context.cache(child.codegenNode!)
} }
} }
// put the slot cached keys on the slot object, so that the cache
// can be removed when component unmounting to prevent memory leaks
if (
slotCacheKeys.length &&
node.type === NodeTypes.ELEMENT &&
node.tagType === ElementTypes.COMPONENT &&
node.codegenNode &&
node.codegenNode.type === NodeTypes.VNODE_CALL &&
node.codegenNode.children &&
!isArray(node.codegenNode.children) &&
node.codegenNode.children.type === NodeTypes.JS_OBJECT_EXPRESSION
) {
node.codegenNode.children.properties.push(
createObjectProperty(
`__`,
createSimpleExpression(JSON.stringify(slotCacheKeys), false),
) as SlotsObjectProperty,
)
}
function getCacheExpression(value: JSChildNode): CacheExpression { function getCacheExpression(value: JSChildNode): CacheExpression {
const exp = context.cache(value) const exp = context.cache(value)
// #6978, #7138, #7114 // #6978, #7138, #7114

View File

@ -594,11 +594,9 @@ export function buildProps(
hasDynamicKeys = true hasDynamicKeys = true
if (exp) { if (exp) {
if (isVBind) { if (isVBind) {
// #10696 in case a v-bind object contains ref if (__COMPAT__) {
pushRefVForMarker()
// have to merge early for compat build check // have to merge early for compat build check
pushMergeArg() pushMergeArg()
if (__COMPAT__) {
// 2.x v-bind object order compat // 2.x v-bind object order compat
if (__DEV__) { if (__DEV__) {
const hasOverridableKeys = mergeArgs.some(arg => { const hasOverridableKeys = mergeArgs.some(arg => {
@ -641,6 +639,9 @@ export function buildProps(
} }
} }
// #10696 in case a v-bind object contains ref
pushRefVForMarker()
pushMergeArg()
mergeArgs.push(exp) mergeArgs.push(exp)
} else { } else {
// v-on="obj" -> toHandlers(obj) // v-on="obj" -> toHandlers(obj)

View File

@ -24,7 +24,7 @@ import {
isStaticPropertyKey, isStaticPropertyKey,
walkIdentifiers, walkIdentifiers,
} from '../babelUtils' } from '../babelUtils'
import { advancePositionWithClone, isSimpleIdentifier } from '../utils' import { advancePositionWithClone, findDir, isSimpleIdentifier } from '../utils'
import { import {
genPropsAccessExp, genPropsAccessExp,
hasOwn, hasOwn,
@ -54,6 +54,7 @@ export const transformExpression: NodeTransform = (node, context) => {
) )
} else if (node.type === NodeTypes.ELEMENT) { } else if (node.type === NodeTypes.ELEMENT) {
// handle directives on element // handle directives on element
const memo = findDir(node, 'memo')
for (let i = 0; i < node.props.length; i++) { for (let i = 0; i < node.props.length; i++) {
const dir = node.props[i] const dir = node.props[i]
// do not process for v-on & v-for since they are special handled // do not process for v-on & v-for since they are special handled
@ -65,7 +66,14 @@ export const transformExpression: NodeTransform = (node, context) => {
if ( if (
exp && exp &&
exp.type === NodeTypes.SIMPLE_EXPRESSION && exp.type === NodeTypes.SIMPLE_EXPRESSION &&
!(dir.name === 'on' && arg) !(dir.name === 'on' && arg) &&
// key has been processed in transformFor(vMemo + vFor)
!(
memo &&
arg &&
arg.type === NodeTypes.SIMPLE_EXPRESSION &&
arg.content === 'key'
)
) { ) {
dir.exp = processExpression( dir.exp = processExpression(
exp, exp,

View File

@ -12,7 +12,7 @@ import { camelize } from '@vue/shared'
import { CAMELIZE } from '../runtimeHelpers' import { CAMELIZE } from '../runtimeHelpers'
import { processExpression } from './transformExpression' import { processExpression } from './transformExpression'
// v-bind without arg is handled directly in ./transformElements.ts due to it affecting // v-bind without arg is handled directly in ./transformElement.ts due to its affecting
// codegen for the entire props object. This transform here is only for v-bind // codegen for the entire props object. This transform here is only for v-bind
// *with* args. // *with* args.
export const transformBind: DirectiveTransform = (dir, _node, context) => { export const transformBind: DirectiveTransform = (dir, _node, context) => {

View File

@ -63,17 +63,27 @@ export const transformFor: NodeTransform = createStructuralDirectiveTransform(
const isTemplate = isTemplateNode(node) const isTemplate = isTemplateNode(node)
const memo = findDir(node, 'memo') const memo = findDir(node, 'memo')
const keyProp = findProp(node, `key`, false, true) const keyProp = findProp(node, `key`, false, true)
if (keyProp && keyProp.type === NodeTypes.DIRECTIVE && !keyProp.exp) { const isDirKey = keyProp && keyProp.type === NodeTypes.DIRECTIVE
if (isDirKey && !keyProp.exp) {
// resolve :key shorthand #10882 // resolve :key shorthand #10882
transformBindShorthand(keyProp, context) transformBindShorthand(keyProp, context)
} }
const keyExp = let keyExp =
keyProp && keyProp &&
(keyProp.type === NodeTypes.ATTRIBUTE (keyProp.type === NodeTypes.ATTRIBUTE
? keyProp.value ? keyProp.value
? createSimpleExpression(keyProp.value.content, true) ? createSimpleExpression(keyProp.value.content, true)
: undefined : undefined
: keyProp.exp) : keyProp.exp)
if (memo && keyExp && isDirKey) {
if (!__BROWSER__) {
keyProp.exp = keyExp = processExpression(
keyExp as SimpleExpressionNode,
context,
)
}
}
const keyProperty = const keyProperty =
keyProp && keyExp ? createObjectProperty(`key`, keyExp) : null keyProp && keyExp ? createObjectProperty(`key`, keyExp) : null
@ -253,7 +263,7 @@ export function processFor(
dir: DirectiveNode, dir: DirectiveNode,
context: TransformContext, context: TransformContext,
processCodegen?: (forNode: ForNode) => (() => void) | undefined, processCodegen?: (forNode: ForNode) => (() => void) | undefined,
) { ): (() => void) | undefined {
if (!dir.exp) { if (!dir.exp) {
context.onError( context.onError(
createCompilerError(ErrorCodes.X_V_FOR_NO_EXPRESSION, dir.loc), createCompilerError(ErrorCodes.X_V_FOR_NO_EXPRESSION, dir.loc),

View File

@ -30,6 +30,7 @@ import {
import { ErrorCodes, createCompilerError } from '../errors' import { ErrorCodes, createCompilerError } from '../errors'
import { processExpression } from './transformExpression' import { processExpression } from './transformExpression'
import { validateBrowserExpression } from '../validateExpression' import { validateBrowserExpression } from '../validateExpression'
import { cloneLoc } from '../parser'
import { CREATE_COMMENT, FRAGMENT } from '../runtimeHelpers' import { CREATE_COMMENT, FRAGMENT } from '../runtimeHelpers'
import { findDir, findProp, getMemoedVNodeCall, injectProp } from '../utils' import { findDir, findProp, getMemoedVNodeCall, injectProp } from '../utils'
import { PatchFlags } from '@vue/shared' import { PatchFlags } from '@vue/shared'
@ -110,7 +111,7 @@ export function processIf(
const branch = createIfBranch(node, dir) const branch = createIfBranch(node, dir)
const ifNode: IfNode = { const ifNode: IfNode = {
type: NodeTypes.IF, type: NodeTypes.IF,
loc: node.loc, loc: cloneLoc(node.loc),
branches: [branch], branches: [branch],
} }
context.replaceNode(ifNode) context.replaceNode(ifNode)

View File

@ -17,7 +17,7 @@ import { hasScopeRef, isFnExpression, isMemberExpression } from '../utils'
import { TO_HANDLER_KEY } from '../runtimeHelpers' import { TO_HANDLER_KEY } from '../runtimeHelpers'
export interface VOnDirectiveNode extends DirectiveNode { export interface VOnDirectiveNode extends DirectiveNode {
// v-on without arg is handled directly in ./transformElements.ts due to it affecting // v-on without arg is handled directly in ./transformElement.ts due to its affecting
// codegen for the entire props object. This transform here is only for v-on // codegen for the entire props object. This transform here is only for v-on
// *with* args. // *with* args.
arg: ExpressionNode arg: ExpressionNode

View File

@ -17,7 +17,11 @@ export const transformOnce: NodeTransform = (node, context) => {
context.inVOnce = false context.inVOnce = false
const cur = context.currentNode as ElementNode | IfNode | ForNode const cur = context.currentNode as ElementNode | IfNode | ForNode
if (cur.codegenNode) { if (cur.codegenNode) {
cur.codegenNode = context.cache(cur.codegenNode, true /* isVNode */) cur.codegenNode = context.cache(
cur.codegenNode,
true /* isVNode */,
true /* inVOnce */,
)
} }
} }
} }

View File

@ -222,7 +222,7 @@ export function buildSlots(
let prev let prev
while (j--) { while (j--) {
prev = children[j] prev = children[j]
if (prev.type !== NodeTypes.COMMENT) { if (prev.type !== NodeTypes.COMMENT && isNonWhitespaceContent(prev)) {
break break
} }
} }
@ -342,7 +342,6 @@ export function buildSlots(
: hasForwardedSlots(node.children) : hasForwardedSlots(node.children)
? SlotFlags.FORWARDED ? SlotFlags.FORWARDED
: SlotFlags.STABLE : SlotFlags.STABLE
let slots = createObjectExpression( let slots = createObjectExpression(
slotsProperties.concat( slotsProperties.concat(
createObjectProperty( createObjectProperty(

View File

@ -6,7 +6,7 @@ exports[`stringify static html > eligible content (elements > 20) + non-eligible
return function render(_ctx, _cache) { return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [ return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
_createStaticVNode("<span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span>", 20), _createStaticVNode("<span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span>", 20),
_createElementVNode("div", { key: "1" }, "1", -1 /* HOISTED */), _createElementVNode("div", { key: "1" }, "1", -1 /* CACHED */),
_createStaticVNode("<span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span>", 20) _createStaticVNode("<span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span>", 20)
]))) ])))
}" }"
@ -32,6 +32,33 @@ return function render(_ctx, _cache) {
}" }"
`; `;
exports[`stringify static html > serializing template string style 1`] = `
"const { toDisplayString: _toDisplayString, normalizeClass: _normalizeClass, createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
_createStaticVNode("<div style=\\"color:red;\\"><span class=\\"foo bar\\">1 + false</span><span class=\\"foo bar\\">1 + false</span><span class=\\"foo bar\\">1 + false</span><span class=\\"foo bar\\">1 + false</span><span class=\\"foo bar\\">1 + false</span></div>", 1)
])))
}"
`;
exports[`stringify static html > should bail for <option> elements with null values 1`] = `
"const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
_createElementVNode("select", null, [
_createElementVNode("option", { value: null }),
_createElementVNode("option", { value: "1" }),
_createElementVNode("option", { value: "1" }),
_createElementVNode("option", { value: "1" }),
_createElementVNode("option", { value: "1" }),
_createElementVNode("option", { value: "1" })
], -1 /* CACHED */)
])))
}"
`;
exports[`stringify static html > should bail for <option> elements with number values 1`] = ` exports[`stringify static html > should bail for <option> elements with number values 1`] = `
"const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue "const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
@ -43,11 +70,27 @@ return function render(_ctx, _cache) {
_createElementVNode("option", { value: 1 }), _createElementVNode("option", { value: 1 }),
_createElementVNode("option", { value: 1 }), _createElementVNode("option", { value: 1 }),
_createElementVNode("option", { value: 1 }) _createElementVNode("option", { value: 1 })
], -1 /* HOISTED */) ], -1 /* CACHED */)
]))) ])))
}" }"
`; `;
exports[`stringify static html > should bail for comments 1`] = `
"const { createCommentVNode: _createCommentVNode, createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
const _hoisted_1 = { class: "a" }
return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock(_Fragment, null, [
_createCommentVNode(" Comment 1 "),
_createElementVNode("div", _hoisted_1, [
_createCommentVNode(" Comment 2 "),
_cache[0] || (_cache[0] = _createStaticVNode("<span class=\\"b\\"></span><span class=\\"b\\"></span><span class=\\"b\\"></span><span class=\\"b\\"></span><span class=\\"b\\"></span>", 5))
])
], 2112 /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */))
}"
`;
exports[`stringify static html > should bail on bindings that are cached but not stringifiable 1`] = ` exports[`stringify static html > should bail on bindings that are cached but not stringifiable 1`] = `
"const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue "const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
@ -60,7 +103,7 @@ return function render(_ctx, _cache) {
_createElementVNode("span", { class: "foo" }, "foo"), _createElementVNode("span", { class: "foo" }, "foo"),
_createElementVNode("span", { class: "foo" }, "foo"), _createElementVNode("span", { class: "foo" }, "foo"),
_createElementVNode("img", { src: _imports_0_ }) _createElementVNode("img", { src: _imports_0_ })
], -1 /* HOISTED */) ], -1 /* CACHED */)
]))) ])))
}" }"
`; `;

View File

@ -162,6 +162,27 @@ describe('stringify static html', () => {
expect(code).toMatchSnapshot() expect(code).toMatchSnapshot()
}) })
// #12391
test('serializing template string style', () => {
const { ast, code } = compileWithStringify(
`<div><div :style="\`color:red;\`">${repeat(
`<span :class="[{ foo: true }, { bar: true }]">{{ 1 }} + {{ false }}</span>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}</div></div>`,
)
// should be optimized now
expect(ast.cached).toMatchObject([
cachedArrayStaticNodeMatcher(
`<div style="color:red;">${repeat(
`<span class="foo bar">1 + false</span>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}</div>`,
1,
),
])
expect(code).toMatchSnapshot()
})
test('escape', () => { test('escape', () => {
const { ast, code } = compileWithStringify( const { ast, code } = compileWithStringify(
`<div><div>${repeat( `<div><div>${repeat(
@ -470,6 +491,27 @@ describe('stringify static html', () => {
expect(code).toMatchSnapshot() expect(code).toMatchSnapshot()
}) })
test('should bail for comments', () => {
const { code } = compileWithStringify(
`<!-- Comment 1 --><div class="a"><!-- Comment 2 -->${repeat(
`<span class="b"/>`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}</div>`,
)
expect(code).toMatchSnapshot()
})
test('should bail for <option> elements with null values', () => {
const { ast, code } = compileWithStringify(
`<div><select><option :value="null" />${repeat(
`<option value="1" />`,
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
)}</select></div>`,
)
expect(ast.cached).toMatchObject([cachedArrayBailedMatcher()])
expect(code).toMatchSnapshot()
})
test('eligible content (elements > 20) + non-eligible content', () => { test('eligible content (elements > 20) + non-eligible content', () => {
const { code } = compileWithStringify( const { code } = compileWithStringify(
`<div>${repeat( `<div>${repeat(

View File

@ -1,4 +1,5 @@
import { type CompilerError, compile } from '../../src' import { type CompilerError, compile } from '../../src'
import { isValidHTMLNesting } from '../../src/htmlNesting'
describe('validate html nesting', () => { describe('validate html nesting', () => {
it('should warn with p > div', () => { it('should warn with p > div', () => {
@ -17,4 +18,185 @@ describe('validate html nesting', () => {
}) })
expect(err).toBeUndefined() expect(err).toBeUndefined()
}) })
// #13318
it('should not warn when parent tag is template', () => {
let err: CompilerError | undefined
compile(`<template><tr/></template>`, {
onWarn: e => (err = e),
})
expect(err).toBeUndefined()
})
})
/**
* Copied from https://github.com/MananTank/validate-html-nesting
* with ISC license
*/
describe('isValidHTMLNesting', () => {
test('form', () => {
// invalid
expect(isValidHTMLNesting('form', 'form')).toBe(false)
// valid
expect(isValidHTMLNesting('form', 'div')).toBe(true)
expect(isValidHTMLNesting('form', 'input')).toBe(true)
expect(isValidHTMLNesting('form', 'select')).toBe(true)
expect(isValidHTMLNesting('form', 'button')).toBe(true)
expect(isValidHTMLNesting('form', 'label')).toBe(true)
expect(isValidHTMLNesting('form', 'h1')).toBe(true)
})
test('p', () => {
// invalid
expect(isValidHTMLNesting('p', 'p')).toBe(false)
expect(isValidHTMLNesting('p', 'div')).toBe(false)
expect(isValidHTMLNesting('p', 'hr')).toBe(false)
expect(isValidHTMLNesting('p', 'blockquote')).toBe(false)
expect(isValidHTMLNesting('p', 'pre')).toBe(false)
// valid
expect(isValidHTMLNesting('p', 'a')).toBe(true)
expect(isValidHTMLNesting('p', 'span')).toBe(true)
expect(isValidHTMLNesting('p', 'abbr')).toBe(true)
expect(isValidHTMLNesting('p', 'button')).toBe(true)
expect(isValidHTMLNesting('p', 'b')).toBe(true)
expect(isValidHTMLNesting('p', 'i')).toBe(true)
expect(isValidHTMLNesting('p', 'input')).toBe(true)
expect(isValidHTMLNesting('p', 'label')).toBe(true)
})
test('a', () => {
// invalid
expect(isValidHTMLNesting('a', 'a')).toBe(false)
// valid
expect(isValidHTMLNesting('a', 'div')).toBe(true)
expect(isValidHTMLNesting('a', 'span')).toBe(true)
})
test('button', () => {
// invalid
expect(isValidHTMLNesting('button', 'button')).toBe(false)
// valid
expect(isValidHTMLNesting('button', 'div')).toBe(true)
expect(isValidHTMLNesting('button', 'span')).toBe(true)
})
test('table', () => {
// invalid
expect(isValidHTMLNesting('table', 'tr')).toBe(false)
expect(isValidHTMLNesting('table', 'table')).toBe(false)
expect(isValidHTMLNesting('table', 'td')).toBe(false)
// valid
expect(isValidHTMLNesting('table', 'thead')).toBe(true)
expect(isValidHTMLNesting('table', 'tbody')).toBe(true)
expect(isValidHTMLNesting('table', 'tfoot')).toBe(true)
expect(isValidHTMLNesting('table', 'caption')).toBe(true)
expect(isValidHTMLNesting('table', 'colgroup')).toBe(true)
})
test('td', () => {
// valid
expect(isValidHTMLNesting('td', 'span')).toBe(true)
expect(isValidHTMLNesting('tr', 'td')).toBe(true)
// invalid
expect(isValidHTMLNesting('td', 'td')).toBe(false)
expect(isValidHTMLNesting('div', 'td')).toBe(false)
})
test('tbody', () => {
// invalid
expect(isValidHTMLNesting('tbody', 'td')).toBe(false)
// valid
expect(isValidHTMLNesting('tbody', 'tr')).toBe(true)
})
test('tr', () => {
// invalid
expect(isValidHTMLNesting('tr', 'tr')).toBe(false)
expect(isValidHTMLNesting('table', 'tr')).toBe(false)
// valid
expect(isValidHTMLNesting('tbody', 'tr')).toBe(true)
expect(isValidHTMLNesting('thead', 'tr')).toBe(true)
expect(isValidHTMLNesting('tfoot', 'tr')).toBe(true)
expect(isValidHTMLNesting('tr', 'td')).toBe(true)
expect(isValidHTMLNesting('tr', 'th')).toBe(true)
})
test('li', () => {
// invalid
expect(isValidHTMLNesting('li', 'li')).toBe(false)
// valid
expect(isValidHTMLNesting('li', 'div')).toBe(true)
expect(isValidHTMLNesting('li', 'ul')).toBe(true)
})
test('headings', () => {
// invalid
expect(isValidHTMLNesting('h1', 'h1')).toBe(false)
expect(isValidHTMLNesting('h2', 'h1')).toBe(false)
expect(isValidHTMLNesting('h3', 'h1')).toBe(false)
expect(isValidHTMLNesting('h1', 'h6')).toBe(false)
// valid
expect(isValidHTMLNesting('h1', 'div')).toBe(true)
})
describe('SVG', () => {
test('svg', () => {
// invalid non-svg tags as children
expect(isValidHTMLNesting('svg', 'div')).toBe(false)
expect(isValidHTMLNesting('svg', 'img')).toBe(false)
expect(isValidHTMLNesting('svg', 'p')).toBe(false)
expect(isValidHTMLNesting('svg', 'h2')).toBe(false)
expect(isValidHTMLNesting('svg', 'span')).toBe(false)
// valid non-svg tags as children
expect(isValidHTMLNesting('svg', 'a')).toBe(true)
expect(isValidHTMLNesting('svg', 'textarea')).toBe(true)
expect(isValidHTMLNesting('svg', 'input')).toBe(true)
expect(isValidHTMLNesting('svg', 'select')).toBe(true)
// valid svg tags as children
expect(isValidHTMLNesting('svg', 'g')).toBe(true)
expect(isValidHTMLNesting('svg', 'ellipse')).toBe(true)
expect(isValidHTMLNesting('svg', 'feOffset')).toBe(true)
})
test('foreignObject', () => {
// valid
expect(isValidHTMLNesting('foreignObject', 'g')).toBe(true)
expect(isValidHTMLNesting('foreignObject', 'div')).toBe(true)
expect(isValidHTMLNesting('foreignObject', 'a')).toBe(true)
expect(isValidHTMLNesting('foreignObject', 'textarea')).toBe(true)
})
test('g', () => {
// valid
expect(isValidHTMLNesting('g', 'div')).toBe(true)
expect(isValidHTMLNesting('g', 'p')).toBe(true)
expect(isValidHTMLNesting('g', 'a')).toBe(true)
expect(isValidHTMLNesting('g', 'textarea')).toBe(true)
expect(isValidHTMLNesting('g', 'g')).toBe(true)
})
test('dl', () => {
// valid
expect(isValidHTMLNesting('dl', 'dt')).toBe(true)
expect(isValidHTMLNesting('dl', 'dd')).toBe(true)
expect(isValidHTMLNesting('dl', 'div')).toBe(true)
expect(isValidHTMLNesting('div', 'dt')).toBe(true)
expect(isValidHTMLNesting('div', 'dd')).toBe(true)
// invalid
expect(isValidHTMLNesting('span', 'dt')).toBe(false)
expect(isValidHTMLNesting('span', 'dd')).toBe(false)
})
})
}) })

View File

@ -1,6 +1,6 @@
{ {
"name": "@vue/compiler-dom", "name": "@vue/compiler-dom",
"version": "3.5.9", "version": "3.5.16",
"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",

View File

@ -11,6 +11,11 @@
* returns true if given parent-child nesting is valid HTML * returns true if given parent-child nesting is valid HTML
*/ */
export function isValidHTMLNesting(parent: string, child: string): boolean { export function isValidHTMLNesting(parent: string, child: string): boolean {
// if the parent is a template, it can have any child
if (parent === 'template') {
return true
}
// if we know the list of children that are the only valid children for the given parent // if we know the list of children that are the only valid children for the given parent
if (parent in onlyValidChildren) { if (parent in onlyValidChildren) {
return onlyValidChildren[parent].has(child) return onlyValidChildren[parent].has(child)

View File

@ -261,8 +261,7 @@ function analyzeNode(node: StringifiableNode): [number, number] | false {
isOptionTag && isOptionTag &&
isStaticArgOf(p.arg, 'value') && isStaticArgOf(p.arg, 'value') &&
p.exp && p.exp &&
p.exp.ast && !p.exp.isStatic
p.exp.ast.type !== 'StringLiteral'
) { ) {
return bail() return bail()
} }

View File

@ -861,7 +861,7 @@ export default {
return (_ctx, _cache) => { return (_ctx, _cache) => {
return (_openBlock(), _createElementBlock(_Fragment, null, [ return (_openBlock(), _createElementBlock(_Fragment, null, [
_createElementVNode("div", null, _toDisplayString(count.value), 1 /* TEXT */), _createElementVNode("div", null, _toDisplayString(count.value), 1 /* TEXT */),
_cache[0] || (_cache[0] = _createElementVNode("div", null, "static", -1 /* HOISTED */)) _cache[0] || (_cache[0] = _createElementVNode("div", null, "static", -1 /* CACHED */))
], 64 /* STABLE_FRAGMENT */)) ], 64 /* STABLE_FRAGMENT */))
} }
} }

View File

@ -41,8 +41,8 @@ const _hoisted_1 = _imports_0 + '#fragment'
export function render(_ctx, _cache) { export function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock(_Fragment, null, [ return (_openBlock(), _createElementBlock(_Fragment, null, [
_cache[0] || (_cache[0] = _createElementVNode("use", { href: _hoisted_1 }, null, -1 /* HOISTED */)), _cache[0] || (_cache[0] = _createElementVNode("use", { href: _hoisted_1 }, null, -1 /* CACHED */)),
_cache[1] || (_cache[1] = _createElementVNode("use", { href: _hoisted_1 }, null, -1 /* HOISTED */)) _cache[1] || (_cache[1] = _createElementVNode("use", { href: _hoisted_1 }, null, -1 /* CACHED */))
], 64 /* STABLE_FRAGMENT */)) ], 64 /* STABLE_FRAGMENT */))
}" }"
`; `;

View File

@ -10,8 +10,8 @@ const _hoisted_2 = _imports_0 + ' 1x, ' + "/foo/logo.png" + ' 2x'
export function render(_ctx, _cache) { export function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock(_Fragment, null, [ return (_openBlock(), _createElementBlock(_Fragment, null, [
_cache[0] || (_cache[0] = _createElementVNode("img", { srcset: _hoisted_1 }, null, -1 /* HOISTED */)), _cache[0] || (_cache[0] = _createElementVNode("img", { srcset: _hoisted_1 }, null, -1 /* CACHED */)),
_cache[1] || (_cache[1] = _createElementVNode("img", { srcset: _hoisted_2 }, null, -1 /* HOISTED */)) _cache[1] || (_cache[1] = _createElementVNode("img", { srcset: _hoisted_2 }, null, -1 /* CACHED */))
], 64 /* STABLE_FRAGMENT */)) ], 64 /* STABLE_FRAGMENT */))
}" }"
`; `;
@ -35,51 +35,51 @@ export function render(_ctx, _cache) {
_cache[0] || (_cache[0] = _createElementVNode("img", { _cache[0] || (_cache[0] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: "" srcset: ""
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[1] || (_cache[1] = _createElementVNode("img", { _cache[1] || (_cache[1] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: _hoisted_1 srcset: _hoisted_1
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[2] || (_cache[2] = _createElementVNode("img", { _cache[2] || (_cache[2] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: _hoisted_2 srcset: _hoisted_2
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[3] || (_cache[3] = _createElementVNode("img", { _cache[3] || (_cache[3] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: _hoisted_3 srcset: _hoisted_3
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[4] || (_cache[4] = _createElementVNode("img", { _cache[4] || (_cache[4] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: _hoisted_4 srcset: _hoisted_4
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[5] || (_cache[5] = _createElementVNode("img", { _cache[5] || (_cache[5] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: _hoisted_5 srcset: _hoisted_5
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[6] || (_cache[6] = _createElementVNode("img", { _cache[6] || (_cache[6] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: _hoisted_6 srcset: _hoisted_6
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[7] || (_cache[7] = _createElementVNode("img", { _cache[7] || (_cache[7] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: _hoisted_7 srcset: _hoisted_7
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[8] || (_cache[8] = _createElementVNode("img", { _cache[8] || (_cache[8] = _createElementVNode("img", {
src: "/logo.png", src: "/logo.png",
srcset: "/logo.png, /logo.png 2x" srcset: "/logo.png, /logo.png 2x"
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[9] || (_cache[9] = _createElementVNode("img", { _cache[9] || (_cache[9] = _createElementVNode("img", {
src: "https://example.com/logo.png", src: "https://example.com/logo.png",
srcset: "https://example.com/logo.png, https://example.com/logo.png 2x" srcset: "https://example.com/logo.png, https://example.com/logo.png 2x"
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[10] || (_cache[10] = _createElementVNode("img", { _cache[10] || (_cache[10] = _createElementVNode("img", {
src: "/logo.png", src: "/logo.png",
srcset: _hoisted_8 srcset: _hoisted_8
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[11] || (_cache[11] = _createElementVNode("img", { _cache[11] || (_cache[11] = _createElementVNode("img", {
src: "data:image/png;base64,i", src: "data:image/png;base64,i",
srcset: "data:image/png;base64,i 1x, data:image/png;base64,i 2x" srcset: "data:image/png;base64,i 1x, data:image/png;base64,i 2x"
}, null, -1 /* HOISTED */)) }, null, -1 /* CACHED */))
], 64 /* STABLE_FRAGMENT */)) ], 64 /* STABLE_FRAGMENT */))
}" }"
`; `;
@ -92,51 +92,51 @@ export function render(_ctx, _cache) {
_cache[0] || (_cache[0] = _createElementVNode("img", { _cache[0] || (_cache[0] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: "" srcset: ""
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[1] || (_cache[1] = _createElementVNode("img", { _cache[1] || (_cache[1] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: "/foo/logo.png" srcset: "/foo/logo.png"
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[2] || (_cache[2] = _createElementVNode("img", { _cache[2] || (_cache[2] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: "/foo/logo.png 2x" srcset: "/foo/logo.png 2x"
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[3] || (_cache[3] = _createElementVNode("img", { _cache[3] || (_cache[3] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: "/foo/logo.png 2x" srcset: "/foo/logo.png 2x"
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[4] || (_cache[4] = _createElementVNode("img", { _cache[4] || (_cache[4] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: "/foo/logo.png, /foo/logo.png 2x" srcset: "/foo/logo.png, /foo/logo.png 2x"
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[5] || (_cache[5] = _createElementVNode("img", { _cache[5] || (_cache[5] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: "/foo/logo.png 2x, /foo/logo.png" srcset: "/foo/logo.png 2x, /foo/logo.png"
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[6] || (_cache[6] = _createElementVNode("img", { _cache[6] || (_cache[6] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: "/foo/logo.png 2x, /foo/logo.png 3x" srcset: "/foo/logo.png 2x, /foo/logo.png 3x"
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[7] || (_cache[7] = _createElementVNode("img", { _cache[7] || (_cache[7] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: "/foo/logo.png, /foo/logo.png 2x, /foo/logo.png 3x" srcset: "/foo/logo.png, /foo/logo.png 2x, /foo/logo.png 3x"
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[8] || (_cache[8] = _createElementVNode("img", { _cache[8] || (_cache[8] = _createElementVNode("img", {
src: "/logo.png", src: "/logo.png",
srcset: "/logo.png, /logo.png 2x" srcset: "/logo.png, /logo.png 2x"
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[9] || (_cache[9] = _createElementVNode("img", { _cache[9] || (_cache[9] = _createElementVNode("img", {
src: "https://example.com/logo.png", src: "https://example.com/logo.png",
srcset: "https://example.com/logo.png, https://example.com/logo.png 2x" srcset: "https://example.com/logo.png, https://example.com/logo.png 2x"
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[10] || (_cache[10] = _createElementVNode("img", { _cache[10] || (_cache[10] = _createElementVNode("img", {
src: "/logo.png", src: "/logo.png",
srcset: "/logo.png, /foo/logo.png 2x" srcset: "/logo.png, /foo/logo.png 2x"
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[11] || (_cache[11] = _createElementVNode("img", { _cache[11] || (_cache[11] = _createElementVNode("img", {
src: "data:image/png;base64,i", src: "data:image/png;base64,i",
srcset: "data:image/png;base64,i 1x, data:image/png;base64,i 2x" srcset: "data:image/png;base64,i 1x, data:image/png;base64,i 2x"
}, null, -1 /* HOISTED */)) }, null, -1 /* CACHED */))
], 64 /* STABLE_FRAGMENT */)) ], 64 /* STABLE_FRAGMENT */))
}" }"
`; `;
@ -162,51 +162,51 @@ export function render(_ctx, _cache) {
_cache[0] || (_cache[0] = _createElementVNode("img", { _cache[0] || (_cache[0] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: "" srcset: ""
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[1] || (_cache[1] = _createElementVNode("img", { _cache[1] || (_cache[1] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: _hoisted_1 srcset: _hoisted_1
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[2] || (_cache[2] = _createElementVNode("img", { _cache[2] || (_cache[2] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: _hoisted_2 srcset: _hoisted_2
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[3] || (_cache[3] = _createElementVNode("img", { _cache[3] || (_cache[3] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: _hoisted_3 srcset: _hoisted_3
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[4] || (_cache[4] = _createElementVNode("img", { _cache[4] || (_cache[4] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: _hoisted_4 srcset: _hoisted_4
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[5] || (_cache[5] = _createElementVNode("img", { _cache[5] || (_cache[5] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: _hoisted_5 srcset: _hoisted_5
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[6] || (_cache[6] = _createElementVNode("img", { _cache[6] || (_cache[6] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: _hoisted_6 srcset: _hoisted_6
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[7] || (_cache[7] = _createElementVNode("img", { _cache[7] || (_cache[7] = _createElementVNode("img", {
src: "./logo.png", src: "./logo.png",
srcset: _hoisted_7 srcset: _hoisted_7
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[8] || (_cache[8] = _createElementVNode("img", { _cache[8] || (_cache[8] = _createElementVNode("img", {
src: "/logo.png", src: "/logo.png",
srcset: _hoisted_8 srcset: _hoisted_8
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[9] || (_cache[9] = _createElementVNode("img", { _cache[9] || (_cache[9] = _createElementVNode("img", {
src: "https://example.com/logo.png", src: "https://example.com/logo.png",
srcset: "https://example.com/logo.png, https://example.com/logo.png 2x" srcset: "https://example.com/logo.png, https://example.com/logo.png 2x"
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[10] || (_cache[10] = _createElementVNode("img", { _cache[10] || (_cache[10] = _createElementVNode("img", {
src: "/logo.png", src: "/logo.png",
srcset: _hoisted_9 srcset: _hoisted_9
}, null, -1 /* HOISTED */)), }, null, -1 /* CACHED */)),
_cache[11] || (_cache[11] = _createElementVNode("img", { _cache[11] || (_cache[11] = _createElementVNode("img", {
src: "data:image/png;base64,i", src: "data:image/png;base64,i",
srcset: "data:image/png;base64,i 1x, data:image/png;base64,i 2x" srcset: "data:image/png;base64,i 1x, data:image/png;base64,i 2x"
}, null, -1 /* HOISTED */)) }, null, -1 /* CACHED */))
], 64 /* STABLE_FRAGMENT */)) ], 64 /* STABLE_FRAGMENT */))
}" }"
`; `;

View File

@ -1,5 +1,11 @@
import { BindingTypes } from '@vue/compiler-core' import { BindingTypes } from '@vue/compiler-core'
import { assertCode, compileSFCScript as compile, mockId } from './utils' import {
assertCode,
compileSFCScript as compile,
getPositionInCode,
mockId,
} from './utils'
import { type RawSourceMap, SourceMapConsumer } from 'source-map-js'
describe('SFC compile <script setup>', () => { describe('SFC compile <script setup>', () => {
test('should compile JS syntax', () => { test('should compile JS syntax', () => {
@ -690,6 +696,27 @@ describe('SFC compile <script setup>', () => {
expect(content).toMatch(`new (_unref(Foo)).Bar()`) expect(content).toMatch(`new (_unref(Foo)).Bar()`)
assertCode(content) assertCode(content)
}) })
// #12682
test('source map', () => {
const source = `
<script setup>
const count = ref(0)
</script>
<template>
<button @click="throw new Error(\`msg\`);"></button>
</template>
`
const { content, map } = compile(source, { inlineTemplate: true })
expect(map).not.toBeUndefined()
const consumer = new SourceMapConsumer(map as RawSourceMap)
expect(
consumer.originalPositionFor(getPositionInCode(content, 'count')),
).toMatchObject(getPositionInCode(source, `count`))
expect(
consumer.originalPositionFor(getPositionInCode(content, 'Error')),
).toMatchObject(getPositionInCode(source, `Error`))
})
}) })
describe('with TypeScript', () => { describe('with TypeScript', () => {

View File

@ -148,6 +148,27 @@ export default /*@__PURE__*/_defineComponent({
return { }
}
})"
`;
exports[`defineProps > w/ TSTypeAliasDeclaration 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
type FunFoo<O> = (item: O) => boolean;
type FunBar = FunFoo<number>;
export default /*@__PURE__*/_defineComponent({
props: {
foo: { type: Function, required: false, default: () => true },
bar: { type: Function, required: false, default: () => true }
},
setup(__props: any, { expose: __expose }) {
__expose();
return { } return { }
} }
@ -233,6 +254,33 @@ export default /*@__PURE__*/_defineComponent({
return { }
}
})"
`;
exports[`defineProps > w/ extends intersection type 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
type Foo = {
x?: number;
};
interface Props extends Foo {
z: number
y: string
}
export default /*@__PURE__*/_defineComponent({
props: {
z: { type: Number, required: true },
y: { type: String, required: true },
x: { type: Number, required: false }
},
setup(__props: any, { expose: __expose }) {
__expose();
return { } return { }
} }
@ -268,6 +316,31 @@ export default /*@__PURE__*/_defineComponent({
return { }
}
})"
`;
exports[`defineProps > w/ intersection type 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
type Foo = {
x?: number;
};
type Bar = {
y: string;
};
export default /*@__PURE__*/_defineComponent({
props: {
x: { type: Number, required: false },
y: { type: String, required: true }
},
setup(__props: any, { expose: __expose }) {
__expose();
return { } return { }
} }

View File

@ -192,6 +192,25 @@ return () => {}
}" }"
`; `;
exports[`sfc reactive props destructure > handle function parameters with same name as destructured props 1`] = `
"
export default {
setup(__props) {
function test(value) {
try {
} catch {
}
}
console.log(__props.value)
return () => {}
}
}"
`;
exports[`sfc reactive props destructure > multi-variable declaration 1`] = ` exports[`sfc reactive props destructure > multi-variable declaration 1`] = `
" "
export default { export default {
@ -320,3 +339,22 @@ return { rest }
}" }"
`; `;
exports[`sfc reactive props destructure > with TSInstantiationExpression 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
type Foo = <T extends string | number>(data: T) => void
export default /*@__PURE__*/_defineComponent({
props: {
value: { type: Function }
},
setup(__props: any) {
const foo = __props.value<123>
return () => {}
}
})"
`;

View File

@ -261,6 +261,51 @@ const props = defineProps({ foo: String })
}) })
}) })
test('w/ extends intersection type', () => {
const { content, bindings } = compile(`
<script setup lang="ts">
type Foo = {
x?: number;
};
interface Props extends Foo {
z: number
y: string
}
defineProps<Props>()
</script>
`)
assertCode(content)
expect(content).toMatch(`z: { type: Number, required: true }`)
expect(content).toMatch(`y: { type: String, required: true }`)
expect(content).toMatch(`x: { type: Number, required: false }`)
expect(bindings).toStrictEqual({
x: BindingTypes.PROPS,
y: BindingTypes.PROPS,
z: BindingTypes.PROPS,
})
})
test('w/ intersection type', () => {
const { content, bindings } = compile(`
<script setup lang="ts">
type Foo = {
x?: number;
};
type Bar = {
y: string;
};
defineProps<Foo & Bar>()
</script>
`)
assertCode(content)
expect(content).toMatch(`y: { type: String, required: true }`)
expect(content).toMatch(`x: { type: Number, required: false }`)
expect(bindings).toStrictEqual({
x: BindingTypes.PROPS,
y: BindingTypes.PROPS,
})
})
test('w/ exported interface', () => { test('w/ exported interface', () => {
const { content, bindings } = compile(` const { content, bindings } = compile(`
<script setup lang="ts"> <script setup lang="ts">
@ -763,4 +808,30 @@ const props = defineProps({ foo: String })
expect(content).toMatch(`foo: { default: 5.5, type: Number }`) expect(content).toMatch(`foo: { default: 5.5, type: Number }`)
assertCode(content) assertCode(content)
}) })
test('w/ TSTypeAliasDeclaration', () => {
const { content } = compile(`
<script setup lang="ts">
type FunFoo<O> = (item: O) => boolean;
type FunBar = FunFoo<number>;
withDefaults(
defineProps<{
foo?: FunFoo<number>;
bar?: FunBar;
}>(),
{
foo: () => true,
bar: () => true,
},
);
</script>
`)
assertCode(content)
expect(content).toMatch(
`foo: { type: Function, required: false, default: () => true }`,
)
expect(content).toMatch(
`bar: { type: Function, required: false, default: () => true }`,
)
})
}) })

View File

@ -198,6 +198,21 @@ describe('sfc reactive props destructure', () => {
}`) }`)
}) })
test('with TSInstantiationExpression', () => {
const { content } = compile(
`
<script setup lang="ts">
type Foo = <T extends string | number>(data: T) => void
const { value } = defineProps<{ value: Foo }>()
const foo = value<123>
</script>
`,
{ isProd: true },
)
assertCode(content)
expect(content).toMatch(`const foo = __props.value<123>`)
})
test('aliasing', () => { test('aliasing', () => {
const { content, bindings } = compile(` const { content, bindings } = compile(`
<script setup> <script setup>
@ -343,6 +358,22 @@ describe('sfc reactive props destructure', () => {
expect(content).toMatch(`props: ['item'],`) expect(content).toMatch(`props: ['item'],`)
}) })
test('handle function parameters with same name as destructured props', () => {
const { content } = compile(`
<script setup>
const { value } = defineProps()
function test(value) {
try {
} catch {
}
}
console.log(value)
</script>
`)
assertCode(content)
expect(content).toMatch(`console.log(__props.value)`)
})
test('defineProps/defineEmits in multi-variable declaration (full removal)', () => { test('defineProps/defineEmits in multi-variable declaration (full removal)', () => {
const { content } = compile(` const { content } = compile(`
<script setup> <script setup>

View File

@ -278,6 +278,23 @@ describe('resolveType', () => {
}) })
}) })
test('utility type: mapped type with Omit and Pick', () => {
expect(
resolve(`
type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
interface Test {
foo: string;
bar?: string;
}
type OptionalTest = Optional<Test, 'foo'>
defineProps<OptionalTest>()
`).props,
).toStrictEqual({
foo: ['String'],
bar: ['String'],
})
})
test('utility type: ReadonlyArray', () => { test('utility type: ReadonlyArray', () => {
expect( expect(
resolve(` resolve(`
@ -1434,6 +1451,29 @@ describe('resolveType', () => {
colsLg: ['Number'], colsLg: ['Number'],
}) })
}) })
test('allowArbitraryExtensions', () => {
const files = {
'/foo.d.vue.ts': 'export type Foo = number;',
'/foo.vue': '<template><div /></template>',
'/bar.d.css.ts': 'export type Bar = string;',
'/bar.css': ':root { --color: red; }',
}
const { props } = resolve(
`
import { Foo } from './foo.vue'
import { Bar } from './bar.css'
defineProps<{ foo: Foo; bar: Bar }>()
`,
files,
)
expect(props).toStrictEqual({
foo: ['Number'],
bar: ['String'],
})
})
}) })
}) })

View File

@ -39,6 +39,24 @@ describe('SFC scoped CSS', () => {
expect(compileScoped(`h1 .foo { color: red; }`)).toMatch( expect(compileScoped(`h1 .foo { color: red; }`)).toMatch(
`h1 .foo[data-v-test] { color: red;`, `h1 .foo[data-v-test] { color: red;`,
) )
// #13387
expect(
compileScoped(`main {
width: 100%;
> * {
max-width: 200px;
}
}`),
).toMatchInlineSnapshot(`
"main {
&[data-v-test] {
width: 100%;
}
> *[data-v-test] {
max-width: 200px;
}
}"`)
}) })
test('nesting selector', () => { test('nesting selector', () => {
@ -214,7 +232,8 @@ color: red
".div[data-v-test] { color: red; ".div[data-v-test] { color: red;
} }
.div[data-v-test]:where(:hover) { color: blue; .div[data-v-test]:where(:hover) { color: blue;
}"`) }"
`)
expect( expect(
compileScoped(`.div { color: red; } .div:is(:hover) { color: blue; }`), compileScoped(`.div { color: red; } .div:is(:hover) { color: blue; }`),
@ -222,7 +241,8 @@ color: red
".div[data-v-test] { color: red; ".div[data-v-test] { color: red;
} }
.div[data-v-test]:is(:hover) { color: blue; .div[data-v-test]:is(:hover) { color: blue;
}"`) }"
`)
expect( expect(
compileScoped( compileScoped(
@ -232,7 +252,8 @@ color: red
".div[data-v-test] { color: red; ".div[data-v-test] { color: red;
} }
.div[data-v-test]:where(.foo:hover) { color: blue; .div[data-v-test]:where(.foo:hover) { color: blue;
}"`) }"
`)
expect( expect(
compileScoped( compileScoped(
@ -242,7 +263,8 @@ color: red
".div[data-v-test] { color: red; ".div[data-v-test] { color: red;
} }
.div[data-v-test]:is(.foo:hover) { color: blue; .div[data-v-test]:is(.foo:hover) { color: blue;
}"`) }"
`)
}) })
test('media query', () => { test('media query', () => {

View File

@ -6,6 +6,7 @@ import {
} from '../src/compileTemplate' } from '../src/compileTemplate'
import { type SFCTemplateBlock, parse } from '../src/parse' import { type SFCTemplateBlock, parse } from '../src/parse'
import { compileScript } from '../src' import { compileScript } from '../src'
import { getPositionInCode } from './utils'
function compile(opts: Omit<SFCTemplateCompileOptions, 'id'>) { function compile(opts: Omit<SFCTemplateCompileOptions, 'id'>) {
return compileTemplate({ return compileTemplate({
@ -157,6 +158,35 @@ test('source map', () => {
).toMatchObject(getPositionInCode(template.content, `foobar`)) ).toMatchObject(getPositionInCode(template.content, `foobar`))
}) })
test('source map: v-if generated comment should not have original position', () => {
const template = parse(
`
<template>
<div v-if="true"></div>
</template>
`,
{ filename: 'example.vue', sourceMap: true },
).descriptor.template!
const { code, map } = compile({
filename: 'example.vue',
source: template.content,
})
expect(map!.sources).toEqual([`example.vue`])
expect(map!.sourcesContent).toEqual([template.content])
const consumer = new SourceMapConsumer(map as RawSourceMap)
const commentNode = code.match(/_createCommentVNode\("v-if", true\)/)
expect(commentNode).not.toBeNull()
const commentPosition = getPositionInCode(code, commentNode![0])
const originalPosition = consumer.originalPositionFor(commentPosition)
// the comment node should not be mapped to the original source
expect(originalPosition.column).toBeNull()
expect(originalPosition.line).toBeNull()
expect(originalPosition.source).toBeNull()
})
test('should work w/ AST from descriptor', () => { test('should work w/ AST from descriptor', () => {
const source = ` const source = `
<template> <template>
@ -482,36 +512,3 @@ test('non-identifier expression in legacy filter syntax', () => {
babelParse(compilationResult.code, { sourceType: 'module' }) babelParse(compilationResult.code, { sourceType: 'module' })
}).not.toThrow() }).not.toThrow()
}) })
interface Pos {
line: number
column: number
name?: string
}
function getPositionInCode(
code: string,
token: string,
expectName: string | boolean = false,
): Pos {
const generatedOffset = code.indexOf(token)
let line = 1
let lastNewLinePos = -1
for (let i = 0; i < generatedOffset; i++) {
if (code.charCodeAt(i) === 10 /* newline char code */) {
line++
lastNewLinePos = i
}
}
const res: Pos = {
line,
column:
lastNewLinePos === -1
? generatedOffset
: generatedOffset - lastNewLinePos - 1,
}
if (expectName) {
res.name = typeof expectName === 'string' ? expectName : token
}
return res
}

View File

@ -81,7 +81,7 @@ font-weight: bold;
const consumer = new SourceMapConsumer(script!.map!) const consumer = new SourceMapConsumer(script!.map!)
consumer.eachMapping(mapping => { consumer.eachMapping(mapping => {
expect(mapping.originalLine - mapping.generatedLine).toBe(padding) expect(mapping.originalLine! - mapping.generatedLine).toBe(padding)
}) })
}) })
@ -100,8 +100,8 @@ font-weight: bold;
const consumer = new SourceMapConsumer(template.map!) const consumer = new SourceMapConsumer(template.map!)
consumer.eachMapping(mapping => { consumer.eachMapping(mapping => {
expect(mapping.originalLine - mapping.generatedLine).toBe(padding) expect(mapping.originalLine! - mapping.generatedLine).toBe(padding)
expect(mapping.originalColumn - mapping.generatedColumn).toBe(2) expect(mapping.originalColumn! - mapping.generatedColumn).toBe(2)
}) })
}) })
@ -115,7 +115,7 @@ font-weight: bold;
const consumer = new SourceMapConsumer(custom!.map!) const consumer = new SourceMapConsumer(custom!.map!)
consumer.eachMapping(mapping => { consumer.eachMapping(mapping => {
expect(mapping.originalLine - mapping.generatedLine).toBe(padding) expect(mapping.originalLine! - mapping.generatedLine).toBe(padding)
}) })
}) })
}) })

View File

@ -40,3 +40,36 @@ export function assertCode(code: string): void {
} }
expect(code).toMatchSnapshot() expect(code).toMatchSnapshot()
} }
interface Pos {
line: number
column: number
name?: string
}
export function getPositionInCode(
code: string,
token: string,
expectName: string | boolean = false,
): Pos {
const generatedOffset = code.indexOf(token)
let line = 1
let lastNewLinePos = -1
for (let i = 0; i < generatedOffset; i++) {
if (code.charCodeAt(i) === 10 /* newline char code */) {
line++
lastNewLinePos = i
}
}
const res: Pos = {
line,
column:
lastNewLinePos === -1
? generatedOffset
: generatedOffset - lastNewLinePos - 1,
}
if (expectName) {
res.name = typeof expectName === 'string' ? expectName : token
}
return res
}

View File

@ -1,6 +1,6 @@
{ {
"name": "@vue/compiler-sfc", "name": "@vue/compiler-sfc",
"version": "3.5.9", "version": "3.5.16",
"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",
@ -49,7 +49,7 @@
"@vue/shared": "workspace:*", "@vue/shared": "workspace:*",
"estree-walker": "catalog:", "estree-walker": "catalog:",
"magic-string": "catalog:", "magic-string": "catalog:",
"postcss": "^8.4.47", "postcss": "^8.5.3",
"source-map-js": "catalog:" "source-map-js": "catalog:"
}, },
"devDependencies": { "devDependencies": {
@ -58,10 +58,10 @@
"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.5", "minimatch": "~10.0.1",
"postcss-modules": "^6.0.0", "postcss-modules": "^6.0.1",
"postcss-selector-parser": "^6.1.2", "postcss-selector-parser": "^7.1.0",
"pug": "^3.0.3", "pug": "^3.0.3",
"sass": "^1.78.0" "sass": "^1.89.1"
} }
} }

View File

@ -23,7 +23,11 @@ import type {
Statement, Statement,
} from '@babel/types' } from '@babel/types'
import { walk } from 'estree-walker' import { walk } from 'estree-walker'
import type { RawSourceMap } from 'source-map-js' import {
type RawSourceMap,
SourceMapConsumer,
SourceMapGenerator,
} from 'source-map-js'
import { import {
normalScriptDefaultVar, normalScriptDefaultVar,
processNormalScript, processNormalScript,
@ -170,8 +174,6 @@ export function compileScript(
const scriptLang = script && script.lang const scriptLang = script && script.lang
const scriptSetupLang = scriptSetup && scriptSetup.lang const scriptSetupLang = scriptSetup && scriptSetup.lang
let refBindings: string[] | undefined
if (!scriptSetup) { if (!scriptSetup) {
if (!script) { if (!script) {
throw new Error(`[@vue/compiler-sfc] SFC contains no <script> tags.`) throw new Error(`[@vue/compiler-sfc] SFC contains no <script> tags.`)
@ -740,12 +742,6 @@ export function compileScript(
for (const key in setupBindings) { for (const key in setupBindings) {
ctx.bindingMetadata[key] = setupBindings[key] ctx.bindingMetadata[key] = setupBindings[key]
} }
// known ref bindings
if (refBindings) {
for (const key of refBindings) {
ctx.bindingMetadata[key] = BindingTypes.SETUP_REF
}
}
// 7. inject `useCssVars` calls // 7. inject `useCssVars` calls
if ( if (
@ -817,6 +813,7 @@ export function compileScript(
args += `, { ${destructureElements.join(', ')} }` args += `, { ${destructureElements.join(', ')} }`
} }
let templateMap
// 9. generate return statement // 9. generate return statement
let returned let returned
if ( if (
@ -866,7 +863,7 @@ export function compileScript(
} }
// inline render function mode - we are going to compile the template and // inline render function mode - we are going to compile the template and
// inline it right here // inline it right here
const { code, ast, preamble, tips, errors } = compileTemplate({ const { code, ast, preamble, tips, errors, map } = compileTemplate({
filename, filename,
ast: sfc.template.ast, ast: sfc.template.ast,
source: sfc.template.content, source: sfc.template.content,
@ -884,6 +881,7 @@ export function compileScript(
bindingMetadata: ctx.bindingMetadata, bindingMetadata: ctx.bindingMetadata,
}, },
}) })
templateMap = map
if (tips.length) { if (tips.length) {
tips.forEach(warnOnce) tips.forEach(warnOnce)
} }
@ -1022,19 +1020,28 @@ export function compileScript(
) )
} }
return { const content = ctx.s.toString()
...scriptSetup, let map =
bindings: ctx.bindingMetadata,
imports: ctx.userImports,
content: ctx.s.toString(),
map:
options.sourceMap !== false options.sourceMap !== false
? (ctx.s.generateMap({ ? (ctx.s.generateMap({
source: filename, source: filename,
hires: true, hires: true,
includeContent: true, includeContent: true,
}) as unknown as RawSourceMap) }) as unknown as RawSourceMap)
: undefined, : undefined
// merge source maps of the script setup and template in inline mode
if (templateMap && map) {
const offset = content.indexOf(returned)
const templateLineOffset =
content.slice(0, offset).split(/\r?\n/).length - 1
map = mergeSourceMaps(map, templateMap, templateLineOffset)
}
return {
...scriptSetup,
bindings: ctx.bindingMetadata,
imports: ctx.userImports,
content,
map,
scriptAst: scriptAst?.body, scriptAst: scriptAst?.body,
scriptSetupAst: scriptSetupAst?.body, scriptSetupAst: scriptSetupAst?.body,
deps: ctx.deps ? [...ctx.deps] : undefined, deps: ctx.deps ? [...ctx.deps] : undefined,
@ -1112,6 +1119,7 @@ function walkDeclaration(
m === userImportAliases['shallowRef'] || m === userImportAliases['shallowRef'] ||
m === userImportAliases['customRef'] || m === userImportAliases['customRef'] ||
m === userImportAliases['toRef'] || m === userImportAliases['toRef'] ||
m === userImportAliases['useTemplateRef'] ||
m === DEFINE_MODEL, m === DEFINE_MODEL,
) )
) { ) {
@ -1291,3 +1299,42 @@ function isStaticNode(node: Node): boolean {
} }
return false return false
} }
export function mergeSourceMaps(
scriptMap: RawSourceMap,
templateMap: RawSourceMap,
templateLineOffset: number,
): RawSourceMap {
const generator = new SourceMapGenerator()
const addMapping = (map: RawSourceMap, lineOffset = 0) => {
const consumer = new SourceMapConsumer(map)
;(consumer as any).sources.forEach((sourceFile: string) => {
;(generator as any)._sources.add(sourceFile)
const sourceContent = consumer.sourceContentFor(sourceFile)
if (sourceContent != null) {
generator.setSourceContent(sourceFile, sourceContent)
}
})
consumer.eachMapping(m => {
if (m.originalLine == null) return
generator.addMapping({
generated: {
line: m.generatedLine + lineOffset,
column: m.generatedColumn,
},
original: {
line: m.originalLine,
column: m.originalColumn!,
},
source: m.source,
name: m.name,
})
})
}
addMapping(scriptMap)
addMapping(templateMap, templateLineOffset)
;(generator as any)._sourceRoot = scriptMap.sourceRoot
;(generator as any)._file = scriptMap.file
return (generator as any).toJSON()
}

View File

@ -289,7 +289,7 @@ function mapLines(oldMap: RawSourceMap, newMap: RawSourceMap): RawSourceMap {
const origPosInOldMap = oldMapConsumer.originalPositionFor({ const origPosInOldMap = oldMapConsumer.originalPositionFor({
line: m.originalLine, line: m.originalLine,
column: m.originalColumn, column: m.originalColumn!,
}) })
if (origPosInOldMap.source == null) { if (origPosInOldMap.source == null) {
@ -305,7 +305,7 @@ function mapLines(oldMap: RawSourceMap, newMap: RawSourceMap): RawSourceMap {
line: origPosInOldMap.line, // map line line: origPosInOldMap.line, // map line
// use current column, since the oldMap produced by @vue/compiler-sfc // use current column, since the oldMap produced by @vue/compiler-sfc
// does not // does not
column: m.originalColumn, column: m.originalColumn!,
}, },
source: origPosInOldMap.source, source: origPosInOldMap.source,
name: origPosInOldMap.name, name: origPosInOldMap.name,

View File

@ -39,7 +39,7 @@ export function rewriteDefaultAST(
ast.forEach(node => { ast.forEach(node => {
if (node.type === 'ExportDefaultDeclaration') { if (node.type === 'ExportDefaultDeclaration') {
if (node.declaration.type === 'ClassDeclaration' && node.declaration.id) { if (node.declaration.type === 'ClassDeclaration' && node.declaration.id) {
let start: number = const start: number =
node.declaration.decorators && node.declaration.decorators.length > 0 node.declaration.decorators && node.declaration.decorators.length > 0
? node.declaration.decorators[ ? node.declaration.decorators[
node.declaration.decorators.length - 1 node.declaration.decorators.length - 1

View File

@ -10,6 +10,7 @@ import type {
import { walk } from 'estree-walker' import { walk } from 'estree-walker'
import { import {
BindingTypes, BindingTypes,
TS_NODE_TYPES,
extractIdentifiers, extractIdentifiers,
isFunctionType, isFunctionType,
isInDestructureAssignment, isInDestructureAssignment,
@ -240,9 +241,7 @@ export function transformDestructuredProps(
if ( if (
parent && parent &&
parent.type.startsWith('TS') && parent.type.startsWith('TS') &&
parent.type !== 'TSAsExpression' && !TS_NODE_TYPES.includes(parent.type)
parent.type !== 'TSNonNullExpression' &&
parent.type !== 'TSTypeAssertion'
) { ) {
return this.skip() return this.skip()
} }
@ -292,7 +291,8 @@ export function transformDestructuredProps(
parent && parentStack.pop() parent && parentStack.pop()
if ( if (
(node.type === 'BlockStatement' && !isFunctionType(parent!)) || (node.type === 'BlockStatement' && !isFunctionType(parent!)) ||
isFunctionType(node) isFunctionType(node) ||
node.type === 'CatchClause'
) { ) {
popScope() popScope()
} }

View File

@ -546,26 +546,43 @@ function resolveStringType(
ctx: TypeResolveContext, ctx: TypeResolveContext,
node: Node, node: Node,
scope: TypeScope, scope: TypeScope,
typeParameters?: Record<string, Node>,
): string[] { ): string[] {
switch (node.type) { switch (node.type) {
case 'StringLiteral': case 'StringLiteral':
return [node.value] return [node.value]
case 'TSLiteralType': case 'TSLiteralType':
return resolveStringType(ctx, node.literal, scope) return resolveStringType(ctx, node.literal, scope, typeParameters)
case 'TSUnionType': case 'TSUnionType':
return node.types.map(t => resolveStringType(ctx, t, scope)).flat() return node.types
.map(t => resolveStringType(ctx, t, scope, typeParameters))
.flat()
case 'TemplateLiteral': { case 'TemplateLiteral': {
return resolveTemplateKeys(ctx, node, scope) return resolveTemplateKeys(ctx, node, scope)
} }
case 'TSTypeReference': { case 'TSTypeReference': {
const resolved = resolveTypeReference(ctx, node, scope) const resolved = resolveTypeReference(ctx, node, scope)
if (resolved) { if (resolved) {
return resolveStringType(ctx, resolved, scope) return resolveStringType(ctx, resolved, scope, typeParameters)
} }
if (node.typeName.type === 'Identifier') { if (node.typeName.type === 'Identifier') {
const name = node.typeName.name
if (typeParameters && typeParameters[name]) {
return resolveStringType(
ctx,
typeParameters[name],
scope,
typeParameters,
)
}
const getParam = (index = 0) => const getParam = (index = 0) =>
resolveStringType(ctx, node.typeParameters!.params[index], scope) resolveStringType(
switch (node.typeName.name) { ctx,
node.typeParameters!.params[index],
scope,
typeParameters,
)
switch (name) {
case 'Extract': case 'Extract':
return getParam(1) return getParam(1)
case 'Exclude': { case 'Exclude': {
@ -671,6 +688,7 @@ function resolveBuiltin(
ctx, ctx,
node.typeParameters!.params[1], node.typeParameters!.params[1],
scope, scope,
typeParameters,
) )
const res: ResolvedElements = { props: {}, calls: t.calls } const res: ResolvedElements = { props: {}, calls: t.calls }
for (const key of picked) { for (const key of picked) {
@ -683,6 +701,7 @@ function resolveBuiltin(
ctx, ctx,
node.typeParameters!.params[1], node.typeParameters!.params[1],
scope, scope,
typeParameters,
) )
const res: ResolvedElements = { props: {}, calls: t.calls } const res: ResolvedElements = { props: {}, calls: t.calls }
for (const key in t.props) { for (const key in t.props) {
@ -860,13 +879,13 @@ function resolveFS(ctx: TypeResolveContext): FS | undefined {
} }
return (ctx.fs = { return (ctx.fs = {
fileExists(file) { fileExists(file) {
if (file.endsWith('.vue.ts')) { if (file.endsWith('.vue.ts') && !file.endsWith('.d.vue.ts')) {
file = file.replace(/\.ts$/, '') file = file.replace(/\.ts$/, '')
} }
return fs.fileExists(file) return fs.fileExists(file)
}, },
readFile(file) { readFile(file) {
if (file.endsWith('.vue.ts')) { if (file.endsWith('.vue.ts') && !file.endsWith('.d.vue.ts')) {
file = file.replace(/\.ts$/, '') file = file.replace(/\.ts$/, '')
} }
return fs.readFile(file) return fs.readFile(file)
@ -1059,7 +1078,7 @@ function resolveWithTS(
if (res.resolvedModule) { if (res.resolvedModule) {
let filename = res.resolvedModule.resolvedFileName let filename = res.resolvedModule.resolvedFileName
if (filename.endsWith('.vue.ts')) { if (filename.endsWith('.vue.ts') && !filename.endsWith('.d.vue.ts')) {
filename = filename.replace(/\.ts$/, '') filename = filename.replace(/\.ts$/, '')
} }
return fs.realpath ? fs.realpath(filename) : filename return fs.realpath ? fs.realpath(filename) : filename
@ -1129,7 +1148,7 @@ export function fileToScope(
// fs should be guaranteed to exist here // fs should be guaranteed to exist here
const fs = resolveFS(ctx)! const fs = resolveFS(ctx)!
const source = fs.readFile(filename) || '' const source = fs.readFile(filename) || ''
const body = parseFile(filename, source, ctx.options.babelParserPlugins) const body = parseFile(filename, source, fs, ctx.options.babelParserPlugins)
const scope = new TypeScope(filename, source, 0, recordImports(body)) const scope = new TypeScope(filename, source, 0, recordImports(body))
recordTypes(ctx, body, scope, asGlobal) recordTypes(ctx, body, scope, asGlobal)
fileToScopeCache.set(filename, scope) fileToScopeCache.set(filename, scope)
@ -1139,6 +1158,7 @@ export function fileToScope(
function parseFile( function parseFile(
filename: string, filename: string,
content: string, content: string,
fs: FS,
parserPlugins?: SFCScriptCompileOptions['babelParserPlugins'], parserPlugins?: SFCScriptCompileOptions['babelParserPlugins'],
): Statement[] { ): Statement[] {
const ext = extname(filename) const ext = extname(filename)
@ -1151,7 +1171,21 @@ function parseFile(
), ),
sourceType: 'module', sourceType: 'module',
}).program.body }).program.body
} else if (ext === '.vue') { }
// simulate `allowArbitraryExtensions` on TypeScript >= 5.0
const isUnknownTypeSource = !/\.[cm]?[tj]sx?$/.test(filename)
const arbitraryTypeSource = `${filename.slice(0, -ext.length)}.d${ext}.ts`
const hasArbitraryTypeDeclaration =
isUnknownTypeSource && fs.fileExists(arbitraryTypeSource)
if (hasArbitraryTypeDeclaration) {
return babelParse(fs.readFile(arbitraryTypeSource)!, {
plugins: resolveParserPlugins('ts', parserPlugins, true),
sourceType: 'module',
}).program.body
}
if (ext === '.vue') {
const { const {
descriptor: { script, scriptSetup }, descriptor: { script, scriptSetup },
} = parse(content) } = parse(content)
@ -1554,6 +1588,14 @@ export function inferRuntimeType(
case 'TSTypeReference': { case 'TSTypeReference': {
const resolved = resolveTypeReference(ctx, node, scope) const resolved = resolveTypeReference(ctx, node, scope)
if (resolved) { if (resolved) {
if (resolved.type === 'TSTypeAliasDeclaration') {
return inferRuntimeType(
ctx,
resolved.typeAnnotation,
resolved._ownerScope,
isKeyOf,
)
}
return inferRuntimeType(ctx, resolved, resolved._ownerScope, isKeyOf) return inferRuntimeType(ctx, resolved, resolved._ownerScope, isKeyOf)
} }

View File

@ -189,8 +189,7 @@ function rewriteSelector(
// global: replace with inner selector and do not inject [id]. // global: replace with inner selector and do not inject [id].
// ::v-global(.foo) -> .foo // ::v-global(.foo) -> .foo
if (value === ':global' || value === '::v-global') { if (value === ':global' || value === '::v-global') {
selectorRoot.insertAfter(selector, n.nodes[0]) selector.replaceWith(n.nodes[0])
selectorRoot.removeChild(selector)
return false return false
} }
} }

View File

@ -23,28 +23,48 @@ export interface StylePreprocessorResults {
// .scss/.sass processor // .scss/.sass processor
const scss: StylePreprocessor = (source, map, options, load = require) => { const scss: StylePreprocessor = (source, map, options, load = require) => {
const nodeSass = load('sass') const nodeSass: typeof import('sass') = load('sass')
const finalOptions = { const { compileString, renderSync } = nodeSass
const data = getSource(source, options.filename, options.additionalData)
let css: string
let dependencies: string[]
let sourceMap: any
try {
if (compileString) {
const { pathToFileURL, fileURLToPath }: typeof import('url') = load('url')
const result = compileString(data, {
...options, ...options,
data: getSource(source, options.filename, options.additionalData), url: pathToFileURL(options.filename),
sourceMap: !!map,
})
css = result.css
dependencies = result.loadedUrls.map(url => fileURLToPath(url))
sourceMap = map ? result.sourceMap! : undefined
} else {
const result = renderSync({
...options,
data,
file: options.filename, file: options.filename,
outFile: options.filename, outFile: options.filename,
sourceMap: !!map, sourceMap: !!map,
})
css = result.css.toString()
dependencies = result.stats.includedFiles
sourceMap = map ? JSON.parse(result.map!.toString()) : undefined
} }
try {
const result = nodeSass.renderSync(finalOptions)
const dependencies = result.stats.includedFiles
if (map) { if (map) {
return { return {
code: result.css.toString(), code: css,
map: merge(map, JSON.parse(result.map.toString())),
errors: [], errors: [],
dependencies, dependencies,
map: merge(map, sourceMap!),
} }
} }
return { code: css, errors: [], dependencies }
return { code: result.css.toString(), errors: [], dependencies }
} catch (e: any) { } catch (e: any) {
return { code: '', errors: [e], dependencies: [] } return { code: '', errors: [e], dependencies: [] }
} }

View File

@ -337,6 +337,39 @@ describe('ssr: element', () => {
`) `)
}) })
test('custom dir with v-text', () => {
expect(getCompiledString(`<div v-xxx v-text="foo" />`))
.toMatchInlineSnapshot(`
"\`<div\${
_ssrRenderAttrs(_ssrGetDirectiveProps(_ctx, _directive_xxx))
}>\${
_ssrInterpolate(_ctx.foo)
}</div>\`"
`)
})
test('custom dir with v-text and normal attrs', () => {
expect(getCompiledString(`<div class="test" v-xxx v-text="foo" />`))
.toMatchInlineSnapshot(`
"\`<div\${
_ssrRenderAttrs(_mergeProps({ class: "test" }, _ssrGetDirectiveProps(_ctx, _directive_xxx)))
}>\${
_ssrInterpolate(_ctx.foo)
}</div>\`"
`)
})
test('mulptiple custom dirs with v-text', () => {
expect(getCompiledString(`<div v-xxx v-yyy v-text="foo" />`))
.toMatchInlineSnapshot(`
"\`<div\${
_ssrRenderAttrs(_mergeProps(_ssrGetDirectiveProps(_ctx, _directive_xxx), _ssrGetDirectiveProps(_ctx, _directive_yyy)))
}>\${
_ssrInterpolate(_ctx.foo)
}</div>\`"
`)
})
test('custom dir with object v-bind', () => { test('custom dir with object v-bind', () => {
expect(getCompiledString(`<div v-bind="x" v-xxx />`)) expect(getCompiledString(`<div v-bind="x" v-xxx />`))
.toMatchInlineSnapshot(` .toMatchInlineSnapshot(`

View File

@ -52,6 +52,52 @@ describe('ssr: v-model', () => {
}" }"
`) `)
expect(
compileWithWrapper(
`<select v-model="model"><option v-for="i in items" :value="i"></option></select>`,
).code,
).toMatchInlineSnapshot(`
"const { ssrRenderAttr: _ssrRenderAttr, ssrIncludeBooleanAttr: _ssrIncludeBooleanAttr, ssrLooseContain: _ssrLooseContain, ssrLooseEqual: _ssrLooseEqual, ssrRenderAttrs: _ssrRenderAttrs, ssrRenderList: _ssrRenderList } = require("vue/server-renderer")
return function ssrRender(_ctx, _push, _parent, _attrs) {
_push(\`<div\${_ssrRenderAttrs(_attrs)}><select><!--[-->\`)
_ssrRenderList(_ctx.items, (i) => {
_push(\`<option\${
_ssrRenderAttr("value", i)
}\${
(_ssrIncludeBooleanAttr((Array.isArray(_ctx.model))
? _ssrLooseContain(_ctx.model, i)
: _ssrLooseEqual(_ctx.model, i))) ? " selected" : ""
}></option>\`)
})
_push(\`<!--]--></select></div>\`)
}"
`)
expect(
compileWithWrapper(
`<select v-model="model"><option v-if="true" :value="i"></option></select>`,
).code,
).toMatchInlineSnapshot(`
"const { ssrRenderAttr: _ssrRenderAttr, ssrIncludeBooleanAttr: _ssrIncludeBooleanAttr, ssrLooseContain: _ssrLooseContain, ssrLooseEqual: _ssrLooseEqual, ssrRenderAttrs: _ssrRenderAttrs } = require("vue/server-renderer")
return function ssrRender(_ctx, _push, _parent, _attrs) {
_push(\`<div\${_ssrRenderAttrs(_attrs)}><select>\`)
if (true) {
_push(\`<option\${
_ssrRenderAttr("value", _ctx.i)
}\${
(_ssrIncludeBooleanAttr((Array.isArray(_ctx.model))
? _ssrLooseContain(_ctx.model, _ctx.i)
: _ssrLooseEqual(_ctx.model, _ctx.i))) ? " selected" : ""
}></option>\`)
} else {
_push(\`<!---->\`)
}
_push(\`</select></div>\`)
}"
`)
expect( expect(
compileWithWrapper( compileWithWrapper(
`<select multiple v-model="model"><option value="1" selected></option><option value="2"></option></select>`, `<select multiple v-model="model"><option value="1" selected></option><option value="2"></option></select>`,

View File

@ -1,6 +1,6 @@
{ {
"name": "@vue/compiler-ssr", "name": "@vue/compiler-ssr",
"version": "3.5.9", "version": "3.5.16",
"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",

View File

@ -28,6 +28,7 @@ import {
createSequenceExpression, createSequenceExpression,
createSimpleExpression, createSimpleExpression,
createTemplateLiteral, createTemplateLiteral,
findDir,
hasDynamicKeyVBind, hasDynamicKeyVBind,
isStaticArgOf, isStaticArgOf,
isStaticExp, isStaticExp,
@ -164,6 +165,9 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
] ]
} }
} else if (directives.length && !node.children.length) { } else if (directives.length && !node.children.length) {
// v-text directive has higher priority than the merged props
const vText = findDir(node, 'text')
if (!vText) {
const tempId = `_temp${context.temps++}` const tempId = `_temp${context.temps++}`
propsExp.arguments = [ propsExp.arguments = [
createAssignmentExpression( createAssignmentExpression(
@ -183,6 +187,7 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
), ),
) )
} }
}
if (needTagForRuntime) { if (needTagForRuntime) {
propsExp.arguments.push(`"${node.tag}"`) propsExp.arguments.push(`"${node.tag}"`)

View File

@ -5,6 +5,7 @@ import {
type ExpressionNode, type ExpressionNode,
NodeTypes, NodeTypes,
type PlainElementNode, type PlainElementNode,
type TemplateChildNode,
createCallExpression, createCallExpression,
createConditionalExpression, createConditionalExpression,
createDOMCompilerError, createDOMCompilerError,
@ -162,11 +163,18 @@ export const ssrTransformModel: DirectiveTransform = (dir, node, context) => {
checkDuplicatedValue() checkDuplicatedValue()
node.children = [createInterpolation(model, model.loc)] node.children = [createInterpolation(model, model.loc)]
} else if (node.tag === 'select') { } else if (node.tag === 'select') {
node.children.forEach(child => { const processChildren = (children: TemplateChildNode[]) => {
children.forEach(child => {
if (child.type === NodeTypes.ELEMENT) { if (child.type === NodeTypes.ELEMENT) {
processOption(child as PlainElementNode) processOption(child as PlainElementNode)
} else if (child.type === NodeTypes.FOR) {
processChildren(child.children)
} else if (child.type === NodeTypes.IF) {
child.branches.forEach(b => processChildren(b.children))
} }
}) })
}
processChildren(node.children)
} else { } else {
context.onError( context.onError(
createDOMCompilerError( createDOMCompilerError(

View File

@ -1,5 +1,10 @@
import { bench, describe } from 'vitest' import { bench, describe } from 'vitest'
import { type ComputedRef, type Ref, computed, effect, ref } from '../src' import type { ComputedRef, Ref } from '../src'
import { computed, effect, ref } from '../dist/reactivity.esm-browser.prod'
declare module '../dist/reactivity.esm-browser.prod' {
function computed(...args: any[]): any
}
describe('computed', () => { describe('computed', () => {
bench('create computed', () => { bench('create computed', () => {

View File

@ -1,5 +1,6 @@
import { bench, describe } from 'vitest' import { bench, describe } from 'vitest'
import { type Ref, effect, ref } from '../src' import type { Ref } from '../src'
import { effect, ref } from '../dist/reactivity.esm-browser.prod'
describe('effect', () => { describe('effect', () => {
{ {

View File

@ -1,5 +1,9 @@
import { bench } from 'vitest' import { bench } from 'vitest'
import { effect, reactive, shallowReadArray } from '../src' import {
effect,
reactive,
shallowReadArray,
} from '../dist/reactivity.esm-browser.prod'
for (let amount = 1e1; amount < 1e4; amount *= 10) { for (let amount = 1e1; amount < 1e4; amount *= 10) {
{ {

View File

@ -1,5 +1,6 @@
import { bench } from 'vitest' import { bench } from 'vitest'
import { type ComputedRef, computed, reactive } from '../src' import type { ComputedRef } from '../src'
import { computed, reactive } from '../dist/reactivity.esm-browser.prod'
function createMap(obj: Record<string, any>) { function createMap(obj: Record<string, any>) {
const map = new Map() const map = new Map()

View File

@ -1,5 +1,5 @@
import { bench } from 'vitest' import { bench } from 'vitest'
import { reactive } from '../src' import { reactive } from '../dist/reactivity.esm-browser.prod'
bench('create reactive obj', () => { bench('create reactive obj', () => {
reactive({ a: 1 }) reactive({ a: 1 })

View File

@ -1,5 +1,5 @@
import { bench, describe } from 'vitest' import { bench, describe } from 'vitest'
import { ref } from '../src/index' import { ref } from '../dist/reactivity.esm-browser.prod'
describe('ref', () => { describe('ref', () => {
bench('create ref', () => { bench('create ref', () => {

View File

@ -1012,6 +1012,17 @@ describe('reactivity/computed', () => {
expect(cValue.value).toBe(1) expect(cValue.value).toBe(1)
}) })
test('should not recompute if computed does not track reactive data', async () => {
const spy = vi.fn()
const c1 = computed(() => spy())
c1.value
ref(0).value++ // update globalVersion
c1.value
expect(spy).toBeCalledTimes(1)
})
test('computed should remain live after losing all subscribers', () => { test('computed should remain live after losing all subscribers', () => {
const state = reactive({ a: 1 }) const state = reactive({ a: 1 })
const p = computed(() => state.a + 1) const p = computed(() => state.a + 1)
@ -1057,4 +1068,86 @@ describe('reactivity/computed', () => {
obj.flag = 1 obj.flag = 1
expect(foo).toBe(2) expect(foo).toBe(2)
}) })
// #11928
test('should not lead to exponential perf cost with deeply chained computed', () => {
const start = {
prop1: shallowRef(1),
prop2: shallowRef(2),
prop3: shallowRef(3),
prop4: shallowRef(4),
}
let layer = start
const LAYERS = 1000
for (let i = LAYERS; i > 0; i--) {
const m = layer
const s = {
prop1: computed(() => m.prop2.value),
prop2: computed(() => m.prop1.value - m.prop3.value),
prop3: computed(() => m.prop2.value + m.prop4.value),
prop4: computed(() => m.prop3.value),
}
effect(() => s.prop1.value)
effect(() => s.prop2.value)
effect(() => s.prop3.value)
effect(() => s.prop4.value)
s.prop1.value
s.prop2.value
s.prop3.value
s.prop4.value
layer = s
}
const t = performance.now()
start.prop1.value = 4
start.prop2.value = 3
start.prop3.value = 2
start.prop4.value = 1
expect(performance.now() - t).toBeLessThan(process.env.CI ? 100 : 30)
const end = layer
expect([
end.prop1.value,
end.prop2.value,
end.prop3.value,
end.prop4.value,
]).toMatchObject([-2, -4, 2, 3])
})
test('performance when removing dependencies from deeply nested computeds', () => {
const base = ref(1)
const trigger = ref(true)
const computeds: ComputedRef<number>[] = []
const LAYERS = 30
for (let i = 0; i < LAYERS; i++) {
const earlier = [...computeds]
computeds.push(
computed(() => {
return base.value + earlier.reduce((sum, c) => sum + c.value, 0)
}),
)
}
const tail = computed(() =>
trigger.value ? computeds[computeds.length - 1].value : 0,
)
const t0 = performance.now()
expect(tail.value).toBe(2 ** (LAYERS - 1))
const t1 = performance.now()
expect(t1 - t0).toBeLessThan(process.env.CI ? 100 : 30)
trigger.value = false
expect(tail.value).toBe(0)
const t2 = performance.now()
expect(t2 - t1).toBeLessThan(process.env.CI ? 100 : 30)
})
}) })

View File

@ -176,7 +176,7 @@ describe('reactivity/effect/scope', () => {
expect('[Vue warn] cannot run an inactive effect scope.').toHaveBeenWarned() expect('[Vue warn] cannot run an inactive effect scope.').toHaveBeenWarned()
expect(scope.effects.length).toBe(1) expect(scope.effects.length).toBe(0)
counter.num = 7 counter.num = 7
expect(dummy).toBe(0) expect(dummy).toBe(0)
@ -322,4 +322,44 @@ describe('reactivity/effect/scope', () => {
scope.resume() scope.resume()
expect(fnSpy).toHaveBeenCalledTimes(3) expect(fnSpy).toHaveBeenCalledTimes(3)
}) })
test('removing a watcher while stopping its effectScope', async () => {
const count = ref(0)
const scope = effectScope()
let watcherCalls = 0
let cleanupCalls = 0
scope.run(() => {
const stop1 = watch(count, () => {
watcherCalls++
})
watch(count, (val, old, onCleanup) => {
watcherCalls++
onCleanup(() => {
cleanupCalls++
stop1()
})
})
watch(count, () => {
watcherCalls++
})
})
expect(watcherCalls).toBe(0)
expect(cleanupCalls).toBe(0)
count.value++
await nextTick()
expect(watcherCalls).toBe(3)
expect(cleanupCalls).toBe(0)
scope.stop()
count.value++
await nextTick()
expect(watcherCalls).toBe(3)
expect(cleanupCalls).toBe(1)
expect(scope.effects.length).toBe(0)
expect(scope.cleanups.length).toBe(0)
})
}) })

View File

@ -1,4 +1,4 @@
import { isRef, ref } from '../src/ref' import { isRef, ref, shallowRef } from '../src/ref'
import { import {
isProxy, isProxy,
isReactive, isReactive,
@ -195,8 +195,8 @@ describe('reactivity/reactive', () => {
test('toRaw on object using reactive as prototype', () => { test('toRaw on object using reactive as prototype', () => {
const original = { foo: 1 } const original = { foo: 1 }
const observed = reactive(original) const observed = reactive(original)
const inherted = Object.create(observed) const inherited = Object.create(observed)
expect(toRaw(inherted)).toBe(inherted) expect(toRaw(inherited)).toBe(inherited)
}) })
test('toRaw on user Proxy wrapping reactive', () => { test('toRaw on user Proxy wrapping reactive', () => {
@ -301,6 +301,13 @@ describe('reactivity/reactive', () => {
expect(() => markRaw(obj)).not.toThrowError() expect(() => markRaw(obj)).not.toThrowError()
}) })
test('should not markRaw object as reactive', () => {
const a = reactive({ a: 1 })
const b = reactive({ b: 2 }) as any
b.a = markRaw(toRaw(a))
expect(b.a === a).toBe(false)
})
test('should not observe non-extensible objects', () => { test('should not observe non-extensible objects', () => {
const obj = reactive({ const obj = reactive({
foo: Object.preventExtensions({ a: 1 }), foo: Object.preventExtensions({ a: 1 }),
@ -409,4 +416,27 @@ describe('reactivity/reactive', () => {
e.effect.stop() e.effect.stop()
expect(targetMap.get(obj)?.get('x')).toBeFalsy() expect(targetMap.get(obj)?.get('x')).toBeFalsy()
}) })
test('should trigger reactivity when Map key is undefined', () => {
const map = reactive(new Map())
const c = computed(() => map.get(void 0))
expect(c.value).toBe(void 0)
map.set(void 0, 1)
expect(c.value).toBe(1)
})
test('should return true for reactive objects', () => {
expect(isReactive(reactive({}))).toBe(true)
expect(isReactive(readonly(reactive({})))).toBe(true)
expect(isReactive(ref({}).value)).toBe(true)
expect(isReactive(readonly(ref({})).value)).toBe(true)
expect(isReactive(shallowReactive({}))).toBe(true)
})
test('should return false for non-reactive objects', () => {
expect(isReactive(ref(true))).toBe(false)
expect(isReactive(shallowRef({}).value)).toBe(false)
})
}) })

View File

@ -51,6 +51,7 @@ describe('reactivity/reactive/Array', () => {
const raw = {} const raw = {}
const arr = reactive([{}, {}]) const arr = reactive([{}, {}])
arr.push(raw) arr.push(raw)
expect(arr.indexOf(raw)).toBe(2) expect(arr.indexOf(raw)).toBe(2)
expect(arr.indexOf(raw, 3)).toBe(-1) expect(arr.indexOf(raw, 3)).toBe(-1)
expect(arr.includes(raw)).toBe(true) expect(arr.includes(raw)).toBe(true)
@ -89,6 +90,84 @@ describe('reactivity/reactive/Array', () => {
expect(index).toBe(1) expect(index).toBe(1)
}) })
// only non-existent reactive will try to search by using its raw value
describe('Array identity methods should not be called more than necessary', () => {
const identityMethods = ['includes', 'indexOf', 'lastIndexOf'] as const
function instrumentArr(rawTarget: any[]) {
identityMethods.forEach(key => {
const spy = vi.fn(rawTarget[key] as any)
rawTarget[key] = spy
})
}
function searchValue(target: any[], ...args: unknown[]) {
return identityMethods.map(key => (target[key] as any)(...args))
}
function unInstrumentArr(rawTarget: any[]) {
identityMethods.forEach(key => {
;(rawTarget[key] as any).mockClear()
// relink to prototype method
rawTarget[key] = Array.prototype[key] as any
})
}
function expectHaveBeenCalledTimes(rawTarget: any[], times: number) {
identityMethods.forEach(key => {
expect(rawTarget[key]).toHaveBeenCalledTimes(times)
})
}
test('should be called once with a non-existent raw value', () => {
const reactiveArr = reactive([])
instrumentArr(toRaw(reactiveArr))
const searchResult = searchValue(reactiveArr, {})
expectHaveBeenCalledTimes(toRaw(reactiveArr), 1)
expect(searchResult).toStrictEqual([false, -1, -1])
unInstrumentArr(toRaw(reactiveArr))
})
test('should be called once with an existent reactive value', () => {
const existReactiveValue = reactive({})
const reactiveArr = reactive([existReactiveValue, existReactiveValue])
instrumentArr(toRaw(reactiveArr))
const searchResult = searchValue(reactiveArr, existReactiveValue)
expectHaveBeenCalledTimes(toRaw(reactiveArr), 1)
expect(searchResult).toStrictEqual([true, 0, 1])
unInstrumentArr(toRaw(reactiveArr))
})
test('should be called twice with a non-existent reactive value', () => {
const reactiveArr = reactive([])
instrumentArr(toRaw(reactiveArr))
const searchResult = searchValue(reactiveArr, reactive({}))
expectHaveBeenCalledTimes(toRaw(reactiveArr), 2)
expect(searchResult).toStrictEqual([false, -1, -1])
unInstrumentArr(toRaw(reactiveArr))
})
test('should be called twice with a non-existent reactive value, but the raw value exists', () => {
const existRaw = {}
const reactiveArr = reactive([existRaw, existRaw])
instrumentArr(toRaw(reactiveArr))
const searchResult = searchValue(reactiveArr, reactive(existRaw))
expectHaveBeenCalledTimes(toRaw(reactiveArr), 2)
expect(searchResult).toStrictEqual([true, 0, 1])
unInstrumentArr(toRaw(reactiveArr))
})
})
test('delete on Array should not trigger length dependency', () => { test('delete on Array should not trigger length dependency', () => {
const arr = reactive([1, 2, 3]) const arr = reactive([1, 2, 3])
const fn = vi.fn() const fn = vi.fn()

View File

@ -8,7 +8,9 @@ import {
reactive, reactive,
readonly, readonly,
ref, ref,
shallowRef,
toRaw, toRaw,
triggerRef,
} from '../src' } from '../src'
/** /**
@ -520,3 +522,16 @@ describe('reactivity/readonly', () => {
expect(r.value).toBe(ro) expect(r.value).toBe(ro)
}) })
}) })
test('should be able to trigger with triggerRef', () => {
const r = shallowRef({ a: 1 })
const ror = readonly(r)
let dummy
effect(() => {
dummy = ror.value.a
})
r.value.a = 2
expect(dummy).toBe(1)
triggerRef(ror)
expect(dummy).toBe(2)
})

Some files were not shown because too many files have changed in this diff Show More