mirror of https://github.com/vuejs/core.git
Compare commits
556 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
c68bebfa6d | |
|
|
e857e12c0a | |
|
|
f33b308102 | |
|
|
94aeb64ccd | |
|
|
ed85953e28 | |
|
|
4783118919 | |
|
|
6611dda298 | |
|
|
e24ff7d302 | |
|
|
69ce3c7d75 | |
|
|
1904053f1f | |
|
|
f5b3bf264d | |
|
|
945a543152 | |
|
|
dfe667c856 | |
|
|
d8a2de4485 | |
|
|
1e34871149 | |
|
|
965641af39 | |
|
|
918fd5a029 | |
|
|
f5adc4b8cd | |
|
|
9a51742176 | |
|
|
8c605cc3ef | |
|
|
22cd4a399a | |
|
|
9d481f826d | |
|
|
5c461352fc | |
|
|
edbd5ec81b | |
|
|
f51d3e2789 | |
|
|
44ee43848f | |
|
|
92019e4a2d | |
|
|
25ebe3a42c | |
|
|
c0f63ddbfa | |
|
|
301020b481 | |
|
|
0d2357e697 | |
|
|
247b2c2067 | |
|
|
b50eb68c50 | |
|
|
5af3dd9b45 | |
|
|
2214f7ab29 | |
|
|
8f82f23846 | |
|
|
83f6ab686d | |
|
|
3942dbe613 | |
|
|
f40baa2d50 | |
|
|
e9c676ff2b | |
|
|
e131369833 | |
|
|
90ce838a94 | |
|
|
11ec51aa5a | |
|
|
5cf0097f33 | |
|
|
f411c6604c | |
|
|
dc4dd594fb | |
|
|
40c4b2a876 | |
|
|
e6544ac292 | |
|
|
75d44c7189 | |
|
|
dcc6f36257 | |
|
|
8fbe48fe39 | |
|
|
6cbdf7823b | |
|
|
006a0c1011 | |
|
|
b8aab3d209 | |
|
|
84ca349fef | |
|
|
8ca2b3fbb7 | |
|
|
5689884c8e | |
|
|
b3cca2611c | |
|
|
8ec7cb12e4 | |
|
|
c13e674fb9 | |
|
|
1df8990504 | |
|
|
d715e5f6f1 | |
|
|
475539c154 | |
|
|
cd7c9a371c | |
|
|
c35e880f7f | |
|
|
90d3ff4dec | |
|
|
7065cee4fd | |
|
|
f00e5c7885 | |
|
|
2d65306949 | |
|
|
45547e69b2 | |
|
|
079010a38c | |
|
|
2dbe30177f | |
|
|
c16f8a94c7 | |
|
|
5a8aa0b2ba | |
|
|
1be5ddfe87 | |
|
|
d44a5a98c8 | |
|
|
c8a99172cc | |
|
|
b46481a47f | |
|
|
8593647e37 | |
|
|
f2487d86ea | |
|
|
b374ec7ca9 | |
|
|
9612b95220 | |
|
|
5953c9ff90 | |
|
|
565741a9b2 | |
|
|
47e628df1c | |
|
|
6b68f72673 | |
|
|
8bb8fb2362 | |
|
|
c4a88cdd0d | |
|
|
e388f1a09f | |
|
|
fda47ac702 | |
|
|
5e1e791880 | |
|
|
95c1975604 | |
|
|
4b7170625d | |
|
|
9c279517b9 | |
|
|
aba7feda17 | |
|
|
ba7f7f90f6 | |
|
|
5358bca4a8 | |
|
|
836b82976f | |
|
|
8620a616eb | |
|
|
2078f8b756 | |
|
|
abd563822a | |
|
|
b555f02eed | |
|
|
8c1f61d050 | |
|
|
e5a6fe42ea | |
|
|
75220c7995 | |
|
|
4b6cb1f52a | |
|
|
5d75a170c8 | |
|
|
55922ff316 | |
|
|
1e8b65aa49 | |
|
|
f2699a5cb3 | |
|
|
99d54b28b4 | |
|
|
15fc75f403 | |
|
|
4810f1489f | |
|
|
7171defb45 | |
|
|
26bce3dc6c | |
|
|
842a392ae5 | |
|
|
1392734ae5 | |
|
|
8696e346b4 | |
|
|
93ba107672 | |
|
|
00978f7d14 | |
|
|
ef20b86b36 | |
|
|
35da3c6dcb | |
|
|
8f6b505051 | |
|
|
e322436887 | |
|
|
d11cdd4a01 | |
|
|
ce9e6d1f4c | |
|
|
bbf0f4cc44 | |
|
|
a28794edfa | |
|
|
63279661e8 | |
|
|
233b1250ce | |
|
|
24fccb4ee4 | |
|
|
3aa782df38 | |
|
|
1031e8de08 | |
|
|
0f916d8c39 | |
|
|
952886e299 | |
|
|
a48ffdad65 | |
|
|
cde15b07bf | |
|
|
20b888bd59 | |
|
|
0a202d890f | |
|
|
d9dd628800 | |
|
|
4a2953f57b | |
|
|
19a0cbd431 | |
|
|
40d8d61c64 | |
|
|
5bdb2b4693 | |
|
|
be7c7e57ac | |
|
|
40654d4aa4 | |
|
|
10edfb5fc0 | |
|
|
2a0382ca7a | |
|
|
5eed143dd1 | |
|
|
a8713159ee | |
|
|
0562548ab3 | |
|
|
d7283f3b7f | |
|
|
3190b179b0 | |
|
|
7f60ef83e7 | |
|
|
6e5143d963 | |
|
|
1498821ed9 | |
|
|
439e1a543e | |
|
|
7420564b20 | |
|
|
8963b7979a | |
|
|
c875019d49 | |
|
|
31f798581c | |
|
|
911e67045e | |
|
|
c486536105 | |
|
|
7343f7c95f | |
|
|
8cfc10a80b | |
|
|
7f2994393d | |
|
|
9b029239ed | |
|
|
d8e40ef7e1 | |
|
|
90573b06bf | |
|
|
c5f7db1154 | |
|
|
a9269c642b | |
|
|
00695a5b41 | |
|
|
da1f8d7987 | |
|
|
0b6616a9c1 | |
|
|
42b272da57 | |
|
|
e60edc06f2 | |
|
|
21b685ad9d | |
|
|
ce933390ad | |
|
|
d3af67e878 | |
|
|
e0e8221d7f | |
|
|
347ef1d3f5 | |
|
|
f97c4d4e6e | |
|
|
a0bd1f518e | |
|
|
01a122283f | |
|
|
eca0e1ccff | |
|
|
c85f1b5a13 | |
|
|
7e133dbe01 | |
|
|
ba391f5fdf | |
|
|
50a1c30899 | |
|
|
b8b926cdee | |
|
|
5f8314cb7f | |
|
|
15520954f9 | |
|
|
f3479aac96 | |
|
|
919c44744b | |
|
|
cb14b860f1 | |
|
|
9818456f20 | |
|
|
52571655f8 | |
|
|
c0c9c5baea | |
|
|
532cfae349 | |
|
|
c91afec9c2 | |
|
|
4e9e9ceeb1 | |
|
|
a6e2032f43 | |
|
|
6c68421e4d | |
|
|
c7d3207cde | |
|
|
cdffaf6b9e | |
|
|
a47832e75e | |
|
|
e416f84d74 | |
|
|
1b98aafa05 | |
|
|
55dad625ac | |
|
|
47ddf98602 | |
|
|
e8d8f5f604 | |
|
|
5ba1afba09 | |
|
|
73055d8d95 | |
|
|
4aa7a4aba3 | |
|
|
4eb46e443f | |
|
|
10ebcef8c8 | |
|
|
f05a8d613b | |
|
|
762fae4b57 | |
|
|
e53a4ffbe0 | |
|
|
62f2aa11a2 | |
|
|
a60f2bd371 | |
|
|
e7381761cc | |
|
|
19f23b180b | |
|
|
d9bd436b1a | |
|
|
42f879fcab | |
|
|
d5ada3d235 | |
|
|
c017c7b8d3 | |
|
|
004f488a67 | |
|
|
1ee3fcf929 | |
|
|
c46d9f37ae | |
|
|
9fa787cfd2 | |
|
|
2c6c0794a1 | |
|
|
93949e6587 | |
|
|
949df80880 | |
|
|
a683c80cf4 | |
|
|
1d41d4de7f | |
|
|
5179d328d9 | |
|
|
d53daf1f29 | |
|
|
2b894746bd | |
|
|
64d2ba9f47 | |
|
|
dc18a159e8 | |
|
|
00734afef5 | |
|
|
89edc6cdcb | |
|
|
f44feed6fa | |
|
|
c69c4bb59c | |
|
|
1a664749d4 | |
|
|
013749e75e | |
|
|
35aeae7fa3 | |
|
|
d15dce3142 | |
|
|
163b3651d1 | |
|
|
f7ce5ae666 | |
|
|
772b0087cb | |
|
|
cf5a5e0edf | |
|
|
d37a2ac59d | |
|
|
80055fddfb | |
|
|
b9910755a5 | |
|
|
d0253a0b7e | |
|
|
1f98a9c493 | |
|
|
626450590d | |
|
|
8e3435779a | |
|
|
343c891224 | |
|
|
9c4dbbc518 | |
|
|
f7dad6da2f | |
|
|
258f78b643 | |
|
|
3cb4db21ef | |
|
|
d79aa70c61 | |
|
|
f556c925ac | |
|
|
56be3dd4db | |
|
|
3f27c58ffb | |
|
|
9196222ae1 | |
|
|
2206cd235a | |
|
|
5e37dd0095 | |
|
|
0b23fd2383 | |
|
|
8b848cbbd2 | |
|
|
016c472bd2 | |
|
|
5d166f3796 | |
|
|
b3ecee3da8 | |
|
|
e4d9e7ee52 | |
|
|
bfc458f7bf | |
|
|
d9923c3503 | |
|
|
a23fb59e83 | |
|
|
c3e3396475 | |
|
|
b92ae84ce5 | |
|
|
b782cd6c3c | |
|
|
4085ed9052 | |
|
|
4f792535e2 | |
|
|
c15ed52030 | |
|
|
9d84d64fee | |
|
|
8ae11226e8 | |
|
|
32bc647fab | |
|
|
4f6ef92ad9 | |
|
|
347c7849ad | |
|
|
1faca599cd | |
|
|
466b30f404 | |
|
|
f6e84af30a | |
|
|
5f14669d29 | |
|
|
25e803773a | |
|
|
1499135c22 | |
|
|
733e266cdd | |
|
|
c97cc4cdb0 | |
|
|
93d663a046 | |
|
|
60b7bf50e6 | |
|
|
40fd95ffd3 | |
|
|
d65b25cdda | |
|
|
07064f3522 | |
|
|
c65b8d1519 | |
|
|
7278d35213 | |
|
|
de7959ea47 | |
|
|
021f8f3b69 | |
|
|
f6f64befb8 | |
|
|
10e54dcc86 | |
|
|
4fea167b57 | |
|
|
fbf88b6062 | |
|
|
1722090022 | |
|
|
36509d8561 | |
|
|
4eba2c53bb | |
|
|
d2c8c19ae8 | |
|
|
388295b27f | |
|
|
fdbd026583 | |
|
|
636a8619f0 | |
|
|
d48937fb95 | |
|
|
fb0c3ca519 | |
|
|
87e0cd71c2 | |
|
|
4b1931cf89 | |
|
|
9b708cf5f7 | |
|
|
8bd9cdb77e | |
|
|
d18c248691 | |
|
|
2dd2feab9c | |
|
|
79d5d6cf4d | |
|
|
604d08760e | |
|
|
5e776ae97e | |
|
|
295b5ec19b | |
|
|
0c8dd94ef9 | |
|
|
efed3ebee6 | |
|
|
2785d70382 | |
|
|
cbf5821028 | |
|
|
4a1884f8dc | |
|
|
ce0554fc2c | |
|
|
633327e14d | |
|
|
4f4425e0df | |
|
|
d6a6ec13ce | |
|
|
263f63f735 | |
|
|
99551e387a | |
|
|
2ab70c202f | |
|
|
de0bf335cb | |
|
|
119f18c773 | |
|
|
a117a7a84b | |
|
|
992a05dd48 | |
|
|
22f359bdbe | |
|
|
7ecd2a22c7 | |
|
|
4650715197 | |
|
|
a63679f2ef | |
|
|
29216853d4 | |
|
|
0f12fb7ea9 | |
|
|
08e153c48c | |
|
|
f2263229ff | |
|
|
50b7aa17e9 | |
|
|
26162b4999 | |
|
|
c48a00d85e | |
|
|
82da43d167 | |
|
|
2e6ec39811 | |
|
|
c950b4c0c4 | |
|
|
f399dd3588 | |
|
|
2d6bcc4537 | |
|
|
4170dec5a1 | |
|
|
18555fa7b2 | |
|
|
23d2f453d1 | |
|
|
fbdd084acc | |
|
|
db57d21c17 | |
|
|
22dcbf3e20 | |
|
|
e8e842241a | |
|
|
5a6e98ca32 | |
|
|
eb618fd889 | |
|
|
21f8d9dba9 | |
|
|
3faa0a3a9e | |
|
|
b7085a85f1 | |
|
|
289f4bd94f | |
|
|
234b6cbb74 | |
|
|
6da11a7d22 | |
|
|
bc688434af | |
|
|
833f9ea1f7 | |
|
|
ec22b79fd4 | |
|
|
76bdd78f17 | |
|
|
f74146f40e | |
|
|
d07cdead2c | |
|
|
11c053a542 | |
|
|
201936f9a3 | |
|
|
11f76741fb | |
|
|
c86a08b946 | |
|
|
5a5406d002 | |
|
|
d82fb465a6 | |
|
|
fc4bbf95c1 | |
|
|
06310e82f5 | |
|
|
14f6917c3c | |
|
|
01057fc74c | |
|
|
fdaff720d7 | |
|
|
c028aeafa9 | |
|
|
6eb29d345a | |
|
|
4f8d807822 | |
|
|
983eb50a17 | |
|
|
da7ad5e3d2 | |
|
|
1f75d4e6df | |
|
|
4b479db61d | |
|
|
a20a4cb36a | |
|
|
352bc88c1b | |
|
|
10ab8c0e7b | |
|
|
d637bd6c01 | |
|
|
2d78539da3 | |
|
|
54812eacaa | |
|
|
1022eabaa1 | |
|
|
660132df6c | |
|
|
4aeff318bd | |
|
|
70b44ca835 | |
|
|
a49858f3ee | |
|
|
8bff142f99 | |
|
|
c4312f9c71 | |
|
|
2d5c5e25e9 | |
|
|
99009eee0e | |
|
|
37300fc261 | |
|
|
bee2f5ee62 | |
|
|
21932840ea | |
|
|
e9f3e6b546 | |
|
|
3656364b06 | |
|
|
506ed4e75f | |
|
|
83430a35f4 | |
|
|
b5ff930089 | |
|
|
852642729a | |
|
|
a0901756da | |
|
|
76c43c6040 | |
|
|
e81ecc9a9d | |
|
|
7d0dc7394f | |
|
|
394902c2e9 | |
|
|
664d2e553d | |
|
|
3a043e8c16 | |
|
|
6c0f4741ed | |
|
|
ad247b3323 | |
|
|
5652c5ad83 | |
|
|
ed01d92571 | |
|
|
1222437ec2 | |
|
|
536d600199 | |
|
|
657603d7b7 | |
|
|
2442c3b061 | |
|
|
5b17afa89d | |
|
|
828d4a4439 | |
|
|
a038505c65 | |
|
|
4e19a99461 | |
|
|
3b5d8d2511 | |
|
|
aa6879f987 | |
|
|
be9eed2593 | |
|
|
1755ac0a10 | |
|
|
770ea67a9c | |
|
|
c82b66214b | |
|
|
ea943afe40 | |
|
|
d82fa611e8 | |
|
|
d96883cf7d | |
|
|
1ae545a378 | |
|
|
05685a9d7c | |
|
|
cde2c0671b | |
|
|
4474c113d1 | |
|
|
9da1ac1565 | |
|
|
10a46f43c0 | |
|
|
d3ecde8a69 | |
|
|
76a8223199 | |
|
|
b4d35349d8 | |
|
|
ec917cfdb9 | |
|
|
f6d9926236 | |
|
|
7ad289e1e7 | |
|
|
c0418a3b8f | |
|
|
f1a4f67aed | |
|
|
e0a591e1cd | |
|
|
704173e242 | |
|
|
d9d4d4e158 | |
|
|
e16e9a7341 | |
|
|
35785f3cd7 | |
|
|
723f588716 | |
|
|
73a3666dee | |
|
|
f7cbea2111 | |
|
|
b094c72b3d | |
|
|
6e4de8d75e | |
|
|
6f85894376 | |
|
|
c97bb84d0b | |
|
|
57315ab968 | |
|
|
577edca8e7 | |
|
|
3a55c3e421 | |
|
|
435e4fefad | |
|
|
d3f5e6e531 | |
|
|
29de6f8b0b | |
|
|
2328b051f4 | |
|
|
4b09ab2074 | |
|
|
93c95dd4cd | |
|
|
aa9ef2386a | |
|
|
60c2029f77 | |
|
|
e2c19c20cf | |
|
|
ea3efa09e0 | |
|
|
a77b95992a | |
|
|
01f15beeb0 | |
|
|
10ff159240 | |
|
|
cb34b28a4a | |
|
|
faf55a15d7 | |
|
|
fa0ba24b3a | |
|
|
4da688141d | |
|
|
6001e5c81a | |
|
|
c0e9434414 | |
|
|
7a00f6f093 | |
|
|
5d9e81d3da | |
|
|
a177092754 | |
|
|
5e8898572f | |
|
|
0267a58801 | |
|
|
d1764a142a | |
|
|
6fcb80172f | |
|
|
960706eebf | |
|
|
b030c8bc73 | |
|
|
9eca65ee98 | |
|
|
235ea4772e | |
|
|
5c8b76ed6c | |
|
|
f927a4ae6f | |
|
|
a2f6edeb02 | |
|
|
62242886d7 | |
|
|
902bd9c438 | |
|
|
215e154072 | |
|
|
d18d6aa1b2 | |
|
|
7257e6a342 | |
|
|
e075dfad5c | |
|
|
9a36f2a0b8 | |
|
|
c74bb8c2dd | |
|
|
cbc39d54f0 | |
|
|
3db0a0f979 | |
|
|
8492c3c49a | |
|
|
fbae210d9d | |
|
|
726db0ad2c | |
|
|
47bda40653 | |
|
|
732a38ef63 | |
|
|
6b07244dd5 | |
|
|
85c138ced1 | |
|
|
49fa673493 | |
|
|
2d6adf78a0 | |
|
|
bc3ddca9d0 | |
|
|
1bad606eb3 | |
|
|
aa5dafd2b5 | |
|
|
346bfaf760 | |
|
|
817dca8712 | |
|
|
effcccd258 | |
|
|
7f2de3f53e | |
|
|
a5f3c2eb4d | |
|
|
3c4bf76276 | |
|
|
10a2c6053b | |
|
|
f2d8019188 | |
|
|
1d99d61c1b | |
|
|
7571f20bc3 | |
|
|
8ea5d6d698 | |
|
|
11eebcb4df | |
|
|
7fe6c795a1 | |
|
|
0e7bc717e6 | |
|
|
706d4ac1d0 | |
|
|
d0b513eb46 | |
|
|
f599321a65 |
|
|
@ -38,7 +38,6 @@ Hi! I'm really excited that you are interested in contributing to Vue.js. Before
|
||||||
### Pull Request Checklist
|
### Pull Request Checklist
|
||||||
|
|
||||||
- Vue core has two primary work branches: `main` and `minor`.
|
- Vue core has two primary work branches: `main` and `minor`.
|
||||||
|
|
||||||
- If your pull request is a feature that adds new API surface, it should be submitted against the `minor` branch.
|
- If your pull request is a feature that adds new API surface, it should be submitted against the `minor` branch.
|
||||||
|
|
||||||
- Otherwise, it should be submitted against the `main` branch.
|
- Otherwise, it should be submitted against the `main` branch.
|
||||||
|
|
@ -46,12 +45,10 @@ Hi! I'm really excited that you are interested in contributing to Vue.js. Before
|
||||||
- [Make sure to tick the "Allow edits from maintainers" box](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork). This allows us to directly make minor edits / refactors and saves a lot of time.
|
- [Make sure to tick the "Allow edits from maintainers" box](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork). This allows us to directly make minor edits / refactors and saves a lot of time.
|
||||||
|
|
||||||
- If adding a new feature:
|
- If adding a new feature:
|
||||||
|
|
||||||
- Add accompanying test case.
|
- Add accompanying test case.
|
||||||
- Provide a convincing reason to add this feature. Ideally, you should open a suggestion issue first and have it approved before working on it.
|
- Provide a convincing reason to add this feature. Ideally, you should open a suggestion issue first and have it approved before working on it.
|
||||||
|
|
||||||
- If fixing a bug:
|
- If fixing a bug:
|
||||||
|
|
||||||
- If you are resolving a special issue, add `(fix #xxxx[,#xxxx])` (#xxxx is the issue id) in your PR title for a better release log, e.g. `update entities encoding/decoding (fix #3899)`.
|
- If you are resolving a special issue, add `(fix #xxxx[,#xxxx])` (#xxxx is the issue id) in your PR title for a better release log, e.g. `update entities encoding/decoding (fix #3899)`.
|
||||||
- Provide a detailed description of the bug in the PR. Live demo preferred.
|
- Provide a detailed description of the bug in the PR. Live demo preferred.
|
||||||
- Add appropriate test coverage if applicable. You can check the coverage of your code addition by running `nr test-coverage`.
|
- Add appropriate test coverage if applicable. You can check the coverage of your code addition by running `nr test-coverage`.
|
||||||
|
|
@ -69,9 +66,7 @@ Hi! I'm really excited that you are interested in contributing to Vue.js. Before
|
||||||
- The PR should fix the intended bug **only** and not introduce unrelated changes. This includes unnecessary refactors - a PR should focus on the fix and not code style, this makes it easier to trace changes in the future.
|
- The PR should fix the intended bug **only** and not introduce unrelated changes. This includes unnecessary refactors - a PR should focus on the fix and not code style, this makes it easier to trace changes in the future.
|
||||||
|
|
||||||
- Consider the performance / size impact of the changes, and whether the bug being fixes justifies the cost. If the bug being fixed is a very niche edge case, we should try to minimize the size / perf cost to make it worthwhile.
|
- Consider the performance / size impact of the changes, and whether the bug being fixes justifies the cost. If the bug being fixed is a very niche edge case, we should try to minimize the size / perf cost to make it worthwhile.
|
||||||
|
|
||||||
- Is the code perf-sensitive (e.g. in "hot paths" like component updates or the vdom patch function?)
|
- Is the code perf-sensitive (e.g. in "hot paths" like component updates or the vdom patch function?)
|
||||||
|
|
||||||
- If the branch is dev-only, performance is less of a concern.
|
- If the branch is dev-only, performance is less of a concern.
|
||||||
|
|
||||||
- Check how much extra bundle size the change introduces.
|
- Check how much extra bundle size the change introduces.
|
||||||
|
|
@ -265,7 +260,6 @@ This repository employs a [monorepo](https://en.wikipedia.org/wiki/Monorepo) set
|
||||||
- `vue`: The public facing "full build" which includes both the runtime AND the compiler.
|
- `vue`: The public facing "full build" which includes both the runtime AND the compiler.
|
||||||
|
|
||||||
- Private utility packages:
|
- Private utility packages:
|
||||||
|
|
||||||
- `dts-test`: Contains type-only tests against generated dts files.
|
- `dts-test`: Contains type-only tests against generated dts files.
|
||||||
|
|
||||||
- `sfc-playground`: The playground continuously deployed at https://play.vuejs.org. To run the playground locally, use [`nr dev-sfc`](#nr-dev-sfc).
|
- `sfc-playground`: The playground continuously deployed at https://play.vuejs.org. To run the playground locally, use [`nr dev-sfc`](#nr-dev-sfc).
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,6 @@ Depending on the type of the PR, different considerations need to be taken into
|
||||||
- Performance: if a refactor PR claims to improve performance, there should be benchmarks showcasing said performance unless the improvement is self-explanatory.
|
- Performance: if a refactor PR claims to improve performance, there should be benchmarks showcasing said performance unless the improvement is self-explanatory.
|
||||||
|
|
||||||
- Code quality / stylistic PRs: we should be conservative on merging this type PRs because (1) they can be subjective in many cases, and (2) they often come with large git diffs, causing merge conflicts with other pending PRs, and leading to unwanted noise when tracing changes through git history. Use your best judgement on this type of PRs on whether they are worth it.
|
- Code quality / stylistic PRs: we should be conservative on merging this type PRs because (1) they can be subjective in many cases, and (2) they often come with large git diffs, causing merge conflicts with other pending PRs, and leading to unwanted noise when tracing changes through git history. Use your best judgement on this type of PRs on whether they are worth it.
|
||||||
|
|
||||||
- For PRs in this category that are approved, do not merge immediately. Group them before releasing a new minor, after all feature-oriented PRs are merged.
|
- For PRs in this category that are approved, do not merge immediately. Group them before releasing a new minor, after all feature-oriented PRs are merged.
|
||||||
|
|
||||||
### Reviewing a Feature
|
### Reviewing a Feature
|
||||||
|
|
@ -56,7 +55,6 @@ Depending on the type of the PR, different considerations need to be taken into
|
||||||
- Feature PRs should always have clear context and explanation on why the feature should be added, ideally in the form of an RFC. If the PR doesn't explain what real-world problem it is solving, ask the contributor to clarify.
|
- Feature PRs should always have clear context and explanation on why the feature should be added, ideally in the form of an RFC. If the PR doesn't explain what real-world problem it is solving, ask the contributor to clarify.
|
||||||
|
|
||||||
- Decide if the feature should require an RFC process. The line isn't always clear, but a rough criteria is whether it is augmenting an existing API vs. adding a new API. Some examples:
|
- Decide if the feature should require an RFC process. The line isn't always clear, but a rough criteria is whether it is augmenting an existing API vs. adding a new API. Some examples:
|
||||||
|
|
||||||
- Adding a new built-in component or directive is "significant" and definitely requires an RFC.
|
- Adding a new built-in component or directive is "significant" and definitely requires an RFC.
|
||||||
- Template syntax additions like adding a new `v-on` modifier or a new `v-bind` syntax sugar are "substantial". It would be nice to have an RFC for it, but a detailed explanation on the use case and reasoning behind the design directly in the PR itself can be acceptable.
|
- Template syntax additions like adding a new `v-on` modifier or a new `v-bind` syntax sugar are "substantial". It would be nice to have an RFC for it, but a detailed explanation on the use case and reasoning behind the design directly in the PR itself can be acceptable.
|
||||||
- Small, low-impact additions like exposing a new utility type or adding a new app config option can be self-explanatory, but should still provide enough context in the PR.
|
- Small, low-impact additions like exposing a new utility type or adding a new app config option can be self-explanatory, but should still provide enough context in the PR.
|
||||||
|
|
@ -70,7 +68,6 @@ Depending on the type of the PR, different considerations need to be taken into
|
||||||
- Implementation: code style should be consistent with the rest of the codebase, follow common best practices. Prefer code that is boring but easy to understand over "clever" code.
|
- Implementation: code style should be consistent with the rest of the codebase, follow common best practices. Prefer code that is boring but easy to understand over "clever" code.
|
||||||
|
|
||||||
- Size: bundle size matters. We have a GitHub action that compares the size change for every PR. We should always aim to realize the desired changes with the smallest amount of code size increase.
|
- Size: bundle size matters. We have a GitHub action that compares the size change for every PR. We should always aim to realize the desired changes with the smallest amount of code size increase.
|
||||||
|
|
||||||
- Sometimes we need to compare the size increase vs. perceived benefits to decide whether a change is justifiable. Also take extra care to make sure added code can be tree-shaken if not needed.
|
- Sometimes we need to compare the size increase vs. perceived benefits to decide whether a change is justifiable. Also take extra care to make sure added code can be tree-shaken if not needed.
|
||||||
|
|
||||||
- Make sure to put dev-only code in `__DEV__` branches so they are tree-shakable.
|
- Make sure to put dev-only code in `__DEV__` branches so they are tree-shakable.
|
||||||
|
|
@ -80,7 +77,6 @@ Depending on the type of the PR, different considerations need to be taken into
|
||||||
- Make sure it doesn't accidentally cause dev-only or compiler-only code branches to be included in the runtime build. Notable case is that some functions in @vue/shared are compiler-only and should not be used in runtime code, e.g. `isHTMLTag` and `isSVGTag`.
|
- Make sure it doesn't accidentally cause dev-only or compiler-only code branches to be included in the runtime build. Notable case is that some functions in @vue/shared are compiler-only and should not be used in runtime code, e.g. `isHTMLTag` and `isSVGTag`.
|
||||||
|
|
||||||
- Performance
|
- Performance
|
||||||
|
|
||||||
- Be careful about code changes in "hot paths", in particular the Virtual DOM renderer (`runtime-core/src/renderer.ts`) and component instantiation code.
|
- Be careful about code changes in "hot paths", in particular the Virtual DOM renderer (`runtime-core/src/renderer.ts`) and component instantiation code.
|
||||||
|
|
||||||
- Potential Breakage
|
- Potential Breakage
|
||||||
|
|
|
||||||
|
|
@ -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: [
|
||||||
|
|
@ -58,9 +67,5 @@
|
||||||
// pinned
|
// pinned
|
||||||
// only used in example for e2e tests
|
// only used in example for e2e tests
|
||||||
'marked',
|
'marked',
|
||||||
|
|
||||||
// pinned, 5.0+ has exports issues
|
|
||||||
// https://github.com/vuejs/core/issues/11603
|
|
||||||
'entities',
|
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,13 @@ jobs:
|
||||||
env:
|
env:
|
||||||
PUPPETEER_SKIP_DOWNLOAD: 'true'
|
PUPPETEER_SKIP_DOWNLOAD: 'true'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v4.0.0
|
uses: pnpm/action-setup@v4.2.0
|
||||||
|
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
registry-url: 'https://registry.npmjs.org'
|
registry-url: 'https://registry.npmjs.org'
|
||||||
|
|
@ -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@635ffb0c9798bd160680f18fd73371e355b85f27
|
||||||
|
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
name: canary minor release
|
|
||||||
on:
|
|
||||||
# Runs every Monday at 1 AM UTC (9:00 AM in Singapore)
|
|
||||||
schedule:
|
|
||||||
- cron: 0 1 * * MON
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
canary:
|
|
||||||
# prevents this action from running on forks
|
|
||||||
if: github.repository == 'vuejs/core'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
environment: Release
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: minor
|
|
||||||
|
|
||||||
- name: Install pnpm
|
|
||||||
uses: pnpm/action-setup@v4.0.0
|
|
||||||
|
|
||||||
- name: Install Node.js
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version-file: '.node-version'
|
|
||||||
registry-url: 'https://registry.npmjs.org'
|
|
||||||
cache: 'pnpm'
|
|
||||||
|
|
||||||
- run: pnpm install
|
|
||||||
|
|
||||||
- run: pnpm release --canary --publish --tag minor
|
|
||||||
env:
|
|
||||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
name: canary release
|
|
||||||
on:
|
|
||||||
# Runs every Monday at 1 AM UTC (9:00 AM in Singapore)
|
|
||||||
schedule:
|
|
||||||
- cron: 0 1 * * MON
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
canary:
|
|
||||||
# prevents this action from running on forks
|
|
||||||
if: github.repository == 'vuejs/core'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
environment: Release
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install pnpm
|
|
||||||
uses: pnpm/action-setup@v4.0.0
|
|
||||||
|
|
||||||
- name: Install Node.js
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version-file: '.node-version'
|
|
||||||
registry-url: 'https://registry.npmjs.org'
|
|
||||||
cache: 'pnpm'
|
|
||||||
|
|
||||||
- run: pnpm install
|
|
||||||
|
|
||||||
- run: pnpm release --canary --publish
|
|
||||||
env:
|
|
||||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
||||||
|
|
@ -20,13 +20,13 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v4
|
uses: pnpm/action-setup@v4
|
||||||
|
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
registry-url: 'https://registry.npmjs.org'
|
registry-url: 'https://registry.npmjs.org'
|
||||||
|
|
@ -39,4 +39,4 @@ jobs:
|
||||||
run: pnpm build --withTypes
|
run: pnpm build --withTypes
|
||||||
|
|
||||||
- name: Release
|
- name: Release
|
||||||
run: pnpx pkg-pr-new publish --compact --pnpm './packages/*'
|
run: pnpx pkg-pr-new publish --compact --pnpm './packages/*' --packageManager=pnpm,npm,yarn
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ jobs:
|
||||||
if: github.repository == 'vuejs/core' && github.event.issue.pull_request && startsWith(github.event.comment.body, '/ecosystem-ci run')
|
if: github.repository == 'vuejs/core' && github.event.issue.pull_request && startsWith(github.event.comment.body, '/ecosystem-ci run')
|
||||||
steps:
|
steps:
|
||||||
- name: Check user permission
|
- name: Check user permission
|
||||||
uses: actions/github-script@v7
|
uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const user = context.payload.sender.login
|
const user = context.payload.sender.login
|
||||||
|
|
@ -45,7 +45,7 @@ jobs:
|
||||||
throw new Error('not allowed')
|
throw new Error('not allowed')
|
||||||
}
|
}
|
||||||
- name: Get PR info
|
- name: Get PR info
|
||||||
uses: actions/github-script@v7
|
uses: actions/github-script@v8
|
||||||
id: get-pr-data
|
id: get-pr-data
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
|
|
@ -62,7 +62,7 @@ jobs:
|
||||||
commit: pr.head.sha
|
commit: pr.head.sha
|
||||||
}
|
}
|
||||||
- name: Trigger run
|
- name: Trigger run
|
||||||
uses: actions/github-script@v7
|
uses: actions/github-script@v8
|
||||||
id: trigger
|
id: trigger
|
||||||
env:
|
env:
|
||||||
COMMENT: ${{ github.event.comment.body }}
|
COMMENT: ${{ github.event.comment.body }}
|
||||||
|
|
|
||||||
|
|
@ -21,13 +21,13 @@ jobs:
|
||||||
environment: Release
|
environment: Release
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v4
|
uses: pnpm/action-setup@v4
|
||||||
|
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
registry-url: 'https://registry.npmjs.org'
|
registry-url: 'https://registry.npmjs.org'
|
||||||
|
|
@ -36,12 +36,13 @@ jobs:
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
run: pnpm install
|
run: pnpm install
|
||||||
|
|
||||||
|
- name: Update npm
|
||||||
|
run: npm i -g npm@latest
|
||||||
|
|
||||||
- name: Build and publish
|
- name: Build and publish
|
||||||
id: publish
|
id: publish
|
||||||
run: |
|
run: |
|
||||||
pnpm release --publishOnly
|
pnpm release --publishOnly
|
||||||
env:
|
|
||||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
||||||
|
|
||||||
- name: Create GitHub release
|
- name: Create GitHub release
|
||||||
id: release_tag
|
id: release_tag
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,13 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v4.0.0
|
uses: pnpm/action-setup@v4.2.0
|
||||||
|
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
|
@ -45,7 +45,7 @@ jobs:
|
||||||
echo ${{ github.base_ref }} > ./temp/size/base.txt
|
echo ${{ github.base_ref }} > ./temp/size/base.txt
|
||||||
|
|
||||||
- name: Upload Size Data
|
- name: Upload Size Data
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v5
|
||||||
with:
|
with:
|
||||||
name: size-data
|
name: size-data
|
||||||
path: temp/size
|
path: temp/size
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,13 @@ jobs:
|
||||||
github.event.workflow_run.event == 'pull_request' &&
|
github.event.workflow_run.event == 'pull_request' &&
|
||||||
github.event.workflow_run.conclusion == 'success'
|
github.event.workflow_run.conclusion == 'success'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v4.0.0
|
uses: pnpm/action-setup@v4.2.0
|
||||||
|
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
|
@ -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@v11
|
||||||
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@v11
|
||||||
with:
|
with:
|
||||||
branch: ${{ steps.pr-base.outputs.content }}
|
branch: ${{ steps.pr-base.outputs.content }}
|
||||||
workflow: size-data.yml
|
workflow: size-data.yml
|
||||||
|
|
@ -66,7 +66,7 @@ jobs:
|
||||||
if_no_artifact_found: warn
|
if_no_artifact_found: warn
|
||||||
|
|
||||||
- name: Prepare report
|
- name: Prepare report
|
||||||
run: pnpm tsx scripts/size-report.ts > size-report.md
|
run: node scripts/size-report.js > size-report.md
|
||||||
|
|
||||||
- name: Read Size Report
|
- name: Read Size Report
|
||||||
id: size-report
|
id: size-report
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,13 @@ jobs:
|
||||||
env:
|
env:
|
||||||
PUPPETEER_SKIP_DOWNLOAD: 'true'
|
PUPPETEER_SKIP_DOWNLOAD: 'true'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v4.0.0
|
uses: pnpm/action-setup@v4.2.0
|
||||||
|
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
@ -32,13 +32,13 @@ jobs:
|
||||||
env:
|
env:
|
||||||
PUPPETEER_SKIP_DOWNLOAD: 'true'
|
PUPPETEER_SKIP_DOWNLOAD: 'true'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v4.0.0
|
uses: pnpm/action-setup@v4.2.0
|
||||||
|
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
@ -54,7 +54,7 @@ jobs:
|
||||||
e2e-test:
|
e2e-test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Setup cache for Chromium binary
|
- name: Setup cache for Chromium binary
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
|
|
@ -63,10 +63,10 @@ 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.2.0
|
||||||
|
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
@ -85,13 +85,13 @@ jobs:
|
||||||
env:
|
env:
|
||||||
PUPPETEER_SKIP_DOWNLOAD: 'true'
|
PUPPETEER_SKIP_DOWNLOAD: 'true'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v4.0.0
|
uses: pnpm/action-setup@v4.2.0
|
||||||
|
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
20
|
22.14.0
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
"cSpell.enabledLanguageIds": ["markdown", "plaintext", "text", "yml"],
|
"cSpell.enabledLanguageIds": ["markdown", "plaintext", "text", "yml"],
|
||||||
|
|
||||||
// Use prettier to format typescript, javascript and JSON files
|
// Use prettier to format TypeScript, JavaScript and JSON files
|
||||||
"[typescript]": {
|
"[typescript]": {
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
},
|
},
|
||||||
|
|
@ -13,5 +13,6 @@
|
||||||
},
|
},
|
||||||
"[json]": {
|
"[json]": {
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
}
|
},
|
||||||
|
"editor.formatOnSave": true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
https://vuejs.org/funding.json
|
||||||
443
CHANGELOG.md
443
CHANGELOG.md
|
|
@ -1,3 +1,446 @@
|
||||||
|
## [3.5.26](https://github.com/vuejs/core/compare/v3.5.25...v3.5.26) (2025-12-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compat:** fix compat handler of draggable ([#12445](https://github.com/vuejs/core/issues/12445)) ([ed85953](https://github.com/vuejs/core/commit/ed85953e28741ae1913cfc92b7b66e1a8da47f8c)), closes [#12444](https://github.com/vuejs/core/issues/12444)
|
||||||
|
* **compat:** handle v-model deprecation warning with missing appContext ([#14203](https://github.com/vuejs/core/issues/14203)) ([945a543](https://github.com/vuejs/core/commit/945a543152e8d80903d4f7a18a84ebe8d36e56f8)), closes [#14202](https://github.com/vuejs/core/issues/14202)
|
||||||
|
* **compiler-sfc:** demote const reactive bindings used in v-model ([#14214](https://github.com/vuejs/core/issues/14214)) ([e24ff7d](https://github.com/vuejs/core/commit/e24ff7d302a887ea532571c231a385362fa17279)), closes [#11265](https://github.com/vuejs/core/issues/11265) [#11275](https://github.com/vuejs/core/issues/11275)
|
||||||
|
* **compiler-ssr:** handle ssr attr fallthrough when preserve whitespace ([#12304](https://github.com/vuejs/core/issues/12304)) ([4783118](https://github.com/vuejs/core/commit/47831189196b62b12dd17f6e909efc51d9d22fd2)), closes [#8072](https://github.com/vuejs/core/issues/8072)
|
||||||
|
* **hmr:** handle cached text node update ([#14134](https://github.com/vuejs/core/issues/14134)) ([69ce3c7](https://github.com/vuejs/core/commit/69ce3c7d755db868cfa66d67ab5b3f383a44e053)), closes [#14127](https://github.com/vuejs/core/issues/14127)
|
||||||
|
* **keep-alive:** use resolved component name for async components in cache pruning ([#14212](https://github.com/vuejs/core/issues/14212)) ([dfe667c](https://github.com/vuejs/core/commit/dfe667c8567d48167c250062483d2d2cfc7bdc03)), closes [#14210](https://github.com/vuejs/core/issues/14210)
|
||||||
|
* **runtime-core:** ensure correct anchor el for deeper unresolved async components ([#14182](https://github.com/vuejs/core/issues/14182)) ([f5b3bf2](https://github.com/vuejs/core/commit/f5b3bf264d2e12725381bed1c492069437069b03)), closes [#14173](https://github.com/vuejs/core/issues/14173)
|
||||||
|
* **runtime-core:** handle patch stable fragment edge case ([#12411](https://github.com/vuejs/core/issues/12411)) ([94aeb64](https://github.com/vuejs/core/commit/94aeb64ccdf20d541059b533c9780977c14db9cb)), closes [#12410](https://github.com/vuejs/core/issues/12410)
|
||||||
|
* **runtime-core:** pass component instance to flushPreFlushCbs on unmount ([#14221](https://github.com/vuejs/core/issues/14221)) ([e857e12](https://github.com/vuejs/core/commit/e857e12c0aff03c0148e3e52d92935918872dc33)), closes [#14215](https://github.com/vuejs/core/issues/14215)
|
||||||
|
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* **compiler-core:** use binary-search to get line and column ([#14222](https://github.com/vuejs/core/issues/14222)) ([1904053](https://github.com/vuejs/core/commit/1904053f1f7986c2d6dbe858ee1b594b4b229c17))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.5.25](https://github.com/vuejs/core/compare/v3.5.24...v3.5.25) (2025-11-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler:** share logic for comments and whitespace ([#13550](https://github.com/vuejs/core/issues/13550)) ([2214f7a](https://github.com/vuejs/core/commit/2214f7ab2940bcb751cd20130c020d895db6c042))
|
||||||
|
* **provide:** warn when using `provide` after mounting ([#13954](https://github.com/vuejs/core/issues/13954)) ([247b2c2](https://github.com/vuejs/core/commit/247b2c2067afc4dee52f9f7bc194f3aab347ac55)), closes [#13921](https://github.com/vuejs/core/issues/13921) [#13924](https://github.com/vuejs/core/issues/13924)
|
||||||
|
* **reactivity:** correctly wrap iterated array items to preserve their readonly status ([#14120](https://github.com/vuejs/core/issues/14120)) ([301020b](https://github.com/vuejs/core/commit/301020b481e85d03b0c96000f3221372063c41c6))
|
||||||
|
* **reactivity:** toRef edge cases for ref unwrapping ([#12420](https://github.com/vuejs/core/issues/12420)) ([0d2357e](https://github.com/vuejs/core/commit/0d2357e6974678d5484751c869f429dc6ea85582))
|
||||||
|
* **runtime-core:** keep options API typing intact when expose is used ([#14118](https://github.com/vuejs/core/issues/14118)) ([8f82f23](https://github.com/vuejs/core/commit/8f82f238463160284e504d1751d61b72dabb395e)), closes [#14117](https://github.com/vuejs/core/issues/14117) [vuejs/language-tools#5069](https://github.com/vuejs/language-tools/issues/5069)
|
||||||
|
* **suspense:** defer clearing fallback vnode el in case it has dirs ([#14080](https://github.com/vuejs/core/issues/14080)) ([c0f63dd](https://github.com/vuejs/core/commit/c0f63ddbfa8fa221d66b683b5c26e471851c2b50)), closes [#14078](https://github.com/vuejs/core/issues/14078)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.5.24](https://github.com/vuejs/core/compare/v3.5.23...v3.5.24) (2025-11-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Reverts
|
||||||
|
|
||||||
|
* Revert "fix(compiler-core): correctly handle ts type assertions in expression…" (#14062) ([11ec51a](https://github.com/vuejs/core/commit/11ec51aa5a7914745fee10ed2b9f9464fab4d02c)), closes [#14062](https://github.com/vuejs/core/issues/14062) [#14060](https://github.com/vuejs/core/issues/14060)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.5.23](https://github.com/vuejs/core/compare/v3.5.22...v3.5.23) (2025-11-06)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler-core:** correctly handle ts type assertions in expressions ([#13397](https://github.com/vuejs/core/issues/13397)) ([e6544ac](https://github.com/vuejs/core/commit/e6544ac292b5b473274f87cdb83ebeac3e7e61a4)), closes [#13395](https://github.com/vuejs/core/issues/13395)
|
||||||
|
* **compiler-core:** fix v-bind shorthand handling for in-DOM templates ([#13933](https://github.com/vuejs/core/issues/13933)) ([b3cca26](https://github.com/vuejs/core/commit/b3cca2611c656b85f0c4e737b9ec248d2627dded)), closes [#13930](https://github.com/vuejs/core/issues/13930)
|
||||||
|
* **compiler-sfc:** resolve numeric literals and template literals without expressions as static property key ([#13998](https://github.com/vuejs/core/issues/13998)) ([75d44c7](https://github.com/vuejs/core/commit/75d44c718981f91843e197265cc68e82fe2532dd))
|
||||||
|
* **compiler-ssr:** textarea with v-text directive SSR ([#13975](https://github.com/vuejs/core/issues/13975)) ([006a0c1](https://github.com/vuejs/core/commit/006a0c1011a224bcbf21195c6df76812c3a7e757))
|
||||||
|
* **compiler:** using guard instead of non-nullish assertion ([#13982](https://github.com/vuejs/core/issues/13982)) ([dcc6f36](https://github.com/vuejs/core/commit/dcc6f362577ed86ccad31c2623c6cf75137dd27a))
|
||||||
|
* **custom-element:** batch custom element prop patching ([#13478](https://github.com/vuejs/core/issues/13478)) ([c13e674](https://github.com/vuejs/core/commit/c13e674fb9f92ab9339d28a862d18de460faf56e)), closes [#12619](https://github.com/vuejs/core/issues/12619)
|
||||||
|
* **custom-element:** optimize slot retrieval to avoid duplicates ([#13961](https://github.com/vuejs/core/issues/13961)) ([84ca349](https://github.com/vuejs/core/commit/84ca349fef73f6f55fc98299fcfa5c1eeef721db)), closes [#13955](https://github.com/vuejs/core/issues/13955)
|
||||||
|
* **hydration:** avoid mismatch during hydrate text with newlines in interpolation ([#9232](https://github.com/vuejs/core/issues/9232)) ([6cbdf78](https://github.com/vuejs/core/commit/6cbdf7823b0c961190bee5b7c117b7f2bbeb832f)), closes [#9229](https://github.com/vuejs/core/issues/9229)
|
||||||
|
* **runtime-core:** pass props and children to loadingComponent ([#13997](https://github.com/vuejs/core/issues/13997)) ([40c4b2a](https://github.com/vuejs/core/commit/40c4b2a876ce606973521dfc3024e26bfc10953a))
|
||||||
|
* **runtime-dom:** ensure iframe sandbox is handled as an attribute to prevent unintended behavior ([#13950](https://github.com/vuejs/core/issues/13950)) ([5689884](https://github.com/vuejs/core/commit/5689884c8e32cda6a802ac36b4d23218f67b38ed)), closes [#13946](https://github.com/vuejs/core/issues/13946)
|
||||||
|
* **suspense:** clear placeholder and fallback el after resolve to enable GC ([#13928](https://github.com/vuejs/core/issues/13928)) ([f411c66](https://github.com/vuejs/core/commit/f411c6604c12c531883aa0d30b81a7f69092f8a6))
|
||||||
|
* **transition-group:** use offsetLeft and offsetTop instead of getBoundingClientRect to avoid transform scale affect animation ([#6108](https://github.com/vuejs/core/issues/6108)) ([dc4dd59](https://github.com/vuejs/core/commit/dc4dd594fbecce6ed7f44ffa69dc8b5d022287b6)), closes [#6105](https://github.com/vuejs/core/issues/6105)
|
||||||
|
* **v-model:** handle number modifier on change ([#13959](https://github.com/vuejs/core/issues/13959)) ([8fbe48f](https://github.com/vuejs/core/commit/8fbe48fe396d830999afd07f9413d899157d5f5e)), closes [#13958](https://github.com/vuejs/core/issues/13958)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.5.22](https://github.com/vuejs/core/compare/v3.5.21...v3.5.22) (2025-09-25)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler-core:** identifiers in switch-case should not be inferred as references ([#13923](https://github.com/vuejs/core/issues/13923)) ([5953c9f](https://github.com/vuejs/core/commit/5953c9ff90090e128372f645d377bd99137a5fb4))
|
||||||
|
* **compiler-dom:** nodes with v-once shouldn't be stringified ([#13878](https://github.com/vuejs/core/issues/13878)) ([95c1975](https://github.com/vuejs/core/commit/95c197560409f5d39a0d376c0a43d89a47a604e8))
|
||||||
|
* **compiler-sfc:** add support for `@vue-ignore` in runtime type resolution ([#13906](https://github.com/vuejs/core/issues/13906)) ([ba7f7f9](https://github.com/vuejs/core/commit/ba7f7f90f689f6e7e0417a192d081db542de28ec))
|
||||||
|
* **compiler-sfc:** enhance inferRuntimeType to support TSMappedType with indexed access ([#13848](https://github.com/vuejs/core/issues/13848)) ([e388f1a](https://github.com/vuejs/core/commit/e388f1a09fde78cf006450f060813d972ac8c23d)), closes [#13847](https://github.com/vuejs/core/issues/13847)
|
||||||
|
* **compiler-sfc:** ensure css custom properties do not start with a digit ([#13870](https://github.com/vuejs/core/issues/13870)) ([9c27951](https://github.com/vuejs/core/commit/9c279517b9bc1f4c250c555ec9b9eb6104756d56))
|
||||||
|
* **compiler-sfc:** ensure props bindings register before compiling template ([#13922](https://github.com/vuejs/core/issues/13922)) ([abd5638](https://github.com/vuejs/core/commit/abd563822abafe63047f7b599bff266380ee2b64)), closes [#13920](https://github.com/vuejs/core/issues/13920)
|
||||||
|
* **compiler-ssr:** ensure v-show has a higher priority in SSR ([#12171](https://github.com/vuejs/core/issues/12171)) ([836b829](https://github.com/vuejs/core/commit/836b82976ffb7aa0ea9cbe417bef07deae3ca47c)), closes [#12162](https://github.com/vuejs/core/issues/12162)
|
||||||
|
* **custom-element:** properly mount multiple Teleports in custom element component w/ shadowRoot false ([#13900](https://github.com/vuejs/core/issues/13900)) ([5e1e791](https://github.com/vuejs/core/commit/5e1e791880238380a1038ae2c505e206ceb34d77)), closes [#13899](https://github.com/vuejs/core/issues/13899)
|
||||||
|
* **custom-element:** set prop runs pending mutations before disconnect ([#13897](https://github.com/vuejs/core/issues/13897)) ([c4a88cd](https://github.com/vuejs/core/commit/c4a88cdd0dfed3ef46a8aa9be448c01781fdc4f0)), closes [#13315](https://github.com/vuejs/core/issues/13315)
|
||||||
|
* **custom-element:** use `PatchFlags.BAIL` for slot when props are present ([#13907](https://github.com/vuejs/core/issues/13907)) ([5358bca](https://github.com/vuejs/core/commit/5358bca4a80cf52d19ed91967eeaa025a786083d)), closes [#13904](https://github.com/vuejs/core/issues/13904)
|
||||||
|
* **reactivity:** respect readonly during ref unwrapping ([#13905](https://github.com/vuejs/core/issues/13905)) ([aba7fed](https://github.com/vuejs/core/commit/aba7feda1703e69e5a7c37f784718de0371adadc)), closes [#13903](https://github.com/vuejs/core/issues/13903)
|
||||||
|
* **reactivity:** update iterator to check for completion instead of value presence ([#13761](https://github.com/vuejs/core/issues/13761)) ([2078f8b](https://github.com/vuejs/core/commit/2078f8b7565cf637f47fcd5b0abdfb2b264225bb))
|
||||||
|
* **runtime-core:** simplify block-tracking disabling in `h` helper ([#13841](https://github.com/vuejs/core/issues/13841)) ([75220c7](https://github.com/vuejs/core/commit/75220c7995a13a483ae9599a739075be1c8e17f8))
|
||||||
|
* **transition-group:** run `forceReflow` on the correct document (fix [#13849](https://github.com/vuejs/core/issues/13849)) ([#13853](https://github.com/vuejs/core/issues/13853)) ([1be5ddf](https://github.com/vuejs/core/commit/1be5ddfe878c8bfddaa2c50e82105b247f50b9ba))
|
||||||
|
* **types:** more precise types for Events and added missing definitions ([#9675](https://github.com/vuejs/core/issues/9675)) ([8bb8fb2](https://github.com/vuejs/core/commit/8bb8fb236257c03bfa0bccadcfffe3eb4592f71b))
|
||||||
|
* **types:** set dom stub type to `never` instead of `{}` ([#13915](https://github.com/vuejs/core/issues/13915)) ([8620a61](https://github.com/vuejs/core/commit/8620a616eb02a64fe32dd52d9be68e360687ef9d)), closes [#11564](https://github.com/vuejs/core/issues/11564)
|
||||||
|
* **types:** widen directive arg type from string to any ([#13758](https://github.com/vuejs/core/issues/13758)) ([4b71706](https://github.com/vuejs/core/commit/4b7170625d0bc93b26a3343aeda98850c1138f82)), closes [#13757](https://github.com/vuejs/core/issues/13757)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **custom-element:** allow specifying additional options for `shadowRoot` in custom elements ([#12965](https://github.com/vuejs/core/issues/12965)) ([47e628d](https://github.com/vuejs/core/commit/47e628df1ce1914c5677010ad5bddd18d037cb3c)), closes [#12964](https://github.com/vuejs/core/issues/12964)
|
||||||
|
|
||||||
|
|
||||||
|
### Reverts
|
||||||
|
|
||||||
|
* Revert "fix(hmr): prevent __VUE_HMR_RUNTIME__ from being overwritten by vue runtime in 3rd-party libraries" (#13925) ([6b68f72](https://github.com/vuejs/core/commit/6b68f72673dac5db349f26eeefb2f2e0e342586b)), closes [#13925](https://github.com/vuejs/core/issues/13925)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.5.21](https://github.com/vuejs/core/compare/v3.5.20...v3.5.21) (2025-09-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler-core:** force dynamic slots when slot referencing scope vars ([#9427](https://github.com/vuejs/core/issues/9427)) ([99d54b2](https://github.com/vuejs/core/commit/99d54b28b46dbea006205dff71c383a31dd1b87a)), closes [#9380](https://github.com/vuejs/core/issues/9380)
|
||||||
|
* **compiler-sfc:** check lang before attempt to compile script ([#13508](https://github.com/vuejs/core/issues/13508)) ([55922ff](https://github.com/vuejs/core/commit/55922ff3168a1397ad72f18946eb1c4051cdab3b)), closes [#8368](https://github.com/vuejs/core/issues/8368)
|
||||||
|
* **compiler-sfc:** support `${configDir}` in paths for TypeScript 5.5+ ([#13491](https://github.com/vuejs/core/issues/13491)) ([8696e34](https://github.com/vuejs/core/commit/8696e346b4780d88247464490f1a992cc0c3658c)), closes [#13484](https://github.com/vuejs/core/issues/13484)
|
||||||
|
* **compiler-sfc:** support global augments with named exports ([#13789](https://github.com/vuejs/core/issues/13789)) ([35da3c6](https://github.com/vuejs/core/commit/35da3c6dcb30030ef60fa22e30aa83a56e396c60))
|
||||||
|
* **custom-element:** prevent defineCustomElement from mutating the options object ([#13791](https://github.com/vuejs/core/issues/13791)) ([e322436](https://github.com/vuejs/core/commit/e322436887549c129e61eb58a0084167103451bb))
|
||||||
|
* **hmr:** prevent `__VUE_HMR_RUNTIME__` from being overwritten by vue runtime in 3rd-party libraries ([#13817](https://github.com/vuejs/core/issues/13817)) ([1392734](https://github.com/vuejs/core/commit/1392734ae5d5a3b2be124753e198eafa324f6815)), closes [vitejs/vite-plugin-vue#644](https://github.com/vitejs/vite-plugin-vue/issues/644)
|
||||||
|
* **hmr:** prevent update unmounting component during HMR reload ([#13815](https://github.com/vuejs/core/issues/13815)) ([ef20b86](https://github.com/vuejs/core/commit/ef20b86b36a127e317f8981df970dc8efd277053)), closes [vitejs/vite-plugin-vue#599](https://github.com/vitejs/vite-plugin-vue/issues/599)
|
||||||
|
* **runtime-core:** disable tracking block in h function ([#8213](https://github.com/vuejs/core/issues/8213)) ([8f6b505](https://github.com/vuejs/core/commit/8f6b5050518441a5047d128138da44f798836002)), closes [#6913](https://github.com/vuejs/core/issues/6913)
|
||||||
|
* **runtime-core:** use separate emits caches for components and mixins ([#11661](https://github.com/vuejs/core/issues/11661)) ([15fc75f](https://github.com/vuejs/core/commit/15fc75f4031dea805c3bbb67a75e48a9dc307c11))
|
||||||
|
* **Suspence:** handle Suspense + KeepAlive HMR updating edge case ([#13076](https://github.com/vuejs/core/issues/13076)) ([5d75a17](https://github.com/vuejs/core/commit/5d75a170c8d23acd11ef2513173d4cbc4d0b54de)), closes [#13075](https://github.com/vuejs/core/issues/13075)
|
||||||
|
* **Teleport:** hydrate disabled Teleport with undefined target ([#11235](https://github.com/vuejs/core/issues/11235)) ([00978f7](https://github.com/vuejs/core/commit/00978f7d14e85b49d9d334ea92fa8c03733ce64c)), closes [#11230](https://github.com/vuejs/core/issues/11230)
|
||||||
|
* **templateRef:** prevent unnecessary set ref on dynamic ref change or component unmount ([#12642](https://github.com/vuejs/core/issues/12642)) ([93ba107](https://github.com/vuejs/core/commit/93ba10767230872fcdca974a1e19e8bd69b7eb6a)), closes [#12639](https://github.com/vuejs/core/issues/12639)
|
||||||
|
* **watch:** use maximum depth for duplicates ([#13434](https://github.com/vuejs/core/issues/13434)) ([f2699a5](https://github.com/vuejs/core/commit/f2699a5cb376ffa452a54feb171c14411c67287c))
|
||||||
|
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* improve regexp performance with non-capturing groups ([#13567](https://github.com/vuejs/core/issues/13567)) ([1e8b65a](https://github.com/vuejs/core/commit/1e8b65aa4934c94ef6142b4f49cdfb13ba5e6ce5))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.5.20](https://github.com/vuejs/core/compare/v3.5.19...v3.5.20) (2025-08-25)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **runtime-dom:** add name to vShow for prop mismatch check ([#13806](https://github.com/vuejs/core/issues/13806)) ([1031e8d](https://github.com/vuejs/core/commit/1031e8de08b735059217b1ad0057f62565c99c4f)), closes [#13805](https://github.com/vuejs/core/issues/13805) re-fix [#13744](https://github.com/vuejs/core/issues/13744) revert [#13777](https://github.com/vuejs/core/issues/13777)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.5.19](https://github.com/vuejs/core/compare/v3.5.18...v3.5.19) (2025-08-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler-core:** adjacent v-else should cause a compiler error ([#13699](https://github.com/vuejs/core/issues/13699)) ([911e670](https://github.com/vuejs/core/commit/911e67045e2a63e0ecbd198ed4f567530f6d1c17)), closes [#13698](https://github.com/vuejs/core/issues/13698)
|
||||||
|
* **compiler-core:** prevent cached array children from retaining detached dom nodes ([#13691](https://github.com/vuejs/core/issues/13691)) ([7f60ef8](https://github.com/vuejs/core/commit/7f60ef83e735dbd29d323347acecf69f22b06d53)), closes [element-plus/element-plus#21408](https://github.com/element-plus/element-plus/issues/21408) [#13211](https://github.com/vuejs/core/issues/13211)
|
||||||
|
* **compiler-sfc:** improve type inference for generic type aliases types ([#12876](https://github.com/vuejs/core/issues/12876)) ([d9dd628](https://github.com/vuejs/core/commit/d9dd628800ae32e673bdfabfe79f1988037991d0)), closes [#12872](https://github.com/vuejs/core/issues/12872)
|
||||||
|
* **compiler-sfc:** throw mismatched script langs error before invoking babel ([#13194](https://github.com/vuejs/core/issues/13194)) ([0562548](https://github.com/vuejs/core/commit/0562548ab3a040073386021222225e0e9d43c632)), closes [#13193](https://github.com/vuejs/core/issues/13193)
|
||||||
|
* **compiler-ssr:** disable v-memo transform in ssr vdom fallback branch ([#13725](https://github.com/vuejs/core/issues/13725)) ([0a202d8](https://github.com/vuejs/core/commit/0a202d890ff2a564b1fab51e4ac621708640818e)), closes [#13724](https://github.com/vuejs/core/issues/13724)
|
||||||
|
* **devtools:** clear performance measures ([#13701](https://github.com/vuejs/core/issues/13701)) ([c875019](https://github.com/vuejs/core/commit/c875019d49b4c36a88d929ccadc31ad414747c7b)), closes [#13700](https://github.com/vuejs/core/issues/13700)
|
||||||
|
* **hmr:** prevent updating unmounting component during HMR rerender ([#13775](https://github.com/vuejs/core/issues/13775)) ([6e5143d](https://github.com/vuejs/core/commit/6e5143d9635dac3f20fb394a827109df30e232ae)), closes [#13771](https://github.com/vuejs/core/issues/13771) [#13772](https://github.com/vuejs/core/issues/13772)
|
||||||
|
* **hydration:** also set vShow name if `__FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__` flag is enabled ([#13777](https://github.com/vuejs/core/issues/13777)) ([439e1a5](https://github.com/vuejs/core/commit/439e1a543e62de4dbf7658d78d05c358c9677c86)), closes [#13744](https://github.com/vuejs/core/issues/13744)
|
||||||
|
* **reactivity:** warn on nested readonly ref update during unwrapping ([#12141](https://github.com/vuejs/core/issues/12141)) ([1498821](https://github.com/vuejs/core/commit/1498821ed9eeb22a0767e53ddc1f6a2840598a29))
|
||||||
|
* **runtime-core:** avoid setting direct ref of useTemplateRef in dev ([#13449](https://github.com/vuejs/core/issues/13449)) ([4a2953f](https://github.com/vuejs/core/commit/4a2953f57b90dfc24e34ff1a87cc1ebb0b97636d))
|
||||||
|
* **runtime-core:** improve consistency of `PublicInstanceProxyHandlers.has` ([#13507](https://github.com/vuejs/core/issues/13507)) ([d7283f3](https://github.com/vuejs/core/commit/d7283f3b7f0631c8b8a4a31a05983dac9f078c4f))
|
||||||
|
* **suspense:** don't immediately resolve suspense on last dep unmount ([#13456](https://github.com/vuejs/core/issues/13456)) ([a871315](https://github.com/vuejs/core/commit/a8713159ee24602c7c2b70c5fd52d2e5cd37dca5)), closes [#13453](https://github.com/vuejs/core/issues/13453)
|
||||||
|
* **transition:** handle KeepAlive + transition leaving edge case ([#13152](https://github.com/vuejs/core/issues/13152)) ([3190b17](https://github.com/vuejs/core/commit/3190b179b0545a3dc4549737793eec630cf9f0d1)), closes [#13153](https://github.com/vuejs/core/issues/13153)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.5.18](https://github.com/vuejs/core/compare/v3.5.17...v3.5.18) (2025-07-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler-core:** avoid cached text vnodes retaining detached DOM nodes ([#13662](https://github.com/vuejs/core/issues/13662)) ([00695a5](https://github.com/vuejs/core/commit/00695a5b41b2d032deaeada83831ff83aa6bfd4e)), closes [#13661](https://github.com/vuejs/core/issues/13661)
|
||||||
|
* **compiler-core:** avoid self updates of `v-pre` ([#12556](https://github.com/vuejs/core/issues/12556)) ([21b685a](https://github.com/vuejs/core/commit/21b685ad9d9d0e6060fc7d07b719bf35f2d9ae1f))
|
||||||
|
* **compiler-core:** identifiers in function parameters should not be inferred as references ([#13548](https://github.com/vuejs/core/issues/13548)) ([9b02923](https://github.com/vuejs/core/commit/9b029239edf88558465b941e1e4c085f92b1ebff))
|
||||||
|
* **compiler-core:** recognize empty string as non-identifier ([#12553](https://github.com/vuejs/core/issues/12553)) ([ce93339](https://github.com/vuejs/core/commit/ce933390ad1c72bed258f7ad959a78f0e8acdf57))
|
||||||
|
* **compiler-core:** transform empty `v-bind` dynamic argument content correctly ([#12554](https://github.com/vuejs/core/issues/12554)) ([d3af67e](https://github.com/vuejs/core/commit/d3af67e878790892f9d34cfea15d13625aabe733))
|
||||||
|
* **compiler-sfc:** transform empty srcset w/ includeAbsolute: true ([#13639](https://github.com/vuejs/core/issues/13639)) ([d8e40ef](https://github.com/vuejs/core/commit/d8e40ef7e1c20ee86b294e7cf78e2de60d12830e)), closes [vitejs/vite-plugin-vue#631](https://github.com/vitejs/vite-plugin-vue/issues/631)
|
||||||
|
* **css-vars:** nullish v-bind in style should not lead to unexpected inheritance ([#12461](https://github.com/vuejs/core/issues/12461)) ([c85f1b5](https://github.com/vuejs/core/commit/c85f1b5a132eb8ec25f71b250e25e65a5c20964f)), closes [#12434](https://github.com/vuejs/core/issues/12434) [#12439](https://github.com/vuejs/core/issues/12439) [#7474](https://github.com/vuejs/core/issues/7474) [#7475](https://github.com/vuejs/core/issues/7475)
|
||||||
|
* **custom-element:** ensure exposed methods are accessible from custom elements by making them enumerable ([#13634](https://github.com/vuejs/core/issues/13634)) ([90573b0](https://github.com/vuejs/core/commit/90573b06bf6fb6c14c6bbff6c4e34e0ab108953a)), closes [#13632](https://github.com/vuejs/core/issues/13632)
|
||||||
|
* **hydration:** prevent lazy hydration for updated components ([#13511](https://github.com/vuejs/core/issues/13511)) ([a9269c6](https://github.com/vuejs/core/commit/a9269c642bf944560bc29adb5dae471c11cd9ee8)), closes [#13510](https://github.com/vuejs/core/issues/13510)
|
||||||
|
* **runtime-core:** ensure correct anchor el for unresolved async components ([#13560](https://github.com/vuejs/core/issues/13560)) ([7f29943](https://github.com/vuejs/core/commit/7f2994393dcdb82cacbf62e02b5ba5565f32588b)), closes [#13559](https://github.com/vuejs/core/issues/13559)
|
||||||
|
* **slots:** refine internal key checking to support slot names starting with an underscore ([#13612](https://github.com/vuejs/core/issues/13612)) ([c5f7db1](https://github.com/vuejs/core/commit/c5f7db11542bb2246363aef78c88a8e6cef0ee93)), closes [#13611](https://github.com/vuejs/core/issues/13611)
|
||||||
|
* **ssr:** ensure empty slots render as a comment node in Transition ([#13396](https://github.com/vuejs/core/issues/13396)) ([8cfc10a](https://github.com/vuejs/core/commit/8cfc10a80b9cbf5d801ab149e49b8506d192e7e1)), closes [#13394](https://github.com/vuejs/core/issues/13394)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.5.17](https://github.com/vuejs/core/compare/v3.5.16...v3.5.17) (2025-06-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compat:** allow v-model built in modifiers on component ([#12654](https://github.com/vuejs/core/issues/12654)) ([cb14b86](https://github.com/vuejs/core/commit/cb14b860f150c4a83bcd52cd26096b7a5aa3a2bf)), closes [#12652](https://github.com/vuejs/core/issues/12652)
|
||||||
|
* **compile-sfc:** handle mapped types work with omit and pick ([#12648](https://github.com/vuejs/core/issues/12648)) ([4eb46e4](https://github.com/vuejs/core/commit/4eb46e443f1878199755cb73d481d318a9714392)), closes [#12647](https://github.com/vuejs/core/issues/12647)
|
||||||
|
* **compiler-core:** do not increase newlines in `InEntity` state ([#13362](https://github.com/vuejs/core/issues/13362)) ([f05a8d6](https://github.com/vuejs/core/commit/f05a8d613bd873b811cfdb9979ccac8382dba322))
|
||||||
|
* **compiler-core:** ignore whitespace when matching adjacent v-if ([#12321](https://github.com/vuejs/core/issues/12321)) ([10ebcef](https://github.com/vuejs/core/commit/10ebcef8c870dbc042b0ea49b1424b2e8f692145)), closes [#9173](https://github.com/vuejs/core/issues/9173)
|
||||||
|
* **compiler-core:** prevent comments from blocking static node hoisting ([#13345](https://github.com/vuejs/core/issues/13345)) ([55dad62](https://github.com/vuejs/core/commit/55dad625acd9e9ddd5a933d5e323ecfdec1a612f)), closes [#13344](https://github.com/vuejs/core/issues/13344)
|
||||||
|
* **compiler-sfc:** improved type resolution for function type aliases ([#13452](https://github.com/vuejs/core/issues/13452)) ([f3479aa](https://github.com/vuejs/core/commit/f3479aac9625f4459e650d1c0a70e73863147903)), closes [#13444](https://github.com/vuejs/core/issues/13444)
|
||||||
|
* **custom-element:** ensure configureApp is applied to async component ([#12607](https://github.com/vuejs/core/issues/12607)) ([5ba1afb](https://github.com/vuejs/core/commit/5ba1afba09c3ea56c1c17484f5d8aeae210ce52a)), closes [#12448](https://github.com/vuejs/core/issues/12448)
|
||||||
|
* **custom-element:** prevent injecting child styles if shadowRoot is false ([#12769](https://github.com/vuejs/core/issues/12769)) ([73055d8](https://github.com/vuejs/core/commit/73055d8d9578d485e3fe846726b50666e1aa56f5)), closes [#12630](https://github.com/vuejs/core/issues/12630)
|
||||||
|
* **reactivity:** add `__v_skip` flag to `Dep` to prevent reactive conversion ([#12804](https://github.com/vuejs/core/issues/12804)) ([e8d8f5f](https://github.com/vuejs/core/commit/e8d8f5f604e821acc46b4200d5b06979c05af1c2)), closes [#12803](https://github.com/vuejs/core/issues/12803)
|
||||||
|
* **runtime-core:** unset old ref during patching when new ref is absent ([#12900](https://github.com/vuejs/core/issues/12900)) ([47ddf98](https://github.com/vuejs/core/commit/47ddf986021dff8de68b0da72787e53a6c19de4c)), closes [#12898](https://github.com/vuejs/core/issues/12898)
|
||||||
|
* **slots:** make cache indexes marker non-enumerable ([#13469](https://github.com/vuejs/core/issues/13469)) ([919c447](https://github.com/vuejs/core/commit/919c44744bba1f0c661c87d2059c3b429611aa7e)), closes [#13468](https://github.com/vuejs/core/issues/13468)
|
||||||
|
* **ssr:** handle initial selected state for select with v-model + v-for/v-if option ([#13487](https://github.com/vuejs/core/issues/13487)) ([1552095](https://github.com/vuejs/core/commit/15520954f9f1c7f834175938a50dba5d4be0e6c4)), closes [#13486](https://github.com/vuejs/core/issues/13486)
|
||||||
|
* **types:** typo of `vOnce` and `vSlot` ([#13343](https://github.com/vuejs/core/issues/13343)) ([762fae4](https://github.com/vuejs/core/commit/762fae4b57ad60602e5c84465a3bff562785b314))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [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)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **reactivity:** fix property dep removal regression ([6001e5c](https://github.com/vuejs/core/commit/6001e5c81a05c894586f9287fbd991677bdd0455)), closes [#12020](https://github.com/vuejs/core/issues/12020) [#12021](https://github.com/vuejs/core/issues/12021)
|
||||||
|
* **reactivity:** fix recursive sync watcher on computed edge case ([10ff159](https://github.com/vuejs/core/commit/10ff15924053d9bd95ad706f78ce09e288213fcf)), closes [#12033](https://github.com/vuejs/core/issues/12033) [#12037](https://github.com/vuejs/core/issues/12037)
|
||||||
|
* **runtime-core:** avoid rendering plain object as VNode ([#12038](https://github.com/vuejs/core/issues/12038)) ([cb34b28](https://github.com/vuejs/core/commit/cb34b28a4a9bf868be4785b001c526163eda342e)), closes [#12035](https://github.com/vuejs/core/issues/12035) [vitejs/vite-plugin-vue#353](https://github.com/vitejs/vite-plugin-vue/issues/353)
|
||||||
|
* **runtime-core:** make useId() always return a string ([a177092](https://github.com/vuejs/core/commit/a177092754642af2f98c33a4feffe8f198c3c950))
|
||||||
|
* **types:** correct type inference of union event names ([#12022](https://github.com/vuejs/core/issues/12022)) ([4da6881](https://github.com/vuejs/core/commit/4da688141d9e7c15b622c289deaa81b11845b2c7))
|
||||||
|
* **vue:** properly cache runtime compilation ([#12019](https://github.com/vuejs/core/issues/12019)) ([fa0ba24](https://github.com/vuejs/core/commit/fa0ba24b3ace02d7ecab65e57c2bea89a2550dcb))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.5.8](https://github.com/vuejs/core/compare/v3.5.7...v3.5.8) (2024-09-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **reactivity:** do not remove dep from depsMap when cleaning up deps of computed ([#11995](https://github.com/vuejs/core/issues/11995)) ([0267a58](https://github.com/vuejs/core/commit/0267a588017eee4951ac2a877fe1ccae84cad905))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.5.7](https://github.com/vuejs/core/compare/v3.5.6...v3.5.7) (2024-09-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compile-core:** fix v-model with newlines edge case ([#11960](https://github.com/vuejs/core/issues/11960)) ([6224288](https://github.com/vuejs/core/commit/62242886d705ece88dbcad45bb78072ecccad0ca)), closes [#8306](https://github.com/vuejs/core/issues/8306)
|
||||||
|
* **compiler-sfc:** initialize scope with null prototype object ([#11963](https://github.com/vuejs/core/issues/11963)) ([215e154](https://github.com/vuejs/core/commit/215e15407294bf667261360218f975b88c99c2e5))
|
||||||
|
* **hydration:** avoid observing non-Element node ([#11954](https://github.com/vuejs/core/issues/11954)) ([7257e6a](https://github.com/vuejs/core/commit/7257e6a34200409b3fc347d3bb807e11e2785974)), closes [#11952](https://github.com/vuejs/core/issues/11952)
|
||||||
|
* **reactivity:** do not remove dep from depsMap when unsubbed by computed ([960706e](https://github.com/vuejs/core/commit/960706eebf73f08ebc9d5dd853a05def05e2c153))
|
||||||
|
* **reactivity:** fix dev-only memory leak by updating dep.subsHead on sub removal ([5c8b76e](https://github.com/vuejs/core/commit/5c8b76ed6cfbbcee4cbaac0b72beab7291044e4f)), closes [#11956](https://github.com/vuejs/core/issues/11956)
|
||||||
|
* **reactivity:** fix memory leak from dep instances of garbage collected objects ([235ea47](https://github.com/vuejs/core/commit/235ea4772ed2972914cf142da8b7ac1fb04f7585)), closes [#11979](https://github.com/vuejs/core/issues/11979) [#11971](https://github.com/vuejs/core/issues/11971)
|
||||||
|
* **reactivity:** fix triggerRef call on ObjectRefImpl returned by toRef ([#11986](https://github.com/vuejs/core/issues/11986)) ([b030c8b](https://github.com/vuejs/core/commit/b030c8bc7327877efb98aa3d9a58eb287a6ff07a)), closes [#11982](https://github.com/vuejs/core/issues/11982)
|
||||||
|
* **scheduler:** ensure recursive jobs can't be queued twice ([#11955](https://github.com/vuejs/core/issues/11955)) ([d18d6aa](https://github.com/vuejs/core/commit/d18d6aa1b20dc57a8103c51ec4d61e8e53ed936d))
|
||||||
|
* **ssr:** don't render comments in TransitionGroup ([#11961](https://github.com/vuejs/core/issues/11961)) ([a2f6ede](https://github.com/vuejs/core/commit/a2f6edeb02faedbb673c4bc5c6a59d9a79a37d07)), closes [#11958](https://github.com/vuejs/core/issues/11958)
|
||||||
|
* **transition:** respect `duration` setting even when it is `0` ([#11967](https://github.com/vuejs/core/issues/11967)) ([f927a4a](https://github.com/vuejs/core/commit/f927a4ae6f7c453f70ba89498ee0c737dc9866fd))
|
||||||
|
* **types:** correct type inference of all-optional props ([#11644](https://github.com/vuejs/core/issues/11644)) ([9eca65e](https://github.com/vuejs/core/commit/9eca65ee9871d1ac878755afa9a3eb1b02030350)), closes [#11733](https://github.com/vuejs/core/issues/11733) [vuejs/language-tools#4704](https://github.com/vuejs/language-tools/issues/4704)
|
||||||
|
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* **hydration:** avoid observer if element is in viewport ([#11639](https://github.com/vuejs/core/issues/11639)) ([e075dfa](https://github.com/vuejs/core/commit/e075dfad5c7649c6045e3711687ec888e7aa1a39))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.5.6](https://github.com/vuejs/core/compare/v3.5.5...v3.5.6) (2024-09-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compile-dom:** should be able to stringify mathML ([#11891](https://github.com/vuejs/core/issues/11891)) ([85c138c](https://github.com/vuejs/core/commit/85c138ced108268f7656b568dfd3036a1e0aae34))
|
||||||
|
* **compiler-sfc:** preserve old behavior when using withDefaults with desutructure ([8492c3c](https://github.com/vuejs/core/commit/8492c3c49a922363d6c77ef192c133a8fbce6514)), closes [#11930](https://github.com/vuejs/core/issues/11930)
|
||||||
|
* **reactivity:** avoid exponential perf cost and reduce call stack depth for deeply chained computeds ([#11944](https://github.com/vuejs/core/issues/11944)) ([c74bb8c](https://github.com/vuejs/core/commit/c74bb8c2dd9e82aaabb0a2a2b368e900929b513b)), closes [#11928](https://github.com/vuejs/core/issues/11928)
|
||||||
|
* **reactivity:** rely on dirty check only when computed has deps ([#11931](https://github.com/vuejs/core/issues/11931)) ([aa5dafd](https://github.com/vuejs/core/commit/aa5dafd2b55d42d6a29316a3bc91aea85c676a0b)), closes [#11929](https://github.com/vuejs/core/issues/11929)
|
||||||
|
* **watch:** `once` option should be ignored by watchEffect ([#11884](https://github.com/vuejs/core/issues/11884)) ([49fa673](https://github.com/vuejs/core/commit/49fa673493d93b77ddba2165ab6545bae84fd1ae))
|
||||||
|
* **watch:** unwatch should be callable during SSR ([#11925](https://github.com/vuejs/core/issues/11925)) ([2d6adf7](https://github.com/vuejs/core/commit/2d6adf78a047eed091db277ffbd9df0822fb0bdd)), closes [#11924](https://github.com/vuejs/core/issues/11924)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.5.5](https://github.com/vuejs/core/compare/v3.5.4...v3.5.5) (2024-09-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler-core:** fix handling of delimiterOpen in VPre ([#11915](https://github.com/vuejs/core/issues/11915)) ([706d4ac](https://github.com/vuejs/core/commit/706d4ac1d0210b2d9134b3228280187fe02fc971)), closes [#11913](https://github.com/vuejs/core/issues/11913)
|
||||||
|
* **compiler-dom:** fix stringify static edge for partially eligible chunks in cached parent ([1d99d61](https://github.com/vuejs/core/commit/1d99d61c1bd77f9ea6743f6214a82add8346a121)), closes [#11879](https://github.com/vuejs/core/issues/11879) [#11890](https://github.com/vuejs/core/issues/11890)
|
||||||
|
* **compiler-dom:** should ignore leading newline in `<textarea>` per spec ([3c4bf76](https://github.com/vuejs/core/commit/3c4bf7627649ec1e3220f8c4e4163c20d2afb367))
|
||||||
|
* **compiler-sfc:** nested css supports atrule and comment ([#11899](https://github.com/vuejs/core/issues/11899)) ([0e7bc71](https://github.com/vuejs/core/commit/0e7bc717e6640644f062957ec5031506f0dab215)), closes [#11896](https://github.com/vuejs/core/issues/11896)
|
||||||
|
* **custom-element:** handle nested customElement mount w/ shadowRoot false ([#11861](https://github.com/vuejs/core/issues/11861)) ([f2d8019](https://github.com/vuejs/core/commit/f2d801918841e7673ff3f048d0d895592a2f7e23)), closes [#11851](https://github.com/vuejs/core/issues/11851) [#11871](https://github.com/vuejs/core/issues/11871)
|
||||||
|
* **hmr:** reload async child wrapped in Suspense + KeepAlive ([#11907](https://github.com/vuejs/core/issues/11907)) ([10a2c60](https://github.com/vuejs/core/commit/10a2c6053bd30d160d0214bb3566f540187e6874)), closes [#11868](https://github.com/vuejs/core/issues/11868)
|
||||||
|
* **hydration:** fix mismatch of leading newline in `<textarea>` and `<pre>` ([a5f3c2e](https://github.com/vuejs/core/commit/a5f3c2eb4d2e7fae93ff93ce865b269f01cc825e)), closes [#11873](https://github.com/vuejs/core/issues/11873) [#11874](https://github.com/vuejs/core/issues/11874)
|
||||||
|
* **reactivity:** properly clean up deps, fix memory leak ([8ea5d6d](https://github.com/vuejs/core/commit/8ea5d6d6981ab7febda0be43c3c92b18869c3a2a)), closes [#11901](https://github.com/vuejs/core/issues/11901)
|
||||||
|
* **runtime-core:** properly update async component nested in KeepAlive ([#11917](https://github.com/vuejs/core/issues/11917)) ([7fe6c79](https://github.com/vuejs/core/commit/7fe6c795a1fc7ddcea5ad91a56141561192373ac)), closes [#11916](https://github.com/vuejs/core/issues/11916)
|
||||||
|
* **TransitionGroup:** not warn unkeyed text children with whitespece preserve ([#11888](https://github.com/vuejs/core/issues/11888)) ([7571f20](https://github.com/vuejs/core/commit/7571f20bc3d1854377a146f41d211e05bb68cd47)), closes [#11885](https://github.com/vuejs/core/issues/11885)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [3.5.4](https://github.com/vuejs/core/compare/v3.5.3...v3.5.4) (2024-09-10)
|
## [3.5.4](https://github.com/vuejs/core/compare/v3.5.3...v3.5.4) (2024-09-10)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,3 +13,4 @@ We would like to thank the following security researchers for responsibly disclo
|
||||||
- Jeet Pal - [@jeetpal2007](https://github.com/jeetpal2007) | [Email](mailto:jeetpal2007@gmail.com) | [LinkedIn](https://in.linkedin.com/in/jeet-pal-22601a290)
|
- Jeet Pal - [@jeetpal2007](https://github.com/jeetpal2007) | [Email](mailto:jeetpal2007@gmail.com) | [LinkedIn](https://in.linkedin.com/in/jeet-pal-22601a290)
|
||||||
- Mix - [@mnixry](https://github.com/mnixry)
|
- Mix - [@mnixry](https://github.com/mnixry)
|
||||||
- Aviv Keller - [@RedYetiDev](https://github.com/redyetidev) | [LinkedIn](https://www.linkedin.com/in/redyetidev) <redyetidev@gmail.com>
|
- Aviv Keller - [@RedYetiDev](https://github.com/redyetidev) | [LinkedIn](https://www.linkedin.com/in/redyetidev) <redyetidev@gmail.com>
|
||||||
|
- Ben Zimmermann - [@bzzimmy](https://github.com/bzzimmy) | [Email](mailto:kernelrocks@proton.me)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
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 { defineConfig } from 'eslint/config'
|
||||||
|
import vitest from '@vitest/eslint-plugin'
|
||||||
import { builtinModules } from 'node:module'
|
import { builtinModules } from 'node:module'
|
||||||
|
|
||||||
const DOMGlobals = ['window', 'document']
|
const DOMGlobals = ['window', 'document']
|
||||||
|
|
@ -12,7 +13,7 @@ const banConstEnum = {
|
||||||
'Please use non-const enums. This project automatically inlines enums.',
|
'Please use non-const enums. This project automatically inlines enums.',
|
||||||
}
|
}
|
||||||
|
|
||||||
export default tseslint.config(
|
export default defineConfig(
|
||||||
{
|
{
|
||||||
files: ['**/*.js', '**/*.ts', '**/*.tsx'],
|
files: ['**/*.js', '**/*.ts', '**/*.tsx'],
|
||||||
extends: [tseslint.configs.base],
|
extends: [tseslint.configs.base],
|
||||||
|
|
@ -60,7 +61,10 @@ export default tseslint.config(
|
||||||
],
|
],
|
||||||
// This rule enforces the preference for using '@ts-expect-error' comments in TypeScript
|
// This rule enforces the preference for using '@ts-expect-error' comments in TypeScript
|
||||||
// code to indicate intentional type errors, improving code clarity and maintainability.
|
// code to indicate intentional type errors, improving code clarity and maintainability.
|
||||||
'@typescript-eslint/prefer-ts-expect-error': 'error',
|
'@typescript-eslint/ban-ts-comment': [
|
||||||
|
'error',
|
||||||
|
{ minimumDescriptionLength: 0 },
|
||||||
|
],
|
||||||
// Enforce the use of 'import type' for importing types
|
// Enforce the use of 'import type' for importing types
|
||||||
'@typescript-eslint/consistent-type-imports': [
|
'@typescript-eslint/consistent-type-imports': [
|
||||||
'error',
|
'error',
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
91
package.json
91
package.json
|
|
@ -1,14 +1,14 @@
|
||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "3.5.4",
|
"version": "3.5.26",
|
||||||
"packageManager": "pnpm@9.10.0",
|
"packageManager": "pnpm@10.25.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "node scripts/dev.js",
|
"dev": "node scripts/dev.js",
|
||||||
"build": "node scripts/build.js",
|
"build": "node scripts/build.js",
|
||||||
"build-dts": "tsc -p tsconfig.build.json --noCheck && rollup -c rollup.dts.config.js",
|
"build-dts": "tsc -p tsconfig.build.json --noCheck && rollup -c rollup.dts.config.js",
|
||||||
"clean": "rimraf --glob packages/*/dist temp .eslintcache",
|
"clean": "rimraf --glob packages/*/dist temp .eslintcache",
|
||||||
"size": "run-s \"size-*\" && tsx scripts/usage-size.ts",
|
"size": "run-s \"size-*\" && node scripts/usage-size.js",
|
||||||
"size-global": "node scripts/build.js vue runtime-dom -f global -p --size",
|
"size-global": "node scripts/build.js vue runtime-dom -f global -p --size",
|
||||||
"size-esm-runtime": "node scripts/build.js vue -f esm-bundler-runtime",
|
"size-esm-runtime": "node scripts/build.js vue -f esm-bundler-runtime",
|
||||||
"size-esm": "node scripts/build.js runtime-dom runtime-core reactivity shared -f esm-bundler",
|
"size-esm": "node scripts/build.js runtime-dom runtime-core reactivity shared -f esm-bundler",
|
||||||
|
|
@ -17,12 +17,15 @@
|
||||||
"format": "prettier --write --cache .",
|
"format": "prettier --write --cache .",
|
||||||
"format-check": "prettier --check --cache .",
|
"format-check": "prettier --check --cache .",
|
||||||
"test": "vitest",
|
"test": "vitest",
|
||||||
"test-unit": "vitest -c vitest.unit.config.ts",
|
"test-unit": "vitest --project unit*",
|
||||||
"test-e2e": "node scripts/build.js vue -f global -d && vitest -c vitest.e2e.config.ts",
|
"test-e2e": "node scripts/build.js vue -f global -d && vitest --project e2e",
|
||||||
"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 -c vitest.unit.config.ts --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",
|
||||||
|
|
@ -61,64 +64,52 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/parser": "catalog:",
|
"@babel/parser": "catalog:",
|
||||||
"@babel/types": "catalog:",
|
"@babel/types": "catalog:",
|
||||||
"@rollup/plugin-alias": "^5.1.0",
|
"@rollup/plugin-alias": "^6.0.0",
|
||||||
"@rollup/plugin-commonjs": "^26.0.1",
|
"@rollup/plugin-commonjs": "^29.0.0",
|
||||||
"@rollup/plugin-json": "^6.1.0",
|
"@rollup/plugin-json": "^6.1.0",
|
||||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
||||||
"@rollup/plugin-replace": "5.0.4",
|
"@rollup/plugin-replace": "5.0.4",
|
||||||
"@swc/core": "^1.7.24",
|
"@swc/core": "^1.15.4",
|
||||||
"@types/hash-sum": "^1.0.2",
|
"@types/hash-sum": "^1.0.2",
|
||||||
"@types/node": "^20.16.5",
|
"@types/node": "^24.10.4",
|
||||||
"@types/semver": "^7.5.8",
|
"@types/semver": "^7.7.1",
|
||||||
"@types/serve-handler": "^6.1.4",
|
"@types/serve-handler": "^6.1.4",
|
||||||
"@vitest/coverage-v8": "^2.0.5",
|
"@vitest/coverage-v8": "^3.2.4",
|
||||||
|
"@vitest/eslint-plugin": "^1.5.2",
|
||||||
"@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.23.1",
|
"esbuild": "^0.27.1",
|
||||||
"esbuild-plugin-polyfill-node": "^0.3.0",
|
"esbuild-plugin-polyfill-node": "^0.3.0",
|
||||||
"eslint": "^9.9.1",
|
"eslint": "^9.39.2",
|
||||||
"eslint-plugin-import-x": "^3.1.0",
|
"eslint-plugin-import-x": "^4.16.1",
|
||||||
"eslint-plugin-vitest": "^0.5.4",
|
|
||||||
"estree-walker": "catalog:",
|
"estree-walker": "catalog:",
|
||||||
"jsdom": "^25.0.0",
|
"jsdom": "^27.3.0",
|
||||||
"lint-staged": "^15.2.10",
|
"lint-staged": "^16.2.7",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"magic-string": "^0.30.11",
|
"magic-string": "^0.30.21",
|
||||||
"markdown-table": "^3.0.3",
|
"markdown-table": "^3.0.4",
|
||||||
"marked": "13.0.3",
|
"marked": "13.0.3",
|
||||||
"npm-run-all2": "^6.2.2",
|
"npm-run-all2": "^8.0.4",
|
||||||
"picocolors": "^1.1.0",
|
"picocolors": "^1.1.1",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.7.4",
|
||||||
"pretty-bytes": "^6.1.1",
|
"pretty-bytes": "^7.1.0",
|
||||||
"pug": "^3.0.3",
|
"pug": "^3.0.3",
|
||||||
"puppeteer": "~23.3.0",
|
"puppeteer": "~24.33.0",
|
||||||
"rimraf": "^6.0.1",
|
"rimraf": "^6.1.2",
|
||||||
"rollup": "^4.21.2",
|
"rollup": "^4.53.3",
|
||||||
"rollup-plugin-dts": "^6.1.1",
|
"rollup-plugin-dts": "^6.3.0",
|
||||||
"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.3",
|
||||||
"serve": "^14.2.3",
|
"serve": "^14.2.5",
|
||||||
"serve-handler": "^6.1.5",
|
"serve-handler": "^6.1.6",
|
||||||
"simple-git-hooks": "^2.11.1",
|
"simple-git-hooks": "^2.13.1",
|
||||||
"todomvc-app-css": "^2.4.3",
|
"todomvc-app-css": "^2.4.3",
|
||||||
"tslib": "^2.7.0",
|
"tslib": "^2.8.1",
|
||||||
"tsx": "^4.19.0",
|
|
||||||
"typescript": "~5.6.2",
|
"typescript": "~5.6.2",
|
||||||
"typescript-eslint": "^8.4.0",
|
"typescript-eslint": "^8.49.0",
|
||||||
"vite": "catalog:",
|
"vite": "catalog:",
|
||||||
"vitest": "^2.0.5"
|
"vitest": "^3.2.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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,17 @@ import { expectType } from './utils'
|
||||||
|
|
||||||
const app = createApp({})
|
const app = createApp({})
|
||||||
|
|
||||||
app.directive<HTMLElement, string>('custom', {
|
app.directive<HTMLElement, string, 'prevent' | 'stop', 'arg1' | 'arg2'>(
|
||||||
|
'custom',
|
||||||
|
{
|
||||||
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<'arg1' | 'arg2'>(binding.arg!)
|
||||||
|
|
||||||
// @ts-expect-error not any
|
// @ts-expect-error not any
|
||||||
expectType<number>(binding.value)
|
expectType<number>(binding.value)
|
||||||
},
|
},
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -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 = ''
|
||||||
|
|
|
||||||
|
|
@ -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']
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,48 @@ 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)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// #14117
|
||||||
|
defineComponent({
|
||||||
|
setup() {
|
||||||
|
const setup1 = ref('setup1')
|
||||||
|
const setup2 = ref('setup2')
|
||||||
|
return { setup1, setup2 }
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
data1: 1,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
props1: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
methods1() {
|
||||||
|
return `methods1`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
computed1() {
|
||||||
|
this.setup1
|
||||||
|
this.setup2
|
||||||
|
this.data1
|
||||||
|
this.props1
|
||||||
|
this.methods1()
|
||||||
|
return `computed1`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expose: ['setup1'],
|
||||||
|
})
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ type ExtractBinding<T> = T extends (
|
||||||
declare function testDirective<
|
declare function testDirective<
|
||||||
Value,
|
Value,
|
||||||
Modifiers extends string = string,
|
Modifiers extends string = string,
|
||||||
Arg extends string = string,
|
Arg = any,
|
||||||
>(): ExtractBinding<Directive<any, Value, Modifiers, Arg>>
|
>(): ExtractBinding<Directive<any, Value, Modifiers, Arg>>
|
||||||
|
|
||||||
describe('vmodel', () => {
|
describe('vmodel', () => {
|
||||||
|
|
@ -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<{
|
||||||
|
|
@ -44,7 +44,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>>
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
}>(testDirective<number, 'a' | 'b', 'Argx'>())
|
}>(testDirective<number, 'a' | 'b', 'Argx'>())
|
||||||
|
|
||||||
|
|
@ -52,7 +52,29 @@ 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>>
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
}>(testDirective<string, 'a' | 'b', 'Arg'>())
|
}>(testDirective<string, 'a' | 'b', 'Arg'>())
|
||||||
|
|
||||||
|
expectType<{
|
||||||
|
value: number
|
||||||
|
oldValue: number | null
|
||||||
|
arg?: HTMLElement
|
||||||
|
modifiers: Partial<Record<'a' | 'b', boolean>>
|
||||||
|
}>(testDirective<number, 'a' | 'b', HTMLElement>())
|
||||||
|
|
||||||
|
expectType<{
|
||||||
|
value: number
|
||||||
|
oldValue: number | null
|
||||||
|
arg?: HTMLElement
|
||||||
|
modifiers: Partial<Record<'a' | 'b', boolean>>
|
||||||
|
// @ts-expect-error
|
||||||
|
}>(testDirective<number, 'a' | 'b', string>())
|
||||||
|
|
||||||
|
expectType<{
|
||||||
|
value: number
|
||||||
|
oldValue: number | null
|
||||||
|
arg?: HTMLElement
|
||||||
|
modifiers: Partial<Record<'a' | 'b', boolean>>
|
||||||
|
}>(testDirective<number, 'a' | 'b'>())
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
import { nextTick } from 'vue'
|
||||||
|
import { describe, expectType } from './utils'
|
||||||
|
|
||||||
|
describe('nextTick', async () => {
|
||||||
|
expectType<Promise<void>>(nextTick())
|
||||||
|
expectType<Promise<string>>(nextTick(() => 'foo'))
|
||||||
|
expectType<Promise<string>>(nextTick(() => Promise.resolve('foo')))
|
||||||
|
expectType<Promise<string>>(
|
||||||
|
nextTick(() => Promise.resolve(Promise.resolve('foo'))),
|
||||||
|
)
|
||||||
|
|
||||||
|
expectType<void>(await nextTick())
|
||||||
|
expectType<string>(await nextTick(() => 'foo'))
|
||||||
|
expectType<string>(await nextTick(() => Promise.resolve('foo')))
|
||||||
|
expectType<string>(
|
||||||
|
await nextTick(() => Promise.resolve(Promise.resolve('foo'))),
|
||||||
|
)
|
||||||
|
|
||||||
|
nextTick().then(value => {
|
||||||
|
expectType<void>(value)
|
||||||
|
})
|
||||||
|
nextTick(() => 'foo').then(value => {
|
||||||
|
expectType<string>(value)
|
||||||
|
})
|
||||||
|
nextTick(() => Promise.resolve('foo')).then(value => {
|
||||||
|
expectType<string>(value)
|
||||||
|
})
|
||||||
|
nextTick(() => Promise.resolve(Promise.resolve('foo'))).then(value => {
|
||||||
|
expectType<string>(value)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
@ -33,6 +33,16 @@ describe('defineProps w/ type declaration', () => {
|
||||||
expectType<boolean>(props.boolAndUndefined)
|
expectType<boolean>(props.boolAndUndefined)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('defineProps w/ never prop', () => {
|
||||||
|
const props = defineProps<{
|
||||||
|
foo?: never
|
||||||
|
bar: number
|
||||||
|
}>()
|
||||||
|
|
||||||
|
expectType<never | undefined>(props.foo)
|
||||||
|
expectType<number>(props.bar)
|
||||||
|
})
|
||||||
|
|
||||||
describe('defineProps w/ generics', () => {
|
describe('defineProps w/ generics', () => {
|
||||||
function test<T extends boolean>() {
|
function test<T extends boolean>() {
|
||||||
const props = defineProps<{ foo: T; bar: string; x?: boolean }>()
|
const props = defineProps<{ foo: T; bar: string; x?: boolean }>()
|
||||||
|
|
@ -240,6 +250,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 +316,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]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
|
// Global compile-time constants
|
||||||
|
declare var __COMMIT__: string
|
||||||
|
|
||||||
|
declare module 'file-saver' {
|
||||||
|
export function saveAs(blob: any, name: any): void
|
||||||
|
}
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
"vite": "catalog:"
|
"vite": "catalog:"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/repl": "^4.3.1",
|
"@vue/repl": "^4.7.1",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"vue": "workspace:*"
|
"vue": "workspace:*"
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
import Header from './Header.vue'
|
import Header from './Header.vue'
|
||||||
import { Repl, useStore, SFCOptions, useVueImportMap } from '@vue/repl'
|
import { Repl, useStore, SFCOptions, useVueImportMap } from '@vue/repl'
|
||||||
import Monaco from '@vue/repl/monaco-editor'
|
import Monaco from '@vue/repl/monaco-editor'
|
||||||
import { ref, watchEffect, onMounted, computed } from 'vue'
|
import { ref, watchEffect, onMounted, computed, watch } from 'vue'
|
||||||
|
|
||||||
const replRef = ref<InstanceType<typeof Repl>>()
|
const replRef = ref<InstanceType<typeof Repl>>()
|
||||||
|
|
||||||
|
|
@ -14,6 +14,12 @@ setVH()
|
||||||
|
|
||||||
const useSSRMode = ref(false)
|
const useSSRMode = ref(false)
|
||||||
|
|
||||||
|
const AUTO_SAVE_STORAGE_KEY = 'vue-sfc-playground-auto-save'
|
||||||
|
const initAutoSave: boolean = JSON.parse(
|
||||||
|
localStorage.getItem(AUTO_SAVE_STORAGE_KEY) ?? 'true',
|
||||||
|
)
|
||||||
|
const autoSave = ref(initAutoSave)
|
||||||
|
|
||||||
const { productionMode, vueVersion, importMap } = useVueImportMap({
|
const { productionMode, vueVersion, importMap } = useVueImportMap({
|
||||||
runtimeDev: import.meta.env.PROD
|
runtimeDev: import.meta.env.PROD
|
||||||
? `${location.origin}/vue.runtime.esm-browser.js`
|
? `${location.origin}/vue.runtime.esm-browser.js`
|
||||||
|
|
@ -89,6 +95,11 @@ function toggleSSR() {
|
||||||
useSSRMode.value = !useSSRMode.value
|
useSSRMode.value = !useSSRMode.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleAutoSave() {
|
||||||
|
autoSave.value = !autoSave.value
|
||||||
|
localStorage.setItem(AUTO_SAVE_STORAGE_KEY, String(autoSave.value))
|
||||||
|
}
|
||||||
|
|
||||||
function reloadPage() {
|
function reloadPage() {
|
||||||
replRef.value?.reload()
|
replRef.value?.reload()
|
||||||
}
|
}
|
||||||
|
|
@ -104,6 +115,34 @@ onMounted(() => {
|
||||||
// @ts-expect-error process shim for old versions of @vue/compiler-sfc dependency
|
// @ts-expect-error process shim for old versions of @vue/compiler-sfc dependency
|
||||||
window.process = { env: {} }
|
window.process = { env: {} }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const isVaporSupported = ref(false)
|
||||||
|
watch(
|
||||||
|
() => store.vueVersion,
|
||||||
|
(version, oldVersion) => {
|
||||||
|
const [major, minor] = (version || store.compiler.version)
|
||||||
|
.split('.')
|
||||||
|
.map((v: string) => parseInt(v, 10))
|
||||||
|
isVaporSupported.value = major > 3 || (major === 3 && minor >= 6)
|
||||||
|
if (oldVersion) reloadPage()
|
||||||
|
},
|
||||||
|
{ immediate: true, flush: 'pre' },
|
||||||
|
)
|
||||||
|
|
||||||
|
const previewOptions = computed(() => ({
|
||||||
|
customCode: {
|
||||||
|
importCode: `import { initCustomFormatter${isVaporSupported.value ? ', vaporInteropPlugin' : ''} } from 'vue'`,
|
||||||
|
useCode: `
|
||||||
|
${isVaporSupported.value ? 'app.use(vaporInteropPlugin)' : ''}
|
||||||
|
if (window.devtoolsFormatters) {
|
||||||
|
const index = window.devtoolsFormatters.findIndex((v) => v.__vue_custom_formatter)
|
||||||
|
window.devtoolsFormatters.splice(index, 1)
|
||||||
|
initCustomFormatter()
|
||||||
|
} else {
|
||||||
|
initCustomFormatter()
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
}))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -111,9 +150,12 @@ onMounted(() => {
|
||||||
:store="store"
|
:store="store"
|
||||||
:prod="productionMode"
|
:prod="productionMode"
|
||||||
:ssr="useSSRMode"
|
:ssr="useSSRMode"
|
||||||
|
:autoSave="autoSave"
|
||||||
|
:theme="theme"
|
||||||
@toggle-theme="toggleTheme"
|
@toggle-theme="toggleTheme"
|
||||||
@toggle-prod="toggleProdMode"
|
@toggle-prod="toggleProdMode"
|
||||||
@toggle-ssr="toggleSSR"
|
@toggle-ssr="toggleSSR"
|
||||||
|
@toggle-autosave="toggleAutoSave"
|
||||||
@reload-page="reloadPage"
|
@reload-page="reloadPage"
|
||||||
/>
|
/>
|
||||||
<Repl
|
<Repl
|
||||||
|
|
@ -123,22 +165,15 @@ onMounted(() => {
|
||||||
@keydown.ctrl.s.prevent
|
@keydown.ctrl.s.prevent
|
||||||
@keydown.meta.s.prevent
|
@keydown.meta.s.prevent
|
||||||
:ssr="useSSRMode"
|
:ssr="useSSRMode"
|
||||||
|
:model-value="autoSave"
|
||||||
|
:editorOptions="{ autoSaveText: false }"
|
||||||
:store="store"
|
:store="store"
|
||||||
:showCompileOutput="true"
|
:showCompileOutput="true"
|
||||||
|
:showSsrOutput="useSSRMode"
|
||||||
|
:showOpenSourceMap="true"
|
||||||
:autoResize="true"
|
:autoResize="true"
|
||||||
:clearConsole="false"
|
:clearConsole="false"
|
||||||
:preview-options="{
|
:preview-options="previewOptions"
|
||||||
customCode: {
|
|
||||||
importCode: `import { initCustomFormatter } from 'vue'`,
|
|
||||||
useCode: `if (window.devtoolsFormatters) {
|
|
||||||
const index = window.devtoolsFormatters.findIndex((v) => v.__vue_custom_formatter)
|
|
||||||
window.devtoolsFormatters.splice(index, 1)
|
|
||||||
initCustomFormatter()
|
|
||||||
} else {
|
|
||||||
initCustomFormatter()
|
|
||||||
}`,
|
|
||||||
},
|
|
||||||
}"
|
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -149,8 +184,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;
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,14 @@ const props = defineProps<{
|
||||||
store: ReplStore
|
store: ReplStore
|
||||||
prod: boolean
|
prod: boolean
|
||||||
ssr: boolean
|
ssr: boolean
|
||||||
|
autoSave: boolean
|
||||||
|
theme: 'dark' | 'light'
|
||||||
}>()
|
}>()
|
||||||
const emit = defineEmits([
|
const emit = defineEmits([
|
||||||
'toggle-theme',
|
'toggle-theme',
|
||||||
'toggle-ssr',
|
'toggle-ssr',
|
||||||
'toggle-prod',
|
'toggle-prod',
|
||||||
|
'toggle-autosave',
|
||||||
'reload-page',
|
'reload-page',
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
@ -43,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
|
||||||
|
|
@ -107,7 +111,19 @@ function toggleDark() {
|
||||||
>
|
>
|
||||||
<span>{{ ssr ? 'SSR ON' : 'SSR OFF' }}</span>
|
<span>{{ ssr ? 'SSR ON' : 'SSR OFF' }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button title="Toggle dark mode" class="toggle-dark" @click="toggleDark">
|
<button
|
||||||
|
title="Toggle editor auto save mode"
|
||||||
|
class="toggle-autosave"
|
||||||
|
:class="{ enabled: autoSave }"
|
||||||
|
@click="$emit('toggle-autosave')"
|
||||||
|
>
|
||||||
|
<span>{{ autoSave ? 'AutoSave ON' : 'AutoSave OFF' }}</span>
|
||||||
|
</button>
|
||||||
|
<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>
|
||||||
|
|
@ -199,7 +215,8 @@ h1 img {
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle-prod span,
|
.toggle-prod span,
|
||||||
.toggle-ssr span {
|
.toggle-ssr span,
|
||||||
|
.toggle-autosave span {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 4px 6px;
|
padding: 4px 6px;
|
||||||
|
|
@ -214,11 +231,13 @@ h1 img {
|
||||||
background: var(--purple);
|
background: var(--purple);
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle-ssr span {
|
.toggle-ssr span,
|
||||||
|
.toggle-autosave span {
|
||||||
background-color: var(--btn-bg);
|
background-color: var(--btn-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle-ssr.enabled span {
|
.toggle-ssr.enabled span,
|
||||||
|
.toggle-autosave.enabled span {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background-color: var(--green);
|
background-color: var(--green);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.3",
|
"@vitejs/plugin-vue": "^6.0.3",
|
||||||
"vite": "^5.4.3"
|
"vite": "^7.2.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
"enableNonBrowserBranches": true
|
"enableNonBrowserBranches": true
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"monaco-editor": "^0.51.0",
|
"monaco-editor": "^0.55.1",
|
||||||
"source-map-js": "^1.2.0"
|
"source-map-js": "^1.2.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2019,6 +2019,21 @@ describe('compiler: parse', () => {
|
||||||
children: [{ type: NodeTypes.TEXT, content: `{{ number ` }],
|
children: [{ type: NodeTypes.TEXT, content: `{{ number ` }],
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const ast3 = baseParse(`<div v-pre><textarea>{{ foo </textarea></div>`, {
|
||||||
|
parseMode: 'html',
|
||||||
|
})
|
||||||
|
expect((ast3.children[0] as ElementNode).children).toMatchObject([
|
||||||
|
{
|
||||||
|
type: NodeTypes.ELEMENT,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: NodeTypes.TEXT,
|
||||||
|
content: `{{ foo `,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
test('self-closing v-pre', () => {
|
test('self-closing v-pre', () => {
|
||||||
|
|
@ -2256,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', () => {
|
||||||
|
|
@ -2354,6 +2374,7 @@ describe('compiler: parse', () => {
|
||||||
test('should remove leading newline character immediately following the pre element start tag', () => {
|
test('should remove leading newline character immediately following the pre element start tag', () => {
|
||||||
const ast = parse(`<pre>\n foo bar </pre>`, {
|
const ast = parse(`<pre>\n foo bar </pre>`, {
|
||||||
isPreTag: tag => tag === 'pre',
|
isPreTag: tag => tag === 'pre',
|
||||||
|
isIgnoreNewlineTag: tag => tag === 'pre',
|
||||||
})
|
})
|
||||||
expect(ast.children).toHaveLength(1)
|
expect(ast.children).toHaveLength(1)
|
||||||
const preElement = ast.children[0] as ElementNode
|
const preElement = ast.children[0] as ElementNode
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ return function render(_ctx, _cache) {
|
||||||
with (_ctx) {
|
with (_ctx) {
|
||||||
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 */)
|
||||||
])))
|
]))]))
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
@ -21,16 +21,16 @@ return function render(_ctx, _cache) {
|
||||||
with (_ctx) {
|
with (_ctx) {
|
||||||
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("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 */)
|
||||||
])))
|
]))]))
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
@ -42,11 +42,11 @@ return function render(_ctx, _cache) {
|
||||||
with (_ctx) {
|
with (_ctx) {
|
||||||
const { createCommentVNode: _createCommentVNode, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
const { createCommentVNode: _createCommentVNode, 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", null, [
|
_createElementVNode("div", null, [
|
||||||
_createCommentVNode("comment")
|
_createCommentVNode("comment")
|
||||||
], -1 /* HOISTED */)
|
], -1 /* CACHED */)
|
||||||
])))
|
]))]))
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
@ -58,11 +58,11 @@ return function render(_ctx, _cache) {
|
||||||
with (_ctx) {
|
with (_ctx) {
|
||||||
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", -1 /* CACHED */),
|
||||||
_createElementVNode("div", null, null, -1 /* HOISTED */)
|
_createElementVNode("div", null, null, -1 /* CACHED */)
|
||||||
])))
|
]))]))
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
@ -74,9 +74,9 @@ return function render(_ctx, _cache) {
|
||||||
with (_ctx) {
|
with (_ctx) {
|
||||||
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 */)
|
||||||
])))
|
]))]))
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
@ -147,9 +147,9 @@ return function render(_ctx, _cache) {
|
||||||
with (_ctx) {
|
with (_ctx) {
|
||||||
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 */)
|
||||||
])))
|
]))]))
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
@ -161,9 +161,9 @@ return function render(_ctx, _cache) {
|
||||||
with (_ctx) {
|
with (_ctx) {
|
||||||
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 */))
|
||||||
]))
|
]))
|
||||||
|
|
@ -215,9 +215,9 @@ return function render(_ctx, _cache) {
|
||||||
const _directive_foo = _resolveDirective("foo")
|
const _directive_foo = _resolveDirective("foo")
|
||||||
|
|
||||||
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]
|
||||||
])
|
])
|
||||||
]))
|
]))
|
||||||
|
|
@ -401,15 +401,41 @@ 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)
|
||||||
]))
|
]))
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
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
|
||||||
|
|
@ -422,9 +448,9 @@ 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 */))
|
||||||
]))
|
]))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,24 @@ return function render(_ctx, _cache) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: transform component slots > named slots w/ implicit default slot containing non-breaking space 1`] = `
|
||||||
|
"const _Vue = Vue
|
||||||
|
|
||||||
|
return function render(_ctx, _cache) {
|
||||||
|
with (_ctx) {
|
||||||
|
const { resolveComponent: _resolveComponent, withCtx: _withCtx, openBlock: _openBlock, createBlock: _createBlock } = _Vue
|
||||||
|
|
||||||
|
const _component_Comp = _resolveComponent("Comp")
|
||||||
|
|
||||||
|
return (_openBlock(), _createBlock(_component_Comp, null, {
|
||||||
|
one: _withCtx(() => ["foo"]),
|
||||||
|
default: _withCtx(() => [" "]),
|
||||||
|
_: 1 /* STABLE */
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`compiler: transform component slots > nested slots scoping 1`] = `
|
exports[`compiler: transform component slots > nested slots scoping 1`] = `
|
||||||
"const { toDisplayString: _toDisplayString, resolveComponent: _resolveComponent, withCtx: _withCtx, createVNode: _createVNode, openBlock: _openBlock, createBlock: _createBlock } = Vue
|
"const { toDisplayString: _toDisplayString, resolveComponent: _resolveComponent, withCtx: _withCtx, createVNode: _createVNode, openBlock: _openBlock, createBlock: _createBlock } = Vue
|
||||||
|
|
||||||
|
|
@ -232,6 +250,20 @@ return function render(_ctx, _cache) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: transform component slots > with whitespace: 'preserve' > implicit default slot with non-breaking space 1`] = `
|
||||||
|
"const { resolveComponent: _resolveComponent, withCtx: _withCtx, openBlock: _openBlock, createBlock: _createBlock } = Vue
|
||||||
|
|
||||||
|
return function render(_ctx, _cache) {
|
||||||
|
const _component_Comp = _resolveComponent("Comp")
|
||||||
|
|
||||||
|
return (_openBlock(), _createBlock(_component_Comp, null, {
|
||||||
|
header: _withCtx(() => [" Header "]),
|
||||||
|
default: _withCtx(() => ["\\n \\n "]),
|
||||||
|
_: 1 /* STABLE */
|
||||||
|
}))
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`compiler: transform component slots > with whitespace: 'preserve' > named default slot + implicit whitespace content 1`] = `
|
exports[`compiler: transform component slots > with whitespace: 'preserve' > named default slot + implicit whitespace content 1`] = `
|
||||||
"const { resolveComponent: _resolveComponent, withCtx: _withCtx, openBlock: _openBlock, createBlock: _createBlock } = Vue
|
"const { resolveComponent: _resolveComponent, withCtx: _withCtx, openBlock: _openBlock, createBlock: _createBlock } = Vue
|
||||||
|
|
||||||
|
|
@ -246,6 +278,54 @@ 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' > named slot with v-if + v-else and comments 1`] = `
|
||||||
|
"const { createTextVNode: _createTextVNode, createCommentVNode: _createCommentVNode, 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(() => [
|
||||||
|
_createTextVNode("foo")
|
||||||
|
]),
|
||||||
|
key: "0"
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
name: "two",
|
||||||
|
fn: _withCtx(() => [
|
||||||
|
_createTextVNode("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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ import { PatchFlags } from '@vue/shared'
|
||||||
|
|
||||||
const cachedChildrenArrayMatcher = (
|
const cachedChildrenArrayMatcher = (
|
||||||
tags: string[],
|
tags: string[],
|
||||||
needArraySpread = false,
|
needArraySpread = true,
|
||||||
) => ({
|
) => ({
|
||||||
type: NodeTypes.JS_CACHE_EXPRESSION,
|
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||||
needArraySpread,
|
needArraySpread,
|
||||||
|
|
@ -533,6 +533,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(
|
||||||
|
|
|
||||||
|
|
@ -716,4 +716,42 @@ describe('compiler: expression transform', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('switch case variable declarations', () => {
|
||||||
|
test('should handle const declarations in switch case without braces', () => {
|
||||||
|
const { code } = compile(
|
||||||
|
`{{ (() => { switch (1) { case 1: const foo = "bar"; return \`\${foo}\`; } })() }}`,
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(code).toMatch(`const foo = "bar";`)
|
||||||
|
expect(code).toMatch(`return \`\${foo}\`;`)
|
||||||
|
expect(code).not.toMatch(`_ctx.foo`)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should handle const declarations in switch case with braces (existing behavior)', () => {
|
||||||
|
const { code } = compile(
|
||||||
|
`{{ (() => {
|
||||||
|
switch (true) {
|
||||||
|
case true: {
|
||||||
|
const foo = "bar";
|
||||||
|
return \`\${foo}\`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})() }}`,
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(code).toMatch(`const foo = "bar";`)
|
||||||
|
expect(code).toMatch(`return \`\${foo}\`;`)
|
||||||
|
expect(code).not.toMatch(`_ctx.foo`)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should parse switch case test as local scoped variables', () => {
|
||||||
|
const { code } = compile(
|
||||||
|
`{{ (() => { switch (foo) { case bar: return \`\${bar}\`; } })() }}`,
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(code).toMatch('_ctx.foo')
|
||||||
|
expect(code).toMatch(`_ctx.bar`)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import {
|
||||||
type ForNode,
|
type ForNode,
|
||||||
NodeTypes,
|
NodeTypes,
|
||||||
generate,
|
generate,
|
||||||
|
isWhitespaceText,
|
||||||
baseParse as parse,
|
baseParse as parse,
|
||||||
transform,
|
transform,
|
||||||
} from '../../src'
|
} from '../../src'
|
||||||
|
|
@ -109,6 +110,24 @@ describe('compiler: transform text', () => {
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('whitespace text', () => {
|
||||||
|
const root = transformWithTextOpt(`<div/>hello<div/> <div/>`)
|
||||||
|
expect(root.children.length).toBe(5)
|
||||||
|
expect(root.children[0].type).toBe(NodeTypes.ELEMENT)
|
||||||
|
expect(root.children[1].type).toBe(NodeTypes.TEXT_CALL)
|
||||||
|
expect(root.children[2].type).toBe(NodeTypes.ELEMENT)
|
||||||
|
expect(root.children[3].type).toBe(NodeTypes.TEXT_CALL)
|
||||||
|
expect(root.children[4].type).toBe(NodeTypes.ELEMENT)
|
||||||
|
|
||||||
|
expect(root.children.map(isWhitespaceText)).toEqual([
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
test('consecutive text mixed with elements', () => {
|
test('consecutive text mixed with elements', () => {
|
||||||
const root = transformWithTextOpt(
|
const root = transformWithTextOpt(
|
||||||
`<div/>{{ foo }} bar {{ baz }}<div/>hello<div/>`,
|
`<div/>{{ foo }} bar {{ baz }}<div/>hello<div/>`,
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import {
|
||||||
helperNameMap,
|
helperNameMap,
|
||||||
} from '../../src/runtimeHelpers'
|
} from '../../src/runtimeHelpers'
|
||||||
import { transformExpression } from '../../src/transforms/transformExpression'
|
import { transformExpression } from '../../src/transforms/transformExpression'
|
||||||
|
import { transformVBindShorthand } from '../../src/transforms/transformVBindShorthand'
|
||||||
|
|
||||||
function parseWithVBind(
|
function parseWithVBind(
|
||||||
template: string,
|
template: string,
|
||||||
|
|
@ -25,6 +26,7 @@ function parseWithVBind(
|
||||||
const ast = parse(template)
|
const ast = parse(template)
|
||||||
transform(ast, {
|
transform(ast, {
|
||||||
nodeTransforms: [
|
nodeTransforms: [
|
||||||
|
transformVBindShorthand,
|
||||||
...(options.prefixIdentifiers ? [transformExpression] : []),
|
...(options.prefixIdentifiers ? [transformExpression] : []),
|
||||||
transformElement,
|
transformElement,
|
||||||
],
|
],
|
||||||
|
|
@ -110,6 +112,27 @@ describe('compiler: transform v-bind', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('no expression (shorthand) in-DOM templates', () => {
|
||||||
|
try {
|
||||||
|
__BROWSER__ = true
|
||||||
|
// :id in in-DOM templates will be parsed into :id="" by browser
|
||||||
|
const node = parseWithVBind(`<div :id="" />`)
|
||||||
|
const props = (node.codegenNode as VNodeCall).props as ObjectExpression
|
||||||
|
expect(props.properties[0]).toMatchObject({
|
||||||
|
key: {
|
||||||
|
content: `id`,
|
||||||
|
isStatic: true,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
content: `id`,
|
||||||
|
isStatic: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} finally {
|
||||||
|
__BROWSER__ = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
test('dynamic arg', () => {
|
test('dynamic arg', () => {
|
||||||
const node = parseWithVBind(`<div v-bind:[id]="id"/>`)
|
const node = parseWithVBind(`<div v-bind:[id]="id"/>`)
|
||||||
const props = (node.codegenNode as VNodeCall).props as CallExpression
|
const props = (node.codegenNode as VNodeCall).props as CallExpression
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import { type CompilerOptions, generate } from '../../src'
|
||||||
import { FRAGMENT, RENDER_LIST, RENDER_SLOT } from '../../src/runtimeHelpers'
|
import { FRAGMENT, RENDER_LIST, RENDER_SLOT } from '../../src/runtimeHelpers'
|
||||||
import { PatchFlags } from '@vue/shared'
|
import { PatchFlags } from '@vue/shared'
|
||||||
import { createObjectMatcher } from '../testUtils'
|
import { createObjectMatcher } from '../testUtils'
|
||||||
|
import { transformVBindShorthand } from '../../src/transforms/transformVBindShorthand'
|
||||||
|
|
||||||
export function parseWithForTransform(
|
export function parseWithForTransform(
|
||||||
template: string,
|
template: string,
|
||||||
|
|
@ -32,6 +33,7 @@ export function parseWithForTransform(
|
||||||
const ast = parse(template, options)
|
const ast = parse(template, options)
|
||||||
transform(ast, {
|
transform(ast, {
|
||||||
nodeTransforms: [
|
nodeTransforms: [
|
||||||
|
transformVBindShorthand,
|
||||||
transformIf,
|
transformIf,
|
||||||
transformFor,
|
transformFor,
|
||||||
...(options.prefixIdentifiers ? [transformExpression] : []),
|
...(options.prefixIdentifiers ? [transformExpression] : []),
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,12 @@ import {
|
||||||
type VNodeCall,
|
type VNodeCall,
|
||||||
} from '../../src/ast'
|
} from '../../src/ast'
|
||||||
import { ErrorCodes } from '../../src/errors'
|
import { ErrorCodes } from '../../src/errors'
|
||||||
import { type CompilerOptions, TO_HANDLERS, generate } from '../../src'
|
import {
|
||||||
|
type CompilerOptions,
|
||||||
|
TO_HANDLERS,
|
||||||
|
generate,
|
||||||
|
transformVBindShorthand,
|
||||||
|
} from '../../src'
|
||||||
import {
|
import {
|
||||||
CREATE_COMMENT,
|
CREATE_COMMENT,
|
||||||
FRAGMENT,
|
FRAGMENT,
|
||||||
|
|
@ -35,7 +40,12 @@ function parseWithIfTransform(
|
||||||
) {
|
) {
|
||||||
const ast = parse(template, options)
|
const ast = parse(template, options)
|
||||||
transform(ast, {
|
transform(ast, {
|
||||||
nodeTransforms: [transformIf, transformSlotOutlet, transformElement],
|
nodeTransforms: [
|
||||||
|
transformVBindShorthand,
|
||||||
|
transformIf,
|
||||||
|
transformSlotOutlet,
|
||||||
|
transformElement,
|
||||||
|
],
|
||||||
...options,
|
...options,
|
||||||
})
|
})
|
||||||
if (!options.onError) {
|
if (!options.onError) {
|
||||||
|
|
@ -209,6 +219,16 @@ describe('compiler: v-if', () => {
|
||||||
content: `_ctx.ok`,
|
content: `_ctx.ok`,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
//#11321
|
||||||
|
test('v-if + :key shorthand', () => {
|
||||||
|
const { node } = parseWithIfTransform(`<div v-if="ok" :key></div>`)
|
||||||
|
expect(node.type).toBe(NodeTypes.IF)
|
||||||
|
expect(node.branches[0].userKey).toMatchObject({
|
||||||
|
arg: { content: 'key' },
|
||||||
|
exp: { content: 'key' },
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('errors', () => {
|
describe('errors', () => {
|
||||||
|
|
@ -246,6 +266,31 @@ describe('compiler: v-if', () => {
|
||||||
loc: node3.loc,
|
loc: node3.loc,
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const { node: node4 } = parseWithIfTransform(
|
||||||
|
`<div v-if="bar"/>foo<div v-else/>`,
|
||||||
|
{ onError },
|
||||||
|
2,
|
||||||
|
)
|
||||||
|
expect(onError.mock.calls[3]).toMatchObject([
|
||||||
|
{
|
||||||
|
code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
|
||||||
|
loc: node4.loc,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
// Non-breaking space
|
||||||
|
const { node: node5 } = parseWithIfTransform(
|
||||||
|
`<div v-if="bar"/>\u00a0<div v-else/>`,
|
||||||
|
{ onError },
|
||||||
|
2,
|
||||||
|
)
|
||||||
|
expect(onError.mock.calls[4]).toMatchObject([
|
||||||
|
{
|
||||||
|
code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
|
||||||
|
loc: node5.loc,
|
||||||
|
},
|
||||||
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
test('error on v-else-if missing adjacent v-if or v-else-if', () => {
|
test('error on v-else-if missing adjacent v-if or v-else-if', () => {
|
||||||
|
|
@ -285,6 +330,31 @@ describe('compiler: v-if', () => {
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const { node: node4 } = parseWithIfTransform(
|
||||||
|
`<div v-if="bar"/>foo<div v-else-if="foo"/>`,
|
||||||
|
{ onError },
|
||||||
|
2,
|
||||||
|
)
|
||||||
|
expect(onError.mock.calls[3]).toMatchObject([
|
||||||
|
{
|
||||||
|
code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
|
||||||
|
loc: node4.loc,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
// Non-breaking space
|
||||||
|
const { node: node5 } = parseWithIfTransform(
|
||||||
|
`<div v-if="bar"/>\u00a0<div v-else-if="foo"/>`,
|
||||||
|
{ onError },
|
||||||
|
2,
|
||||||
|
)
|
||||||
|
expect(onError.mock.calls[4]).toMatchObject([
|
||||||
|
{
|
||||||
|
code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
|
||||||
|
loc: node5.loc,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
const {
|
const {
|
||||||
node: { branches },
|
node: { branches },
|
||||||
} = parseWithIfTransform(
|
} = parseWithIfTransform(
|
||||||
|
|
@ -293,7 +363,26 @@ describe('compiler: v-if', () => {
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(onError.mock.calls[3]).toMatchObject([
|
expect(onError.mock.calls[5]).toMatchObject([
|
||||||
|
{
|
||||||
|
code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
|
||||||
|
loc: branches[branches.length - 1].loc,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
test('error on adjacent v-else', () => {
|
||||||
|
const onError = vi.fn()
|
||||||
|
|
||||||
|
const {
|
||||||
|
node: { branches },
|
||||||
|
} = parseWithIfTransform(
|
||||||
|
`<div v-if="false"/><div v-else/><div v-else/>`,
|
||||||
|
{ onError },
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(onError.mock.calls[0]).toMatchObject([
|
||||||
{
|
{
|
||||||
code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
|
code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
|
||||||
loc: branches[branches.length - 1].loc,
|
loc: branches[branches.length - 1].loc,
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -582,5 +582,22 @@ describe('compiler: transform v-model', () => {
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('used on const binding', () => {
|
||||||
|
const onError = vi.fn()
|
||||||
|
parseWithVModel('<div v-model="c" />', {
|
||||||
|
onError,
|
||||||
|
bindingMetadata: {
|
||||||
|
c: BindingTypes.LITERAL_CONST,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(onError).toHaveBeenCalledTimes(1)
|
||||||
|
expect(onError).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
code: ErrorCodes.X_V_MODEL_ON_CONST,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,12 @@ import { createObjectMatcher } from '../testUtils'
|
||||||
import { PatchFlags } from '@vue/shared'
|
import { PatchFlags } from '@vue/shared'
|
||||||
import { transformFor } from '../../src/transforms/vFor'
|
import { transformFor } from '../../src/transforms/vFor'
|
||||||
import { transformIf } from '../../src/transforms/vIf'
|
import { transformIf } from '../../src/transforms/vIf'
|
||||||
|
import { transformText } from '../../src/transforms/transformText'
|
||||||
|
|
||||||
function parseWithSlots(template: string, options: CompilerOptions = {}) {
|
function parseWithSlots(
|
||||||
|
template: string,
|
||||||
|
options: CompilerOptions & { transformText?: boolean } = {},
|
||||||
|
) {
|
||||||
const ast = parse(template, {
|
const ast = parse(template, {
|
||||||
whitespace: options.whitespace,
|
whitespace: options.whitespace,
|
||||||
})
|
})
|
||||||
|
|
@ -43,6 +47,7 @@ function parseWithSlots(template: string, options: CompilerOptions = {}) {
|
||||||
transformSlotOutlet,
|
transformSlotOutlet,
|
||||||
transformElement,
|
transformElement,
|
||||||
trackSlotScopes,
|
trackSlotScopes,
|
||||||
|
...(options.transformText ? [transformText] : []),
|
||||||
],
|
],
|
||||||
directiveTransforms: {
|
directiveTransforms: {
|
||||||
on: transformOn,
|
on: transformOn,
|
||||||
|
|
@ -307,6 +312,40 @@ describe('compiler: transform component slots', () => {
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('named slots w/ implicit default slot containing non-breaking space', () => {
|
||||||
|
const { root, slots } = parseWithSlots(
|
||||||
|
`<Comp>
|
||||||
|
\u00a0
|
||||||
|
<template #one>foo</template>
|
||||||
|
</Comp>`,
|
||||||
|
)
|
||||||
|
expect(slots).toMatchObject(
|
||||||
|
createSlotMatcher({
|
||||||
|
one: {
|
||||||
|
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||||
|
params: undefined,
|
||||||
|
returns: [
|
||||||
|
{
|
||||||
|
type: NodeTypes.TEXT,
|
||||||
|
content: `foo`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
default: {
|
||||||
|
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||||
|
params: undefined,
|
||||||
|
returns: [
|
||||||
|
{
|
||||||
|
type: NodeTypes.TEXT,
|
||||||
|
content: ` \u00a0 `,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
test('dynamically named slots', () => {
|
test('dynamically named slots', () => {
|
||||||
const { root, slots } = parseWithSlots(
|
const { root, slots } = parseWithSlots(
|
||||||
`<Comp>
|
`<Comp>
|
||||||
|
|
@ -478,7 +517,10 @@ describe('compiler: transform component slots', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should only force dynamic slots when actually using scope vars w/ prefixIdentifiers: true', () => {
|
test('should only force dynamic slots when actually using scope vars w/ prefixIdentifiers: true', () => {
|
||||||
function assertDynamicSlots(template: string, shouldForce: boolean) {
|
function assertDynamicSlots(
|
||||||
|
template: string,
|
||||||
|
expectedPatchFlag?: PatchFlags,
|
||||||
|
) {
|
||||||
const { root } = parseWithSlots(template, { prefixIdentifiers: true })
|
const { root } = parseWithSlots(template, { prefixIdentifiers: true })
|
||||||
let flag: any
|
let flag: any
|
||||||
if (root.children[0].type === NodeTypes.FOR) {
|
if (root.children[0].type === NodeTypes.FOR) {
|
||||||
|
|
@ -491,8 +533,8 @@ describe('compiler: transform component slots', () => {
|
||||||
.children[0] as ComponentNode
|
.children[0] as ComponentNode
|
||||||
flag = (innerComp.codegenNode as VNodeCall).patchFlag
|
flag = (innerComp.codegenNode as VNodeCall).patchFlag
|
||||||
}
|
}
|
||||||
if (shouldForce) {
|
if (expectedPatchFlag) {
|
||||||
expect(flag).toBe(PatchFlags.DYNAMIC_SLOTS)
|
expect(flag).toBe(expectedPatchFlag)
|
||||||
} else {
|
} else {
|
||||||
expect(flag).toBeUndefined()
|
expect(flag).toBeUndefined()
|
||||||
}
|
}
|
||||||
|
|
@ -502,14 +544,13 @@ describe('compiler: transform component slots', () => {
|
||||||
`<div v-for="i in list">
|
`<div v-for="i in list">
|
||||||
<Comp v-slot="bar">foo</Comp>
|
<Comp v-slot="bar">foo</Comp>
|
||||||
</div>`,
|
</div>`,
|
||||||
false,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
assertDynamicSlots(
|
assertDynamicSlots(
|
||||||
`<div v-for="i in list">
|
`<div v-for="i in list">
|
||||||
<Comp v-slot="bar">{{ i }}</Comp>
|
<Comp v-slot="bar">{{ i }}</Comp>
|
||||||
</div>`,
|
</div>`,
|
||||||
true,
|
PatchFlags.DYNAMIC_SLOTS,
|
||||||
)
|
)
|
||||||
|
|
||||||
// reference the component's own slot variable should not force dynamic slots
|
// reference the component's own slot variable should not force dynamic slots
|
||||||
|
|
@ -517,14 +558,13 @@ describe('compiler: transform component slots', () => {
|
||||||
`<Comp v-slot="foo">
|
`<Comp v-slot="foo">
|
||||||
<Comp v-slot="bar">{{ bar }}</Comp>
|
<Comp v-slot="bar">{{ bar }}</Comp>
|
||||||
</Comp>`,
|
</Comp>`,
|
||||||
false,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
assertDynamicSlots(
|
assertDynamicSlots(
|
||||||
`<Comp v-slot="foo">
|
`<Comp v-slot="foo">
|
||||||
<Comp v-slot="bar">{{ foo }}</Comp>
|
<Comp v-slot="bar">{{ foo }}</Comp>
|
||||||
</Comp>`,
|
</Comp>`,
|
||||||
true,
|
PatchFlags.DYNAMIC_SLOTS,
|
||||||
)
|
)
|
||||||
|
|
||||||
// #2564
|
// #2564
|
||||||
|
|
@ -532,14 +572,35 @@ describe('compiler: transform component slots', () => {
|
||||||
`<div v-for="i in list">
|
`<div v-for="i in list">
|
||||||
<Comp v-slot="bar"><button @click="fn(i)" /></Comp>
|
<Comp v-slot="bar"><button @click="fn(i)" /></Comp>
|
||||||
</div>`,
|
</div>`,
|
||||||
true,
|
PatchFlags.DYNAMIC_SLOTS,
|
||||||
)
|
)
|
||||||
|
|
||||||
assertDynamicSlots(
|
assertDynamicSlots(
|
||||||
`<div v-for="i in list">
|
`<div v-for="i in list">
|
||||||
<Comp v-slot="bar"><button @click="fn()" /></Comp>
|
<Comp v-slot="bar"><button @click="fn()" /></Comp>
|
||||||
</div>`,
|
</div>`,
|
||||||
false,
|
)
|
||||||
|
|
||||||
|
// #9380
|
||||||
|
assertDynamicSlots(
|
||||||
|
`<div v-for="i in list">
|
||||||
|
<Comp :i="i">foo</Comp>
|
||||||
|
</div>`,
|
||||||
|
PatchFlags.PROPS,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertDynamicSlots(
|
||||||
|
`<div v-for="i in list">
|
||||||
|
<Comp v-slot="{ value = i }"><button @click="fn()" /></Comp>
|
||||||
|
</div>`,
|
||||||
|
PatchFlags.DYNAMIC_SLOTS,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertDynamicSlots(
|
||||||
|
`<div v-for="i in list">
|
||||||
|
<Comp v-slot:[i]><button @click="fn()" /></Comp>
|
||||||
|
</div>`,
|
||||||
|
PatchFlags.DYNAMIC_SLOTS,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -988,5 +1049,58 @@ describe('compiler: transform component slots', () => {
|
||||||
|
|
||||||
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
|
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('implicit default slot with non-breaking space', () => {
|
||||||
|
const source = `
|
||||||
|
<Comp>
|
||||||
|
|
||||||
|
<template #header> Header </template>
|
||||||
|
</Comp>
|
||||||
|
`
|
||||||
|
const { root } = parseWithSlots(source, {
|
||||||
|
whitespace: 'preserve',
|
||||||
|
})
|
||||||
|
|
||||||
|
const slots = (root as any).children[0].codegenNode.children
|
||||||
|
.properties as ObjectExpression['properties']
|
||||||
|
|
||||||
|
expect(
|
||||||
|
slots.some(p => (p.key as SimpleExpressionNode).content === 'default'),
|
||||||
|
).toBe(true)
|
||||||
|
|
||||||
|
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()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('named slot with v-if + v-else and comments', () => {
|
||||||
|
const source = `
|
||||||
|
<Comp>
|
||||||
|
<template #one v-if="ok">foo</template>
|
||||||
|
<!-- start -->
|
||||||
|
|
||||||
|
<!-- end -->
|
||||||
|
<template #two v-else>baz</template>
|
||||||
|
</Comp>
|
||||||
|
`
|
||||||
|
const { root } = parseWithSlots(source, {
|
||||||
|
transformText: true,
|
||||||
|
whitespace: 'preserve',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
import type { ExpressionNode, TransformContext } from '../src'
|
import { babelParse, walkIdentifiers } from '@vue/compiler-sfc'
|
||||||
|
import {
|
||||||
|
type ExpressionNode,
|
||||||
|
type TransformContext,
|
||||||
|
isReferencedIdentifier,
|
||||||
|
} from '../src'
|
||||||
import { type Position, createSimpleExpression } from '../src/ast'
|
import { type Position, createSimpleExpression } from '../src/ast'
|
||||||
import {
|
import {
|
||||||
advancePositionWithClone,
|
advancePositionWithClone,
|
||||||
|
|
@ -115,3 +120,18 @@ test('toValidAssetId', () => {
|
||||||
'_component_test_2797935797_1',
|
'_component_test_2797935797_1',
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('isReferencedIdentifier', () => {
|
||||||
|
test('identifiers in function parameters should not be inferred as references', () => {
|
||||||
|
expect.assertions(4)
|
||||||
|
const ast = babelParse(`(({ title }) => [])`)
|
||||||
|
walkIdentifiers(
|
||||||
|
ast.program.body[0],
|
||||||
|
(node, parent, parentStack, isReference) => {
|
||||||
|
expect(isReference).toBe(false)
|
||||||
|
expect(isReferencedIdentifier(node, parent, parentStack)).toBe(false)
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vue/compiler-core",
|
"name": "@vue/compiler-core",
|
||||||
"version": "3.5.4",
|
"version": "3.5.26",
|
||||||
"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",
|
||||||
|
|
@ -48,7 +48,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": "catalog:",
|
"@babel/parser": "catalog:",
|
||||||
"@vue/shared": "workspace:*",
|
"@vue/shared": "workspace:*",
|
||||||
"entities": "^4.5.0",
|
"entities": "^7.0.0",
|
||||||
"estree-walker": "catalog:",
|
"estree-walker": "catalog:",
|
||||||
"source-map-js": "catalog:"
|
"source-map-js": "catalog:"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import type {
|
||||||
Node,
|
Node,
|
||||||
ObjectProperty,
|
ObjectProperty,
|
||||||
Program,
|
Program,
|
||||||
|
SwitchCase,
|
||||||
|
SwitchStatement,
|
||||||
} from '@babel/types'
|
} from '@babel/types'
|
||||||
import { walk } from 'estree-walker'
|
import { walk } from 'estree-walker'
|
||||||
|
|
||||||
|
|
@ -80,15 +82,32 @@ export function walkIdentifiers(
|
||||||
markScopeIdentifier(node, id, knownIds),
|
markScopeIdentifier(node, id, knownIds),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
} else if (node.type === 'SwitchStatement') {
|
||||||
|
if (node.scopeIds) {
|
||||||
|
node.scopeIds.forEach(id => markKnownIds(id, knownIds))
|
||||||
|
} else {
|
||||||
|
// record switch case block-level local variables
|
||||||
|
walkSwitchStatement(node, false, id =>
|
||||||
|
markScopeIdentifier(node, id, knownIds),
|
||||||
|
)
|
||||||
|
}
|
||||||
} else if (node.type === 'CatchClause' && node.param) {
|
} else if (node.type === 'CatchClause' && node.param) {
|
||||||
|
if (node.scopeIds) {
|
||||||
|
node.scopeIds.forEach(id => markKnownIds(id, knownIds))
|
||||||
|
} else {
|
||||||
for (const id of extractIdentifiers(node.param)) {
|
for (const id of extractIdentifiers(node.param)) {
|
||||||
markScopeIdentifier(node, id, knownIds)
|
markScopeIdentifier(node, id, knownIds)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if (isForStatement(node)) {
|
} else if (isForStatement(node)) {
|
||||||
|
if (node.scopeIds) {
|
||||||
|
node.scopeIds.forEach(id => markKnownIds(id, knownIds))
|
||||||
|
} else {
|
||||||
walkForStatement(node, false, id =>
|
walkForStatement(node, false, id =>
|
||||||
markScopeIdentifier(node, id, knownIds),
|
markScopeIdentifier(node, id, knownIds),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
leave(node: Node & { scopeIds?: Set<string> }, parent: Node | null) {
|
leave(node: Node & { scopeIds?: Set<string> }, parent: Node | null) {
|
||||||
parent && parentStack.pop()
|
parent && parentStack.pop()
|
||||||
|
|
@ -122,7 +141,7 @@ export function isReferencedIdentifier(
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isReferenced(id, parent)) {
|
if (isReferenced(id, parent, parentStack[parentStack.length - 2])) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -132,7 +151,8 @@ export function isReferencedIdentifier(
|
||||||
case 'AssignmentExpression':
|
case 'AssignmentExpression':
|
||||||
case 'AssignmentPattern':
|
case 'AssignmentPattern':
|
||||||
return true
|
return true
|
||||||
case 'ObjectPattern':
|
case 'ObjectProperty':
|
||||||
|
return parent.key !== id && isInDestructureAssignment(parent, parentStack)
|
||||||
case 'ArrayPattern':
|
case 'ArrayPattern':
|
||||||
return isInDestructureAssignment(parent, parentStack)
|
return isInDestructureAssignment(parent, parentStack)
|
||||||
}
|
}
|
||||||
|
|
@ -186,10 +206,11 @@ export function walkFunctionParams(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function walkBlockDeclarations(
|
export function walkBlockDeclarations(
|
||||||
block: BlockStatement | Program,
|
block: BlockStatement | SwitchCase | Program,
|
||||||
onIdent: (node: Identifier) => void,
|
onIdent: (node: Identifier) => void,
|
||||||
): void {
|
): void {
|
||||||
for (const stmt of block.body) {
|
const body = block.type === 'SwitchCase' ? block.consequent : block.body
|
||||||
|
for (const stmt of body) {
|
||||||
if (stmt.type === 'VariableDeclaration') {
|
if (stmt.type === 'VariableDeclaration') {
|
||||||
if (stmt.declare) continue
|
if (stmt.declare) continue
|
||||||
for (const decl of stmt.declarations) {
|
for (const decl of stmt.declarations) {
|
||||||
|
|
@ -205,6 +226,8 @@ export function walkBlockDeclarations(
|
||||||
onIdent(stmt.id)
|
onIdent(stmt.id)
|
||||||
} else if (isForStatement(stmt)) {
|
} else if (isForStatement(stmt)) {
|
||||||
walkForStatement(stmt, true, onIdent)
|
walkForStatement(stmt, true, onIdent)
|
||||||
|
} else if (stmt.type === 'SwitchStatement') {
|
||||||
|
walkSwitchStatement(stmt, true, onIdent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -238,6 +261,28 @@ function walkForStatement(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function walkSwitchStatement(
|
||||||
|
stmt: SwitchStatement,
|
||||||
|
isVar: boolean,
|
||||||
|
onIdent: (id: Identifier) => void,
|
||||||
|
) {
|
||||||
|
for (const cs of stmt.cases) {
|
||||||
|
for (const stmt of cs.consequent) {
|
||||||
|
if (
|
||||||
|
stmt.type === 'VariableDeclaration' &&
|
||||||
|
(stmt.kind === 'var' ? isVar : !isVar)
|
||||||
|
) {
|
||||||
|
for (const decl of stmt.declarations) {
|
||||||
|
for (const id of extractIdentifiers(decl.id)) {
|
||||||
|
onIdent(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
walkBlockDeclarations(cs, onIdent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function extractIdentifiers(
|
export function extractIdentifiers(
|
||||||
param: Node,
|
param: Node,
|
||||||
nodes: Identifier[] = [],
|
nodes: Identifier[] = [],
|
||||||
|
|
|
||||||
|
|
@ -119,8 +119,10 @@ enum NewlineType {
|
||||||
Unknown = -3,
|
Unknown = -3,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CodegenContext
|
export interface CodegenContext extends Omit<
|
||||||
extends Omit<Required<CodegenOptions>, 'bindingMetadata' | 'inline'> {
|
Required<CodegenOptions>,
|
||||||
|
'bindingMetadata' | 'inline'
|
||||||
|
> {
|
||||||
source: string
|
source: string
|
||||||
code: string
|
code: string
|
||||||
line: number
|
line: number
|
||||||
|
|
@ -188,8 +190,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 +229,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 +1021,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(`(`)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import { transformModel } from './transforms/vModel'
|
||||||
import { transformFilter } from './compat/transformFilter'
|
import { transformFilter } from './compat/transformFilter'
|
||||||
import { ErrorCodes, createCompilerError, defaultOnError } from './errors'
|
import { ErrorCodes, createCompilerError, defaultOnError } from './errors'
|
||||||
import { transformMemo } from './transforms/vMemo'
|
import { transformMemo } from './transforms/vMemo'
|
||||||
|
import { transformVBindShorthand } from './transforms/transformVBindShorthand'
|
||||||
|
|
||||||
export type TransformPreset = [
|
export type TransformPreset = [
|
||||||
NodeTransform[],
|
NodeTransform[],
|
||||||
|
|
@ -33,6 +34,7 @@ export function getBaseTransformPreset(
|
||||||
): TransformPreset {
|
): TransformPreset {
|
||||||
return [
|
return [
|
||||||
[
|
[
|
||||||
|
transformVBindShorthand,
|
||||||
transformOnce,
|
transformOnce,
|
||||||
transformIf,
|
transformIf,
|
||||||
transformMemo,
|
transformMemo,
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,7 @@ export enum ErrorCodes {
|
||||||
X_V_MODEL_MALFORMED_EXPRESSION,
|
X_V_MODEL_MALFORMED_EXPRESSION,
|
||||||
X_V_MODEL_ON_SCOPE_VARIABLE,
|
X_V_MODEL_ON_SCOPE_VARIABLE,
|
||||||
X_V_MODEL_ON_PROPS,
|
X_V_MODEL_ON_PROPS,
|
||||||
|
X_V_MODEL_ON_CONST,
|
||||||
X_INVALID_EXPRESSION,
|
X_INVALID_EXPRESSION,
|
||||||
X_KEEP_ALIVE_INVALID_CHILDREN,
|
X_KEEP_ALIVE_INVALID_CHILDREN,
|
||||||
|
|
||||||
|
|
@ -176,6 +177,7 @@ export const errorMessages: Record<ErrorCodes, string> = {
|
||||||
[ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION]: `v-model value must be a valid JavaScript member expression.`,
|
[ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION]: `v-model value must be a valid JavaScript member expression.`,
|
||||||
[ErrorCodes.X_V_MODEL_ON_SCOPE_VARIABLE]: `v-model cannot be used on v-for or v-slot scope variables because they are not writable.`,
|
[ErrorCodes.X_V_MODEL_ON_SCOPE_VARIABLE]: `v-model cannot be used on v-for or v-slot scope variables because they are not writable.`,
|
||||||
[ErrorCodes.X_V_MODEL_ON_PROPS]: `v-model cannot be used on a prop, because local prop bindings are not writable.\nUse a v-bind binding combined with a v-on listener that emits update:x event instead.`,
|
[ErrorCodes.X_V_MODEL_ON_PROPS]: `v-model cannot be used on a prop, because local prop bindings are not writable.\nUse a v-bind binding combined with a v-on listener that emits update:x event instead.`,
|
||||||
|
[ErrorCodes.X_V_MODEL_ON_CONST]: `v-model cannot be used on a const binding because it is not writable.`,
|
||||||
[ErrorCodes.X_INVALID_EXPRESSION]: `Error parsing JavaScript expression: `,
|
[ErrorCodes.X_INVALID_EXPRESSION]: `Error parsing JavaScript expression: `,
|
||||||
[ErrorCodes.X_KEEP_ALIVE_INVALID_CHILDREN]: `<KeepAlive> expects exactly one child component.`,
|
[ErrorCodes.X_KEEP_ALIVE_INVALID_CHILDREN]: `<KeepAlive> expects exactly one child component.`,
|
||||||
[ErrorCodes.X_VNODE_HOOKS]: `@vnode-* hooks in templates are no longer supported. Use the vue: prefix instead. For example, @vnode-mounted should be changed to @vue:mounted. @vnode-* hooks support has been removed in 3.4.`,
|
[ErrorCodes.X_VNODE_HOOKS]: `@vnode-* hooks in templates are no longer supported. Use the vue: prefix instead. For example, @vnode-mounted should be changed to @vue:mounted. @vnode-* hooks support has been removed in 3.4.`,
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ export {
|
||||||
buildDirectiveArgs,
|
buildDirectiveArgs,
|
||||||
type PropsExpression,
|
type PropsExpression,
|
||||||
} from './transforms/transformElement'
|
} from './transforms/transformElement'
|
||||||
|
export { transformVBindShorthand } from './transforms/transformVBindShorthand'
|
||||||
export { processSlotOutlet } from './transforms/transformSlotOutlet'
|
export { processSlotOutlet } from './transforms/transformSlotOutlet'
|
||||||
export { getConstantType } from './transforms/cacheStatic'
|
export { getConstantType } from './transforms/cacheStatic'
|
||||||
export { generateCodeFrame } from '@vue/shared'
|
export { generateCodeFrame } from '@vue/shared'
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,7 @@ export interface ErrorHandlingOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ParserOptions
|
export interface ParserOptions
|
||||||
extends ErrorHandlingOptions,
|
extends ErrorHandlingOptions, CompilerCompatOptions {
|
||||||
CompilerCompatOptions {
|
|
||||||
/**
|
/**
|
||||||
* Base mode is platform agnostic and only parses HTML-like template syntax,
|
* Base mode is platform agnostic and only parses HTML-like template syntax,
|
||||||
* treating all tags the same way. Specific tag parsing behavior can be
|
* treating all tags the same way. Specific tag parsing behavior can be
|
||||||
|
|
@ -52,6 +51,11 @@ export interface ParserOptions
|
||||||
* e.g. elements that should preserve whitespace inside, e.g. `<pre>`
|
* e.g. elements that should preserve whitespace inside, e.g. `<pre>`
|
||||||
*/
|
*/
|
||||||
isPreTag?: (tag: string) => boolean
|
isPreTag?: (tag: string) => boolean
|
||||||
|
/**
|
||||||
|
* Elements that should ignore the first newline token per parinsg spec
|
||||||
|
* e.g. `<textarea>` and `<pre>`
|
||||||
|
*/
|
||||||
|
isIgnoreNewlineTag?: (tag: string) => boolean
|
||||||
/**
|
/**
|
||||||
* Platform-specific built-in components e.g. `<Transition>`
|
* Platform-specific built-in components e.g. `<Transition>`
|
||||||
*/
|
*/
|
||||||
|
|
@ -212,7 +216,8 @@ interface SharedTransformCodegenOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TransformOptions
|
export interface TransformOptions
|
||||||
extends SharedTransformCodegenOptions,
|
extends
|
||||||
|
SharedTransformCodegenOptions,
|
||||||
ErrorHandlingOptions,
|
ErrorHandlingOptions,
|
||||||
CompilerCompatOptions {
|
CompilerCompatOptions {
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -40,11 +40,13 @@ import {
|
||||||
} from './errors'
|
} from './errors'
|
||||||
import {
|
import {
|
||||||
forAliasRE,
|
forAliasRE,
|
||||||
|
isAllWhitespace,
|
||||||
isCoreComponent,
|
isCoreComponent,
|
||||||
isSimpleIdentifier,
|
isSimpleIdentifier,
|
||||||
isStaticArgOf,
|
isStaticArgOf,
|
||||||
|
isVPre,
|
||||||
} from './utils'
|
} from './utils'
|
||||||
import { decodeHTML } from 'entities/lib/decode.js'
|
import { decodeHTML } from 'entities/decode'
|
||||||
import {
|
import {
|
||||||
type ParserOptions as BabelOptions,
|
type ParserOptions as BabelOptions,
|
||||||
parse,
|
parse,
|
||||||
|
|
@ -72,6 +74,7 @@ export const defaultParserOptions: MergedParserOptions = {
|
||||||
getNamespace: () => Namespaces.HTML,
|
getNamespace: () => Namespaces.HTML,
|
||||||
isVoidTag: NO,
|
isVoidTag: NO,
|
||||||
isPreTag: NO,
|
isPreTag: NO,
|
||||||
|
isIgnoreNewlineTag: NO,
|
||||||
isCustomElement: NO,
|
isCustomElement: NO,
|
||||||
onError: defaultOnError,
|
onError: defaultOnError,
|
||||||
onWarn: defaultOnWarn,
|
onWarn: defaultOnWarn,
|
||||||
|
|
@ -245,7 +248,7 @@ const tokenizer = new Tokenizer(stack, {
|
||||||
ondirarg(start, end) {
|
ondirarg(start, end) {
|
||||||
if (start === end) return
|
if (start === end) return
|
||||||
const arg = getSlice(start, end)
|
const arg = getSlice(start, end)
|
||||||
if (inVPre) {
|
if (inVPre && !isVPre(currentProp!)) {
|
||||||
;(currentProp as AttributeNode).name += arg
|
;(currentProp as AttributeNode).name += arg
|
||||||
setLocEnd((currentProp as AttributeNode).nameLoc, end)
|
setLocEnd((currentProp as AttributeNode).nameLoc, end)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -261,7 +264,7 @@ const tokenizer = new Tokenizer(stack, {
|
||||||
|
|
||||||
ondirmodifier(start, end) {
|
ondirmodifier(start, end) {
|
||||||
const mod = getSlice(start, end)
|
const mod = getSlice(start, end)
|
||||||
if (inVPre) {
|
if (inVPre && !isVPre(currentProp!)) {
|
||||||
;(currentProp as AttributeNode).name += '.' + mod
|
;(currentProp as AttributeNode).name += '.' + mod
|
||||||
setLocEnd((currentProp as AttributeNode).nameLoc, end)
|
setLocEnd((currentProp as AttributeNode).nameLoc, end)
|
||||||
} else if ((currentProp as DirectiveNode).name === 'slot') {
|
} else if ((currentProp as DirectiveNode).name === 'slot') {
|
||||||
|
|
@ -387,7 +390,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'
|
||||||
|
|
@ -633,7 +636,7 @@ function onCloseTag(el: ElementNode, end: number, isImplied = false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// refine element type
|
// refine element type
|
||||||
const { tag, ns } = el
|
const { tag, ns, children } = el
|
||||||
if (!inVPre) {
|
if (!inVPre) {
|
||||||
if (tag === 'slot') {
|
if (tag === 'slot') {
|
||||||
el.tagType = ElementTypes.SLOT
|
el.tagType = ElementTypes.SLOT
|
||||||
|
|
@ -646,8 +649,18 @@ function onCloseTag(el: ElementNode, end: number, isImplied = false) {
|
||||||
|
|
||||||
// whitespace management
|
// whitespace management
|
||||||
if (!tokenizer.inRCDATA) {
|
if (!tokenizer.inRCDATA) {
|
||||||
el.children = condenseWhitespace(el.children, el.tag)
|
el.children = condenseWhitespace(children)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ns === Namespaces.HTML && currentOptions.isIgnoreNewlineTag(tag)) {
|
||||||
|
// remove leading newline for <textarea> and <pre> per html spec
|
||||||
|
// https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inbody
|
||||||
|
const first = children[0]
|
||||||
|
if (first && first.type === NodeTypes.TEXT) {
|
||||||
|
first.content = first.content.replace(/^\r?\n/, '')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ns === Namespaces.HTML && currentOptions.isPreTag(tag)) {
|
if (ns === Namespaces.HTML && currentOptions.isPreTag(tag)) {
|
||||||
inPre--
|
inPre--
|
||||||
}
|
}
|
||||||
|
|
@ -821,10 +834,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++) {
|
||||||
|
|
@ -869,26 +879,9 @@ function condenseWhitespace(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (inPre && tag && currentOptions.isPreTag(tag)) {
|
|
||||||
// remove leading newline per html spec
|
|
||||||
// https://html.spec.whatwg.org/multipage/grouping-content.html#the-pre-element
|
|
||||||
const first = nodes[0]
|
|
||||||
if (first && first.type === NodeTypes.TEXT) {
|
|
||||||
first.content = first.content.replace(/^\r?\n/, '')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return removedWhitespace ? nodes.filter(Boolean) : nodes
|
return removedWhitespace ? nodes.filter(Boolean) : nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
function isAllWhitespace(str: string) {
|
|
||||||
for (let i = 0; i < str.length; i++) {
|
|
||||||
if (!isWhitespace(str.charCodeAt(i))) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
function hasNewlineChar(str: string) {
|
function hasNewlineChar(str: string) {
|
||||||
for (let i = 0; i < str.length; i++) {
|
for (let i = 0; i < str.length; i++) {
|
||||||
const c = str.charCodeAt(i)
|
const c = str.charCodeAt(i)
|
||||||
|
|
@ -930,6 +923,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)
|
||||||
|
|
@ -1049,7 +1046,7 @@ export function baseParse(input: string, options?: ParserOptions): RootNode {
|
||||||
`[@vue/compiler-core] decodeEntities option is passed but will be ` +
|
`[@vue/compiler-core] decodeEntities option is passed but will be ` +
|
||||||
`ignored in non-browser builds.`,
|
`ignored in non-browser builds.`,
|
||||||
)
|
)
|
||||||
} else if (__BROWSER__ && !currentOptions.decodeEntities) {
|
} else if (__BROWSER__ && !__TEST__ && !currentOptions.decodeEntities) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`[@vue/compiler-core] decodeEntities option is required in browser builds.`,
|
`[@vue/compiler-core] decodeEntities option is required in browser builds.`,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ import {
|
||||||
EntityDecoder,
|
EntityDecoder,
|
||||||
fromCodePoint,
|
fromCodePoint,
|
||||||
htmlDecodeTree,
|
htmlDecodeTree,
|
||||||
} from 'entities/lib/decode.js'
|
} from 'entities/decode'
|
||||||
|
|
||||||
export enum ParseMode {
|
export enum ParseMode {
|
||||||
BASE,
|
BASE,
|
||||||
|
|
@ -296,14 +296,30 @@ export default class Tokenizer {
|
||||||
public getPos(index: number): Position {
|
public getPos(index: number): Position {
|
||||||
let line = 1
|
let line = 1
|
||||||
let column = index + 1
|
let column = index + 1
|
||||||
for (let i = this.newlines.length - 1; i >= 0; i--) {
|
const length = this.newlines.length
|
||||||
const newlineIndex = this.newlines[i]
|
let j = -1
|
||||||
if (index > newlineIndex) {
|
if (length > 100) {
|
||||||
line = i + 2
|
let l = -1
|
||||||
column = index - newlineIndex
|
let r = length
|
||||||
|
while (l + 1 < r) {
|
||||||
|
const m = (l + r) >>> 1
|
||||||
|
this.newlines[m] < index ? (l = m) : (r = m)
|
||||||
|
}
|
||||||
|
j = l
|
||||||
|
} else {
|
||||||
|
for (let i = length - 1; i >= 0; i--) {
|
||||||
|
if (index > this.newlines[i]) {
|
||||||
|
j = i
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j >= 0) {
|
||||||
|
line = j + 2
|
||||||
|
column = index - this.newlines[j]
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
column,
|
column,
|
||||||
line,
|
line,
|
||||||
|
|
@ -438,7 +454,7 @@ export default class Tokenizer {
|
||||||
// We have to parse entities in <title> and <textarea> tags.
|
// We have to parse entities in <title> and <textarea> tags.
|
||||||
if (!__BROWSER__ && c === CharCodes.Amp) {
|
if (!__BROWSER__ && c === CharCodes.Amp) {
|
||||||
this.startEntity()
|
this.startEntity()
|
||||||
} else if (c === this.delimiterOpen[0]) {
|
} else if (!this.inVPre && c === this.delimiterOpen[0]) {
|
||||||
// We also need to handle interpolation
|
// We also need to handle interpolation
|
||||||
this.state = State.InterpolationOpen
|
this.state = State.InterpolationOpen
|
||||||
this.delimiterIndex = 0
|
this.delimiterIndex = 0
|
||||||
|
|
@ -929,7 +945,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) {
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
@ -82,7 +82,8 @@ export interface ImportItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TransformContext
|
export interface TransformContext
|
||||||
extends Required<Omit<TransformOptions, keyof CompilerCompatOptions>>,
|
extends
|
||||||
|
Required<Omit<TransformOptions, keyof CompilerCompatOptions>>,
|
||||||
CompilerCompatOptions {
|
CompilerCompatOptions {
|
||||||
selfName: string | null
|
selfName: string | null
|
||||||
root: RootNode
|
root: RootNode
|
||||||
|
|
@ -116,7 +117,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 +298,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 +357,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 +371,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.
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,13 @@ import {
|
||||||
getVNodeHelper,
|
getVNodeHelper,
|
||||||
} from '../ast'
|
} from '../ast'
|
||||||
import type { TransformContext } from '../transform'
|
import type { TransformContext } from '../transform'
|
||||||
import { PatchFlags, isArray, isString, isSymbol } from '@vue/shared'
|
import {
|
||||||
|
PatchFlagNames,
|
||||||
|
PatchFlags,
|
||||||
|
isArray,
|
||||||
|
isString,
|
||||||
|
isSymbol,
|
||||||
|
} from '@vue/shared'
|
||||||
import { findDir, isSlotOutlet } from '../utils'
|
import { findDir, isSlotOutlet } from '../utils'
|
||||||
import {
|
import {
|
||||||
GUARD_REACTIVE_PROPS,
|
GUARD_REACTIVE_PROPS,
|
||||||
|
|
@ -38,20 +44,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(
|
||||||
|
|
@ -107,6 +112,15 @@ function walk(
|
||||||
? ConstantTypes.NOT_CONSTANT
|
? ConstantTypes.NOT_CONSTANT
|
||||||
: getConstantType(child, context)
|
: getConstantType(child, context)
|
||||||
if (constantType >= ConstantTypes.CAN_CACHE) {
|
if (constantType >= ConstantTypes.CAN_CACHE) {
|
||||||
|
if (
|
||||||
|
child.codegenNode.type === NodeTypes.JS_CALL_EXPRESSION &&
|
||||||
|
child.codegenNode.arguments.length > 0
|
||||||
|
) {
|
||||||
|
child.codegenNode.arguments.push(
|
||||||
|
PatchFlags.CACHED +
|
||||||
|
(__DEV__ ? ` /* ${PatchFlagNames[PatchFlags.CACHED]} */` : ``),
|
||||||
|
)
|
||||||
|
}
|
||||||
toCache.push(child)
|
toCache.push(child)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -205,9 +219,13 @@ function walk(
|
||||||
// #6978, #7138, #7114
|
// #6978, #7138, #7114
|
||||||
// a cached children array inside v-for can caused HMR errors since
|
// a cached children array inside v-for can caused HMR errors since
|
||||||
// it might be mutated when mounting the first item
|
// it might be mutated when mounting the first item
|
||||||
if (inFor && context.hmr) {
|
// #13221
|
||||||
|
// fix memory leak in cached array:
|
||||||
|
// cached vnodes get replaced by cloned ones during mountChildren,
|
||||||
|
// which bind DOM elements. These DOM references persist after unmount,
|
||||||
|
// preventing garbage collection. Array spread avoids mutating cached
|
||||||
|
// array, preventing memory leaks.
|
||||||
exp.needArraySpread = true
|
exp.needArraySpread = true
|
||||||
}
|
|
||||||
return exp
|
return exp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
import { camelize } from '@vue/shared'
|
||||||
|
import {
|
||||||
|
NodeTypes,
|
||||||
|
type SimpleExpressionNode,
|
||||||
|
createSimpleExpression,
|
||||||
|
} from '../ast'
|
||||||
|
import type { NodeTransform } from '../transform'
|
||||||
|
import { ErrorCodes, createCompilerError } from '../errors'
|
||||||
|
import { validFirstIdentCharRE } from '../utils'
|
||||||
|
|
||||||
|
export const transformVBindShorthand: NodeTransform = (node, context) => {
|
||||||
|
if (node.type === NodeTypes.ELEMENT) {
|
||||||
|
for (const prop of node.props) {
|
||||||
|
// same-name shorthand - :arg is expanded to :arg="arg"
|
||||||
|
if (
|
||||||
|
prop.type === NodeTypes.DIRECTIVE &&
|
||||||
|
prop.name === 'bind' &&
|
||||||
|
(!prop.exp ||
|
||||||
|
// #13930 :foo in in-DOM templates will be parsed into :foo="" by browser
|
||||||
|
(__BROWSER__ &&
|
||||||
|
prop.exp.type === NodeTypes.SIMPLE_EXPRESSION &&
|
||||||
|
!prop.exp.content.trim())) &&
|
||||||
|
prop.arg
|
||||||
|
) {
|
||||||
|
const arg = prop.arg
|
||||||
|
if (arg.type !== NodeTypes.SIMPLE_EXPRESSION || !arg.isStatic) {
|
||||||
|
// only simple expression is allowed for same-name shorthand
|
||||||
|
context.onError(
|
||||||
|
createCompilerError(
|
||||||
|
ErrorCodes.X_V_BIND_INVALID_SAME_NAME_ARGUMENT,
|
||||||
|
arg.loc,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
prop.exp = createSimpleExpression('', true, arg.loc)
|
||||||
|
} else {
|
||||||
|
const propName = camelize((arg as SimpleExpressionNode).content)
|
||||||
|
if (
|
||||||
|
validFirstIdentCharRE.test(propName[0]) ||
|
||||||
|
// allow hyphen first char for https://github.com/vuejs/language-tools/pull/3424
|
||||||
|
propName[0] === '-'
|
||||||
|
) {
|
||||||
|
prop.exp = createSimpleExpression(propName, false, arg.loc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,18 +1,15 @@
|
||||||
import type { DirectiveTransform, TransformContext } from '../transform'
|
import type { DirectiveTransform } from '../transform'
|
||||||
import {
|
import {
|
||||||
type DirectiveNode,
|
|
||||||
type ExpressionNode,
|
type ExpressionNode,
|
||||||
NodeTypes,
|
NodeTypes,
|
||||||
type SimpleExpressionNode,
|
|
||||||
createObjectProperty,
|
createObjectProperty,
|
||||||
createSimpleExpression,
|
createSimpleExpression,
|
||||||
} from '../ast'
|
} from '../ast'
|
||||||
import { ErrorCodes, createCompilerError } from '../errors'
|
import { ErrorCodes, createCompilerError } from '../errors'
|
||||||
import { camelize } from '@vue/shared'
|
import { camelize } from '@vue/shared'
|
||||||
import { CAMELIZE } from '../runtimeHelpers'
|
import { CAMELIZE } from '../runtimeHelpers'
|
||||||
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) => {
|
||||||
|
|
@ -40,32 +37,11 @@ export const transformBind: DirectiveTransform = (dir, _node, context) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// same-name shorthand - :arg is expanded to :arg="arg"
|
|
||||||
if (!exp) {
|
|
||||||
if (arg.type !== NodeTypes.SIMPLE_EXPRESSION || !arg.isStatic) {
|
|
||||||
// only simple expression is allowed for same-name shorthand
|
|
||||||
context.onError(
|
|
||||||
createCompilerError(
|
|
||||||
ErrorCodes.X_V_BIND_INVALID_SAME_NAME_ARGUMENT,
|
|
||||||
arg.loc,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
return {
|
|
||||||
props: [
|
|
||||||
createObjectProperty(arg, createSimpleExpression('', true, loc)),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
transformBindShorthand(dir, context)
|
|
||||||
exp = dir.exp!
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg.type !== NodeTypes.SIMPLE_EXPRESSION) {
|
if (arg.type !== NodeTypes.SIMPLE_EXPRESSION) {
|
||||||
arg.children.unshift(`(`)
|
arg.children.unshift(`(`)
|
||||||
arg.children.push(`) || ""`)
|
arg.children.push(`) || ""`)
|
||||||
} else if (!arg.isStatic) {
|
} else if (!arg.isStatic) {
|
||||||
arg.content = `${arg.content} || ""`
|
arg.content = arg.content ? `${arg.content} || ""` : `""`
|
||||||
}
|
}
|
||||||
|
|
||||||
// .sync is replaced by v-model:arg
|
// .sync is replaced by v-model:arg
|
||||||
|
|
@ -92,20 +68,7 @@ export const transformBind: DirectiveTransform = (dir, _node, context) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: [createObjectProperty(arg, exp)],
|
props: [createObjectProperty(arg, exp!)],
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const transformBindShorthand = (
|
|
||||||
dir: DirectiveNode,
|
|
||||||
context: TransformContext,
|
|
||||||
): void => {
|
|
||||||
const arg = dir.arg!
|
|
||||||
|
|
||||||
const propName = camelize((arg as SimpleExpressionNode).content)
|
|
||||||
dir.exp = createSimpleExpression(propName, false, arg.loc)
|
|
||||||
if (!__BROWSER__) {
|
|
||||||
dir.exp = processExpression(dir.exp, context)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,6 @@ import {
|
||||||
import { processExpression } from './transformExpression'
|
import { processExpression } from './transformExpression'
|
||||||
import { validateBrowserExpression } from '../validateExpression'
|
import { validateBrowserExpression } from '../validateExpression'
|
||||||
import { PatchFlags } from '@vue/shared'
|
import { PatchFlags } from '@vue/shared'
|
||||||
import { transformBindShorthand } from './vBind'
|
|
||||||
|
|
||||||
export const transformFor: NodeTransform = createStructuralDirectiveTransform(
|
export const transformFor: NodeTransform = createStructuralDirectiveTransform(
|
||||||
'for',
|
'for',
|
||||||
|
|
@ -63,17 +62,23 @@ 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
|
||||||
// resolve :key shorthand #10882
|
let keyExp =
|
||||||
transformBindShorthand(keyProp, context)
|
|
||||||
}
|
|
||||||
const 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 +258,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),
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,19 @@ 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,
|
||||||
|
isCommentOrWhitespace,
|
||||||
|
} from '../utils'
|
||||||
import { PatchFlags } from '@vue/shared'
|
import { PatchFlags } from '@vue/shared'
|
||||||
|
|
||||||
export const transformIf: NodeTransform = createStructuralDirectiveTransform(
|
export const transformIf: NodeTransform = createStructuralDirectiveTransform(
|
||||||
/^(if|else|else-if)$/,
|
/^(?:if|else|else-if)$/,
|
||||||
(node, dir, context) => {
|
(node, dir, context) => {
|
||||||
return processIf(node, dir, context, (ifNode, branch, isRoot) => {
|
return processIf(node, dir, context, (ifNode, branch, isRoot) => {
|
||||||
// #1587: We need to dynamically increment the key based on the current
|
// #1587: We need to dynamically increment the key based on the current
|
||||||
|
|
@ -110,7 +117,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)
|
||||||
|
|
@ -124,25 +131,18 @@ export function processIf(
|
||||||
let i = siblings.indexOf(node)
|
let i = siblings.indexOf(node)
|
||||||
while (i-- >= -1) {
|
while (i-- >= -1) {
|
||||||
const sibling = siblings[i]
|
const sibling = siblings[i]
|
||||||
if (sibling && sibling.type === NodeTypes.COMMENT) {
|
if (sibling && isCommentOrWhitespace(sibling)) {
|
||||||
context.removeNode(sibling)
|
context.removeNode(sibling)
|
||||||
__DEV__ && comments.unshift(sibling)
|
if (__DEV__ && sibling.type === NodeTypes.COMMENT) {
|
||||||
continue
|
comments.unshift(sibling)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
|
||||||
sibling &&
|
|
||||||
sibling.type === NodeTypes.TEXT &&
|
|
||||||
!sibling.content.trim().length
|
|
||||||
) {
|
|
||||||
context.removeNode(sibling)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sibling && sibling.type === NodeTypes.IF) {
|
if (sibling && sibling.type === NodeTypes.IF) {
|
||||||
// Check if v-else was followed by v-else-if
|
// Check if v-else was followed by v-else-if or there are two adjacent v-else
|
||||||
if (
|
if (
|
||||||
dir.name === 'else-if' &&
|
(dir.name === 'else-if' || dir.name === 'else') &&
|
||||||
sibling.branches[sibling.branches.length - 1].condition === undefined
|
sibling.branches[sibling.branches.length - 1].condition === undefined
|
||||||
) {
|
) {
|
||||||
context.onError(
|
context.onError(
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ const seen = new WeakSet()
|
||||||
export const transformMemo: NodeTransform = (node, context) => {
|
export const transformMemo: NodeTransform = (node, context) => {
|
||||||
if (node.type === NodeTypes.ELEMENT) {
|
if (node.type === NodeTypes.ELEMENT) {
|
||||||
const dir = findDir(node, 'memo')
|
const dir = findDir(node, 'memo')
|
||||||
if (!dir || seen.has(node)) {
|
if (!dir || seen.has(node) || context.inSSR) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
seen.add(node)
|
seen.add(node)
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
|
||||||
|
|
||||||
// we assume v-model directives are always parsed
|
// we assume v-model directives are always parsed
|
||||||
// (not artificially created by a transform)
|
// (not artificially created by a transform)
|
||||||
const rawExp = exp.loc.source
|
const rawExp = exp.loc.source.trim()
|
||||||
const expString =
|
const expString =
|
||||||
exp.type === NodeTypes.SIMPLE_EXPRESSION ? exp.content : rawExp
|
exp.type === NodeTypes.SIMPLE_EXPRESSION ? exp.content : rawExp
|
||||||
|
|
||||||
|
|
@ -48,6 +48,15 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
|
||||||
return createTransformProps()
|
return createTransformProps()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// const bindings are not writable.
|
||||||
|
if (
|
||||||
|
bindingType === BindingTypes.LITERAL_CONST ||
|
||||||
|
bindingType === BindingTypes.SETUP_CONST
|
||||||
|
) {
|
||||||
|
context.onError(createCompilerError(ErrorCodes.X_V_MODEL_ON_CONST, exp.loc))
|
||||||
|
return createTransformProps()
|
||||||
|
}
|
||||||
|
|
||||||
const maybeRef =
|
const maybeRef =
|
||||||
!__BROWSER__ &&
|
!__BROWSER__ &&
|
||||||
context.inline &&
|
context.inline &&
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 */,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,11 @@ import {
|
||||||
assert,
|
assert,
|
||||||
findDir,
|
findDir,
|
||||||
hasScopeRef,
|
hasScopeRef,
|
||||||
|
isCommentOrWhitespace,
|
||||||
isStaticExp,
|
isStaticExp,
|
||||||
isTemplateNode,
|
isTemplateNode,
|
||||||
isVSlot,
|
isVSlot,
|
||||||
|
isWhitespaceText,
|
||||||
} from '../utils'
|
} from '../utils'
|
||||||
import { CREATE_SLOTS, RENDER_LIST, WITH_CTX } from '../runtimeHelpers'
|
import { CREATE_SLOTS, RENDER_LIST, WITH_CTX } from '../runtimeHelpers'
|
||||||
import { createForLoopParams, finalizeForParseResult } from './vFor'
|
import { createForLoopParams, finalizeForParseResult } from './vFor'
|
||||||
|
|
@ -131,9 +133,17 @@ export function buildSlots(
|
||||||
// since it likely uses a scope variable.
|
// since it likely uses a scope variable.
|
||||||
let hasDynamicSlots = context.scopes.vSlot > 0 || context.scopes.vFor > 0
|
let hasDynamicSlots = context.scopes.vSlot > 0 || context.scopes.vFor > 0
|
||||||
// with `prefixIdentifiers: true`, this can be further optimized to make
|
// with `prefixIdentifiers: true`, this can be further optimized to make
|
||||||
// it dynamic only when the slot actually uses the scope variables.
|
// it dynamic when
|
||||||
|
// 1. the slot arg or exp uses the scope variables.
|
||||||
|
// 2. the slot children use the scope variables.
|
||||||
if (!__BROWSER__ && !context.ssr && context.prefixIdentifiers) {
|
if (!__BROWSER__ && !context.ssr && context.prefixIdentifiers) {
|
||||||
hasDynamicSlots = hasScopeRef(node, context.identifiers)
|
hasDynamicSlots =
|
||||||
|
node.props.some(
|
||||||
|
prop =>
|
||||||
|
isVSlot(prop) &&
|
||||||
|
(hasScopeRef(prop.arg, context.identifiers) ||
|
||||||
|
hasScopeRef(prop.exp, context.identifiers)),
|
||||||
|
) || children.some(child => hasScopeRef(child, context.identifiers))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Check for slot with slotProps on component itself.
|
// 1. Check for slot with slotProps on component itself.
|
||||||
|
|
@ -215,18 +225,18 @@ export function buildSlots(
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
} else if (
|
} else if (
|
||||||
(vElse = findDir(slotElement, /^else(-if)?$/, true /* allowEmpty */))
|
(vElse = findDir(slotElement, /^else(?:-if)?$/, true /* allowEmpty */))
|
||||||
) {
|
) {
|
||||||
// find adjacent v-if
|
// find adjacent v-if
|
||||||
let j = i
|
let j = i
|
||||||
let prev
|
let prev
|
||||||
while (j--) {
|
while (j--) {
|
||||||
prev = children[j]
|
prev = children[j]
|
||||||
if (prev.type !== NodeTypes.COMMENT) {
|
if (!isCommentOrWhitespace(prev)) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (prev && isTemplateNode(prev) && findDir(prev, /^(else-)?if$/)) {
|
if (prev && isTemplateNode(prev) && findDir(prev, /^(?:else-)?if$/)) {
|
||||||
__TEST__ && assert(dynamicSlots.length > 0)
|
__TEST__ && assert(dynamicSlots.length > 0)
|
||||||
// attach this slot to previous conditional
|
// attach this slot to previous conditional
|
||||||
let conditional = dynamicSlots[
|
let conditional = dynamicSlots[
|
||||||
|
|
@ -319,7 +329,7 @@ export function buildSlots(
|
||||||
// #3766
|
// #3766
|
||||||
// with whitespace: 'preserve', whitespaces between slots will end up in
|
// with whitespace: 'preserve', whitespaces between slots will end up in
|
||||||
// implicitDefaultChildren. Ignore if all implicit children are whitespaces.
|
// implicitDefaultChildren. Ignore if all implicit children are whitespaces.
|
||||||
implicitDefaultChildren.some(node => isNonWhitespaceContent(node))
|
!implicitDefaultChildren.every(isWhitespaceText)
|
||||||
) {
|
) {
|
||||||
// implicit default slot (mixed with named slots)
|
// implicit default slot (mixed with named slots)
|
||||||
if (hasNamedDefaultSlot) {
|
if (hasNamedDefaultSlot) {
|
||||||
|
|
@ -342,7 +352,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(
|
||||||
|
|
@ -412,11 +421,3 @@ function hasForwardedSlots(children: TemplateChildNode[]): boolean {
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
function isNonWhitespaceContent(node: TemplateChildNode): boolean {
|
|
||||||
if (node.type !== NodeTypes.TEXT && node.type !== NodeTypes.TEXT_CALL)
|
|
||||||
return true
|
|
||||||
return node.type === NodeTypes.TEXT
|
|
||||||
? !!node.content.trim()
|
|
||||||
: isNonWhitespaceContent(node.content)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ import type { PropsExpression } from './transforms/transformElement'
|
||||||
import { parseExpression } from '@babel/parser'
|
import { parseExpression } from '@babel/parser'
|
||||||
import type { Expression, Node } from '@babel/types'
|
import type { Expression, Node } from '@babel/types'
|
||||||
import { unwrapTSNode } from './babelUtils'
|
import { unwrapTSNode } from './babelUtils'
|
||||||
|
import { isWhitespace } from './tokenizer'
|
||||||
|
|
||||||
export const isStaticExp = (p: JSChildNode): p is SimpleExpressionNode =>
|
export const isStaticExp = (p: JSChildNode): p is SimpleExpressionNode =>
|
||||||
p.type === NodeTypes.SIMPLE_EXPRESSION && p.isStatic
|
p.type === NodeTypes.SIMPLE_EXPRESSION && p.isStatic
|
||||||
|
|
@ -63,7 +64,7 @@ export function isCoreComponent(tag: string): symbol | void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const nonIdentifierRE = /^\d|[^\$\w\xA0-\uFFFF]/
|
const nonIdentifierRE = /^$|^\d|[^\$\w\xA0-\uFFFF]/
|
||||||
export const isSimpleIdentifier = (name: string): boolean =>
|
export const isSimpleIdentifier = (name: string): boolean =>
|
||||||
!nonIdentifierRE.test(name)
|
!nonIdentifierRE.test(name)
|
||||||
|
|
||||||
|
|
@ -74,7 +75,7 @@ enum MemberExpLexState {
|
||||||
inString,
|
inString,
|
||||||
}
|
}
|
||||||
|
|
||||||
const validFirstIdentCharRE = /[A-Za-z_$\xA0-\uFFFF]/
|
export const validFirstIdentCharRE: RegExp = /[A-Za-z_$\xA0-\uFFFF]/
|
||||||
const validIdentCharRE = /[\.\?\w$\xA0-\uFFFF]/
|
const validIdentCharRE = /[\.\?\w$\xA0-\uFFFF]/
|
||||||
const whitespaceRE = /\s+[.[]\s*|\s*[.[]\s+/g
|
const whitespaceRE = /\s+[.[]\s*|\s*[.[]\s+/g
|
||||||
|
|
||||||
|
|
@ -189,7 +190,7 @@ export const isMemberExpression: (
|
||||||
) => boolean = __BROWSER__ ? isMemberExpressionBrowser : isMemberExpressionNode
|
) => boolean = __BROWSER__ ? isMemberExpressionBrowser : isMemberExpressionNode
|
||||||
|
|
||||||
const fnExpRE =
|
const fnExpRE =
|
||||||
/^\s*(async\s*)?(\([^)]*?\)|[\w$_]+)\s*(:[^=]+)?=>|^\s*(async\s+)?function(?:\s+[\w$]+)?\s*\(/
|
/^\s*(?:async\s*)?(?:\([^)]*?\)|[\w$_]+)\s*(?::[^=]+)?=>|^\s*(?:async\s+)?function(?:\s+[\w$]+)?\s*\(/
|
||||||
|
|
||||||
export const isFnExpressionBrowser: (exp: ExpressionNode) => boolean = exp =>
|
export const isFnExpressionBrowser: (exp: ExpressionNode) => boolean = exp =>
|
||||||
fnExpRE.test(getExpSource(exp))
|
fnExpRE.test(getExpSource(exp))
|
||||||
|
|
@ -343,6 +344,10 @@ export function isText(
|
||||||
return node.type === NodeTypes.INTERPOLATION || node.type === NodeTypes.TEXT
|
return node.type === NodeTypes.INTERPOLATION || node.type === NodeTypes.TEXT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isVPre(p: ElementNode['props'][0]): p is DirectiveNode {
|
||||||
|
return p.type === NodeTypes.DIRECTIVE && p.name === 'pre'
|
||||||
|
}
|
||||||
|
|
||||||
export function isVSlot(p: ElementNode['props'][0]): p is DirectiveNode {
|
export function isVSlot(p: ElementNode['props'][0]): p is DirectiveNode {
|
||||||
return p.type === NodeTypes.DIRECTIVE && p.name === 'slot'
|
return p.type === NodeTypes.DIRECTIVE && p.name === 'slot'
|
||||||
}
|
}
|
||||||
|
|
@ -564,3 +569,23 @@ export function getMemoedVNodeCall(
|
||||||
}
|
}
|
||||||
|
|
||||||
export const forAliasRE: RegExp = /([\s\S]*?)\s+(?:in|of)\s+(\S[\s\S]*)/
|
export const forAliasRE: RegExp = /([\s\S]*?)\s+(?:in|of)\s+(\S[\s\S]*)/
|
||||||
|
|
||||||
|
export function isAllWhitespace(str: string): boolean {
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
if (!isWhitespace(str.charCodeAt(i))) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isWhitespaceText(node: TemplateChildNode): boolean {
|
||||||
|
return (
|
||||||
|
(node.type === NodeTypes.TEXT && isAllWhitespace(node.content)) ||
|
||||||
|
(node.type === NodeTypes.TEXT_CALL && isWhitespaceText(node.content))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isCommentOrWhitespace(node: TemplateChildNode): boolean {
|
||||||
|
return node.type === NodeTypes.COMMENT || isWhitespaceText(node)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,22 @@ describe('DOM parser', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('<textarea> should remove leading newline', () => {
|
||||||
|
const ast = parse('<textarea>\nhello</textarea>', parserOptions)
|
||||||
|
const element = ast.children[0] as ElementNode
|
||||||
|
const text = element.children[0] as TextNode
|
||||||
|
expect(element.children.length).toBe(1)
|
||||||
|
expect(text).toStrictEqual({
|
||||||
|
type: NodeTypes.TEXT,
|
||||||
|
content: 'hello',
|
||||||
|
loc: {
|
||||||
|
start: { offset: 10, line: 1, column: 11 },
|
||||||
|
end: { offset: 16, line: 2, column: 6 },
|
||||||
|
source: '\nhello',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
test('should not treat Uppercase component as special tag', () => {
|
test('should not treat Uppercase component as special tag', () => {
|
||||||
const ast = parse(
|
const ast = parse(
|
||||||
'<TextArea>some<div>text</div>and<!--comment--></TextArea>',
|
'<TextArea>some<div>text</div>and<!--comment--></TextArea>',
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,18 @@ describe('Transition multi children warnings', () => {
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('non-breaking spaces are treated as normal text', () => {
|
||||||
|
checkWarning(
|
||||||
|
`
|
||||||
|
<transition>
|
||||||
|
\u00a0
|
||||||
|
<div>foo</div>
|
||||||
|
</transition>
|
||||||
|
`,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
test('inject persisted when child has v-show', () => {
|
test('inject persisted when child has v-show', () => {
|
||||||
|
|
@ -164,3 +176,19 @@ test('the v-if/else-if/else branches in Transition should ignore comments', () =
|
||||||
`).code,
|
`).code,
|
||||||
).toMatchSnapshot()
|
).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('comments and preserved whitespace are ignored', () => {
|
||||||
|
expect(
|
||||||
|
compile(
|
||||||
|
`
|
||||||
|
<transition>
|
||||||
|
<!-- foo --> <!-- bar -->
|
||||||
|
<div>foo bar</div>
|
||||||
|
</transition>
|
||||||
|
`,
|
||||||
|
{
|
||||||
|
whitespace: 'preserve',
|
||||||
|
},
|
||||||
|
).code,
|
||||||
|
).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,22 @@
|
||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`comments and preserved whitespace are ignored 1`] = `
|
||||||
|
"const _Vue = Vue
|
||||||
|
|
||||||
|
return function render(_ctx, _cache) {
|
||||||
|
with (_ctx) {
|
||||||
|
const { createCommentVNode: _createCommentVNode, createElementVNode: _createElementVNode, Transition: _Transition, withCtx: _withCtx, openBlock: _openBlock, createBlock: _createBlock } = _Vue
|
||||||
|
|
||||||
|
return (_openBlock(), _createBlock(_Transition, null, {
|
||||||
|
default: _withCtx(() => [
|
||||||
|
_createElementVNode("div", null, "foo bar")
|
||||||
|
]),
|
||||||
|
_: 1 /* STABLE */
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`inject persisted when child has v-show 1`] = `
|
exports[`inject persisted when child has v-show 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,42 @@
|
||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`stringify static html > eligible content (elements > 20) + non-eligible content 1`] = `
|
||||||
|
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||||
|
|
||||||
|
return function render(_ctx, _cache) {
|
||||||
|
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),
|
||||||
|
_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)
|
||||||
|
]))]))
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`stringify static html > eligible content + v-once node 1`] = `
|
||||||
|
"const { setBlockTracking: _setBlockTracking, toDisplayString: _toDisplayString, createTextVNode: _createTextVNode, createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||||
|
|
||||||
|
return function render(_ctx, _cache) {
|
||||||
|
return (_openBlock(), _createElementBlock("div", null, [
|
||||||
|
_cache[0] || (
|
||||||
|
_setBlockTracking(-1, true),
|
||||||
|
(_cache[0] = _createElementVNode("div", null, [
|
||||||
|
_createTextVNode(_toDisplayString(_ctx.msg), 1 /* TEXT */)
|
||||||
|
])).cacheIndex = 0,
|
||||||
|
_setBlockTracking(1),
|
||||||
|
_cache[0]
|
||||||
|
),
|
||||||
|
_cache[1] || (_cache[1] = _createStaticVNode("<span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span>", 5))
|
||||||
|
]))
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`stringify static html > escape 1`] = `
|
exports[`stringify static html > escape 1`] = `
|
||||||
"const { toDisplayString: _toDisplayString, normalizeClass: _normalizeClass, createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
"const { toDisplayString: _toDisplayString, normalizeClass: _normalizeClass, createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||||
|
|
||||||
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("<div><span class=\\"foo>ar\\">1 + <</span><span>&</span><span class=\\"foo>ar\\">1 + <</span><span>&</span><span class=\\"foo>ar\\">1 + <</span><span>&</span><span class=\\"foo>ar\\">1 + <</span><span>&</span><span class=\\"foo>ar\\">1 + <</span><span>&</span></div>", 1)
|
_createStaticVNode("<div><span class=\\"foo>ar\\">1 + <</span><span>&</span><span class=\\"foo>ar\\">1 + <</span><span>&</span><span class=\\"foo>ar\\">1 + <</span><span>&</span><span class=\\"foo>ar\\">1 + <</span><span>&</span><span class=\\"foo>ar\\">1 + <</span><span>&</span></div>", 1)
|
||||||
])))
|
]))]))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
@ -14,9 +44,36 @@ exports[`stringify static html > serializing constant bindings 1`] = `
|
||||||
"const { toDisplayString: _toDisplayString, normalizeClass: _normalizeClass, createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
"const { toDisplayString: _toDisplayString, normalizeClass: _normalizeClass, createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||||
|
|
||||||
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("<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)
|
_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 > 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 */)
|
||||||
|
]))]))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
@ -24,15 +81,31 @@ exports[`stringify static html > should bail for <option> elements with number v
|
||||||
"const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
"const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||||
|
|
||||||
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] = [
|
||||||
_createElementVNode("select", null, [
|
_createElementVNode("select", null, [
|
||||||
_createElementVNode("option", { value: 1 }),
|
_createElementVNode("option", { value: 1 }),
|
||||||
_createElementVNode("option", { value: 1 }),
|
_createElementVNode("option", { value: 1 }),
|
||||||
_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 */))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
@ -40,7 +113,7 @@ exports[`stringify static html > should bail on bindings that are cached but not
|
||||||
"const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
"const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||||
|
|
||||||
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] = [
|
||||||
_createElementVNode("div", null, [
|
_createElementVNode("div", null, [
|
||||||
_createElementVNode("span", { class: "foo" }, "foo"),
|
_createElementVNode("span", { class: "foo" }, "foo"),
|
||||||
_createElementVNode("span", { class: "foo" }, "foo"),
|
_createElementVNode("span", { class: "foo" }, "foo"),
|
||||||
|
|
@ -48,8 +121,8 @@ 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 */)
|
||||||
])))
|
]))]))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
@ -57,9 +130,9 @@ exports[`stringify static html > should work for <option> elements with string v
|
||||||
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||||
|
|
||||||
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("<select><option value=\\"1\\"></option><option value=\\"1\\"></option><option value=\\"1\\"></option><option value=\\"1\\"></option><option value=\\"1\\"></option></select>", 1)
|
_createStaticVNode("<select><option value=\\"1\\"></option><option value=\\"1\\"></option><option value=\\"1\\"></option><option value=\\"1\\"></option><option value=\\"1\\"></option></select>", 1)
|
||||||
])))
|
]))]))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
@ -67,9 +140,9 @@ exports[`stringify static html > should work for multiple adjacent nodes 1`] = `
|
||||||
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||||
|
|
||||||
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 class=\\"foo\\"></span><span class=\\"foo\\"></span><span class=\\"foo\\"></span><span class=\\"foo\\"></span><span class=\\"foo\\"></span>", 5)
|
_createStaticVNode("<span class=\\"foo\\"></span><span class=\\"foo\\"></span><span class=\\"foo\\"></span><span class=\\"foo\\"></span><span class=\\"foo\\"></span>", 5)
|
||||||
])))
|
]))]))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
@ -77,9 +150,9 @@ exports[`stringify static html > should work on eligible content (elements > 20)
|
||||||
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||||
|
|
||||||
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("<div><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></div>", 1)
|
_createStaticVNode("<div><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></div>", 1)
|
||||||
])))
|
]))]))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
@ -87,9 +160,9 @@ exports[`stringify static html > should work on eligible content (elements with
|
||||||
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||||
|
|
||||||
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("<div><span class=\\"foo\\"></span><span class=\\"foo\\"></span><span class=\\"foo\\"></span><span class=\\"foo\\"></span><span class=\\"foo\\"></span></div>", 1)
|
_createStaticVNode("<div><span class=\\"foo\\"></span><span class=\\"foo\\"></span><span class=\\"foo\\"></span><span class=\\"foo\\"></span><span class=\\"foo\\"></span></div>", 1)
|
||||||
])))
|
]))]))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
@ -97,9 +170,9 @@ exports[`stringify static html > should work with bindings that are non-static b
|
||||||
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||||
|
|
||||||
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("<div><span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span><img src=\\"" + _imports_0_ + "\\"></div>", 1)
|
_createStaticVNode("<div><span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span><img src=\\"" + _imports_0_ + "\\"></div>", 1)
|
||||||
])))
|
]))]))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,22 @@ return function render(_ctx, _cache) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: transform v-model > input with v-bind shorthand type after v-model should use dynamic model 1`] = `
|
||||||
|
"const _Vue = Vue
|
||||||
|
|
||||||
|
return function render(_ctx, _cache) {
|
||||||
|
with (_ctx) {
|
||||||
|
const { vModelDynamic: _vModelDynamic, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
||||||
|
|
||||||
|
return _withDirectives((_openBlock(), _createElementBlock("input", {
|
||||||
|
"onUpdate:modelValue": $event => ((model) = $event)
|
||||||
|
}, null, 8 /* PROPS */, ["onUpdate:modelValue"])), [
|
||||||
|
[_vModelDynamic, model]
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`compiler: transform v-model > modifiers > .lazy 1`] = `
|
exports[`compiler: transform v-model > modifiers > .lazy 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
@ -389,6 +410,24 @@ describe('stringify static html', () => {
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('should stringify mathML', () => {
|
||||||
|
const math = `<math xmlns="http://www.w3.org/1998/Math/MathML">`
|
||||||
|
const repeated = `<ms>1</ms>`
|
||||||
|
const { ast } = compileWithStringify(
|
||||||
|
`<div>${math}${repeat(
|
||||||
|
repeated,
|
||||||
|
StringifyThresholds.NODE_COUNT,
|
||||||
|
)}</math></div>`,
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(ast.cached).toMatchObject([
|
||||||
|
cachedArrayStaticNodeMatcher(
|
||||||
|
`${math}${repeat(repeated, StringifyThresholds.NODE_COUNT)}</math>`,
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
// #5439
|
// #5439
|
||||||
test('stringify v-html', () => {
|
test('stringify v-html', () => {
|
||||||
const { code } = compileWithStringify(`
|
const { code } = compileWithStringify(`
|
||||||
|
|
@ -451,4 +490,49 @@ describe('stringify static html', () => {
|
||||||
expect(ast.cached).toMatchObject([cachedArrayBailedMatcher()])
|
expect(ast.cached).toMatchObject([cachedArrayBailedMatcher()])
|
||||||
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', () => {
|
||||||
|
const { code } = compileWithStringify(
|
||||||
|
`<div>${repeat(
|
||||||
|
`<span/>`,
|
||||||
|
StringifyThresholds.NODE_COUNT,
|
||||||
|
)}<div key="1">1</div>${repeat(
|
||||||
|
`<span/>`,
|
||||||
|
StringifyThresholds.NODE_COUNT,
|
||||||
|
)}</div>`,
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(code).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('eligible content + v-once node', () => {
|
||||||
|
const { code } = compileWithStringify(
|
||||||
|
`<div>
|
||||||
|
<div v-once>{{ msg }}</div>
|
||||||
|
${repeat(`<span class="foo">foo</span>`, StringifyThresholds.ELEMENT_WITH_BINDING_COUNT)}
|
||||||
|
</div>`,
|
||||||
|
)
|
||||||
|
expect(code).toMatchSnapshot()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import {
|
||||||
generate,
|
generate,
|
||||||
baseParse as parse,
|
baseParse as parse,
|
||||||
transform,
|
transform,
|
||||||
|
transformVBindShorthand,
|
||||||
} from '@vue/compiler-core'
|
} from '@vue/compiler-core'
|
||||||
import { transformModel } from '../../src/transforms/vModel'
|
import { transformModel } from '../../src/transforms/vModel'
|
||||||
import { transformElement } from '../../../compiler-core/src/transforms/transformElement'
|
import { transformElement } from '../../../compiler-core/src/transforms/transformElement'
|
||||||
|
|
@ -18,7 +19,7 @@ import {
|
||||||
function transformWithModel(template: string, options: CompilerOptions = {}) {
|
function transformWithModel(template: string, options: CompilerOptions = {}) {
|
||||||
const ast = parse(template)
|
const ast = parse(template)
|
||||||
transform(ast, {
|
transform(ast, {
|
||||||
nodeTransforms: [transformElement],
|
nodeTransforms: [transformVBindShorthand, transformElement],
|
||||||
directiveTransforms: {
|
directiveTransforms: {
|
||||||
model: transformModel,
|
model: transformModel,
|
||||||
},
|
},
|
||||||
|
|
@ -63,6 +64,14 @@ describe('compiler: transform v-model', () => {
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #13169
|
||||||
|
test('input with v-bind shorthand type after v-model should use dynamic model', () => {
|
||||||
|
const root = transformWithModel('<input v-model="model" :type/>')
|
||||||
|
|
||||||
|
expect(root.helpers).toContain(V_MODEL_DYNAMIC)
|
||||||
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
test('input w/ dynamic v-bind', () => {
|
test('input w/ dynamic v-bind', () => {
|
||||||
const root = transformWithModel('<input v-bind="obj" v-model="model" />')
|
const root = transformWithModel('<input v-bind="obj" v-model="model" />')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@vue/compiler-dom",
|
"name": "@vue/compiler-dom",
|
||||||
"version": "3.5.4",
|
"version": "3.5.26",
|
||||||
"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",
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ export function createDOMCompilerError(
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum DOMErrorCodes {
|
export enum DOMErrorCodes {
|
||||||
X_V_HTML_NO_EXPRESSION = 53 /* ErrorCodes.__EXTEND_POINT__ */,
|
X_V_HTML_NO_EXPRESSION = 54 /* ErrorCodes.__EXTEND_POINT__ */,
|
||||||
X_V_HTML_WITH_CHILDREN,
|
X_V_HTML_WITH_CHILDREN,
|
||||||
X_V_TEXT_NO_EXPRESSION,
|
X_V_TEXT_NO_EXPRESSION,
|
||||||
X_V_TEXT_WITH_CHILDREN,
|
X_V_TEXT_WITH_CHILDREN,
|
||||||
|
|
@ -42,7 +42,7 @@ if (__TEST__) {
|
||||||
if (DOMErrorCodes.X_V_HTML_NO_EXPRESSION < ErrorCodes.__EXTEND_POINT__) {
|
if (DOMErrorCodes.X_V_HTML_NO_EXPRESSION < ErrorCodes.__EXTEND_POINT__) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`DOMErrorCodes need to be updated to ${
|
`DOMErrorCodes need to be updated to ${
|
||||||
ErrorCodes.__EXTEND_POINT__ + 1
|
ErrorCodes.__EXTEND_POINT__
|
||||||
} to match extension point from core ErrorCodes.`,
|
} to match extension point from core ErrorCodes.`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ export const parserOptions: ParserOptions = {
|
||||||
isVoidTag,
|
isVoidTag,
|
||||||
isNativeTag: tag => isHTMLTag(tag) || isSVGTag(tag) || isMathMLTag(tag),
|
isNativeTag: tag => isHTMLTag(tag) || isSVGTag(tag) || isMathMLTag(tag),
|
||||||
isPreTag: tag => tag === 'pre',
|
isPreTag: tag => tag === 'pre',
|
||||||
|
isIgnoreNewlineTag: tag => tag === 'pre' || tag === 'textarea',
|
||||||
decodeEntities: __BROWSER__ ? decodeHtmlBrowser : undefined,
|
decodeEntities: __BROWSER__ ? decodeHtmlBrowser : undefined,
|
||||||
|
|
||||||
isBuiltInComponent: tag => {
|
isBuiltInComponent: tag => {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import {
|
||||||
type IfBranchNode,
|
type IfBranchNode,
|
||||||
type NodeTransform,
|
type NodeTransform,
|
||||||
NodeTypes,
|
NodeTypes,
|
||||||
|
isCommentOrWhitespace,
|
||||||
} from '@vue/compiler-core'
|
} from '@vue/compiler-core'
|
||||||
import { TRANSITION } from '../runtimeHelpers'
|
import { TRANSITION } from '../runtimeHelpers'
|
||||||
import { DOMErrorCodes, createDOMCompilerError } from '../errors'
|
import { DOMErrorCodes, createDOMCompilerError } from '../errors'
|
||||||
|
|
@ -56,11 +57,9 @@ export const transformTransition: NodeTransform = (node, context) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasMultipleChildren(node: ComponentNode | IfBranchNode): boolean {
|
function hasMultipleChildren(node: ComponentNode | IfBranchNode): boolean {
|
||||||
// #1352 filter out potential comment nodes.
|
// filter out potential comment nodes (#1352) and whitespace (#4637)
|
||||||
const children = (node.children = node.children.filter(
|
const children = (node.children = node.children.filter(
|
||||||
c =>
|
c => !isCommentOrWhitespace(c),
|
||||||
c.type !== NodeTypes.COMMENT &&
|
|
||||||
!(c.type === NodeTypes.TEXT && !c.content.trim()),
|
|
||||||
))
|
))
|
||||||
const child = children[0]
|
const child = children[0]
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,8 @@ import {
|
||||||
type TemplateChildNode,
|
type TemplateChildNode,
|
||||||
type TextCallNode,
|
type TextCallNode,
|
||||||
type TransformContext,
|
type TransformContext,
|
||||||
type VNodeCall,
|
|
||||||
createArrayExpression,
|
|
||||||
createCallExpression,
|
createCallExpression,
|
||||||
|
findDir,
|
||||||
isStaticArgOf,
|
isStaticArgOf,
|
||||||
} from '@vue/compiler-core'
|
} from '@vue/compiler-core'
|
||||||
import {
|
import {
|
||||||
|
|
@ -26,6 +25,7 @@ import {
|
||||||
isArray,
|
isArray,
|
||||||
isBooleanAttr,
|
isBooleanAttr,
|
||||||
isKnownHtmlAttr,
|
isKnownHtmlAttr,
|
||||||
|
isKnownMathMLAttr,
|
||||||
isKnownSvgAttr,
|
isKnownSvgAttr,
|
||||||
isString,
|
isString,
|
||||||
isSymbol,
|
isSymbol,
|
||||||
|
|
@ -106,15 +106,23 @@ export const stringifyStatic: HoistTransform = (children, context, parent) => {
|
||||||
String(currentChunk.length),
|
String(currentChunk.length),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const deleteCount = currentChunk.length - 1
|
||||||
|
|
||||||
if (isParentCached) {
|
if (isParentCached) {
|
||||||
;((parent.codegenNode as VNodeCall).children as CacheExpression).value =
|
// if the parent is cached, then `children` is also the value of the
|
||||||
createArrayExpression([staticCall])
|
// CacheExpression. Just replace the corresponding range in the cached
|
||||||
|
// list with staticCall.
|
||||||
|
children.splice(
|
||||||
|
currentIndex - currentChunk.length,
|
||||||
|
currentChunk.length,
|
||||||
|
// @ts-expect-error
|
||||||
|
staticCall,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
// replace the first node's hoisted expression with the static vnode call
|
// replace the first node's hoisted expression with the static vnode call
|
||||||
;(currentChunk[0].codegenNode as CacheExpression).value = staticCall
|
;(currentChunk[0].codegenNode as CacheExpression).value = staticCall
|
||||||
if (currentChunk.length > 1) {
|
if (currentChunk.length > 1) {
|
||||||
// remove merged nodes from children
|
// remove merged nodes from children
|
||||||
const deleteCount = currentChunk.length - 1
|
|
||||||
children.splice(currentIndex - currentChunk.length + 1, deleteCount)
|
children.splice(currentIndex - currentChunk.length + 1, deleteCount)
|
||||||
// also adjust index for the remaining cache items
|
// also adjust index for the remaining cache items
|
||||||
const cacheIndex = context.cached.indexOf(
|
const cacheIndex = context.cached.indexOf(
|
||||||
|
|
@ -128,10 +136,10 @@ export const stringifyStatic: HoistTransform = (children, context, parent) => {
|
||||||
}
|
}
|
||||||
context.cached.splice(cacheIndex - deleteCount + 1, deleteCount)
|
context.cached.splice(cacheIndex - deleteCount + 1, deleteCount)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return deleteCount
|
return deleteCount
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,13 +185,15 @@ const getCachedNode = (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const dataAriaRE = /^(data|aria)-/
|
const dataAriaRE = /^(?:data|aria)-/
|
||||||
const isStringifiableAttr = (name: string, ns: Namespaces) => {
|
const isStringifiableAttr = (name: string, ns: Namespaces) => {
|
||||||
return (
|
return (
|
||||||
(ns === Namespaces.HTML
|
(ns === Namespaces.HTML
|
||||||
? isKnownHtmlAttr(name)
|
? isKnownHtmlAttr(name)
|
||||||
: ns === Namespaces.SVG
|
: ns === Namespaces.SVG
|
||||||
? isKnownSvgAttr(name)
|
? isKnownSvgAttr(name)
|
||||||
|
: ns === Namespaces.MATH_ML
|
||||||
|
? isKnownMathMLAttr(name)
|
||||||
: false) || dataAriaRE.test(name)
|
: false) || dataAriaRE.test(name)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -204,6 +214,11 @@ function analyzeNode(node: StringifiableNode): [number, number] | false {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// v-once nodes should not be stringified
|
||||||
|
if (node.type === NodeTypes.ELEMENT && findDir(node, 'once', true)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
if (node.type === NodeTypes.TEXT_CALL) {
|
if (node.type === NodeTypes.TEXT_CALL) {
|
||||||
return [1, 0]
|
return [1, 0]
|
||||||
}
|
}
|
||||||
|
|
@ -252,8 +267,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()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ This package contains lower level utilities that you can use if you are writing
|
||||||
The API is intentionally low-level due to the various considerations when integrating Vue SFCs in a build system:
|
The API is intentionally low-level due to the various considerations when integrating Vue SFCs in a build system:
|
||||||
|
|
||||||
- Separate hot-module replacement (HMR) for script, template and styles
|
- Separate hot-module replacement (HMR) for script, template and styles
|
||||||
|
|
||||||
- template updates should not reset component state
|
- template updates should not reset component state
|
||||||
- style updates should be performed without component re-render
|
- style updates should be performed without component re-render
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -639,6 +639,44 @@ return { foo, bar, baz, y, z }
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`SFC compile <script setup> > demote const reactive binding to let when used in v-model (inlineTemplate) 1`] = `
|
||||||
|
"import { unref as _unref, resolveComponent as _resolveComponent, isRef as _isRef, openBlock as _openBlock, createBlock as _createBlock } from "vue"
|
||||||
|
|
||||||
|
import { reactive } from 'vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup(__props) {
|
||||||
|
|
||||||
|
let name = reactive({ first: 'john', last: 'doe' })
|
||||||
|
|
||||||
|
return (_ctx, _cache) => {
|
||||||
|
const _component_MyComponent = _resolveComponent("MyComponent")
|
||||||
|
|
||||||
|
return (_openBlock(), _createBlock(_component_MyComponent, {
|
||||||
|
modelValue: _unref(name),
|
||||||
|
"onUpdate:modelValue": _cache[0] || (_cache[0] = $event => (_isRef(name) ? (name).value = $event : name = $event))
|
||||||
|
}, null, 8 /* PROPS */, ["modelValue"]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`SFC compile <script setup> > demote const reactive binding to let when used in v-model 1`] = `
|
||||||
|
"import { reactive } from 'vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup(__props, { expose: __expose }) {
|
||||||
|
__expose();
|
||||||
|
|
||||||
|
let name = reactive({ first: 'john', last: 'doe' })
|
||||||
|
|
||||||
|
return { get name() { return name }, set name(v) { name = v }, reactive }
|
||||||
|
}
|
||||||
|
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`SFC compile <script setup> > errors > should allow defineProps/Emit() referencing imported binding 1`] = `
|
exports[`SFC compile <script setup> > errors > should allow defineProps/Emit() referencing imported binding 1`] = `
|
||||||
"import { bar } from './bar'
|
"import { bar } from './bar'
|
||||||
|
|
||||||
|
|
@ -861,7 +899,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 */))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -884,9 +922,9 @@ export default {
|
||||||
|
|
||||||
return (_ctx, _push, _parent, _attrs) => {
|
return (_ctx, _push, _parent, _attrs) => {
|
||||||
const _cssVars = { style: {
|
const _cssVars = { style: {
|
||||||
"--xxxxxxxx-count": (count.value),
|
":--xxxxxxxx-count": (count.value),
|
||||||
"--xxxxxxxx-style\\\\.color": (style.color),
|
":--xxxxxxxx-style\\\\.color": (style.color),
|
||||||
"--xxxxxxxx-height\\\\ \\\\+\\\\ \\\\\\"px\\\\\\"": (height.value + "px")
|
":--xxxxxxxx-height\\\\ \\\\+\\\\ \\\\\\"px\\\\\\"": (height.value + "px")
|
||||||
}}
|
}}
|
||||||
_push(\`<!--[--><div\${
|
_push(\`<!--[--><div\${
|
||||||
_ssrRenderAttrs(_cssVars)
|
_ssrRenderAttrs(_cssVars)
|
||||||
|
|
@ -1084,6 +1122,29 @@ return (_ctx, _cache) => {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`SFC compile <script setup> > inlineTemplate mode > v-model w/ newlines codegen 1`] = `
|
||||||
|
"import { unref as _unref, isRef as _isRef, vModelText as _vModelText, withDirectives as _withDirectives, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup(__props) {
|
||||||
|
|
||||||
|
const count = ref(0)
|
||||||
|
|
||||||
|
return (_ctx, _cache) => {
|
||||||
|
return _withDirectives((_openBlock(), _createElementBlock("input", {
|
||||||
|
"onUpdate:modelValue": _cache[0] || (_cache[0] = $event => (_isRef(count) ? (count).value = $event : null))
|
||||||
|
}, null, 512 /* NEED_PATCH */)), [
|
||||||
|
[_vModelText,
|
||||||
|
_unref(count)
|
||||||
|
]
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`SFC compile <script setup> > inlineTemplate mode > with defineExpose() 1`] = `
|
exports[`SFC compile <script setup> > inlineTemplate mode > with defineExpose() 1`] = `
|
||||||
"
|
"
|
||||||
export default {
|
export default {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,27 @@ export function render(_ctx, _cache) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`prefixing props edge case in inline mode 1`] = `
|
||||||
|
"import { defineComponent as _defineComponent } from 'vue'
|
||||||
|
import { unref as _unref, openBlock as _openBlock, createBlock as _createBlock } from "vue"
|
||||||
|
|
||||||
|
|
||||||
|
export default /*@__PURE__*/_defineComponent({
|
||||||
|
props: {
|
||||||
|
Foo: { type: Object, required: true }
|
||||||
|
},
|
||||||
|
setup(__props: any) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (_ctx: any,_cache: any) => {
|
||||||
|
return (_openBlock(), _createBlock(_unref(__props["Foo"]).Bar))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`should not hoist srcset URLs in SSR mode 1`] = `
|
exports[`should not hoist srcset URLs in SSR mode 1`] = `
|
||||||
"import { resolveComponent as _resolveComponent, withCtx as _withCtx, createVNode as _createVNode } from "vue"
|
"import { resolveComponent as _resolveComponent, withCtx as _withCtx, createVNode as _createVNode } from "vue"
|
||||||
import { ssrRenderAttr as _ssrRenderAttr, ssrRenderComponent as _ssrRenderComponent } from "vue/server-renderer"
|
import { ssrRenderAttr as _ssrRenderAttr, ssrRenderComponent as _ssrRenderComponent } from "vue/server-renderer"
|
||||||
|
|
|
||||||
|
|
@ -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 */))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
@ -81,9 +81,9 @@ import _imports_1 from '/bar.png'
|
||||||
|
|
||||||
|
|
||||||
export function render(_ctx, _cache) {
|
export function render(_ctx, _cache) {
|
||||||
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
return (_openBlock(), _createElementBlock("div", null, [...(_cache[0] || (_cache[0] = [
|
||||||
_createStaticVNode("<img src=\\"" + _imports_0 + "\\"><img src=\\"" + _imports_1 + "\\"><img src=\\"https://foo.bar/baz.png\\"><img src=\\"//foo.bar/baz.png\\"><img src=\\"" + _imports_0 + "\\">", 5)
|
_createStaticVNode("<img src=\\"" + _imports_0 + "\\"><img src=\\"" + _imports_1 + "\\"><img src=\\"https://foo.bar/baz.png\\"><img src=\\"//foo.bar/baz.png\\"><img src=\\"" + _imports_0 + "\\">", 5)
|
||||||
])))
|
]))]))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,22 @@ 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 */))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`compiler sfc: transform srcset > transform empty srcset w/ includeAbsolute: true 1`] = `
|
||||||
|
"import { openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
|
||||||
|
|
||||||
|
const _hoisted_1 = { srcset: " " }
|
||||||
|
|
||||||
|
export function render(_ctx, _cache) {
|
||||||
|
return (_openBlock(), _createElementBlock("img", _hoisted_1))
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`compiler sfc: transform srcset > transform srcset 1`] = `
|
exports[`compiler sfc: transform srcset > transform srcset 1`] = `
|
||||||
"import { createElementVNode as _createElementVNode, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
|
"import { createElementVNode as _createElementVNode, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
|
||||||
import _imports_0 from './logo.png'
|
import _imports_0 from './logo.png'
|
||||||
|
|
@ -35,51 +45,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 +102,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 +172,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 */))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
@ -228,8 +238,8 @@ const _hoisted_8 = _imports_1 + ', ' + _imports_1 + ' 2x'
|
||||||
const _hoisted_9 = _imports_1 + ', ' + _imports_0 + ' 2x'
|
const _hoisted_9 = _imports_1 + ', ' + _imports_0 + ' 2x'
|
||||||
|
|
||||||
export function render(_ctx, _cache) {
|
export function render(_ctx, _cache) {
|
||||||
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
return (_openBlock(), _createElementBlock("div", null, [...(_cache[0] || (_cache[0] = [
|
||||||
_createStaticVNode("<img src=\\"./logo.png\\" srcset=\\"\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_1 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_2 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_3 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_4 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_5 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_6 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_7 + "\\"><img src=\\"/logo.png\\" srcset=\\"" + _hoisted_8 + "\\"><img src=\\"https://example.com/logo.png\\" srcset=\\"https://example.com/logo.png, https://example.com/logo.png 2x\\"><img src=\\"/logo.png\\" srcset=\\"" + _hoisted_9 + "\\"><img src=\\"data:image/png;base64,i\\" srcset=\\"data:image/png;base64,i 1x, data:image/png;base64,i 2x\\">", 12)
|
_createStaticVNode("<img src=\\"./logo.png\\" srcset=\\"\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_1 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_2 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_3 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_4 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_5 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_6 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_7 + "\\"><img src=\\"/logo.png\\" srcset=\\"" + _hoisted_8 + "\\"><img src=\\"https://example.com/logo.png\\" srcset=\\"https://example.com/logo.png, https://example.com/logo.png 2x\\"><img src=\\"/logo.png\\" srcset=\\"" + _hoisted_9 + "\\"><img src=\\"data:image/png;base64,i\\" srcset=\\"data:image/png;base64,i 1x, data:image/png;base64,i 2x\\">", 12)
|
||||||
])))
|
]))]))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue