mirror of https://github.com/vuejs/core.git
Compare commits
145 Commits
v3.6.0-alp
...
main
| Author | SHA1 | Date |
|---|---|---|
|
|
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 |
|
|
@ -38,6 +38,7 @@ Hi! I'm really excited that you are interested in contributing to Vue.js. Before
|
|||
### Pull Request Checklist
|
||||
|
||||
- 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.
|
||||
|
||||
- Otherwise, it should be submitted against the `main` branch.
|
||||
|
|
@ -45,10 +46,12 @@ 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.
|
||||
|
||||
- If adding a new feature:
|
||||
|
||||
- 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.
|
||||
|
||||
- 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)`.
|
||||
- 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`.
|
||||
|
|
@ -66,7 +69,9 @@ 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.
|
||||
|
||||
- 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?)
|
||||
|
||||
- If the branch is dev-only, performance is less of a concern.
|
||||
|
||||
- Check how much extra bundle size the change introduces.
|
||||
|
|
@ -260,6 +265,7 @@ 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.
|
||||
|
||||
- Private utility packages:
|
||||
|
||||
- `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).
|
||||
|
|
@ -284,39 +290,27 @@ This is made possible via several configurations:
|
|||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
vue["vue"]
|
||||
compiler-sfc["@vue/compiler-sfc"]
|
||||
compiler-dom["@vue/compiler-dom"]
|
||||
compiler-vapor["@vue/compiler-vapor"]
|
||||
compiler-core["@vue/compiler-core"]
|
||||
vue["vue"]
|
||||
runtime-dom["@vue/runtime-dom"]
|
||||
runtime-vapor["@vue/runtime-vapor"]
|
||||
runtime-core["@vue/runtime-core"]
|
||||
reactivity["@vue/reactivity"]
|
||||
|
||||
subgraph "Runtime Packages"
|
||||
runtime-dom --> runtime-core
|
||||
runtime-vapor --> runtime-core
|
||||
runtime-core --> reactivity
|
||||
end
|
||||
|
||||
subgraph "Compiler Packages"
|
||||
compiler-sfc --> compiler-core
|
||||
compiler-sfc --> compiler-dom
|
||||
compiler-sfc --> compiler-vapor
|
||||
compiler-dom --> compiler-core
|
||||
compiler-vapor --> compiler-core
|
||||
end
|
||||
|
||||
vue --> compiler-sfc
|
||||
vue ---> compiler-dom
|
||||
vue --> runtime-dom
|
||||
vue --> compiler-vapor
|
||||
vue --> runtime-vapor
|
||||
|
||||
%% Highlight class
|
||||
classDef highlight stroke:#35eb9a,stroke-width:3px;
|
||||
class compiler-vapor,runtime-vapor highlight;
|
||||
```
|
||||
|
||||
There are some rules to follow when importing across package boundaries:
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ 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.
|
||||
|
||||
- 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.
|
||||
|
||||
### Reviewing a Feature
|
||||
|
|
@ -55,6 +56,7 @@ 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.
|
||||
|
||||
- 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.
|
||||
- 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.
|
||||
|
|
@ -68,6 +70,7 @@ 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.
|
||||
|
||||
- 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.
|
||||
|
||||
- Make sure to put dev-only code in `__DEV__` branches so they are tree-shakable.
|
||||
|
|
@ -77,6 +80,7 @@ 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`.
|
||||
|
||||
- Performance
|
||||
|
||||
- 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
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@ jobs:
|
|||
env:
|
||||
PUPPETEER_SKIP_DOWNLOAD: 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4.1.0
|
||||
uses: pnpm/action-setup@v4.2.0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version-file: '.node-version'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
|
|
|||
|
|
@ -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.1.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.1.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 }}
|
||||
|
|
@ -9,7 +9,6 @@ on:
|
|||
branches:
|
||||
- main
|
||||
- minor
|
||||
- vapor
|
||||
|
||||
jobs:
|
||||
test:
|
||||
|
|
@ -17,17 +16,17 @@ jobs:
|
|||
uses: ./.github/workflows/test.yml
|
||||
|
||||
continuous-release:
|
||||
if: github.repository == 'vuejs/core' && github.ref_name != 'vapor'
|
||||
if: github.repository == 'vuejs/core'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version-file: '.node-version'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ jobs:
|
|||
if: github.repository == 'vuejs/core' && github.event.issue.pull_request && startsWith(github.event.comment.body, '/ecosystem-ci run')
|
||||
steps:
|
||||
- name: Check user permission
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
script: |
|
||||
const user = context.payload.sender.login
|
||||
|
|
@ -45,7 +45,7 @@ jobs:
|
|||
throw new Error('not allowed')
|
||||
}
|
||||
- name: Get PR info
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@v8
|
||||
id: get-pr-data
|
||||
with:
|
||||
script: |
|
||||
|
|
@ -62,7 +62,7 @@ jobs:
|
|||
commit: pr.head.sha
|
||||
}
|
||||
- name: Trigger run
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@v8
|
||||
id: trigger
|
||||
env:
|
||||
COMMENT: ${{ github.event.comment.body }}
|
||||
|
|
|
|||
|
|
@ -21,13 +21,13 @@ jobs:
|
|||
environment: Release
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version-file: '.node-version'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
|
@ -36,12 +36,13 @@ jobs:
|
|||
- name: Install deps
|
||||
run: pnpm install
|
||||
|
||||
- name: Update npm
|
||||
run: npm i -g npm@latest
|
||||
|
||||
- name: Build and publish
|
||||
id: publish
|
||||
run: |
|
||||
pnpm release --publishOnly
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
- name: Create GitHub release
|
||||
id: release_tag
|
||||
|
|
|
|||
|
|
@ -22,13 +22,13 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4.1.0
|
||||
uses: pnpm/action-setup@v4.2.0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version-file: '.node-version'
|
||||
cache: pnpm
|
||||
|
|
@ -45,7 +45,7 @@ jobs:
|
|||
echo ${{ github.base_ref }} > ./temp/size/base.txt
|
||||
|
||||
- name: Upload Size Data
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: size-data
|
||||
path: temp/size
|
||||
|
|
|
|||
|
|
@ -22,13 +22,13 @@ jobs:
|
|||
github.event.workflow_run.event == 'pull_request' &&
|
||||
github.event.workflow_run.conclusion == 'success'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4.1.0
|
||||
uses: pnpm/action-setup@v4.2.0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version-file: '.node-version'
|
||||
cache: pnpm
|
||||
|
|
@ -37,7 +37,7 @@ jobs:
|
|||
run: pnpm install
|
||||
|
||||
- name: Download Size Data
|
||||
uses: dawidd6/action-download-artifact@v9
|
||||
uses: dawidd6/action-download-artifact@v11
|
||||
with:
|
||||
name: size-data
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
|
|
@ -56,7 +56,7 @@ jobs:
|
|||
path: temp/size/base.txt
|
||||
|
||||
- name: Download Previous Size Data
|
||||
uses: dawidd6/action-download-artifact@v9
|
||||
uses: dawidd6/action-download-artifact@v11
|
||||
with:
|
||||
branch: ${{ steps.pr-base.outputs.content }}
|
||||
workflow: size-data.yml
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@ jobs:
|
|||
env:
|
||||
PUPPETEER_SKIP_DOWNLOAD: 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4.1.0
|
||||
uses: pnpm/action-setup@v4.2.0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version-file: '.node-version'
|
||||
cache: 'pnpm'
|
||||
|
|
@ -32,13 +32,13 @@ jobs:
|
|||
env:
|
||||
PUPPETEER_SKIP_DOWNLOAD: 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4.1.0
|
||||
uses: pnpm/action-setup@v4.2.0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version-file: '.node-version'
|
||||
cache: 'pnpm'
|
||||
|
|
@ -54,7 +54,7 @@ jobs:
|
|||
e2e-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Setup cache for Chromium binary
|
||||
uses: actions/cache@v4
|
||||
|
|
@ -63,10 +63,10 @@ jobs:
|
|||
key: chromium-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4.1.0
|
||||
uses: pnpm/action-setup@v4.2.0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version-file: '.node-version'
|
||||
cache: 'pnpm'
|
||||
|
|
@ -80,44 +80,18 @@ jobs:
|
|||
- name: verify treeshaking
|
||||
run: node scripts/verify-treeshaking.js
|
||||
|
||||
e2e-vapor:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup cache for Chromium binary
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/puppeteer
|
||||
key: chromium-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- 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'
|
||||
cache: 'pnpm'
|
||||
|
||||
- run: pnpm install
|
||||
- run: node node_modules/puppeteer/install.mjs
|
||||
|
||||
- name: Run e2e tests
|
||||
run: pnpm run test-e2e-vapor
|
||||
|
||||
lint-and-test-dts:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
PUPPETEER_SKIP_DOWNLOAD: 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4.1.0
|
||||
uses: pnpm/action-setup@v4.2.0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version-file: '.node-version'
|
||||
cache: 'pnpm'
|
||||
|
|
|
|||
|
|
@ -11,4 +11,3 @@ TODOs.md
|
|||
dts-build/packages
|
||||
*.tsbuildinfo
|
||||
*.tgz
|
||||
packages-private/benchmark/reference
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
"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]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
|
|
@ -14,6 +14,5 @@
|
|||
"[json]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"editor.formatOnSave": true,
|
||||
"vitest.disableWorkspaceWarning": true
|
||||
"editor.formatOnSave": true
|
||||
}
|
||||
|
|
|
|||
775
CHANGELOG.md
775
CHANGELOG.md
|
|
@ -1,128 +1,741 @@
|
|||
# [3.6.0-alpha.1](https://github.com/vuejs/core/compare/v3.5.17...v3.6.0-alpha.1) (2025-07-12)
|
||||
## [3.5.24](https://github.com/vuejs/core/compare/v3.5.23...v3.5.24) (2025-11-07)
|
||||
|
||||
### Features
|
||||
|
||||
- **vapor mode** ([#12359](https://github.com/vuejs/core/issues/12359)) ([bfe5ce3](https://github.com/vuejs/core/commit/bfe5ce309c6fc16bb49cca78e141862bc12708ac))
|
||||
### Reverts
|
||||
|
||||
Please see [About Vapor Mode](#about-vapor-mode) section below for details.
|
||||
* 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)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
- **reactivity:** refactor reactivity core by porting [alien-signals](https://github.com/stackblitz/alien-signals) ([#12349](https://github.com/vuejs/core/issues/12349)) ([313dc61](https://github.com/vuejs/core/commit/313dc61bef59e6869aaec9b5ea47c0bf9044a3fc))
|
||||
|
||||
## [3.5.23](https://github.com/vuejs/core/compare/v3.5.22...v3.5.23) (2025-11-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **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)
|
||||
- **reactivity:** ensure multiple effectScope `on()` and `off()` calls maintains correct active scope ([#12641](https://github.com/vuejs/core/issues/12641)) ([679cbdf](https://github.com/vuejs/core/commit/679cbdf4806cf8c325098f2b579abab60fffb1bb))
|
||||
- **reactivity:** queuing effects in an array ([#13078](https://github.com/vuejs/core/issues/13078)) ([826550c](https://github.com/vuejs/core/commit/826550cd629c59dd91aeb5abdbe101a483497358))
|
||||
- **reactivity:** toRefs should be allowed on plain objects ([ac43b11](https://github.com/vuejs/core/commit/ac43b118975b17d7ce7d9e6886f8806af11bee55))
|
||||
- **scheduler:** improve error handling in job flushing ([#13587](https://github.com/vuejs/core/issues/13587)) ([94b2ddc](https://github.com/vuejs/core/commit/94b2ddc6f97170f4169d9d81b963c6bcaab08be2))
|
||||
- **scheduler:** recover nextTick from error in post flush cb ([2bbb6d2](https://github.com/vuejs/core/commit/2bbb6d2fc56896e64a32b4421822d12bde2bb6e8))
|
||||
* **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)
|
||||
|
||||
### About Vapor Mode
|
||||
|
||||
Vapor Mode is a new compilation mode for Vue Single-File Components (SFC) with the goal of reducing baseline bundle size and improved performance. It is 100% opt-in, and supports a subset of existing Vue APIs with mostly identical behavior.
|
||||
|
||||
Vapor Mode has demonstrated the same level of performance with Solid and Svelte 5 in [3rd party benchmarks](https://github.com/krausest/js-framework-benchmark).
|
||||
## [3.5.22](https://github.com/vuejs/core/compare/v3.5.21...v3.5.22) (2025-09-25)
|
||||
|
||||
#### General Stability Notes
|
||||
|
||||
Vapor Mode is available starting in Vue 3.6 alpha. Please note it is still incomplete and unstable during the alpha phase. The current focus is making it available for wider stability and compatibility testing. For now, we recommend using it for the following cases:
|
||||
### Bug Fixes
|
||||
|
||||
- Partial usage in existing apps, e.g. implementing a perf-sensitive sub page in Vapor Mode.
|
||||
- Build small new apps entirely in Vapor Mode.
|
||||
* **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)
|
||||
|
||||
We do not recommend migrating eixsting components to Vapor Mode yet.
|
||||
|
||||
#### Pending Features
|
||||
### Features
|
||||
|
||||
Things that do not work in this version yet:
|
||||
* **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)
|
||||
|
||||
- SSR hydration\* (which means it does not work with Nuxt yet)
|
||||
- Async Component\*
|
||||
- Transition\*
|
||||
- KeepAlive\*
|
||||
- Suspense
|
||||
|
||||
Features marked with \* have pending PRs which will be merged during the alpha phase.
|
||||
### Reverts
|
||||
|
||||
#### Opting in to Vapor Mode
|
||||
* 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)
|
||||
|
||||
Vapor Mode only works for Single File Components using `<script setup>`. To opt-in, add the `vapor` attribute to `<script setup>`:
|
||||
|
||||
```vue
|
||||
<script setup vapor>
|
||||
// ...
|
||||
</script>
|
||||
```
|
||||
|
||||
Vapor Mode components are usable in two scenarios:
|
||||
## [3.5.21](https://github.com/vuejs/core/compare/v3.5.20...v3.5.21) (2025-09-02)
|
||||
|
||||
1. Inside a Vapor app instance create via `createVaporApp`. Apps created this way avoids pulling in the Virtual DOM runtime code and allows bundle baseline size to be drastically reduced.
|
||||
|
||||
2. To use Vapor components in a VDOM app instance created via `createApp`, the `vaporInteropPlugin` must be installed:
|
||||
### Bug Fixes
|
||||
|
||||
```js
|
||||
import { createApp, vaporInteropPlugin } from 'vue'
|
||||
import App from './App.vue'
|
||||
* **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))
|
||||
|
||||
createApp(App)
|
||||
.use(vaporInteropPlugin) // enable vapor interop
|
||||
.mount('#app')
|
||||
```
|
||||
|
||||
A Vapor app instance can also install `vaporInteropPlugin` to allow vdom components to be used inside, but it will pull in the vdom runtime and offset the benefits of a smaller bundle.
|
||||
### Performance Improvements
|
||||
|
||||
#### VDOM Interop Limitations
|
||||
* improve regexp performance with non-capturing groups ([#13567](https://github.com/vuejs/core/issues/13567)) ([1e8b65a](https://github.com/vuejs/core/commit/1e8b65aa4934c94ef6142b4f49cdfb13ba5e6ce5))
|
||||
|
||||
When the interop plugin is installed, Vapor and non-Vapor components can be nested inside each other. This currently covers standard props, events, and slots usage, but does not yet account for all possible edge cases. For example, there will most likely still be rough edges when using a VDOM-based component library in Vapor Mode.
|
||||
|
||||
This is expected to improve over time, but in general, we recommend having distinct "regions" in your app where it's one mode or another, and avoid mixed nesting as much as possible.
|
||||
|
||||
In the future, we may provide support tooling to enforce Vapor usage boundaries in codebases.
|
||||
## [3.5.20](https://github.com/vuejs/core/compare/v3.5.19...v3.5.20) (2025-08-25)
|
||||
|
||||
#### Feature Compatibility
|
||||
|
||||
By design, Vapor Mode supports a **subset** of existing Vue features. For the supported subset, we aim to deliver the exact same behavior per API specifications. At the same time, this means there are some features that are explicitly not supported in Vapor Mode:
|
||||
### Bug Fixes
|
||||
|
||||
- Options API
|
||||
- `app.config.globalProperties`
|
||||
- `getCurrentInstance()` returns `null` in Vapor components
|
||||
- Implicit instance properties like `$slots` and `$props` are not available in Vapor template expressions
|
||||
- `@vue:xxx` per-element lifecycle events
|
||||
* **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)
|
||||
|
||||
Custom directives in Vapor also have a different interface:
|
||||
|
||||
```ts
|
||||
type VaporDirective = (
|
||||
node: Element | VaporComponentInstance,
|
||||
value?: () => any,
|
||||
argument?: string,
|
||||
modifiers?: DirectiveModifiers,
|
||||
) => (() => void) | void
|
||||
```
|
||||
|
||||
`value` is a reactive getter that returns the binding value. The user can set up reactive effects using `watchEffect` (auto released when component unmounts), and can optionally return a cleanup function. Example:
|
||||
## [3.5.19](https://github.com/vuejs/core/compare/v3.5.18...v3.5.19) (2025-08-21)
|
||||
|
||||
```ts
|
||||
const MyDirective = (el, source) => {
|
||||
watchEffect(() => {
|
||||
el.textContent = source()
|
||||
})
|
||||
return () => console.log('cleanup')
|
||||
}
|
||||
```
|
||||
|
||||
#### Behavior Consistency
|
||||
### 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)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compiler-sfc:** correct scoped injection for nesting selector ([#11854](https://github.com/vuejs/core/issues/11854)) ([b1de75e](https://github.com/vuejs/core/commit/b1de75ed04626b6423085dfde91fb0cb481a25e8)), closes [#10567](https://github.com/vuejs/core/issues/10567)
|
||||
* **reactivity:** fix markRaw error on already marked object ([#11864](https://github.com/vuejs/core/issues/11864)) ([67d6596](https://github.com/vuejs/core/commit/67d6596d40b1807b9cd8eb0d9282932ea77be3c0)), closes [#11862](https://github.com/vuejs/core/issues/11862)
|
||||
* Revert "fix: Revert "fix(reactivity): self-referencing computed should refresh"" ([e596378](https://github.com/vuejs/core/commit/e596378e0be728dad7d60938449f3fa557ca2ec9))
|
||||
* **runtime-core:** handle shallow reactive arrays in renderList correctly ([#11870](https://github.com/vuejs/core/issues/11870)) ([ced59ab](https://github.com/vuejs/core/commit/ced59ab8f2f2e89c13119bab3a0c25a1a1f1c3d6)), closes [#11869](https://github.com/vuejs/core/issues/11869)
|
||||
* **types:** correctly infer `TypeEmits` with both tuple and function syntax ([#11840](https://github.com/vuejs/core/issues/11840)) ([dad6738](https://github.com/vuejs/core/commit/dad673809929c084dcb8e42640eb7daa675d4ea4)), closes [#11836](https://github.com/vuejs/core/issues/11836)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **reactivity:** trigger deps directly instead of storing in an array first ([#11695](https://github.com/vuejs/core/issues/11695)) ([f80d447](https://github.com/vuejs/core/commit/f80d447c17662556e9e3f99f6d199967f4c8cf3d))
|
||||
|
||||
|
||||
|
||||
## [3.5.3](https://github.com/vuejs/core/compare/v3.5.2...v3.5.3) (2024-09-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **hydration:** check __asyncHydrate presence for vue3-lazy-hydration compat ([#11825](https://github.com/vuejs/core/issues/11825)) ([8e6c337](https://github.com/vuejs/core/commit/8e6c3378676be05cea7f53664442acdfb86784f9)), closes [#11793](https://github.com/vuejs/core/issues/11793)
|
||||
* Revert "fix(reactivity): self-referencing computed should refresh" ([35c760f](https://github.com/vuejs/core/commit/35c760f82f749f7c6e3f9bfead8221ce498e892f))
|
||||
* **ssr:** respect app.config.warnHandler during ssr ([bf3d9a2](https://github.com/vuejs/core/commit/bf3d9a2af41659a743706306fc798b3d215df5af)), closes [#11830](https://github.com/vuejs/core/issues/11830)
|
||||
* **Transition:** handle KeepAlive child unmount in Transition out-in mode ([#11833](https://github.com/vuejs/core/issues/11833)) ([6b7901d](https://github.com/vuejs/core/commit/6b7901d28ed3a6a9242c666cc1b8e3c0b0b0fe62)), closes [#11775](https://github.com/vuejs/core/issues/11775)
|
||||
* **useId:** make generated IDs selector compatible ([babfb4c](https://github.com/vuejs/core/commit/babfb4cbcbf98601d76c1d7653eae8d250ce2710)), closes [#11828](https://github.com/vuejs/core/issues/11828)
|
||||
|
||||
|
||||
|
||||
## [3.5.2](https://github.com/vuejs/core/compare/v3.5.1...v3.5.2) (2024-09-05)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **reactivity:** make toRaw work on proxies created by proxyRef ([46c3ab1](https://github.com/vuejs/core/commit/46c3ab1d714024894fa1d33e495d5d35c7817d4d))
|
||||
* **reactivity:** pass oldValue to computed getter ([#11813](https://github.com/vuejs/core/issues/11813)) ([98864a7](https://github.com/vuejs/core/commit/98864a7ef5c8080c407166c8221488a4eacbbc81)), closes [#11812](https://github.com/vuejs/core/issues/11812)
|
||||
* **reactivity:** prevent endless recursion in computed getters ([#11797](https://github.com/vuejs/core/issues/11797)) ([716275d](https://github.com/vuejs/core/commit/716275d1b1d2383d8ef0306fcd94558d4d9170f2))
|
||||
* **reactivity:** self-referencing computed should refresh ([e84c4a6](https://github.com/vuejs/core/commit/e84c4a608e9dc96fb2a4a29d538bcc64f26103a2)), closes [/github.com/vuejs/core/pull/11797#issuecomment-2330738633](https://github.com//github.com/vuejs/core/pull/11797/issues/issuecomment-2330738633)
|
||||
* **scheduler:** prevent duplicate jobs being queued ([#11826](https://github.com/vuejs/core/issues/11826)) ([df56cc5](https://github.com/vuejs/core/commit/df56cc528793b1d6131a1e64095dd5cb95c56bee)), closes [#11712](https://github.com/vuejs/core/issues/11712) [#11807](https://github.com/vuejs/core/issues/11807)
|
||||
* **suspense:** avoid updating anchor if activeBranch has not been rendered to the actual container ([#11818](https://github.com/vuejs/core/issues/11818)) ([3c0d531](https://github.com/vuejs/core/commit/3c0d531fa7fe762bfe46fbe63f318adc95221795)), closes [#11806](https://github.com/vuejs/core/issues/11806)
|
||||
* **Transition:** handle KeepAlive child unmount in Transition out-in mode ([#11778](https://github.com/vuejs/core/issues/11778)) ([3116553](https://github.com/vuejs/core/commit/311655352931863dfcf520b8cf29cebc5b7e1e00)), closes [#11775](https://github.com/vuejs/core/issues/11775)
|
||||
* **types:** add HTMLDialogElement missing close event ([#11811](https://github.com/vuejs/core/issues/11811)) ([3634f7a](https://github.com/vuejs/core/commit/3634f7a4c1649ad2e7e969eb4512512868c61d01))
|
||||
* **types:** added name attribute support to details tag ([#11823](https://github.com/vuejs/core/issues/11823)) ([c74176e](https://github.com/vuejs/core/commit/c74176ec7b4d1d34159ce21d600c04b157ac5549)), closes [#11821](https://github.com/vuejs/core/issues/11821)
|
||||
* **types:** fix defineComponent props inference when setup() has explicit annotation ([fca20a3](https://github.com/vuejs/core/commit/fca20a39aa4a6f98c8f972bd435ebb7dc535648a)), closes [#11803](https://github.com/vuejs/core/issues/11803)
|
||||
* **useTemplateRef:** properly fix readonly warning in dev and ensure prod behavior consistency ([9b7797d](https://github.com/vuejs/core/commit/9b7797d0d1fc773e979e042673d5b9b3151c40fc)), closes [#11808](https://github.com/vuejs/core/issues/11808) [#11816](https://github.com/vuejs/core/issues/11816) [#11810](https://github.com/vuejs/core/issues/11810)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **compiler-core:** parse modifiers as expression to provide location data ([#11819](https://github.com/vuejs/core/issues/11819)) ([3f13203](https://github.com/vuejs/core/commit/3f13203564164eeb2945bdc0b9ef755c37477d75))
|
||||
|
||||
|
||||
|
||||
## [3.5.1](https://github.com/vuejs/core/compare/v3.5.0...v3.5.1) (2024-09-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **build:** improve built-in components treeshakability ([4eee630](https://github.com/vuejs/core/commit/4eee630b3122a10d0baf9b91358cfffa92d6fd81))
|
||||
* **reactivity:** handle non-array arguments in reactive `concat` method ([#11794](https://github.com/vuejs/core/issues/11794)) ([475977a](https://github.com/vuejs/core/commit/475977a6f76b77392610e0a3ec2b0e076d1e1d59)), closes [#11792](https://github.com/vuejs/core/issues/11792)
|
||||
* **Transition:** avoid applying transition hooks on comment vnode ([#11788](https://github.com/vuejs/core/issues/11788)) ([51912f8](https://github.com/vuejs/core/commit/51912f8a02e35f172f6d30ed7a2f3a92c1407cf9)), closes [#11782](https://github.com/vuejs/core/issues/11782)
|
||||
* **types:** avoid using intersection type in `Readonly<...>` to fix JSDoc emit ([#11799](https://github.com/vuejs/core/issues/11799)) ([7518bc1](https://github.com/vuejs/core/commit/7518bc19dc73ba46dcf1eef6e23f9e6e75552675))
|
||||
* **useTemplateRef:** fix readonly warning when useTemplateRef has same variable name as template ref ([bc63df0](https://github.com/vuejs/core/commit/bc63df01992fdbf0b6749ad234153725697ed896)), closes [#11795](https://github.com/vuejs/core/issues/11795) [#11802](https://github.com/vuejs/core/issues/11802) [#11804](https://github.com/vuejs/core/issues/11804)
|
||||
|
||||
|
||||
|
||||
# [3.5.0](https://github.com/vuejs/core/compare/v3.5.0-rc.1...v3.5.0) (2024-09-03)
|
||||
|
||||
## Aggregated Features List for 3.5 (alpha to stable)
|
||||
|
||||
### Reactivity
|
||||
|
||||
- **reactivity**: Refactor reactivity system to use version counting and doubly-linked list tracking ([#10397](https://github.com/vuejs/core/pull/10397)) ([05eb4e0](https://github.com/vuejs/core/commit/05eb4e0fefd585125dd60b7f8fe9c36928d921aa))
|
||||
- **reactivity**: Optimize array tracking ([#9511](https://github.com/vuejs/core/pull/9511)) ([70196a4](https://github.com/vuejs/core/commit/70196a40cc078f50fcc1110c38c06fbcc70b205e))
|
||||
- **compiler-sfc:** enable reactive props destructure by default ([d2dac0e](https://github.com/vuejs/core/commit/d2dac0e359c47d1ed0aa77eda488e76fd6466d2d))
|
||||
- **reactivity:** `onEffectCleanup` API ([2cc5615](https://github.com/vuejs/core/commit/2cc5615590de77126e8df46136de0240dbde5004)), closes [#10173](https://github.com/vuejs/core/issues/10173)
|
||||
- **reactivity:** add `failSilently` argument for `onScopeDispose` ([9a936aa](https://github.com/vuejs/core/commit/9a936aaec489c79433a32791ecf5ddb1739a62bd))
|
||||
- **reactivity/watch:** base `watch`, `getCurrentWatcher`, and `onWatcherCleanup` ([#9927](https://github.com/vuejs/core/issues/9927)) ([205e5b5](https://github.com/vuejs/core/commit/205e5b5e277243c3af2c937d9bd46cf671296b72))
|
||||
- **reactivity/watch:** add pause/resume for ReactiveEffect, EffectScope, and WatchHandle ([#9651](https://github.com/vuejs/core/issues/9651)) ([267093c](https://github.com/vuejs/core/commit/267093c31490050bfcf3ff2b30a2aefee2dad582))
|
||||
- **watch:** support passing number to `deep` option to control the watch depth ([#9572](https://github.com/vuejs/core/issues/9572)) ([22f7d96](https://github.com/vuejs/core/commit/22f7d96757956ebe0baafe52256aa327908cc51c))
|
||||
- **types:** export `MultiWatchSources` type ([#9563](https://github.com/vuejs/core/issues/9563)) ([998dca5](https://github.com/vuejs/core/commit/998dca59f140420280803233f41707580688562c))
|
||||
- **types:** allow computed getter and setter types to be unrelated ([#11472](https://github.com/vuejs/core/issues/11472)) ([a01675e](https://github.com/vuejs/core/commit/a01675ef8f99b5acd6832c53051f4415b18609f2)), closes [#7271](https://github.com/vuejs/core/issues/7271)
|
||||
|
||||
### SSR
|
||||
|
||||
- **runtime-core:** `useId()` and `app.config.idPrefix` ([#11404](https://github.com/vuejs/core/issues/11404)) ([73ef156](https://github.com/vuejs/core/commit/73ef1561f6905d69f968c094d0180c61824f1247))
|
||||
- **hydration:** lazy hydration strategies for async components ([#11458](https://github.com/vuejs/core/issues/11458)) ([d14a11c](https://github.com/vuejs/core/commit/d14a11c1cdcee88452f17ce97758743c863958f4))
|
||||
- **hydration:** support suppressing hydration mismatch via data-allow-mismatch ([94fb2b8](https://github.com/vuejs/core/commit/94fb2b8106a66bcca1a3f922a246a29fdd1274b1))
|
||||
|
||||
### Custom Element
|
||||
|
||||
- **custom-element:** `useHost()` helper ([775103a](https://github.com/vuejs/core/commit/775103af37df69d34c79f12c4c1776c47d07f0a0))
|
||||
- **custom-element:** `useShadowRoot()` helper ([5a1a89b](https://github.com/vuejs/core/commit/5a1a89bd6178cc2f84ba91da7d72aee4c6ec1282)), closes [#6113](https://github.com/vuejs/core/issues/6113) [#8195](https://github.com/vuejs/core/issues/8195)
|
||||
- **custom-element:** expose `this.$host` in Options API ([1ef8f46](https://github.com/vuejs/core/commit/1ef8f46af0cfdec2fed66376772409e0aa25ad50))
|
||||
- **custom-element:** inject child components styles to custom element shadow root ([#11517](https://github.com/vuejs/core/issues/11517)) ([56c76a8](https://github.com/vuejs/core/commit/56c76a8b05c45f782ed3a16ec77c6292b71a17f1)), closes [#4662](https://github.com/vuejs/core/issues/4662) [#7941](https://github.com/vuejs/core/issues/7941) [#7942](https://github.com/vuejs/core/issues/7942)
|
||||
- **custom-element:** support configurable app instance in defineCustomElement ([6758c3c](https://github.com/vuejs/core/commit/6758c3cd0427f97394d95168c655dae3b7fa62cd)), closes [#4356](https://github.com/vuejs/core/issues/4356) [#4635](https://github.com/vuejs/core/issues/4635)
|
||||
- **custom-element:** support css `:host` selector by applying css vars on host element ([#8830](https://github.com/vuejs/core/issues/8830)) ([03a9ea2](https://github.com/vuejs/core/commit/03a9ea2b88df0842a820e09f7445c4b9189e3fcb)), closes [#8826](https://github.com/vuejs/core/issues/8826)
|
||||
- **custom-element:** support emit with options ([e181bff](https://github.com/vuejs/core/commit/e181bff6dc39d5cef92000c10291243c7d6e4d08)), closes [#7605](https://github.com/vuejs/core/issues/7605)
|
||||
- **custom-element:** support expose on customElement ([#6256](https://github.com/vuejs/core/issues/6256)) ([af838c1](https://github.com/vuejs/core/commit/af838c1b5ec23552e52e64ffa7db0eb0246c3624)), closes [#5540](https://github.com/vuejs/core/issues/5540)
|
||||
- **custom-element:** support `nonce` option for injected style tags ([bb4a02a](https://github.com/vuejs/core/commit/bb4a02a70c30e739a3c705b3d96d09258d7d7ded)), closes [#6530](https://github.com/vuejs/core/issues/6530)
|
||||
- **custom-element:** support passing custom-element-specific options via 2nd argument of defineCustomElement ([60a88a2](https://github.com/vuejs/core/commit/60a88a2b129714186cf6ba66f30f31d733d0311e))
|
||||
- **custom-element:** support `shadowRoot: false` in `defineCustomElement()` ([37d2ce5](https://github.com/vuejs/core/commit/37d2ce5d8e0fac4a00064f02b05f91f69b2d5d5e)), closes [#4314](https://github.com/vuejs/core/issues/4314) [#4404](https://github.com/vuejs/core/issues/4404)
|
||||
|
||||
### Teleport
|
||||
|
||||
- **teleport:** support deferred Teleport ([#11387](https://github.com/vuejs/core/issues/11387)) ([59a3e88](https://github.com/vuejs/core/commit/59a3e88903b10ac2278170a44d5a03f24fef23ef)), closes [#2015](https://github.com/vuejs/core/issues/2015) [#11386](https://github.com/vuejs/core/issues/11386)
|
||||
- **teleport/transition:** support directly nesting Teleport inside Transition ([#6548](https://github.com/vuejs/core/issues/6548)) ([0e6e3c7](https://github.com/vuejs/core/commit/0e6e3c7eb0e5320b7c1818e025cb4a490fede9c0)), closes [#5836](https://github.com/vuejs/core/issues/5836)
|
||||
|
||||
### Misc
|
||||
|
||||
- **runtime-core:** `useTemplateRef()` ([3ba70e4](https://github.com/vuejs/core/commit/3ba70e49b5856c53611c314d4855d679a546a7df))
|
||||
- **runtime-core:** add `app.onUnmount()` for registering cleanup functions ([#4619](https://github.com/vuejs/core/issues/4619)) ([582a3a3](https://github.com/vuejs/core/commit/582a3a382b1adda565bac576b913a88d9e8d7a9e)), closes [#4516](https://github.com/vuejs/core/issues/4516)
|
||||
- **runtime-core:** add `app.config.throwUnhandledErrorInProduction` ([f476b7f](https://github.com/vuejs/core/commit/f476b7f030f2dd427ca655fcea36f4933a4b4da0)), closes [#7876](https://github.com/vuejs/core/issues/7876)
|
||||
- **runtime-dom:** Trusted Types compatibility ([#10844](https://github.com/vuejs/core/issues/10844)) ([6d4eb94](https://github.com/vuejs/core/commit/6d4eb94853ed1b2b1675bdd7d5ba9c75cc6daed5))
|
||||
- **compiler-core:** support `Symbol` global in template expressions ([#9069](https://github.com/vuejs/core/issues/9069)) ([a501a85](https://github.com/vuejs/core/commit/a501a85a7c910868e01a5c70a2abea4e9d9e87f3))
|
||||
- **types:** export more emit related types ([#11017](https://github.com/vuejs/core/issues/11017)) ([189573d](https://github.com/vuejs/core/commit/189573dcee2a16bd3ed36ff5589d43f535e5e733))
|
||||
* **types:** add loading prop to iframe ([#11767](https://github.com/vuejs/core/issues/11767)) ([d86fe0e](https://github.com/vuejs/core/commit/d86fe0ec002901dc359a0e85f3a421b4a8538d68))
|
||||
|
||||
### Internals
|
||||
|
||||
- **reactivity:** store value cache on CustomRefs impls ([#11539](https://github.com/vuejs/core/issues/11539)) ([e044b6e](https://github.com/vuejs/core/commit/e044b6e737efc9433d1d84590036b82280da6292))
|
||||
- **types:** provide internal options for directly using user types in language tools ([#10801](https://github.com/vuejs/core/issues/10801)) ([75c8cf6](https://github.com/vuejs/core/commit/75c8cf63a1ef30ac84f91282d66ad3f57c6612e9))
|
||||
- **types:** provide internal options for using refs type in language tools ([#11492](https://github.com/vuejs/core/issues/11492)) ([5ffd1a8](https://github.com/vuejs/core/commit/5ffd1a89455807d5069eb2c28eba0379641dca76))
|
||||
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
* **compiler-sfc:** fix import usage check for kebab-case same name shorthand binding ([0f7c0e5](https://github.com/vuejs/core/commit/0f7c0e5dc0eedada7a5194db87fd0a7dbd1d3354)), closes [#11745](https://github.com/vuejs/core/issues/11745) [#11754](https://github.com/vuejs/core/issues/11754)
|
||||
* **cssVars:** correctly escape double quotes in SSR ([#11784](https://github.com/vuejs/core/issues/11784)) ([7b5b6e0](https://github.com/vuejs/core/commit/7b5b6e0275f35748dca6d7eb842f8ab2364c6b9a)), closes [#11779](https://github.com/vuejs/core/issues/11779)
|
||||
* **deps:** update dependency postcss to ^8.4.44 ([#11774](https://github.com/vuejs/core/issues/11774)) ([cb843e0](https://github.com/vuejs/core/commit/cb843e0be31f9e563ccfc30eca0c06f2a224b505))
|
||||
* **hydration:** escape css var name to avoid mismatch ([#11739](https://github.com/vuejs/core/issues/11739)) ([ca12e77](https://github.com/vuejs/core/commit/ca12e776bc53aaa31f2df6bb6edc6be1b2f10c37)), closes [#11735](https://github.com/vuejs/core/issues/11735)
|
||||
* **hydration:** handle text nodes with 0 during hydration ([#11772](https://github.com/vuejs/core/issues/11772)) ([c756da2](https://github.com/vuejs/core/commit/c756da24b2d8635cf52b4c7d3abf5bf938852cc5)), closes [#11771](https://github.com/vuejs/core/issues/11771)
|
||||
* **reactivity:** correctly handle method calls on user-extended arrays ([#11760](https://github.com/vuejs/core/issues/11760)) ([9817c80](https://github.com/vuejs/core/commit/9817c80187bec6a3344c74d65fac92262de0fcdd)), closes [#11759](https://github.com/vuejs/core/issues/11759)
|
||||
* **runtime-dom:** avoid unnecessary prop patch for checkbox ([#11657](https://github.com/vuejs/core/issues/11657)) ([c3ce9fe](https://github.com/vuejs/core/commit/c3ce9fe3d8fc27d864ce7148cd36da882cfc21ab)), closes [#11647](https://github.com/vuejs/core/issues/11647)
|
||||
* **runtime-dom:** prevent unnecessary DOM update from v-model ([#11656](https://github.com/vuejs/core/issues/11656)) ([b1be9bd](https://github.com/vuejs/core/commit/b1be9bd64f2c7c4286fecb25bad5d5edd49efce9)), closes [#11647](https://github.com/vuejs/core/issues/11647)
|
||||
* **server-renderer:** Fix call to serverPrefetch in server renderer with an async setup ([#10893](https://github.com/vuejs/core/issues/10893)) ([6039e25](https://github.com/vuejs/core/commit/6039e25e04a8c1db5821955f011d57f1615807ab))
|
||||
* **server-renderer:** render `className` during SSR ([#11722](https://github.com/vuejs/core/issues/11722)) ([52cdb0f](https://github.com/vuejs/core/commit/52cdb0f991dc154ae32a2900874d5dbc4e078565))
|
||||
* **types/defineModel:** allow getter and setter types to be unrelated ([#11699](https://github.com/vuejs/core/issues/11699)) ([fe07f70](https://github.com/vuejs/core/commit/fe07f7073617df358c2f8cbc3de433359e873c96)), closes [#11697](https://github.com/vuejs/core/issues/11697)
|
||||
|
||||
|
||||
|
||||
# [3.5.0-rc.1](https://github.com/vuejs/core/compare/v3.5.0-beta.3...v3.5.0-rc.1) (2024-08-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compiler-sfc:** skip circular tsconfig project reference ([#11680](https://github.com/vuejs/core/issues/11680)) ([9c4c2e5](https://github.com/vuejs/core/commit/9c4c2e51b045218d0c5ca64b4fb58b17d5d580cc)), closes [#11382](https://github.com/vuejs/core/issues/11382)
|
||||
* **custom-element:** handle keys set on custom elements ([#11655](https://github.com/vuejs/core/issues/11655)) ([f1d1831](https://github.com/vuejs/core/commit/f1d1831f07fe52d5681a5ec9ec310572463abf26)), closes [#11641](https://github.com/vuejs/core/issues/11641)
|
||||
* **deps:** update dependency monaco-editor to ^0.51.0 ([#11713](https://github.com/vuejs/core/issues/11713)) ([434f8a9](https://github.com/vuejs/core/commit/434f8a97c77f68aeae050e9e4e1f54f63bc4bd26))
|
||||
* **keep-alive:** reset keep alive flag when the component is removed from include ([#11718](https://github.com/vuejs/core/issues/11718)) ([29c321b](https://github.com/vuejs/core/commit/29c321bfd33f9197244dec3d027077e63b2cdf2f)), closes [#11717](https://github.com/vuejs/core/issues/11717)
|
||||
* **reactivity:** avoid infinite recursion when mutating ref wrapped in reactive ([313e4bf](https://github.com/vuejs/core/commit/313e4bf55214ac1e334a99c329a3ba5daca4f156)), closes [#11696](https://github.com/vuejs/core/issues/11696)
|
||||
* **reactivity:** ensure watcher with once: true are properly removed from effect scope ([#11665](https://github.com/vuejs/core/issues/11665)) ([fbc0c42](https://github.com/vuejs/core/commit/fbc0c42bcf6dea5a6ae664223fa19d4375ca39f0))
|
||||
* **runtime-dom:** setting innerHTML when patching props should go through trusted types ([d875de5](https://github.com/vuejs/core/commit/d875de54e9e03e0768fe550aa4c4886a4baf3bd7))
|
||||
* **types:** GlobalDirective / GlobalComponents should not be records ([42e8df6](https://github.com/vuejs/core/commit/42e8df62030e7f2c287d9103f045e67b34a63e3b))
|
||||
|
||||
|
||||
|
||||
# [3.5.0-beta.3](https://github.com/vuejs/core/compare/v3.5.0-beta.2...v3.5.0-beta.3) (2024-08-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **reactivity:** extended methods respect reactive ([#11629](https://github.com/vuejs/core/issues/11629)) ([9de1d10](https://github.com/vuejs/core/commit/9de1d101f98bf6081f41038f6974826f190330a0)), closes [#11628](https://github.com/vuejs/core/issues/11628)
|
||||
* **runtime-core:** correct type inference for PascalCase emits ([#11579](https://github.com/vuejs/core/issues/11579)) ([d7d0371](https://github.com/vuejs/core/commit/d7d0371e74707ee601020f67de88e091cdae2673)), closes [vuejs/language-tools#4269](https://github.com/vuejs/language-tools/issues/4269)
|
||||
* **runtime-core:** ensure suspense content inherit scopeId ([#10652](https://github.com/vuejs/core/issues/10652)) ([ac2a410](https://github.com/vuejs/core/commit/ac2a410e46392db63ca4ed2db3c0fa71ebe1e855)), closes [#5148](https://github.com/vuejs/core/issues/5148)
|
||||
* **runtime-core:** pre jobs without an id should run first ([#7746](https://github.com/vuejs/core/issues/7746)) ([b332f80](https://github.com/vuejs/core/commit/b332f80f0edb018229a23b43b93bb402b6368a3c))
|
||||
* **ssr:** apply ssr props to the the fallback vnode-based branch in ssr ([#7247](https://github.com/vuejs/core/issues/7247)) ([98b83e8](https://github.com/vuejs/core/commit/98b83e86d16c635547a1e735e5fb675aea2f0f1b)), closes [#6123](https://github.com/vuejs/core/issues/6123)
|
||||
* **types/custom-element:** `defineCustomElement` with required props ([#11578](https://github.com/vuejs/core/issues/11578)) ([5e0f6d5](https://github.com/vuejs/core/commit/5e0f6d5f8fe7c4eb8f247357c3e2e281726f36db))
|
||||
* **types:** strip non-prop default values from return type of withDefaults ([#9998](https://github.com/vuejs/core/issues/9998)) ([44973bb](https://github.com/vuejs/core/commit/44973bb3e790db7d8aa7af4eda21c80cac73a8de)), closes [#9899](https://github.com/vuejs/core/issues/9899)
|
||||
* **watch:** handle errors in computed used as watch source ([#11626](https://github.com/vuejs/core/issues/11626)) ([8bcaad4](https://github.com/vuejs/core/commit/8bcaad4a32cf0f1f89e0259f6a53036620b7fe9f)), closes [#11624](https://github.com/vuejs/core/issues/11624)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **reactivity:** base `watch`, `getCurrentWatcher`, and `onWatcherCleanup` ([#9927](https://github.com/vuejs/core/issues/9927)) ([205e5b5](https://github.com/vuejs/core/commit/205e5b5e277243c3af2c937d9bd46cf671296b72))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **runtime-core:** use `apply` to avoid spreading. ([#5985](https://github.com/vuejs/core/issues/5985)) ([bb6babc](https://github.com/vuejs/core/commit/bb6babca8f206615d4e246457cd54d21bb3bc5a4))
|
||||
|
||||
|
||||
|
||||
# [3.5.0-beta.2](https://github.com/vuejs/core/compare/v3.5.0-beta.1...v3.5.0-beta.2) (2024-08-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **build:** revert entities to 4.5 to avoid runtime resolution errors ([e9e0815](https://github.com/vuejs/core/commit/e9e08155bf8d00c3327ed7371330eb2ae467e560)), closes [#11603](https://github.com/vuejs/core/issues/11603)
|
||||
* **compiler-core:** use ast-based check for function expressions when possible ([5861229](https://github.com/vuejs/core/commit/58612294757480974e667652ede5bbcf72b1089d)), closes [#11615](https://github.com/vuejs/core/issues/11615)
|
||||
* **compiler-sfc:** fix prefixIdentifier default value ([3d6f015](https://github.com/vuejs/core/commit/3d6f01571b3fb61b32da599d0419eff4e3ebb231))
|
||||
* **compiler-sfc:** handle keyof operator with index object ([#11581](https://github.com/vuejs/core/issues/11581)) ([fe00815](https://github.com/vuejs/core/commit/fe008152c0612ff3ecc7ad88e7e66a06b1b2bc3f))
|
||||
* **custom-element:** keep instance.isCE for backwards compat ([e19fc27](https://github.com/vuejs/core/commit/e19fc270428b59456fee43224990138c4d6ccb2d))
|
||||
* **deps:** update dependency postcss to ^8.4.41 ([#11585](https://github.com/vuejs/core/issues/11585)) ([4c4e12a](https://github.com/vuejs/core/commit/4c4e12ae28d67d616924b0601e68adc551959971))
|
||||
* **keep-alive:** ensure include/exclude regexp work with global flag ([#11595](https://github.com/vuejs/core/issues/11595)) ([3653bc0](https://github.com/vuejs/core/commit/3653bc0f45d6fedf84e29b64ca52584359c383c0))
|
||||
* **reactivity:** ensure extended method arguments are not lost ([#11574](https://github.com/vuejs/core/issues/11574)) ([4085def](https://github.com/vuejs/core/commit/4085def1bae42d01ee3c22c731cc4a02096464ee)), closes [#11570](https://github.com/vuejs/core/issues/11570)
|
||||
* **reactivity:** sync watch should be executed correctly ([#11589](https://github.com/vuejs/core/issues/11589)) ([3bda3e8](https://github.com/vuejs/core/commit/3bda3e83fd9e2fbe451a1c79dae82ff6a7467683)), closes [#11577](https://github.com/vuejs/core/issues/11577)
|
||||
* **types/computed:** ensure type safety for `WritableComputedRef` ([#11608](https://github.com/vuejs/core/issues/11608)) ([5cf5a16](https://github.com/vuejs/core/commit/5cf5a1620d9a97382d386c277265d9dd051fe484))
|
||||
* **types:** add fallback stub for DOM types when DOM lib is absent ([#11598](https://github.com/vuejs/core/issues/11598)) ([fee6697](https://github.com/vuejs/core/commit/fee669764fbf475adce9e47a7a73b4937ab31ffc))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **deprecated:** remove deprecated parseExpressions option ([#11597](https://github.com/vuejs/core/issues/11597)) ([4e7d5db](https://github.com/vuejs/core/commit/4e7d5db4d276a5d4aaf3af7d43cfd28c171db307))
|
||||
|
||||
|
||||
|
||||
# [3.5.0-beta.1](https://github.com/vuejs/core/compare/v3.4.37...v3.5.0-beta.1) (2024-08-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **custom-element:** delay mounting of custom elements with async parent ([37ccb9b](https://github.com/vuejs/core/commit/37ccb9b9a0e4381f9465e0fc6459609003030da4)), closes [#8127](https://github.com/vuejs/core/issues/8127) [#9341](https://github.com/vuejs/core/issues/9341) [#9351](https://github.com/vuejs/core/issues/9351) [#9351](https://github.com/vuejs/core/issues/9351)
|
||||
* **custom-element:** delete prop on attribute removal ([506c4c5](https://github.com/vuejs/core/commit/506c4c53fdf9766c2ce9517ad58d501ef6b1b9de)), closes [#11276](https://github.com/vuejs/core/issues/11276)
|
||||
* **custom-element:** ignore scoped id ([7f2c505](https://github.com/vuejs/core/commit/7f2c505f92026408a8262ba9b5104a465be19446))
|
||||
* **custom-element:** reflect prop default value on custom element ([63689ed](https://github.com/vuejs/core/commit/63689ed77601d5f9b78540f810612806c3a5de15)), closes [#9006](https://github.com/vuejs/core/issues/9006) [#10537](https://github.com/vuejs/core/issues/10537)
|
||||
* **custom-element:** support early-set domProps for async custom elements ([a07e7bf](https://github.com/vuejs/core/commit/a07e7bf5536a6b3db70ba9bb1c3f366dac1bf5a0)), closes [#11081](https://github.com/vuejs/core/issues/11081) [#11082](https://github.com/vuejs/core/issues/11082)
|
||||
* **types/custome-element:** `defineCustomElement` props inference with array emits ([#11384](https://github.com/vuejs/core/issues/11384)) ([e94b01b](https://github.com/vuejs/core/commit/e94b01bd8a1ec740eddc823839ab2627b307c1b0)), closes [#11353](https://github.com/vuejs/core/issues/11353)
|
||||
* **types:** allow using InjectionKey as valid property key ([321d807](https://github.com/vuejs/core/commit/321d80758c42fccbd39ecbb63f1a4f6632a1580a)), closes [#5089](https://github.com/vuejs/core/issues/5089)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **custom-element:** expose this.$host in Options API ([1ef8f46](https://github.com/vuejs/core/commit/1ef8f46af0cfdec2fed66376772409e0aa25ad50))
|
||||
* **custom-element:** inject child components styles to custom element shadow root ([#11517](https://github.com/vuejs/core/issues/11517)) ([56c76a8](https://github.com/vuejs/core/commit/56c76a8b05c45f782ed3a16ec77c6292b71a17f1)), closes [#4662](https://github.com/vuejs/core/issues/4662) [#7941](https://github.com/vuejs/core/issues/7941) [#7942](https://github.com/vuejs/core/issues/7942)
|
||||
* **custom-element:** support configurable app instance in defineCustomElement ([6758c3c](https://github.com/vuejs/core/commit/6758c3cd0427f97394d95168c655dae3b7fa62cd)), closes [#4356](https://github.com/vuejs/core/issues/4356) [#4635](https://github.com/vuejs/core/issues/4635)
|
||||
* **custom-element:** support css `:host` selector by applying css vars on host element ([#8830](https://github.com/vuejs/core/issues/8830)) ([03a9ea2](https://github.com/vuejs/core/commit/03a9ea2b88df0842a820e09f7445c4b9189e3fcb)), closes [#8826](https://github.com/vuejs/core/issues/8826)
|
||||
* **custom-element:** support emit with options ([e181bff](https://github.com/vuejs/core/commit/e181bff6dc39d5cef92000c10291243c7d6e4d08)), closes [#7605](https://github.com/vuejs/core/issues/7605)
|
||||
* **custom-element:** support for expose on customElement ([#6256](https://github.com/vuejs/core/issues/6256)) ([af838c1](https://github.com/vuejs/core/commit/af838c1b5ec23552e52e64ffa7db0eb0246c3624)), closes [#5540](https://github.com/vuejs/core/issues/5540)
|
||||
* **custom-element:** support nonce option for injected style tags ([bb4a02a](https://github.com/vuejs/core/commit/bb4a02a70c30e739a3c705b3d96d09258d7d7ded)), closes [#6530](https://github.com/vuejs/core/issues/6530)
|
||||
* **custom-element:** support passing custom-element-specific options via 2nd argument of defineCustomElement ([60a88a2](https://github.com/vuejs/core/commit/60a88a2b129714186cf6ba66f30f31d733d0311e))
|
||||
* **custom-element:** support shadowRoot: false in defineCustomElement() ([37d2ce5](https://github.com/vuejs/core/commit/37d2ce5d8e0fac4a00064f02b05f91f69b2d5d5e)), closes [#4314](https://github.com/vuejs/core/issues/4314) [#4404](https://github.com/vuejs/core/issues/4404)
|
||||
* **custom-element:** useHost() helper ([775103a](https://github.com/vuejs/core/commit/775103af37df69d34c79f12c4c1776c47d07f0a0))
|
||||
* **custom-element:** useShadowRoot() helper ([5a1a89b](https://github.com/vuejs/core/commit/5a1a89bd6178cc2f84ba91da7d72aee4c6ec1282)), closes [#6113](https://github.com/vuejs/core/issues/6113) [#8195](https://github.com/vuejs/core/issues/8195)
|
||||
* **hydration:** allow fine tuning of lazy hydration strategy triggers ([#11530](https://github.com/vuejs/core/issues/11530)) ([261c8b1](https://github.com/vuejs/core/commit/261c8b111d046204bd22392a8b920e3c3d4def48))
|
||||
* **reactivity/watch:** add pause/resume for ReactiveEffect, EffectScope, and WatchHandle ([#9651](https://github.com/vuejs/core/issues/9651)) ([267093c](https://github.com/vuejs/core/commit/267093c31490050bfcf3ff2b30a2aefee2dad582))
|
||||
* **reactivity:** store value cache on CustomRefs impls ([#11539](https://github.com/vuejs/core/issues/11539)) ([e044b6e](https://github.com/vuejs/core/commit/e044b6e737efc9433d1d84590036b82280da6292))
|
||||
* **runtime-dom:** Trusted Types compatibility ([#10844](https://github.com/vuejs/core/issues/10844)) ([6d4eb94](https://github.com/vuejs/core/commit/6d4eb94853ed1b2b1675bdd7d5ba9c75cc6daed5))
|
||||
* support specifying allowed keys via generic argument in useTemplateRef() ([1fbfa69](https://github.com/vuejs/core/commit/1fbfa6962b48634ff60837084b82dd57f215c109))
|
||||
* **types:** allow computed getter and setter types to be unrelated ([#11472](https://github.com/vuejs/core/issues/11472)) ([a01675e](https://github.com/vuejs/core/commit/a01675ef8f99b5acd6832c53051f4415b18609f2)), closes [#7271](https://github.com/vuejs/core/issues/7271)
|
||||
* **types:** export `MultiWatchSources` type ([#9563](https://github.com/vuejs/core/issues/9563)) ([998dca5](https://github.com/vuejs/core/commit/998dca59f140420280803233f41707580688562c))
|
||||
* **types:** provide internal options for using refs type in language tools ([#11492](https://github.com/vuejs/core/issues/11492)) ([5ffd1a8](https://github.com/vuejs/core/commit/5ffd1a89455807d5069eb2c28eba0379641dca76))
|
||||
* **watch:** support passing number to `deep` option to control the watch depth ([#9572](https://github.com/vuejs/core/issues/9572)) ([22f7d96](https://github.com/vuejs/core/commit/22f7d96757956ebe0baafe52256aa327908cc51c))
|
||||
|
||||
|
||||
|
||||
# [3.5.0-alpha.5](https://github.com/vuejs/core/compare/v3.4.35...v3.5.0-alpha.5) (2024-07-31)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **hydration:** support suppressing hydration mismatch via data-allow-mismatch ([94fb2b8](https://github.com/vuejs/core/commit/94fb2b8106a66bcca1a3f922a246a29fdd1274b1))
|
||||
* lazy hydration strategies for async components ([#11458](https://github.com/vuejs/core/issues/11458)) ([d14a11c](https://github.com/vuejs/core/commit/d14a11c1cdcee88452f17ce97758743c863958f4))
|
||||
|
||||
|
||||
|
||||
# [3.5.0-alpha.4](https://github.com/vuejs/core/compare/v3.4.34...v3.5.0-alpha.4) (2024-07-24)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **suspense/hydration:** fix hydration timing of async component inside suspense ([1b8e197](https://github.com/vuejs/core/commit/1b8e197a5b65d67a9703b8511786fb81df9aa7cc)), closes [#6638](https://github.com/vuejs/core/issues/6638)
|
||||
* **useId:** properly mark async boundary for already resolved async component ([cd28172](https://github.com/vuejs/core/commit/cd281725781ada2ab279e919031ae307e146a9d9))
|
||||
|
||||
|
||||
|
||||
# [3.5.0-alpha.3](https://github.com/vuejs/core/compare/v3.4.33...v3.5.0-alpha.3) (2024-07-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **build:** enable SSR branches in esm-browser builds ([b14cd9a](https://github.com/vuejs/core/commit/b14cd9a68bab082332b0169be075be357be076ca))
|
||||
* **compiler-core:** change node hoisting to caching per instance ([#11067](https://github.com/vuejs/core/issues/11067)) ([cd0ea0d](https://github.com/vuejs/core/commit/cd0ea0d479a276583fa181d8ecbc97fb0e4a9dce)), closes [#5256](https://github.com/vuejs/core/issues/5256) [#9219](https://github.com/vuejs/core/issues/9219) [#10959](https://github.com/vuejs/core/issues/10959)
|
||||
* **compiler-sfc:** should properly walk desutructured props when reactive destructure is not enabled ([0fd6193](https://github.com/vuejs/core/commit/0fd6193def2380916eb51a118f37f2d9ec2ace23)), closes [#11325](https://github.com/vuejs/core/issues/11325)
|
||||
* **types:** respect props with default on instance type when using __typeProps ([96e4738](https://github.com/vuejs/core/commit/96e473833422342c5ca371ae1aeb186dec9a55e3))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **runtime-core:** useTemplateRef() ([3ba70e4](https://github.com/vuejs/core/commit/3ba70e49b5856c53611c314d4855d679a546a7df))
|
||||
* **runtime-core:** useId() and app.config.idPrefix ([#11404](https://github.com/vuejs/core/issues/11404)) ([73ef156](https://github.com/vuejs/core/commit/73ef1561f6905d69f968c094d0180c61824f1247))
|
||||
* **runtime-core:** add app.config.throwUnhandledErrorInProduction ([f476b7f](https://github.com/vuejs/core/commit/f476b7f030f2dd427ca655fcea36f4933a4b4da0)), closes [#7876](https://github.com/vuejs/core/issues/7876)
|
||||
* **teleport:** support deferred Teleport ([#11387](https://github.com/vuejs/core/issues/11387)) ([59a3e88](https://github.com/vuejs/core/commit/59a3e88903b10ac2278170a44d5a03f24fef23ef)), closes [#2015](https://github.com/vuejs/core/issues/2015) [#11386](https://github.com/vuejs/core/issues/11386)
|
||||
* **compiler-core:** support `Symbol` global in template expressions ([#9069](https://github.com/vuejs/core/issues/9069)) ([a501a85](https://github.com/vuejs/core/commit/a501a85a7c910868e01a5c70a2abea4e9d9e87f3))
|
||||
* **types:** export more emit related types ([#11017](https://github.com/vuejs/core/issues/11017)) ([189573d](https://github.com/vuejs/core/commit/189573dcee2a16bd3ed36ff5589d43f535e5e733))
|
||||
|
||||
|
||||
|
||||
# [3.5.0-alpha.2](https://github.com/vuejs/core/compare/v3.4.26...v3.5.0-alpha.2) (2024-05-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **types:** fix app.component() typing with inline defineComponent ([908f70a](https://github.com/vuejs/core/commit/908f70adc06038d1ea253d96f4024367f4a7545d)), closes [#10843](https://github.com/vuejs/core/issues/10843)
|
||||
* **types:** fix compat with generated types that rely on CreateComponentPublicInstance ([c146186](https://github.com/vuejs/core/commit/c146186396d0c1a65423b8c9a21251c5a6467336)), closes [#10842](https://github.com/vuejs/core/issues/10842)
|
||||
* **types:** props in defineOptions type should be optional ([124c4ca](https://github.com/vuejs/core/commit/124c4cac833a28ae9bc8edc576c1d0c7c41f5985)), closes [#10841](https://github.com/vuejs/core/issues/10841)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **runtime-core:** add app.onUnmount() for registering cleanup functions ([#4619](https://github.com/vuejs/core/issues/4619)) ([582a3a3](https://github.com/vuejs/core/commit/582a3a382b1adda565bac576b913a88d9e8d7a9e)), closes [#4516](https://github.com/vuejs/core/issues/4516)
|
||||
|
||||
|
||||
|
||||
# [3.5.0-alpha.1](https://github.com/vuejs/core/compare/v3.4.25...v3.5.0-alpha.1) (2024-04-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **reactivity:** fix call sequence of ontrigger in effect ([#10501](https://github.com/vuejs/core/issues/10501)) ([28841fe](https://github.com/vuejs/core/commit/28841fee43a45c37905c2c1ed9ace23067539045))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **compiler-sfc:** enable reactive props destructure by default ([d2dac0e](https://github.com/vuejs/core/commit/d2dac0e359c47d1ed0aa77eda488e76fd6466d2d))
|
||||
* **reactivity:** `onEffectCleanup` API ([2cc5615](https://github.com/vuejs/core/commit/2cc5615590de77126e8df46136de0240dbde5004)), closes [#10173](https://github.com/vuejs/core/issues/10173)
|
||||
* **reactivity:** add failSilently argument for onScopeDispose ([9a936aa](https://github.com/vuejs/core/commit/9a936aaec489c79433a32791ecf5ddb1739a62bd))
|
||||
* **transition:** support directly nesting Teleport inside Transition ([#6548](https://github.com/vuejs/core/issues/6548)) ([0e6e3c7](https://github.com/vuejs/core/commit/0e6e3c7eb0e5320b7c1818e025cb4a490fede9c0)), closes [#5836](https://github.com/vuejs/core/issues/5836)
|
||||
* **types:** provide internal options for directly using user types in language tools ([#10801](https://github.com/vuejs/core/issues/10801)) ([75c8cf6](https://github.com/vuejs/core/commit/75c8cf63a1ef30ac84f91282d66ad3f57c6612e9))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **reactivity:** optimize array tracking ([#9511](https://github.com/vuejs/core/issues/9511)) ([70196a4](https://github.com/vuejs/core/commit/70196a40cc078f50fcc1110c38c06fbcc70b205e)), closes [#4318](https://github.com/vuejs/core/issues/4318)
|
||||
|
||||
|
||||
Vapor Mode attempts to match VDOM Mode behavior as much as possible, but there could still be minor behavior inconsistencies in edge cases due to how fundamentally different the two rendering modes are. In general, we do not consider a minor inconsistency to be breaking change unless the behavior has previously been documented.
|
||||
|
||||
## Previous Changelogs
|
||||
|
||||
### 3.5.x (2024-04-29 - 2025-06-18)
|
||||
|
||||
See [3.5 changelog](./changelogs/CHANGELOG-3.5.md)
|
||||
|
||||
### 3.4.x (2023-10-28 - 2024-08-15)
|
||||
|
||||
See [3.4 changelog](./changelogs/CHANGELOG-3.4.md)
|
||||
|
|
|
|||
|
|
@ -1,592 +0,0 @@
|
|||
## [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)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compiler-sfc:** correct scoped injection for nesting selector ([#11854](https://github.com/vuejs/core/issues/11854)) ([b1de75e](https://github.com/vuejs/core/commit/b1de75ed04626b6423085dfde91fb0cb481a25e8)), closes [#10567](https://github.com/vuejs/core/issues/10567)
|
||||
* **reactivity:** fix markRaw error on already marked object ([#11864](https://github.com/vuejs/core/issues/11864)) ([67d6596](https://github.com/vuejs/core/commit/67d6596d40b1807b9cd8eb0d9282932ea77be3c0)), closes [#11862](https://github.com/vuejs/core/issues/11862)
|
||||
* Revert "fix: Revert "fix(reactivity): self-referencing computed should refresh"" ([e596378](https://github.com/vuejs/core/commit/e596378e0be728dad7d60938449f3fa557ca2ec9))
|
||||
* **runtime-core:** handle shallow reactive arrays in renderList correctly ([#11870](https://github.com/vuejs/core/issues/11870)) ([ced59ab](https://github.com/vuejs/core/commit/ced59ab8f2f2e89c13119bab3a0c25a1a1f1c3d6)), closes [#11869](https://github.com/vuejs/core/issues/11869)
|
||||
* **types:** correctly infer `TypeEmits` with both tuple and function syntax ([#11840](https://github.com/vuejs/core/issues/11840)) ([dad6738](https://github.com/vuejs/core/commit/dad673809929c084dcb8e42640eb7daa675d4ea4)), closes [#11836](https://github.com/vuejs/core/issues/11836)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **reactivity:** trigger deps directly instead of storing in an array first ([#11695](https://github.com/vuejs/core/issues/11695)) ([f80d447](https://github.com/vuejs/core/commit/f80d447c17662556e9e3f99f6d199967f4c8cf3d))
|
||||
|
||||
|
||||
|
||||
## [3.5.3](https://github.com/vuejs/core/compare/v3.5.2...v3.5.3) (2024-09-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **hydration:** check __asyncHydrate presence for vue3-lazy-hydration compat ([#11825](https://github.com/vuejs/core/issues/11825)) ([8e6c337](https://github.com/vuejs/core/commit/8e6c3378676be05cea7f53664442acdfb86784f9)), closes [#11793](https://github.com/vuejs/core/issues/11793)
|
||||
* Revert "fix(reactivity): self-referencing computed should refresh" ([35c760f](https://github.com/vuejs/core/commit/35c760f82f749f7c6e3f9bfead8221ce498e892f))
|
||||
* **ssr:** respect app.config.warnHandler during ssr ([bf3d9a2](https://github.com/vuejs/core/commit/bf3d9a2af41659a743706306fc798b3d215df5af)), closes [#11830](https://github.com/vuejs/core/issues/11830)
|
||||
* **Transition:** handle KeepAlive child unmount in Transition out-in mode ([#11833](https://github.com/vuejs/core/issues/11833)) ([6b7901d](https://github.com/vuejs/core/commit/6b7901d28ed3a6a9242c666cc1b8e3c0b0b0fe62)), closes [#11775](https://github.com/vuejs/core/issues/11775)
|
||||
* **useId:** make generated IDs selector compatible ([babfb4c](https://github.com/vuejs/core/commit/babfb4cbcbf98601d76c1d7653eae8d250ce2710)), closes [#11828](https://github.com/vuejs/core/issues/11828)
|
||||
|
||||
|
||||
|
||||
## [3.5.2](https://github.com/vuejs/core/compare/v3.5.1...v3.5.2) (2024-09-05)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **reactivity:** make toRaw work on proxies created by proxyRef ([46c3ab1](https://github.com/vuejs/core/commit/46c3ab1d714024894fa1d33e495d5d35c7817d4d))
|
||||
* **reactivity:** pass oldValue to computed getter ([#11813](https://github.com/vuejs/core/issues/11813)) ([98864a7](https://github.com/vuejs/core/commit/98864a7ef5c8080c407166c8221488a4eacbbc81)), closes [#11812](https://github.com/vuejs/core/issues/11812)
|
||||
* **reactivity:** prevent endless recursion in computed getters ([#11797](https://github.com/vuejs/core/issues/11797)) ([716275d](https://github.com/vuejs/core/commit/716275d1b1d2383d8ef0306fcd94558d4d9170f2))
|
||||
* **reactivity:** self-referencing computed should refresh ([e84c4a6](https://github.com/vuejs/core/commit/e84c4a608e9dc96fb2a4a29d538bcc64f26103a2)), closes [/github.com/vuejs/core/pull/11797#issuecomment-2330738633](https://github.com//github.com/vuejs/core/pull/11797/issues/issuecomment-2330738633)
|
||||
* **scheduler:** prevent duplicate jobs being queued ([#11826](https://github.com/vuejs/core/issues/11826)) ([df56cc5](https://github.com/vuejs/core/commit/df56cc528793b1d6131a1e64095dd5cb95c56bee)), closes [#11712](https://github.com/vuejs/core/issues/11712) [#11807](https://github.com/vuejs/core/issues/11807)
|
||||
* **suspense:** avoid updating anchor if activeBranch has not been rendered to the actual container ([#11818](https://github.com/vuejs/core/issues/11818)) ([3c0d531](https://github.com/vuejs/core/commit/3c0d531fa7fe762bfe46fbe63f318adc95221795)), closes [#11806](https://github.com/vuejs/core/issues/11806)
|
||||
* **Transition:** handle KeepAlive child unmount in Transition out-in mode ([#11778](https://github.com/vuejs/core/issues/11778)) ([3116553](https://github.com/vuejs/core/commit/311655352931863dfcf520b8cf29cebc5b7e1e00)), closes [#11775](https://github.com/vuejs/core/issues/11775)
|
||||
* **types:** add HTMLDialogElement missing close event ([#11811](https://github.com/vuejs/core/issues/11811)) ([3634f7a](https://github.com/vuejs/core/commit/3634f7a4c1649ad2e7e969eb4512512868c61d01))
|
||||
* **types:** added name attribute support to details tag ([#11823](https://github.com/vuejs/core/issues/11823)) ([c74176e](https://github.com/vuejs/core/commit/c74176ec7b4d1d34159ce21d600c04b157ac5549)), closes [#11821](https://github.com/vuejs/core/issues/11821)
|
||||
* **types:** fix defineComponent props inference when setup() has explicit annotation ([fca20a3](https://github.com/vuejs/core/commit/fca20a39aa4a6f98c8f972bd435ebb7dc535648a)), closes [#11803](https://github.com/vuejs/core/issues/11803)
|
||||
* **useTemplateRef:** properly fix readonly warning in dev and ensure prod behavior consistency ([9b7797d](https://github.com/vuejs/core/commit/9b7797d0d1fc773e979e042673d5b9b3151c40fc)), closes [#11808](https://github.com/vuejs/core/issues/11808) [#11816](https://github.com/vuejs/core/issues/11816) [#11810](https://github.com/vuejs/core/issues/11810)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **compiler-core:** parse modifiers as expression to provide location data ([#11819](https://github.com/vuejs/core/issues/11819)) ([3f13203](https://github.com/vuejs/core/commit/3f13203564164eeb2945bdc0b9ef755c37477d75))
|
||||
|
||||
|
||||
|
||||
## [3.5.1](https://github.com/vuejs/core/compare/v3.5.0...v3.5.1) (2024-09-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **build:** improve built-in components treeshakability ([4eee630](https://github.com/vuejs/core/commit/4eee630b3122a10d0baf9b91358cfffa92d6fd81))
|
||||
* **reactivity:** handle non-array arguments in reactive `concat` method ([#11794](https://github.com/vuejs/core/issues/11794)) ([475977a](https://github.com/vuejs/core/commit/475977a6f76b77392610e0a3ec2b0e076d1e1d59)), closes [#11792](https://github.com/vuejs/core/issues/11792)
|
||||
* **Transition:** avoid applying transition hooks on comment vnode ([#11788](https://github.com/vuejs/core/issues/11788)) ([51912f8](https://github.com/vuejs/core/commit/51912f8a02e35f172f6d30ed7a2f3a92c1407cf9)), closes [#11782](https://github.com/vuejs/core/issues/11782)
|
||||
* **types:** avoid using intersection type in `Readonly<...>` to fix JSDoc emit ([#11799](https://github.com/vuejs/core/issues/11799)) ([7518bc1](https://github.com/vuejs/core/commit/7518bc19dc73ba46dcf1eef6e23f9e6e75552675))
|
||||
* **useTemplateRef:** fix readonly warning when useTemplateRef has same variable name as template ref ([bc63df0](https://github.com/vuejs/core/commit/bc63df01992fdbf0b6749ad234153725697ed896)), closes [#11795](https://github.com/vuejs/core/issues/11795) [#11802](https://github.com/vuejs/core/issues/11802) [#11804](https://github.com/vuejs/core/issues/11804)
|
||||
|
||||
|
||||
|
||||
# [3.5.0](https://github.com/vuejs/core/compare/v3.5.0-rc.1...v3.5.0) (2024-09-03)
|
||||
|
||||
## Aggregated Features List for 3.5 (alpha to stable)
|
||||
|
||||
### Reactivity
|
||||
|
||||
- **reactivity**: Refactor reactivity system to use version counting and doubly-linked list tracking ([#10397](https://github.com/vuejs/core/pull/10397)) ([05eb4e0](https://github.com/vuejs/core/commit/05eb4e0fefd585125dd60b7f8fe9c36928d921aa))
|
||||
- **reactivity**: Optimize array tracking ([#9511](https://github.com/vuejs/core/pull/9511)) ([70196a4](https://github.com/vuejs/core/commit/70196a40cc078f50fcc1110c38c06fbcc70b205e))
|
||||
- **compiler-sfc:** enable reactive props destructure by default ([d2dac0e](https://github.com/vuejs/core/commit/d2dac0e359c47d1ed0aa77eda488e76fd6466d2d))
|
||||
- **reactivity:** `onEffectCleanup` API ([2cc5615](https://github.com/vuejs/core/commit/2cc5615590de77126e8df46136de0240dbde5004)), closes [#10173](https://github.com/vuejs/core/issues/10173)
|
||||
- **reactivity:** add `failSilently` argument for `onScopeDispose` ([9a936aa](https://github.com/vuejs/core/commit/9a936aaec489c79433a32791ecf5ddb1739a62bd))
|
||||
- **reactivity/watch:** base `watch`, `getCurrentWatcher`, and `onWatcherCleanup` ([#9927](https://github.com/vuejs/core/issues/9927)) ([205e5b5](https://github.com/vuejs/core/commit/205e5b5e277243c3af2c937d9bd46cf671296b72))
|
||||
- **reactivity/watch:** add pause/resume for ReactiveEffect, EffectScope, and WatchHandle ([#9651](https://github.com/vuejs/core/issues/9651)) ([267093c](https://github.com/vuejs/core/commit/267093c31490050bfcf3ff2b30a2aefee2dad582))
|
||||
- **watch:** support passing number to `deep` option to control the watch depth ([#9572](https://github.com/vuejs/core/issues/9572)) ([22f7d96](https://github.com/vuejs/core/commit/22f7d96757956ebe0baafe52256aa327908cc51c))
|
||||
- **types:** export `MultiWatchSources` type ([#9563](https://github.com/vuejs/core/issues/9563)) ([998dca5](https://github.com/vuejs/core/commit/998dca59f140420280803233f41707580688562c))
|
||||
- **types:** allow computed getter and setter types to be unrelated ([#11472](https://github.com/vuejs/core/issues/11472)) ([a01675e](https://github.com/vuejs/core/commit/a01675ef8f99b5acd6832c53051f4415b18609f2)), closes [#7271](https://github.com/vuejs/core/issues/7271)
|
||||
|
||||
### SSR
|
||||
|
||||
- **runtime-core:** `useId()` and `app.config.idPrefix` ([#11404](https://github.com/vuejs/core/issues/11404)) ([73ef156](https://github.com/vuejs/core/commit/73ef1561f6905d69f968c094d0180c61824f1247))
|
||||
- **hydration:** lazy hydration strategies for async components ([#11458](https://github.com/vuejs/core/issues/11458)) ([d14a11c](https://github.com/vuejs/core/commit/d14a11c1cdcee88452f17ce97758743c863958f4))
|
||||
- **hydration:** support suppressing hydration mismatch via data-allow-mismatch ([94fb2b8](https://github.com/vuejs/core/commit/94fb2b8106a66bcca1a3f922a246a29fdd1274b1))
|
||||
|
||||
### Custom Element
|
||||
|
||||
- **custom-element:** `useHost()` helper ([775103a](https://github.com/vuejs/core/commit/775103af37df69d34c79f12c4c1776c47d07f0a0))
|
||||
- **custom-element:** `useShadowRoot()` helper ([5a1a89b](https://github.com/vuejs/core/commit/5a1a89bd6178cc2f84ba91da7d72aee4c6ec1282)), closes [#6113](https://github.com/vuejs/core/issues/6113) [#8195](https://github.com/vuejs/core/issues/8195)
|
||||
- **custom-element:** expose `this.$host` in Options API ([1ef8f46](https://github.com/vuejs/core/commit/1ef8f46af0cfdec2fed66376772409e0aa25ad50))
|
||||
- **custom-element:** inject child components styles to custom element shadow root ([#11517](https://github.com/vuejs/core/issues/11517)) ([56c76a8](https://github.com/vuejs/core/commit/56c76a8b05c45f782ed3a16ec77c6292b71a17f1)), closes [#4662](https://github.com/vuejs/core/issues/4662) [#7941](https://github.com/vuejs/core/issues/7941) [#7942](https://github.com/vuejs/core/issues/7942)
|
||||
- **custom-element:** support configurable app instance in defineCustomElement ([6758c3c](https://github.com/vuejs/core/commit/6758c3cd0427f97394d95168c655dae3b7fa62cd)), closes [#4356](https://github.com/vuejs/core/issues/4356) [#4635](https://github.com/vuejs/core/issues/4635)
|
||||
- **custom-element:** support css `:host` selector by applying css vars on host element ([#8830](https://github.com/vuejs/core/issues/8830)) ([03a9ea2](https://github.com/vuejs/core/commit/03a9ea2b88df0842a820e09f7445c4b9189e3fcb)), closes [#8826](https://github.com/vuejs/core/issues/8826)
|
||||
- **custom-element:** support emit with options ([e181bff](https://github.com/vuejs/core/commit/e181bff6dc39d5cef92000c10291243c7d6e4d08)), closes [#7605](https://github.com/vuejs/core/issues/7605)
|
||||
- **custom-element:** support expose on customElement ([#6256](https://github.com/vuejs/core/issues/6256)) ([af838c1](https://github.com/vuejs/core/commit/af838c1b5ec23552e52e64ffa7db0eb0246c3624)), closes [#5540](https://github.com/vuejs/core/issues/5540)
|
||||
- **custom-element:** support `nonce` option for injected style tags ([bb4a02a](https://github.com/vuejs/core/commit/bb4a02a70c30e739a3c705b3d96d09258d7d7ded)), closes [#6530](https://github.com/vuejs/core/issues/6530)
|
||||
- **custom-element:** support passing custom-element-specific options via 2nd argument of defineCustomElement ([60a88a2](https://github.com/vuejs/core/commit/60a88a2b129714186cf6ba66f30f31d733d0311e))
|
||||
- **custom-element:** support `shadowRoot: false` in `defineCustomElement()` ([37d2ce5](https://github.com/vuejs/core/commit/37d2ce5d8e0fac4a00064f02b05f91f69b2d5d5e)), closes [#4314](https://github.com/vuejs/core/issues/4314) [#4404](https://github.com/vuejs/core/issues/4404)
|
||||
|
||||
### Teleport
|
||||
|
||||
- **teleport:** support deferred Teleport ([#11387](https://github.com/vuejs/core/issues/11387)) ([59a3e88](https://github.com/vuejs/core/commit/59a3e88903b10ac2278170a44d5a03f24fef23ef)), closes [#2015](https://github.com/vuejs/core/issues/2015) [#11386](https://github.com/vuejs/core/issues/11386)
|
||||
- **teleport/transition:** support directly nesting Teleport inside Transition ([#6548](https://github.com/vuejs/core/issues/6548)) ([0e6e3c7](https://github.com/vuejs/core/commit/0e6e3c7eb0e5320b7c1818e025cb4a490fede9c0)), closes [#5836](https://github.com/vuejs/core/issues/5836)
|
||||
|
||||
### Misc
|
||||
|
||||
- **runtime-core:** `useTemplateRef()` ([3ba70e4](https://github.com/vuejs/core/commit/3ba70e49b5856c53611c314d4855d679a546a7df))
|
||||
- **runtime-core:** add `app.onUnmount()` for registering cleanup functions ([#4619](https://github.com/vuejs/core/issues/4619)) ([582a3a3](https://github.com/vuejs/core/commit/582a3a382b1adda565bac576b913a88d9e8d7a9e)), closes [#4516](https://github.com/vuejs/core/issues/4516)
|
||||
- **runtime-core:** add `app.config.throwUnhandledErrorInProduction` ([f476b7f](https://github.com/vuejs/core/commit/f476b7f030f2dd427ca655fcea36f4933a4b4da0)), closes [#7876](https://github.com/vuejs/core/issues/7876)
|
||||
- **runtime-dom:** Trusted Types compatibility ([#10844](https://github.com/vuejs/core/issues/10844)) ([6d4eb94](https://github.com/vuejs/core/commit/6d4eb94853ed1b2b1675bdd7d5ba9c75cc6daed5))
|
||||
- **compiler-core:** support `Symbol` global in template expressions ([#9069](https://github.com/vuejs/core/issues/9069)) ([a501a85](https://github.com/vuejs/core/commit/a501a85a7c910868e01a5c70a2abea4e9d9e87f3))
|
||||
- **types:** export more emit related types ([#11017](https://github.com/vuejs/core/issues/11017)) ([189573d](https://github.com/vuejs/core/commit/189573dcee2a16bd3ed36ff5589d43f535e5e733))
|
||||
* **types:** add loading prop to iframe ([#11767](https://github.com/vuejs/core/issues/11767)) ([d86fe0e](https://github.com/vuejs/core/commit/d86fe0ec002901dc359a0e85f3a421b4a8538d68))
|
||||
|
||||
### Internals
|
||||
|
||||
- **reactivity:** store value cache on CustomRefs impls ([#11539](https://github.com/vuejs/core/issues/11539)) ([e044b6e](https://github.com/vuejs/core/commit/e044b6e737efc9433d1d84590036b82280da6292))
|
||||
- **types:** provide internal options for directly using user types in language tools ([#10801](https://github.com/vuejs/core/issues/10801)) ([75c8cf6](https://github.com/vuejs/core/commit/75c8cf63a1ef30ac84f91282d66ad3f57c6612e9))
|
||||
- **types:** provide internal options for using refs type in language tools ([#11492](https://github.com/vuejs/core/issues/11492)) ([5ffd1a8](https://github.com/vuejs/core/commit/5ffd1a89455807d5069eb2c28eba0379641dca76))
|
||||
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
* **compiler-sfc:** fix import usage check for kebab-case same name shorthand binding ([0f7c0e5](https://github.com/vuejs/core/commit/0f7c0e5dc0eedada7a5194db87fd0a7dbd1d3354)), closes [#11745](https://github.com/vuejs/core/issues/11745) [#11754](https://github.com/vuejs/core/issues/11754)
|
||||
* **cssVars:** correctly escape double quotes in SSR ([#11784](https://github.com/vuejs/core/issues/11784)) ([7b5b6e0](https://github.com/vuejs/core/commit/7b5b6e0275f35748dca6d7eb842f8ab2364c6b9a)), closes [#11779](https://github.com/vuejs/core/issues/11779)
|
||||
* **deps:** update dependency postcss to ^8.4.44 ([#11774](https://github.com/vuejs/core/issues/11774)) ([cb843e0](https://github.com/vuejs/core/commit/cb843e0be31f9e563ccfc30eca0c06f2a224b505))
|
||||
* **hydration:** escape css var name to avoid mismatch ([#11739](https://github.com/vuejs/core/issues/11739)) ([ca12e77](https://github.com/vuejs/core/commit/ca12e776bc53aaa31f2df6bb6edc6be1b2f10c37)), closes [#11735](https://github.com/vuejs/core/issues/11735)
|
||||
* **hydration:** handle text nodes with 0 during hydration ([#11772](https://github.com/vuejs/core/issues/11772)) ([c756da2](https://github.com/vuejs/core/commit/c756da24b2d8635cf52b4c7d3abf5bf938852cc5)), closes [#11771](https://github.com/vuejs/core/issues/11771)
|
||||
* **reactivity:** correctly handle method calls on user-extended arrays ([#11760](https://github.com/vuejs/core/issues/11760)) ([9817c80](https://github.com/vuejs/core/commit/9817c80187bec6a3344c74d65fac92262de0fcdd)), closes [#11759](https://github.com/vuejs/core/issues/11759)
|
||||
* **runtime-dom:** avoid unnecessary prop patch for checkbox ([#11657](https://github.com/vuejs/core/issues/11657)) ([c3ce9fe](https://github.com/vuejs/core/commit/c3ce9fe3d8fc27d864ce7148cd36da882cfc21ab)), closes [#11647](https://github.com/vuejs/core/issues/11647)
|
||||
* **runtime-dom:** prevent unnecessary DOM update from v-model ([#11656](https://github.com/vuejs/core/issues/11656)) ([b1be9bd](https://github.com/vuejs/core/commit/b1be9bd64f2c7c4286fecb25bad5d5edd49efce9)), closes [#11647](https://github.com/vuejs/core/issues/11647)
|
||||
* **server-renderer:** Fix call to serverPrefetch in server renderer with an async setup ([#10893](https://github.com/vuejs/core/issues/10893)) ([6039e25](https://github.com/vuejs/core/commit/6039e25e04a8c1db5821955f011d57f1615807ab))
|
||||
* **server-renderer:** render `className` during SSR ([#11722](https://github.com/vuejs/core/issues/11722)) ([52cdb0f](https://github.com/vuejs/core/commit/52cdb0f991dc154ae32a2900874d5dbc4e078565))
|
||||
* **types/defineModel:** allow getter and setter types to be unrelated ([#11699](https://github.com/vuejs/core/issues/11699)) ([fe07f70](https://github.com/vuejs/core/commit/fe07f7073617df358c2f8cbc3de433359e873c96)), closes [#11697](https://github.com/vuejs/core/issues/11697)
|
||||
|
||||
|
||||
|
||||
# [3.5.0-rc.1](https://github.com/vuejs/core/compare/v3.5.0-beta.3...v3.5.0-rc.1) (2024-08-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compiler-sfc:** skip circular tsconfig project reference ([#11680](https://github.com/vuejs/core/issues/11680)) ([9c4c2e5](https://github.com/vuejs/core/commit/9c4c2e51b045218d0c5ca64b4fb58b17d5d580cc)), closes [#11382](https://github.com/vuejs/core/issues/11382)
|
||||
* **custom-element:** handle keys set on custom elements ([#11655](https://github.com/vuejs/core/issues/11655)) ([f1d1831](https://github.com/vuejs/core/commit/f1d1831f07fe52d5681a5ec9ec310572463abf26)), closes [#11641](https://github.com/vuejs/core/issues/11641)
|
||||
* **deps:** update dependency monaco-editor to ^0.51.0 ([#11713](https://github.com/vuejs/core/issues/11713)) ([434f8a9](https://github.com/vuejs/core/commit/434f8a97c77f68aeae050e9e4e1f54f63bc4bd26))
|
||||
* **keep-alive:** reset keep alive flag when the component is removed from include ([#11718](https://github.com/vuejs/core/issues/11718)) ([29c321b](https://github.com/vuejs/core/commit/29c321bfd33f9197244dec3d027077e63b2cdf2f)), closes [#11717](https://github.com/vuejs/core/issues/11717)
|
||||
* **reactivity:** avoid infinite recursion when mutating ref wrapped in reactive ([313e4bf](https://github.com/vuejs/core/commit/313e4bf55214ac1e334a99c329a3ba5daca4f156)), closes [#11696](https://github.com/vuejs/core/issues/11696)
|
||||
* **reactivity:** ensure watcher with once: true are properly removed from effect scope ([#11665](https://github.com/vuejs/core/issues/11665)) ([fbc0c42](https://github.com/vuejs/core/commit/fbc0c42bcf6dea5a6ae664223fa19d4375ca39f0))
|
||||
* **runtime-dom:** setting innerHTML when patching props should go through trusted types ([d875de5](https://github.com/vuejs/core/commit/d875de54e9e03e0768fe550aa4c4886a4baf3bd7))
|
||||
* **types:** GlobalDirective / GlobalComponents should not be records ([42e8df6](https://github.com/vuejs/core/commit/42e8df62030e7f2c287d9103f045e67b34a63e3b))
|
||||
|
||||
|
||||
|
||||
# [3.5.0-beta.3](https://github.com/vuejs/core/compare/v3.5.0-beta.2...v3.5.0-beta.3) (2024-08-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **reactivity:** extended methods respect reactive ([#11629](https://github.com/vuejs/core/issues/11629)) ([9de1d10](https://github.com/vuejs/core/commit/9de1d101f98bf6081f41038f6974826f190330a0)), closes [#11628](https://github.com/vuejs/core/issues/11628)
|
||||
* **runtime-core:** correct type inference for PascalCase emits ([#11579](https://github.com/vuejs/core/issues/11579)) ([d7d0371](https://github.com/vuejs/core/commit/d7d0371e74707ee601020f67de88e091cdae2673)), closes [vuejs/language-tools#4269](https://github.com/vuejs/language-tools/issues/4269)
|
||||
* **runtime-core:** ensure suspense content inherit scopeId ([#10652](https://github.com/vuejs/core/issues/10652)) ([ac2a410](https://github.com/vuejs/core/commit/ac2a410e46392db63ca4ed2db3c0fa71ebe1e855)), closes [#5148](https://github.com/vuejs/core/issues/5148)
|
||||
* **runtime-core:** pre jobs without an id should run first ([#7746](https://github.com/vuejs/core/issues/7746)) ([b332f80](https://github.com/vuejs/core/commit/b332f80f0edb018229a23b43b93bb402b6368a3c))
|
||||
* **ssr:** apply ssr props to the the fallback vnode-based branch in ssr ([#7247](https://github.com/vuejs/core/issues/7247)) ([98b83e8](https://github.com/vuejs/core/commit/98b83e86d16c635547a1e735e5fb675aea2f0f1b)), closes [#6123](https://github.com/vuejs/core/issues/6123)
|
||||
* **types/custom-element:** `defineCustomElement` with required props ([#11578](https://github.com/vuejs/core/issues/11578)) ([5e0f6d5](https://github.com/vuejs/core/commit/5e0f6d5f8fe7c4eb8f247357c3e2e281726f36db))
|
||||
* **types:** strip non-prop default values from return type of withDefaults ([#9998](https://github.com/vuejs/core/issues/9998)) ([44973bb](https://github.com/vuejs/core/commit/44973bb3e790db7d8aa7af4eda21c80cac73a8de)), closes [#9899](https://github.com/vuejs/core/issues/9899)
|
||||
* **watch:** handle errors in computed used as watch source ([#11626](https://github.com/vuejs/core/issues/11626)) ([8bcaad4](https://github.com/vuejs/core/commit/8bcaad4a32cf0f1f89e0259f6a53036620b7fe9f)), closes [#11624](https://github.com/vuejs/core/issues/11624)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **reactivity:** base `watch`, `getCurrentWatcher`, and `onWatcherCleanup` ([#9927](https://github.com/vuejs/core/issues/9927)) ([205e5b5](https://github.com/vuejs/core/commit/205e5b5e277243c3af2c937d9bd46cf671296b72))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **runtime-core:** use `apply` to avoid spreading. ([#5985](https://github.com/vuejs/core/issues/5985)) ([bb6babc](https://github.com/vuejs/core/commit/bb6babca8f206615d4e246457cd54d21bb3bc5a4))
|
||||
|
||||
|
||||
|
||||
# [3.5.0-beta.2](https://github.com/vuejs/core/compare/v3.5.0-beta.1...v3.5.0-beta.2) (2024-08-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **build:** revert entities to 4.5 to avoid runtime resolution errors ([e9e0815](https://github.com/vuejs/core/commit/e9e08155bf8d00c3327ed7371330eb2ae467e560)), closes [#11603](https://github.com/vuejs/core/issues/11603)
|
||||
* **compiler-core:** use ast-based check for function expressions when possible ([5861229](https://github.com/vuejs/core/commit/58612294757480974e667652ede5bbcf72b1089d)), closes [#11615](https://github.com/vuejs/core/issues/11615)
|
||||
* **compiler-sfc:** fix prefixIdentifier default value ([3d6f015](https://github.com/vuejs/core/commit/3d6f01571b3fb61b32da599d0419eff4e3ebb231))
|
||||
* **compiler-sfc:** handle keyof operator with index object ([#11581](https://github.com/vuejs/core/issues/11581)) ([fe00815](https://github.com/vuejs/core/commit/fe008152c0612ff3ecc7ad88e7e66a06b1b2bc3f))
|
||||
* **custom-element:** keep instance.isCE for backwards compat ([e19fc27](https://github.com/vuejs/core/commit/e19fc270428b59456fee43224990138c4d6ccb2d))
|
||||
* **deps:** update dependency postcss to ^8.4.41 ([#11585](https://github.com/vuejs/core/issues/11585)) ([4c4e12a](https://github.com/vuejs/core/commit/4c4e12ae28d67d616924b0601e68adc551959971))
|
||||
* **keep-alive:** ensure include/exclude regexp work with global flag ([#11595](https://github.com/vuejs/core/issues/11595)) ([3653bc0](https://github.com/vuejs/core/commit/3653bc0f45d6fedf84e29b64ca52584359c383c0))
|
||||
* **reactivity:** ensure extended method arguments are not lost ([#11574](https://github.com/vuejs/core/issues/11574)) ([4085def](https://github.com/vuejs/core/commit/4085def1bae42d01ee3c22c731cc4a02096464ee)), closes [#11570](https://github.com/vuejs/core/issues/11570)
|
||||
* **reactivity:** sync watch should be executed correctly ([#11589](https://github.com/vuejs/core/issues/11589)) ([3bda3e8](https://github.com/vuejs/core/commit/3bda3e83fd9e2fbe451a1c79dae82ff6a7467683)), closes [#11577](https://github.com/vuejs/core/issues/11577)
|
||||
* **types/computed:** ensure type safety for `WritableComputedRef` ([#11608](https://github.com/vuejs/core/issues/11608)) ([5cf5a16](https://github.com/vuejs/core/commit/5cf5a1620d9a97382d386c277265d9dd051fe484))
|
||||
* **types:** add fallback stub for DOM types when DOM lib is absent ([#11598](https://github.com/vuejs/core/issues/11598)) ([fee6697](https://github.com/vuejs/core/commit/fee669764fbf475adce9e47a7a73b4937ab31ffc))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **deprecated:** remove deprecated parseExpressions option ([#11597](https://github.com/vuejs/core/issues/11597)) ([4e7d5db](https://github.com/vuejs/core/commit/4e7d5db4d276a5d4aaf3af7d43cfd28c171db307))
|
||||
|
||||
|
||||
|
||||
# [3.5.0-beta.1](https://github.com/vuejs/core/compare/v3.4.37...v3.5.0-beta.1) (2024-08-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **custom-element:** delay mounting of custom elements with async parent ([37ccb9b](https://github.com/vuejs/core/commit/37ccb9b9a0e4381f9465e0fc6459609003030da4)), closes [#8127](https://github.com/vuejs/core/issues/8127) [#9341](https://github.com/vuejs/core/issues/9341) [#9351](https://github.com/vuejs/core/issues/9351) [#9351](https://github.com/vuejs/core/issues/9351)
|
||||
* **custom-element:** delete prop on attribute removal ([506c4c5](https://github.com/vuejs/core/commit/506c4c53fdf9766c2ce9517ad58d501ef6b1b9de)), closes [#11276](https://github.com/vuejs/core/issues/11276)
|
||||
* **custom-element:** ignore scoped id ([7f2c505](https://github.com/vuejs/core/commit/7f2c505f92026408a8262ba9b5104a465be19446))
|
||||
* **custom-element:** reflect prop default value on custom element ([63689ed](https://github.com/vuejs/core/commit/63689ed77601d5f9b78540f810612806c3a5de15)), closes [#9006](https://github.com/vuejs/core/issues/9006) [#10537](https://github.com/vuejs/core/issues/10537)
|
||||
* **custom-element:** support early-set domProps for async custom elements ([a07e7bf](https://github.com/vuejs/core/commit/a07e7bf5536a6b3db70ba9bb1c3f366dac1bf5a0)), closes [#11081](https://github.com/vuejs/core/issues/11081) [#11082](https://github.com/vuejs/core/issues/11082)
|
||||
* **types/custome-element:** `defineCustomElement` props inference with array emits ([#11384](https://github.com/vuejs/core/issues/11384)) ([e94b01b](https://github.com/vuejs/core/commit/e94b01bd8a1ec740eddc823839ab2627b307c1b0)), closes [#11353](https://github.com/vuejs/core/issues/11353)
|
||||
* **types:** allow using InjectionKey as valid property key ([321d807](https://github.com/vuejs/core/commit/321d80758c42fccbd39ecbb63f1a4f6632a1580a)), closes [#5089](https://github.com/vuejs/core/issues/5089)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **custom-element:** expose this.$host in Options API ([1ef8f46](https://github.com/vuejs/core/commit/1ef8f46af0cfdec2fed66376772409e0aa25ad50))
|
||||
* **custom-element:** inject child components styles to custom element shadow root ([#11517](https://github.com/vuejs/core/issues/11517)) ([56c76a8](https://github.com/vuejs/core/commit/56c76a8b05c45f782ed3a16ec77c6292b71a17f1)), closes [#4662](https://github.com/vuejs/core/issues/4662) [#7941](https://github.com/vuejs/core/issues/7941) [#7942](https://github.com/vuejs/core/issues/7942)
|
||||
* **custom-element:** support configurable app instance in defineCustomElement ([6758c3c](https://github.com/vuejs/core/commit/6758c3cd0427f97394d95168c655dae3b7fa62cd)), closes [#4356](https://github.com/vuejs/core/issues/4356) [#4635](https://github.com/vuejs/core/issues/4635)
|
||||
* **custom-element:** support css `:host` selector by applying css vars on host element ([#8830](https://github.com/vuejs/core/issues/8830)) ([03a9ea2](https://github.com/vuejs/core/commit/03a9ea2b88df0842a820e09f7445c4b9189e3fcb)), closes [#8826](https://github.com/vuejs/core/issues/8826)
|
||||
* **custom-element:** support emit with options ([e181bff](https://github.com/vuejs/core/commit/e181bff6dc39d5cef92000c10291243c7d6e4d08)), closes [#7605](https://github.com/vuejs/core/issues/7605)
|
||||
* **custom-element:** support for expose on customElement ([#6256](https://github.com/vuejs/core/issues/6256)) ([af838c1](https://github.com/vuejs/core/commit/af838c1b5ec23552e52e64ffa7db0eb0246c3624)), closes [#5540](https://github.com/vuejs/core/issues/5540)
|
||||
* **custom-element:** support nonce option for injected style tags ([bb4a02a](https://github.com/vuejs/core/commit/bb4a02a70c30e739a3c705b3d96d09258d7d7ded)), closes [#6530](https://github.com/vuejs/core/issues/6530)
|
||||
* **custom-element:** support passing custom-element-specific options via 2nd argument of defineCustomElement ([60a88a2](https://github.com/vuejs/core/commit/60a88a2b129714186cf6ba66f30f31d733d0311e))
|
||||
* **custom-element:** support shadowRoot: false in defineCustomElement() ([37d2ce5](https://github.com/vuejs/core/commit/37d2ce5d8e0fac4a00064f02b05f91f69b2d5d5e)), closes [#4314](https://github.com/vuejs/core/issues/4314) [#4404](https://github.com/vuejs/core/issues/4404)
|
||||
* **custom-element:** useHost() helper ([775103a](https://github.com/vuejs/core/commit/775103af37df69d34c79f12c4c1776c47d07f0a0))
|
||||
* **custom-element:** useShadowRoot() helper ([5a1a89b](https://github.com/vuejs/core/commit/5a1a89bd6178cc2f84ba91da7d72aee4c6ec1282)), closes [#6113](https://github.com/vuejs/core/issues/6113) [#8195](https://github.com/vuejs/core/issues/8195)
|
||||
* **hydration:** allow fine tuning of lazy hydration strategy triggers ([#11530](https://github.com/vuejs/core/issues/11530)) ([261c8b1](https://github.com/vuejs/core/commit/261c8b111d046204bd22392a8b920e3c3d4def48))
|
||||
* **reactivity/watch:** add pause/resume for ReactiveEffect, EffectScope, and WatchHandle ([#9651](https://github.com/vuejs/core/issues/9651)) ([267093c](https://github.com/vuejs/core/commit/267093c31490050bfcf3ff2b30a2aefee2dad582))
|
||||
* **reactivity:** store value cache on CustomRefs impls ([#11539](https://github.com/vuejs/core/issues/11539)) ([e044b6e](https://github.com/vuejs/core/commit/e044b6e737efc9433d1d84590036b82280da6292))
|
||||
* **runtime-dom:** Trusted Types compatibility ([#10844](https://github.com/vuejs/core/issues/10844)) ([6d4eb94](https://github.com/vuejs/core/commit/6d4eb94853ed1b2b1675bdd7d5ba9c75cc6daed5))
|
||||
* support specifying allowed keys via generic argument in useTemplateRef() ([1fbfa69](https://github.com/vuejs/core/commit/1fbfa6962b48634ff60837084b82dd57f215c109))
|
||||
* **types:** allow computed getter and setter types to be unrelated ([#11472](https://github.com/vuejs/core/issues/11472)) ([a01675e](https://github.com/vuejs/core/commit/a01675ef8f99b5acd6832c53051f4415b18609f2)), closes [#7271](https://github.com/vuejs/core/issues/7271)
|
||||
* **types:** export `MultiWatchSources` type ([#9563](https://github.com/vuejs/core/issues/9563)) ([998dca5](https://github.com/vuejs/core/commit/998dca59f140420280803233f41707580688562c))
|
||||
* **types:** provide internal options for using refs type in language tools ([#11492](https://github.com/vuejs/core/issues/11492)) ([5ffd1a8](https://github.com/vuejs/core/commit/5ffd1a89455807d5069eb2c28eba0379641dca76))
|
||||
* **watch:** support passing number to `deep` option to control the watch depth ([#9572](https://github.com/vuejs/core/issues/9572)) ([22f7d96](https://github.com/vuejs/core/commit/22f7d96757956ebe0baafe52256aa327908cc51c))
|
||||
|
||||
|
||||
|
||||
# [3.5.0-alpha.5](https://github.com/vuejs/core/compare/v3.4.35...v3.5.0-alpha.5) (2024-07-31)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **hydration:** support suppressing hydration mismatch via data-allow-mismatch ([94fb2b8](https://github.com/vuejs/core/commit/94fb2b8106a66bcca1a3f922a246a29fdd1274b1))
|
||||
* lazy hydration strategies for async components ([#11458](https://github.com/vuejs/core/issues/11458)) ([d14a11c](https://github.com/vuejs/core/commit/d14a11c1cdcee88452f17ce97758743c863958f4))
|
||||
|
||||
|
||||
|
||||
# [3.5.0-alpha.4](https://github.com/vuejs/core/compare/v3.4.34...v3.5.0-alpha.4) (2024-07-24)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **suspense/hydration:** fix hydration timing of async component inside suspense ([1b8e197](https://github.com/vuejs/core/commit/1b8e197a5b65d67a9703b8511786fb81df9aa7cc)), closes [#6638](https://github.com/vuejs/core/issues/6638)
|
||||
* **useId:** properly mark async boundary for already resolved async component ([cd28172](https://github.com/vuejs/core/commit/cd281725781ada2ab279e919031ae307e146a9d9))
|
||||
|
||||
|
||||
|
||||
# [3.5.0-alpha.3](https://github.com/vuejs/core/compare/v3.4.33...v3.5.0-alpha.3) (2024-07-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **build:** enable SSR branches in esm-browser builds ([b14cd9a](https://github.com/vuejs/core/commit/b14cd9a68bab082332b0169be075be357be076ca))
|
||||
* **compiler-core:** change node hoisting to caching per instance ([#11067](https://github.com/vuejs/core/issues/11067)) ([cd0ea0d](https://github.com/vuejs/core/commit/cd0ea0d479a276583fa181d8ecbc97fb0e4a9dce)), closes [#5256](https://github.com/vuejs/core/issues/5256) [#9219](https://github.com/vuejs/core/issues/9219) [#10959](https://github.com/vuejs/core/issues/10959)
|
||||
* **compiler-sfc:** should properly walk desutructured props when reactive destructure is not enabled ([0fd6193](https://github.com/vuejs/core/commit/0fd6193def2380916eb51a118f37f2d9ec2ace23)), closes [#11325](https://github.com/vuejs/core/issues/11325)
|
||||
* **types:** respect props with default on instance type when using __typeProps ([96e4738](https://github.com/vuejs/core/commit/96e473833422342c5ca371ae1aeb186dec9a55e3))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **runtime-core:** useTemplateRef() ([3ba70e4](https://github.com/vuejs/core/commit/3ba70e49b5856c53611c314d4855d679a546a7df))
|
||||
* **runtime-core:** useId() and app.config.idPrefix ([#11404](https://github.com/vuejs/core/issues/11404)) ([73ef156](https://github.com/vuejs/core/commit/73ef1561f6905d69f968c094d0180c61824f1247))
|
||||
* **runtime-core:** add app.config.throwUnhandledErrorInProduction ([f476b7f](https://github.com/vuejs/core/commit/f476b7f030f2dd427ca655fcea36f4933a4b4da0)), closes [#7876](https://github.com/vuejs/core/issues/7876)
|
||||
* **teleport:** support deferred Teleport ([#11387](https://github.com/vuejs/core/issues/11387)) ([59a3e88](https://github.com/vuejs/core/commit/59a3e88903b10ac2278170a44d5a03f24fef23ef)), closes [#2015](https://github.com/vuejs/core/issues/2015) [#11386](https://github.com/vuejs/core/issues/11386)
|
||||
* **compiler-core:** support `Symbol` global in template expressions ([#9069](https://github.com/vuejs/core/issues/9069)) ([a501a85](https://github.com/vuejs/core/commit/a501a85a7c910868e01a5c70a2abea4e9d9e87f3))
|
||||
* **types:** export more emit related types ([#11017](https://github.com/vuejs/core/issues/11017)) ([189573d](https://github.com/vuejs/core/commit/189573dcee2a16bd3ed36ff5589d43f535e5e733))
|
||||
|
||||
|
||||
|
||||
# [3.5.0-alpha.2](https://github.com/vuejs/core/compare/v3.4.26...v3.5.0-alpha.2) (2024-05-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **types:** fix app.component() typing with inline defineComponent ([908f70a](https://github.com/vuejs/core/commit/908f70adc06038d1ea253d96f4024367f4a7545d)), closes [#10843](https://github.com/vuejs/core/issues/10843)
|
||||
* **types:** fix compat with generated types that rely on CreateComponentPublicInstance ([c146186](https://github.com/vuejs/core/commit/c146186396d0c1a65423b8c9a21251c5a6467336)), closes [#10842](https://github.com/vuejs/core/issues/10842)
|
||||
* **types:** props in defineOptions type should be optional ([124c4ca](https://github.com/vuejs/core/commit/124c4cac833a28ae9bc8edc576c1d0c7c41f5985)), closes [#10841](https://github.com/vuejs/core/issues/10841)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **runtime-core:** add app.onUnmount() for registering cleanup functions ([#4619](https://github.com/vuejs/core/issues/4619)) ([582a3a3](https://github.com/vuejs/core/commit/582a3a382b1adda565bac576b913a88d9e8d7a9e)), closes [#4516](https://github.com/vuejs/core/issues/4516)
|
||||
|
||||
|
||||
|
||||
# [3.5.0-alpha.1](https://github.com/vuejs/core/compare/v3.4.25...v3.5.0-alpha.1) (2024-04-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **reactivity:** fix call sequence of ontrigger in effect ([#10501](https://github.com/vuejs/core/issues/10501)) ([28841fe](https://github.com/vuejs/core/commit/28841fee43a45c37905c2c1ed9ace23067539045))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **compiler-sfc:** enable reactive props destructure by default ([d2dac0e](https://github.com/vuejs/core/commit/d2dac0e359c47d1ed0aa77eda488e76fd6466d2d))
|
||||
* **reactivity:** `onEffectCleanup` API ([2cc5615](https://github.com/vuejs/core/commit/2cc5615590de77126e8df46136de0240dbde5004)), closes [#10173](https://github.com/vuejs/core/issues/10173)
|
||||
* **reactivity:** add failSilently argument for onScopeDispose ([9a936aa](https://github.com/vuejs/core/commit/9a936aaec489c79433a32791ecf5ddb1739a62bd))
|
||||
* **transition:** support directly nesting Teleport inside Transition ([#6548](https://github.com/vuejs/core/issues/6548)) ([0e6e3c7](https://github.com/vuejs/core/commit/0e6e3c7eb0e5320b7c1818e025cb4a490fede9c0)), closes [#5836](https://github.com/vuejs/core/issues/5836)
|
||||
* **types:** provide internal options for directly using user types in language tools ([#10801](https://github.com/vuejs/core/issues/10801)) ([75c8cf6](https://github.com/vuejs/core/commit/75c8cf63a1ef30ac84f91282d66ad3f57c6612e9))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **reactivity:** optimize array tracking ([#9511](https://github.com/vuejs/core/issues/9511)) ([70196a4](https://github.com/vuejs/core/commit/70196a40cc078f50fcc1110c38c06fbcc70b205e)), closes [#4318](https://github.com/vuejs/core/issues/4318)
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import importX from 'eslint-plugin-import-x'
|
||||
import tseslint from 'typescript-eslint'
|
||||
import { defineConfig } from 'eslint/config'
|
||||
import vitest from '@vitest/eslint-plugin'
|
||||
import { builtinModules } from 'node:module'
|
||||
|
||||
|
|
@ -12,7 +13,7 @@ const banConstEnum = {
|
|||
'Please use non-const enums. This project automatically inlines enums.',
|
||||
}
|
||||
|
||||
export default tseslint.config(
|
||||
export default defineConfig(
|
||||
{
|
||||
files: ['**/*.js', '**/*.ts', '**/*.tsx'],
|
||||
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
|
||||
// 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
|
||||
'@typescript-eslint/consistent-type-imports': [
|
||||
'error',
|
||||
|
|
@ -106,7 +110,7 @@ export default tseslint.config(
|
|||
|
||||
// Packages targeting DOM
|
||||
{
|
||||
files: ['packages/{vue,vue-compat,runtime-dom,runtime-vapor}/**'],
|
||||
files: ['packages/{vue,vue-compat,runtime-dom}/**'],
|
||||
rules: {
|
||||
'no-restricted-globals': ['error', ...NodeGlobals],
|
||||
},
|
||||
|
|
@ -126,7 +130,6 @@ export default tseslint.config(
|
|||
files: [
|
||||
'packages-private/template-explorer/**',
|
||||
'packages-private/sfc-playground/**',
|
||||
'packages-private/local-playground/**',
|
||||
],
|
||||
rules: {
|
||||
'no-restricted-globals': ['error', ...NodeGlobals],
|
||||
|
|
@ -153,8 +156,6 @@ export default tseslint.config(
|
|||
'./*.{js,ts}',
|
||||
'packages/*/*.js',
|
||||
'packages/vue/*/*.js',
|
||||
'packages-private/benchmark/*',
|
||||
'packages-private/e2e-utils/*',
|
||||
],
|
||||
rules: {
|
||||
'no-restricted-globals': 'off',
|
||||
|
|
|
|||
73
package.json
73
package.json
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"private": true,
|
||||
"version": "3.6.0-alpha.1",
|
||||
"packageManager": "pnpm@10.12.4",
|
||||
"version": "3.5.24",
|
||||
"packageManager": "pnpm@10.20.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "node scripts/dev.js",
|
||||
|
|
@ -9,21 +9,19 @@
|
|||
"build-dts": "tsc -p tsconfig.build.json --noCheck && rollup -c rollup.dts.config.js",
|
||||
"clean": "rimraf --glob packages/*/dist temp .eslintcache",
|
||||
"size": "run-s \"size-*\" && node scripts/usage-size.js",
|
||||
"size-global": "node scripts/build.js vue runtime-dom compiler-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": "node scripts/build.js runtime-shared runtime-dom runtime-core reactivity shared runtime-vapor -f esm-bundler",
|
||||
"size-esm": "node scripts/build.js runtime-dom runtime-core reactivity shared -f esm-bundler",
|
||||
"check": "tsc --incremental --noEmit",
|
||||
"lint": "eslint --cache .",
|
||||
"format": "prettier --write --cache .",
|
||||
"format-check": "prettier --check --cache .",
|
||||
"test": "vitest",
|
||||
"test-unit": "vitest --project unit --project unit-jsdom",
|
||||
"test-unit": "vitest --project unit*",
|
||||
"test-e2e": "node scripts/build.js vue -f global -d && vitest --project e2e",
|
||||
"test-e2e-vapor": "pnpm run prepare-e2e-vapor && vitest --project e2e-vapor",
|
||||
"prepare-e2e-vapor": "node scripts/build.js -f cjs+esm-bundler+esm-bundler-runtime && pnpm run -C packages-private/vapor-e2e-test build",
|
||||
"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-coverage": "vitest run --project unit --coverage",
|
||||
"test-coverage": "vitest run --project unit* --coverage",
|
||||
"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",
|
||||
|
|
@ -31,17 +29,19 @@
|
|||
"release": "node scripts/release.js",
|
||||
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
|
||||
"dev-esm": "node scripts/dev.js -if esm-bundler-runtime",
|
||||
"dev-prepare-cjs": "node scripts/prepare-cjs.js || node scripts/build.js -f cjs",
|
||||
"dev-compiler": "run-p \"dev template-explorer\" serve open",
|
||||
"dev-sfc": "run-s dev-prepare-cjs dev-sfc-run",
|
||||
"dev-sfc-serve": "vite packages-private/sfc-playground",
|
||||
"dev-sfc-run": "run-p \"dev compiler-sfc -f esm-browser\" \"dev vue -if esm-browser-vapor\" \"dev vue -ipf esm-browser-vapor\" \"dev server-renderer -if esm-bundler\" dev-sfc-serve",
|
||||
"dev-vapor": "pnpm -C packages-private/local-playground run dev",
|
||||
"dev-compiler": "run-p \"dev template-explorer\" serve",
|
||||
"dev-sfc": "run-s dev-sfc-prepare dev-sfc-run",
|
||||
"dev-sfc-prepare": "node scripts/pre-dev-sfc.js || npm run build-all-cjs",
|
||||
"dev-sfc-serve": "vite packages-private/sfc-playground --host",
|
||||
"dev-sfc-run": "run-p \"dev compiler-sfc -f esm-browser\" \"dev vue -if esm-bundler-runtime\" \"dev vue -ipf esm-browser-runtime\" \"dev server-renderer -if esm-bundler\" dev-sfc-serve",
|
||||
"serve": "serve",
|
||||
"open": "open http://localhost:3000/packages-private/template-explorer/local.html",
|
||||
"build-sfc-playground": "run-s build-sfc-deps build-sfc-playground-self",
|
||||
"build-sfc-deps": "node scripts/build.js -f ~global+global-runtime",
|
||||
"build-sfc-playground-self": "pnpm run -C packages-private/sfc-playground build",
|
||||
"build-sfc-playground": "run-s build-all-cjs build-runtime-esm build-browser-esm build-ssr-esm build-sfc-playground-self",
|
||||
"build-all-cjs": "node scripts/build.js vue runtime compiler reactivity shared -af cjs",
|
||||
"build-runtime-esm": "node scripts/build.js runtime reactivity shared -af esm-bundler && node scripts/build.js vue -f esm-bundler-runtime && node scripts/build.js vue -f esm-browser-runtime",
|
||||
"build-browser-esm": "node scripts/build.js runtime reactivity shared -af esm-bundler && node scripts/build.js vue -f esm-bundler && node scripts/build.js vue -f esm-browser",
|
||||
"build-ssr-esm": "node scripts/build.js compiler-sfc server-renderer -f esm-browser",
|
||||
"build-sfc-playground-self": "cd packages-private/sfc-playground && npm run build",
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"postinstall": "simple-git-hooks"
|
||||
},
|
||||
|
|
@ -65,45 +65,44 @@
|
|||
"@babel/parser": "catalog:",
|
||||
"@babel/types": "catalog:",
|
||||
"@rollup/plugin-alias": "^5.1.1",
|
||||
"@rollup/plugin-commonjs": "^28.0.6",
|
||||
"@rollup/plugin-commonjs": "^28.0.9",
|
||||
"@rollup/plugin-json": "^6.1.0",
|
||||
"@rollup/plugin-node-resolve": "^16.0.1",
|
||||
"@rollup/plugin-node-resolve": "^16.0.3",
|
||||
"@rollup/plugin-replace": "5.0.4",
|
||||
"@swc/core": "^1.12.9",
|
||||
"@swc/core": "^1.14.0",
|
||||
"@types/hash-sum": "^1.0.2",
|
||||
"@types/node": "^22.16.0",
|
||||
"@types/semver": "^7.7.0",
|
||||
"@types/node": "^22.19.0",
|
||||
"@types/semver": "^7.7.1",
|
||||
"@types/serve-handler": "^6.1.4",
|
||||
"@vitest/ui": "^3.0.2",
|
||||
"@vitest/coverage-v8": "^3.1.4",
|
||||
"@vitest/eslint-plugin": "^1.2.1",
|
||||
"@vitest/coverage-v8": "^3.2.4",
|
||||
"@vitest/eslint-plugin": "^1.4.0",
|
||||
"@vue/consolidate": "1.0.0",
|
||||
"conventional-changelog-cli": "^5.0.0",
|
||||
"enquirer": "^2.4.1",
|
||||
"esbuild": "^0.25.5",
|
||||
"esbuild": "^0.25.12",
|
||||
"esbuild-plugin-polyfill-node": "^0.3.0",
|
||||
"eslint": "^9.27.0",
|
||||
"eslint-plugin-import-x": "^4.13.1",
|
||||
"estree-walker": "catalog:",
|
||||
"jsdom": "^26.1.0",
|
||||
"jsdom": "^27.1.0",
|
||||
"lint-staged": "^16.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"magic-string": "^0.30.17",
|
||||
"magic-string": "^0.30.21",
|
||||
"markdown-table": "^3.0.4",
|
||||
"marked": "13.0.3",
|
||||
"npm-run-all2": "^7.0.2",
|
||||
"npm-run-all2": "^8.0.4",
|
||||
"picocolors": "^1.1.1",
|
||||
"prettier": "^3.5.3",
|
||||
"pretty-bytes": "^6.1.1",
|
||||
"pretty-bytes": "^7.1.0",
|
||||
"pug": "^3.0.3",
|
||||
"puppeteer": "~24.9.0",
|
||||
"rimraf": "^6.0.1",
|
||||
"rollup": "^4.44.1",
|
||||
"rollup-plugin-dts": "^6.2.1",
|
||||
"puppeteer": "~24.28.0",
|
||||
"rimraf": "^6.1.0",
|
||||
"rollup": "^4.52.5",
|
||||
"rollup-plugin-dts": "^6.2.3",
|
||||
"rollup-plugin-esbuild": "^6.2.1",
|
||||
"rollup-plugin-polyfill-node": "^0.13.0",
|
||||
"semver": "^7.7.2",
|
||||
"serve": "^14.2.4",
|
||||
"semver": "^7.7.3",
|
||||
"serve": "^14.2.5",
|
||||
"serve-handler": "^6.1.6",
|
||||
"simple-git-hooks": "^2.13.0",
|
||||
"todomvc-app-css": "^2.4.3",
|
||||
|
|
@ -111,6 +110,6 @@
|
|||
"typescript": "~5.6.2",
|
||||
"typescript-eslint": "^8.32.1",
|
||||
"vite": "catalog:",
|
||||
"vitest": "^3.1.4"
|
||||
"vitest": "^3.2.4"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
results/*
|
||||
|
|
@ -1,136 +0,0 @@
|
|||
<script setup>
|
||||
import { shallowRef, triggerRef } from 'vue'
|
||||
import { buildData } from './data'
|
||||
import { defer, wrap } from './profiling'
|
||||
|
||||
const selected = shallowRef()
|
||||
const rows = shallowRef([])
|
||||
|
||||
// Bench Add: https://jsbench.me/45lzxprzmu/1
|
||||
const add = wrap('add', () => {
|
||||
rows.value.push(...buildData(1000))
|
||||
triggerRef(rows)
|
||||
})
|
||||
|
||||
const remove = wrap('remove', id => {
|
||||
rows.value.splice(
|
||||
rows.value.findIndex(d => d.id === id),
|
||||
1,
|
||||
)
|
||||
triggerRef(rows)
|
||||
})
|
||||
|
||||
const select = wrap('select', id => {
|
||||
selected.value = id
|
||||
})
|
||||
|
||||
const run = wrap('run', () => {
|
||||
rows.value = buildData()
|
||||
selected.value = undefined
|
||||
})
|
||||
|
||||
const update = wrap('update', () => {
|
||||
const _rows = rows.value
|
||||
for (let i = 0, len = _rows.length; i < len; i += 10) {
|
||||
_rows[i].label.value += ' !!!'
|
||||
}
|
||||
})
|
||||
|
||||
const runLots = wrap('runLots', () => {
|
||||
rows.value = buildData(10000)
|
||||
selected.value = undefined
|
||||
})
|
||||
|
||||
const clear = wrap('clear', () => {
|
||||
rows.value = []
|
||||
selected.value = undefined
|
||||
})
|
||||
|
||||
const swapRows = wrap('swap', () => {
|
||||
const _rows = rows.value
|
||||
if (_rows.length > 998) {
|
||||
const d1 = _rows[1]
|
||||
const d998 = _rows[998]
|
||||
_rows[1] = d998
|
||||
_rows[998] = d1
|
||||
triggerRef(rows)
|
||||
}
|
||||
})
|
||||
|
||||
async function bench() {
|
||||
for (let i = 0; i < 30; i++) {
|
||||
rows.value = []
|
||||
await runLots()
|
||||
await defer()
|
||||
}
|
||||
}
|
||||
|
||||
const globalThis = window
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h1>Vue.js (VDOM) Benchmark</h1>
|
||||
|
||||
<div style="display: flex; gap: 4px; margin-bottom: 4px">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
:value="globalThis.doProfile"
|
||||
@change="globalThis.doProfile = $event.target.checked"
|
||||
/>
|
||||
Profiling
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
:value="globalThis.reactivity"
|
||||
@change="globalThis.reactivity = $event.target.checked"
|
||||
/>
|
||||
Reactivity Cost
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div
|
||||
id="control"
|
||||
style="display: flex; flex-direction: column; width: fit-content; gap: 6px"
|
||||
>
|
||||
<button @click="bench">Benchmark mounting</button>
|
||||
<button id="run" @click="run">Create 1,000 rows</button>
|
||||
<button id="runlots" @click="runLots">Create 10,000 rows</button>
|
||||
<button id="add" @click="add">Append 1,000 rows</button>
|
||||
<button id="update" @click="update">Update every 10th row</button>
|
||||
<button id="clear" @click="clear">Clear</button>
|
||||
<button id="swaprows" @click="swapRows">Swap Rows</button>
|
||||
</div>
|
||||
<div id="time"></div>
|
||||
<table class="table table-hover table-striped test-data">
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="row of rows"
|
||||
:key="row.id"
|
||||
:class="selected === row.id ? 'danger' : ''"
|
||||
>
|
||||
<td class="col-md-1">{{ row.id }}</td>
|
||||
<td class="col-md-4">
|
||||
<a @click="select(row.id)">{{ row.label.value }}</a>
|
||||
</td>
|
||||
<td class="col-md-1">
|
||||
<a @click="remove(row.id)">
|
||||
<span class="glyphicon glyphicon-remove" aria-hidden="true">x</span>
|
||||
</a>
|
||||
</td>
|
||||
<td class="col-md-6"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<span
|
||||
class="preloadicon glyphicon glyphicon-remove"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.danger {
|
||||
background-color: red;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,136 +0,0 @@
|
|||
<script setup vapor>
|
||||
import { shallowRef, triggerRef } from 'vue'
|
||||
import { buildData } from './data'
|
||||
import { defer, wrap } from './profiling'
|
||||
|
||||
const selected = shallowRef()
|
||||
const rows = shallowRef([])
|
||||
|
||||
// Bench Add: https://jsbench.me/45lzxprzmu/1
|
||||
const add = wrap('add', () => {
|
||||
rows.value.push(...buildData(1000))
|
||||
triggerRef(rows)
|
||||
})
|
||||
|
||||
const remove = wrap('remove', id => {
|
||||
rows.value.splice(
|
||||
rows.value.findIndex(d => d.id === id),
|
||||
1,
|
||||
)
|
||||
triggerRef(rows)
|
||||
})
|
||||
|
||||
const select = wrap('select', id => {
|
||||
selected.value = id
|
||||
})
|
||||
|
||||
const run = wrap('run', () => {
|
||||
rows.value = buildData()
|
||||
selected.value = undefined
|
||||
})
|
||||
|
||||
const update = wrap('update', () => {
|
||||
const _rows = rows.value
|
||||
for (let i = 0, len = _rows.length; i < len; i += 10) {
|
||||
_rows[i].label.value += ' !!!'
|
||||
}
|
||||
})
|
||||
|
||||
const runLots = wrap('runLots', () => {
|
||||
rows.value = buildData(10000)
|
||||
selected.value = undefined
|
||||
})
|
||||
|
||||
const clear = wrap('clear', () => {
|
||||
rows.value = []
|
||||
selected.value = undefined
|
||||
})
|
||||
|
||||
const swapRows = wrap('swap', () => {
|
||||
const _rows = rows.value
|
||||
if (_rows.length > 998) {
|
||||
const d1 = _rows[1]
|
||||
const d998 = _rows[998]
|
||||
_rows[1] = d998
|
||||
_rows[998] = d1
|
||||
triggerRef(rows)
|
||||
}
|
||||
})
|
||||
|
||||
async function bench() {
|
||||
for (let i = 0; i < 30; i++) {
|
||||
rows.value = []
|
||||
await runLots()
|
||||
await defer()
|
||||
}
|
||||
}
|
||||
|
||||
const globalThis = window
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h1>Vue.js (Vapor) Benchmark</h1>
|
||||
|
||||
<div style="display: flex; gap: 4px; margin-bottom: 4px">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
:value="globalThis.doProfile"
|
||||
@change="globalThis.doProfile = $event.target.checked"
|
||||
/>
|
||||
Profiling
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
:value="globalThis.reactivity"
|
||||
@change="globalThis.reactivity = $event.target.checked"
|
||||
/>
|
||||
Reactivity Cost
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div
|
||||
id="control"
|
||||
style="display: flex; flex-direction: column; width: fit-content; gap: 6px"
|
||||
>
|
||||
<button @click="bench">Benchmark mounting</button>
|
||||
<button id="run" @click="run">Create 1,000 rows</button>
|
||||
<button id="runlots" @click="runLots">Create 10,000 rows</button>
|
||||
<button id="add" @click="add">Append 1,000 rows</button>
|
||||
<button id="update" @click="update">Update every 10th row</button>
|
||||
<button id="clear" @click="clear">Clear</button>
|
||||
<button id="swaprows" @click="swapRows">Swap Rows</button>
|
||||
</div>
|
||||
<div id="time"></div>
|
||||
<table class="table table-hover table-striped test-data">
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="row of rows"
|
||||
:key="row.id"
|
||||
:class="selected === row.id ? 'danger' : ''"
|
||||
>
|
||||
<td class="col-md-1">{{ row.id }}</td>
|
||||
<td class="col-md-4">
|
||||
<a @click="select(row.id)">{{ row.label.value }}</a>
|
||||
</td>
|
||||
<td class="col-md-1">
|
||||
<a @click="remove(row.id)">
|
||||
<span class="glyphicon glyphicon-remove" aria-hidden="true">x</span>
|
||||
</a>
|
||||
</td>
|
||||
<td class="col-md-6"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<span
|
||||
class="preloadicon glyphicon glyphicon-remove"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.danger {
|
||||
background-color: red;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
import { shallowRef } from 'vue'
|
||||
|
||||
let ID = 1
|
||||
|
||||
function _random(max: number) {
|
||||
return Math.round(Math.random() * 1000) % max
|
||||
}
|
||||
|
||||
export function buildData(count = 1000) {
|
||||
const adjectives = [
|
||||
'pretty',
|
||||
'large',
|
||||
'big',
|
||||
'small',
|
||||
'tall',
|
||||
'short',
|
||||
'long',
|
||||
'handsome',
|
||||
'plain',
|
||||
'quaint',
|
||||
'clean',
|
||||
'elegant',
|
||||
'easy',
|
||||
'angry',
|
||||
'crazy',
|
||||
'helpful',
|
||||
'mushy',
|
||||
'odd',
|
||||
'unsightly',
|
||||
'adorable',
|
||||
'important',
|
||||
'inexpensive',
|
||||
'cheap',
|
||||
'expensive',
|
||||
'fancy',
|
||||
]
|
||||
const colours = [
|
||||
'red',
|
||||
'yellow',
|
||||
'blue',
|
||||
'green',
|
||||
'pink',
|
||||
'brown',
|
||||
'purple',
|
||||
'brown',
|
||||
'white',
|
||||
'black',
|
||||
'orange',
|
||||
]
|
||||
const nouns = [
|
||||
'table',
|
||||
'chair',
|
||||
'house',
|
||||
'bbq',
|
||||
'desk',
|
||||
'car',
|
||||
'pony',
|
||||
'cookie',
|
||||
'sandwich',
|
||||
'burger',
|
||||
'pizza',
|
||||
'mouse',
|
||||
'keyboard',
|
||||
]
|
||||
const data = []
|
||||
for (let i = 0; i < count; i++)
|
||||
data.push({
|
||||
id: ID++,
|
||||
label: shallowRef(
|
||||
adjectives[_random(adjectives.length)] +
|
||||
' ' +
|
||||
colours[_random(colours.length)] +
|
||||
' ' +
|
||||
nouns[_random(nouns.length)],
|
||||
),
|
||||
})
|
||||
return data
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vue Vapor Benchmark</title>
|
||||
<style>
|
||||
html {
|
||||
color-scheme: light dark;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="done">
|
||||
<div id="app"></div>
|
||||
<script type="module" src="./index.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
if (import.meta.env.IS_VAPOR) {
|
||||
import('./vapor')
|
||||
} else {
|
||||
import('./vdom')
|
||||
}
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
/* eslint-disable no-console */
|
||||
/* eslint-disable no-restricted-syntax */
|
||||
/* eslint-disable no-restricted-globals */
|
||||
|
||||
import { nextTick } from 'vue'
|
||||
|
||||
declare global {
|
||||
var doProfile: boolean
|
||||
var reactivity: boolean
|
||||
var recordTime: boolean
|
||||
var times: Record<string, number[]>
|
||||
}
|
||||
|
||||
globalThis.recordTime = true
|
||||
globalThis.doProfile = false
|
||||
globalThis.reactivity = false
|
||||
|
||||
export const defer = () => new Promise(r => requestIdleCallback(r))
|
||||
|
||||
const times: Record<string, number[]> = (globalThis.times = {})
|
||||
|
||||
export function wrap(
|
||||
id: string,
|
||||
fn: (...args: any[]) => any,
|
||||
): (...args: any[]) => Promise<void> {
|
||||
return async (...args) => {
|
||||
if (!globalThis.recordTime) {
|
||||
return fn(...args)
|
||||
}
|
||||
|
||||
document.body.classList.remove('done')
|
||||
|
||||
const { doProfile } = globalThis
|
||||
await nextTick()
|
||||
|
||||
doProfile && console.profile(id)
|
||||
const start = performance.now()
|
||||
fn(...args)
|
||||
|
||||
await nextTick()
|
||||
let time: number
|
||||
if (globalThis.reactivity) {
|
||||
time = performance.measure(
|
||||
'flushJobs-measure',
|
||||
'flushJobs-start',
|
||||
'flushJobs-end',
|
||||
).duration
|
||||
performance.clearMarks()
|
||||
performance.clearMeasures()
|
||||
} else {
|
||||
time = performance.now() - start
|
||||
}
|
||||
const prevTimes = times[id] || (times[id] = [])
|
||||
prevTimes.push(time)
|
||||
|
||||
const { min, max, median, mean, std } = compute(prevTimes)
|
||||
const msg =
|
||||
`${id}: min: ${min} / ` +
|
||||
`max: ${max} / ` +
|
||||
`median: ${median}ms / ` +
|
||||
`mean: ${mean}ms / ` +
|
||||
`time: ${time.toFixed(2)}ms / ` +
|
||||
`std: ${std} ` +
|
||||
`over ${prevTimes.length} runs`
|
||||
doProfile && console.profileEnd(id)
|
||||
console.log(msg)
|
||||
const timeEl = document.getElementById('time')!
|
||||
timeEl.textContent = msg
|
||||
|
||||
document.body.classList.add('done')
|
||||
}
|
||||
}
|
||||
|
||||
function compute(array: number[]) {
|
||||
const n = array.length
|
||||
const max = Math.max(...array)
|
||||
const min = Math.min(...array)
|
||||
const mean = array.reduce((a, b) => a + b) / n
|
||||
const std = Math.sqrt(
|
||||
array.map(x => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n,
|
||||
)
|
||||
const median = array.slice().sort((a, b) => a - b)[Math.floor(n / 2)]
|
||||
return {
|
||||
max: round(max),
|
||||
min: round(min),
|
||||
mean: round(mean),
|
||||
std: round(std),
|
||||
median: round(median),
|
||||
}
|
||||
}
|
||||
|
||||
function round(n: number) {
|
||||
return +n.toFixed(2)
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import { createVaporApp } from 'vue'
|
||||
import App from './AppVapor.vue'
|
||||
|
||||
createVaporApp(App as any).mount('#app')
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
||||
|
|
@ -1,393 +0,0 @@
|
|||
// @ts-check
|
||||
import path from 'node:path'
|
||||
import { parseArgs } from 'node:util'
|
||||
import { mkdir, rm, writeFile } from 'node:fs/promises'
|
||||
import Vue from '@vitejs/plugin-vue'
|
||||
import { build } from 'vite'
|
||||
import connect from 'connect'
|
||||
import sirv from 'sirv'
|
||||
import { launch } from 'puppeteer'
|
||||
import colors from 'picocolors'
|
||||
import { exec, getSha } from '../../scripts/utils.js'
|
||||
import process from 'node:process'
|
||||
import readline from 'node:readline'
|
||||
|
||||
// Thanks to https://github.com/krausest/js-framework-benchmark (Apache-2.0 license)
|
||||
const {
|
||||
values: {
|
||||
skipLib,
|
||||
skipApp,
|
||||
skipBench,
|
||||
vdom,
|
||||
noVapor,
|
||||
port: portStr,
|
||||
count: countStr,
|
||||
warmupCount: warmupCountStr,
|
||||
noHeadless,
|
||||
noMinify,
|
||||
reference,
|
||||
},
|
||||
} = parseArgs({
|
||||
allowNegative: true,
|
||||
allowPositionals: true,
|
||||
options: {
|
||||
skipLib: {
|
||||
type: 'boolean',
|
||||
short: 'l',
|
||||
},
|
||||
skipApp: {
|
||||
type: 'boolean',
|
||||
short: 'a',
|
||||
},
|
||||
skipBench: {
|
||||
type: 'boolean',
|
||||
short: 'b',
|
||||
},
|
||||
noVapor: {
|
||||
type: 'boolean',
|
||||
},
|
||||
vdom: {
|
||||
type: 'boolean',
|
||||
short: 'v',
|
||||
},
|
||||
port: {
|
||||
type: 'string',
|
||||
short: 'p',
|
||||
default: '8193',
|
||||
},
|
||||
count: {
|
||||
type: 'string',
|
||||
short: 'c',
|
||||
default: '30',
|
||||
},
|
||||
warmupCount: {
|
||||
type: 'string',
|
||||
short: 'w',
|
||||
default: '5',
|
||||
},
|
||||
noHeadless: {
|
||||
type: 'boolean',
|
||||
},
|
||||
noMinify: {
|
||||
type: 'boolean',
|
||||
},
|
||||
reference: {
|
||||
type: 'boolean',
|
||||
short: 'r',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const port = +(/** @type {string}*/ (portStr))
|
||||
const count = +(/** @type {string}*/ (countStr))
|
||||
const warmupCount = +(/** @type {string}*/ (warmupCountStr))
|
||||
const sha = await getSha(true)
|
||||
|
||||
if (!skipLib && !reference) {
|
||||
await buildLib()
|
||||
}
|
||||
if (!skipApp && !reference) {
|
||||
await rm('client/dist', { recursive: true }).catch(() => {})
|
||||
vdom && (await buildApp(false))
|
||||
!noVapor && (await buildApp(true))
|
||||
}
|
||||
const server = startServer()
|
||||
|
||||
if (!skipBench) {
|
||||
await benchmark()
|
||||
server.close()
|
||||
}
|
||||
|
||||
async function buildLib() {
|
||||
console.info(colors.blue('Building lib...'))
|
||||
|
||||
/** @type {import('node:child_process').SpawnOptions} */
|
||||
const options = {
|
||||
cwd: path.resolve(import.meta.dirname, '../..'),
|
||||
stdio: 'inherit',
|
||||
env: { ...process.env, BENCHMARK: 'true' },
|
||||
}
|
||||
const [{ ok }, { ok: ok2 }, { ok: ok3 }] = await Promise.all([
|
||||
exec(
|
||||
'pnpm',
|
||||
`run --silent build shared compiler-core compiler-dom -pf cjs`.split(' '),
|
||||
options,
|
||||
),
|
||||
exec(
|
||||
'pnpm',
|
||||
'run --silent build compiler-sfc compiler-ssr compiler-vapor -f cjs'.split(
|
||||
' ',
|
||||
),
|
||||
options,
|
||||
),
|
||||
exec(
|
||||
'pnpm',
|
||||
`run --silent build shared reactivity runtime-core runtime-dom runtime-vapor vue -f esm-bundler+esm-bundler-runtime`.split(
|
||||
' ',
|
||||
),
|
||||
options,
|
||||
),
|
||||
])
|
||||
|
||||
if (!ok || !ok2 || !ok3) {
|
||||
console.error('Failed to build')
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
/** @param {boolean} isVapor */
|
||||
async function buildApp(isVapor) {
|
||||
console.info(
|
||||
colors.blue(`\nBuilding ${isVapor ? 'Vapor' : 'Virtual DOM'} app...\n`),
|
||||
)
|
||||
|
||||
process.env.NODE_ENV = 'production'
|
||||
|
||||
const CompilerSFC = await import(
|
||||
'../../packages/compiler-sfc/dist/compiler-sfc.cjs.js'
|
||||
)
|
||||
|
||||
const runtimePath = path.resolve(
|
||||
import.meta.dirname,
|
||||
'../../packages/vue/dist/vue.runtime.esm-bundler.js',
|
||||
)
|
||||
|
||||
const mode = isVapor ? 'vapor' : 'vdom'
|
||||
await build({
|
||||
root: './client',
|
||||
base: `/${mode}`,
|
||||
define: {
|
||||
'import.meta.env.IS_VAPOR': String(isVapor),
|
||||
},
|
||||
build: {
|
||||
minify: !noMinify,
|
||||
outDir: path.resolve('./client/dist', mode),
|
||||
rollupOptions: {
|
||||
onwarn(log, handler) {
|
||||
if (log.code === 'INVALID_ANNOTATION') return
|
||||
handler(log)
|
||||
},
|
||||
},
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
vue: runtimePath,
|
||||
},
|
||||
},
|
||||
clearScreen: false,
|
||||
plugins: [
|
||||
Vue({
|
||||
compiler: CompilerSFC,
|
||||
}),
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
function startServer() {
|
||||
const server = connect()
|
||||
.use(sirv(reference ? './reference' : './client/dist', { dev: true }))
|
||||
.listen(port)
|
||||
printPort()
|
||||
process.on('SIGTERM', () => server.close())
|
||||
return server
|
||||
}
|
||||
|
||||
async function benchmark() {
|
||||
console.info(colors.blue(`\nStarting benchmark...`))
|
||||
|
||||
const browser = await initBrowser()
|
||||
|
||||
await mkdir('results', { recursive: true }).catch(() => {})
|
||||
if (!noVapor) {
|
||||
await doBench(browser, true)
|
||||
}
|
||||
if (vdom) {
|
||||
await doBench(browser, false)
|
||||
}
|
||||
|
||||
await browser.close()
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} isVapor
|
||||
*/
|
||||
function getURL(isVapor) {
|
||||
return `http://localhost:${port}/${reference ? '' : isVapor ? 'vapor' : 'vdom'}/`
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {import('puppeteer').Browser} browser
|
||||
* @param {boolean} isVapor
|
||||
*/
|
||||
async function doBench(browser, isVapor) {
|
||||
const mode = reference ? `reference` : isVapor ? 'vapor' : 'vdom'
|
||||
console.info('\n\nmode:', mode)
|
||||
|
||||
const page = await browser.newPage()
|
||||
page.emulateCPUThrottling(4)
|
||||
await page.goto(getURL(isVapor), {
|
||||
waitUntil: 'networkidle0',
|
||||
})
|
||||
|
||||
await forceGC()
|
||||
const t = performance.now()
|
||||
|
||||
console.log('warmup run')
|
||||
await eachRun(() => withoutRecord(benchOnce), warmupCount)
|
||||
|
||||
console.log('benchmark run')
|
||||
await eachRun(benchOnce, count)
|
||||
|
||||
console.info(
|
||||
'Total time:',
|
||||
colors.cyan(((performance.now() - t) / 1000).toFixed(2)),
|
||||
's',
|
||||
)
|
||||
const times = await getTimes()
|
||||
const result =
|
||||
/** @type {Record<string, typeof compute>} */
|
||||
Object.fromEntries(Object.entries(times).map(([k, v]) => [k, compute(v)]))
|
||||
|
||||
console.table(result)
|
||||
await writeFile(
|
||||
`results/benchmark-${sha}-${mode}.json`,
|
||||
JSON.stringify(result, undefined, 2),
|
||||
)
|
||||
await page.close()
|
||||
return result
|
||||
|
||||
async function benchOnce() {
|
||||
await clickButton('run') // test: create rows
|
||||
await clickButton('update') // partial update
|
||||
await clickButton('swaprows') // swap rows
|
||||
await select() // test: select row, remove row
|
||||
await clickButton('clear') // clear rows
|
||||
|
||||
await withoutRecord(() => clickButton('run'))
|
||||
await clickButton('add') // append rows to large table
|
||||
|
||||
await withoutRecord(() => clickButton('clear'))
|
||||
await clickButton('runlots') // create many rows
|
||||
await withoutRecord(() => clickButton('clear'))
|
||||
|
||||
// TODO replace all rows
|
||||
}
|
||||
|
||||
function getTimes() {
|
||||
return page.evaluate(() => /** @type {any} */ (globalThis).times)
|
||||
}
|
||||
|
||||
async function forceGC() {
|
||||
await page.evaluate(
|
||||
`window.gc({type:'major',execution:'sync',flavor:'last-resort'})`,
|
||||
)
|
||||
}
|
||||
|
||||
/** @param {() => any} fn */
|
||||
async function withoutRecord(fn) {
|
||||
const currentRecordTime = await page.evaluate(() => globalThis.recordTime)
|
||||
await page.evaluate(() => (globalThis.recordTime = false))
|
||||
await fn()
|
||||
await page.evaluate(
|
||||
currentRecordTime => (globalThis.recordTime = currentRecordTime),
|
||||
currentRecordTime,
|
||||
)
|
||||
}
|
||||
|
||||
/** @param {string} id */
|
||||
async function clickButton(id) {
|
||||
await page.click(`#${id}`)
|
||||
await wait()
|
||||
}
|
||||
|
||||
async function select() {
|
||||
for (let i = 1; i <= 10; i++) {
|
||||
await page.click(`tbody > tr:nth-child(2) > td:nth-child(2) > a`)
|
||||
await page.waitForSelector(`tbody > tr:nth-child(2).danger`)
|
||||
await page.click(`tbody > tr:nth-child(2) > td:nth-child(3) > a`)
|
||||
await wait()
|
||||
}
|
||||
}
|
||||
|
||||
async function wait() {
|
||||
await page.waitForSelector('.done')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Function} bench
|
||||
* @param {number} count
|
||||
*/
|
||||
async function eachRun(bench, count) {
|
||||
for (let i = 0; i < count; i++) {
|
||||
readline.cursorTo(process.stdout, 0)
|
||||
readline.clearLine(process.stdout, 0)
|
||||
process.stdout.write(`${i + 1}/${count}`)
|
||||
await bench()
|
||||
}
|
||||
if (count === 0) {
|
||||
process.stdout.write('0/0 (skip)')
|
||||
}
|
||||
process.stdout.write('\n')
|
||||
}
|
||||
|
||||
async function initBrowser() {
|
||||
const disableFeatures = [
|
||||
'Translate', // avoid translation popups
|
||||
'PrivacySandboxSettings4', // avoid privacy popup
|
||||
'IPH_SidePanelGenericMenuFeature', // bookmark popup see https://github.com/krausest/js-framework-benchmark/issues/1688
|
||||
]
|
||||
|
||||
const args = [
|
||||
'--js-flags=--expose-gc', // needed for gc() function
|
||||
'--no-default-browser-check',
|
||||
'--disable-sync',
|
||||
'--no-first-run',
|
||||
'--ash-no-nudges',
|
||||
'--disable-extensions',
|
||||
`--disable-features=${disableFeatures.join(',')}`,
|
||||
]
|
||||
|
||||
const headless = !noHeadless
|
||||
console.info('headless:', headless)
|
||||
const browser = await launch({
|
||||
headless: headless,
|
||||
args,
|
||||
})
|
||||
console.log('browser version:', colors.blue(await browser.version()))
|
||||
|
||||
return browser
|
||||
}
|
||||
|
||||
/** @param {number[]} array */
|
||||
function compute(array) {
|
||||
const n = array.length
|
||||
const max = Math.max(...array)
|
||||
const min = Math.min(...array)
|
||||
const mean = array.reduce((a, b) => a + b) / n
|
||||
const std = Math.sqrt(
|
||||
array.map(x => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n,
|
||||
)
|
||||
const median = array.slice().sort((a, b) => a - b)[Math.floor(n / 2)]
|
||||
return {
|
||||
max: round(max),
|
||||
min: round(min),
|
||||
mean: round(mean),
|
||||
std: round(std),
|
||||
median: round(median),
|
||||
}
|
||||
}
|
||||
|
||||
/** @param {number} n */
|
||||
function round(n) {
|
||||
return +n.toFixed(2)
|
||||
}
|
||||
|
||||
function printPort() {
|
||||
const vaporLink = !noVapor
|
||||
? `\n${reference ? `Reference` : `Vapor`}: ${colors.blue(getURL(true))}`
|
||||
: ''
|
||||
const vdomLink = vdom ? `\nvDom: ${colors.blue(getURL(false))}` : ''
|
||||
console.info(`\n\nServer started at`, vaporLink, vdomLink)
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"name": "benchmark",
|
||||
"version": "0.0.0",
|
||||
"author": "三咲智子 Kevin Deng <sxzz@sxzz.moe>",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "pnpm start --noMinify --skipBench --vdom",
|
||||
"start": "node index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vitejs/plugin-vue": "catalog:",
|
||||
"connect": "^3.7.0",
|
||||
"sirv": "^2.0.4",
|
||||
"vite": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/connect": "^3.4.38"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"lib": ["es2022", "dom"],
|
||||
"allowJs": true,
|
||||
"moduleDetection": "force",
|
||||
"module": "preserve",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"types": ["node", "vite/client"],
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"declaration": true,
|
||||
"esModuleInterop": true,
|
||||
"isolatedModules": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"skipLibCheck": true,
|
||||
"noEmit": true,
|
||||
"paths": {
|
||||
"vue": ["../packages/vue/src/runtime-with-vapor.ts"],
|
||||
"@vue/*": ["../packages/*/src"]
|
||||
}
|
||||
},
|
||||
"include": ["**/*"]
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ type ExtractBinding<T> = T extends (
|
|||
declare function testDirective<
|
||||
Value,
|
||||
Modifiers extends string = string,
|
||||
Arg extends string = string,
|
||||
Arg = any,
|
||||
>(): ExtractBinding<Directive<any, Value, Modifiers, Arg>>
|
||||
|
||||
describe('vmodel', () => {
|
||||
|
|
@ -44,7 +44,7 @@ describe('custom', () => {
|
|||
value: number
|
||||
oldValue: number | null
|
||||
arg?: 'Arg'
|
||||
modifiers: Record<'a' | 'b', boolean>
|
||||
modifiers: Partial<Record<'a' | 'b', boolean>>
|
||||
// @ts-expect-error
|
||||
}>(testDirective<number, 'a' | 'b', 'Argx'>())
|
||||
|
||||
|
|
@ -52,7 +52,29 @@ describe('custom', () => {
|
|||
value: number
|
||||
oldValue: number | null
|
||||
arg?: 'Arg'
|
||||
modifiers: Record<'a' | 'b', boolean>
|
||||
modifiers: Partial<Record<'a' | 'b', boolean>>
|
||||
// @ts-expect-error
|
||||
}>(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'>())
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
})
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vue Vapor</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="./src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
{
|
||||
"name": "playground",
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "node ./setup/vite.js",
|
||||
"build": "vite build -c vite.prod.config.ts",
|
||||
"prepreview": "cd ../ && pnpm run build runtime-vapor -f esm-bundler",
|
||||
"preview": "pnpm run build && vite preview -c vite.prod.config.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vueuse/core": "^11.1.0",
|
||||
"vue": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "catalog:",
|
||||
"@vue/compiler-sfc": "workspace:*",
|
||||
"vite": "catalog:",
|
||||
"vite-hyper-config": "^0.4.0",
|
||||
"vite-plugin-inspect": "^0.8.7"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
// @ts-check
|
||||
import path from 'node:path'
|
||||
|
||||
const resolve = (/** @type {string} */ p) =>
|
||||
path.resolve(import.meta.dirname, '../../../packages', p)
|
||||
|
||||
/**
|
||||
* @param {Object} [env]
|
||||
* @param {boolean} [env.browser]
|
||||
* @returns {import('vite').Plugin}
|
||||
*/
|
||||
export function DevPlugin({ browser = false } = {}) {
|
||||
return {
|
||||
name: 'dev-plugin',
|
||||
config() {
|
||||
return {
|
||||
resolve: {
|
||||
alias: {
|
||||
vue: resolve('vue/src/runtime-with-vapor.ts'),
|
||||
|
||||
'@vue/runtime-core': resolve('runtime-core/src'),
|
||||
'@vue/runtime-dom': resolve('runtime-dom/src'),
|
||||
'@vue/runtime-vapor': resolve('runtime-vapor/src'),
|
||||
|
||||
'@vue/compiler-core': resolve('compiler-core/src'),
|
||||
'@vue/compiler-dom': resolve('compiler-dom/src'),
|
||||
'@vue/compiler-vapor': resolve('compiler-vapor/src'),
|
||||
|
||||
'@vue/compiler-sfc': resolve('compiler-sfc/src'),
|
||||
'@vue/compiler-ssr': resolve('compiler-ssr/src'),
|
||||
|
||||
'@vue/reactivity': resolve('reactivity/src'),
|
||||
'@vue/shared': resolve('shared/src'),
|
||||
'@vue/runtime-shared': resolve('runtime-shared/src'),
|
||||
},
|
||||
},
|
||||
define: {
|
||||
__COMMIT__: `"__COMMIT__"`,
|
||||
__VERSION__: `"0.0.0"`,
|
||||
__DEV__: `true`,
|
||||
// this is only used during Vue's internal tests
|
||||
__TEST__: `false`,
|
||||
// If the build is expected to run directly in the browser (global / esm builds)
|
||||
__BROWSER__: String(browser),
|
||||
__GLOBAL__: String(false),
|
||||
__ESM_BUNDLER__: String(true),
|
||||
__ESM_BROWSER__: String(false),
|
||||
// is targeting Node (SSR)?
|
||||
__NODE_JS__: String(false),
|
||||
// need SSR-specific branches?
|
||||
__SSR__: String(false),
|
||||
__BENCHMARK__: 'false',
|
||||
|
||||
// 2.x compat build
|
||||
__COMPAT__: String(false),
|
||||
|
||||
// feature flags
|
||||
__FEATURE_SUSPENSE__: `true`,
|
||||
__FEATURE_OPTIONS_API__: `true`,
|
||||
__FEATURE_PROD_DEVTOOLS__: `false`,
|
||||
__FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__: `false`,
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
// @ts-check
|
||||
|
||||
import { startVite } from 'vite-hyper-config'
|
||||
import { DevPlugin } from './dev.js'
|
||||
|
||||
startVite(
|
||||
undefined,
|
||||
{ plugins: [DevPlugin()] },
|
||||
{
|
||||
deps: {
|
||||
inline: ['@vitejs/plugin-vue'],
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
*
|
||||
!.gitignore
|
||||
!App.vue
|
||||
!main.ts
|
||||
!style.css
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import VaporComp from './VaporComp.vue'
|
||||
|
||||
const msg = ref('hello')
|
||||
const passSlot = ref(true)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<input v-model="msg" />
|
||||
<button @click="passSlot = !passSlot">toggle #test slot</button>
|
||||
<VaporComp :msg="msg">
|
||||
<template #default="{ foo }">
|
||||
<div>slot props: {{ foo }}</div>
|
||||
<div>component prop: {{ msg }}</div>
|
||||
</template>
|
||||
|
||||
<template #test v-if="passSlot"> A test slot </template>
|
||||
</VaporComp>
|
||||
</template>
|
||||
|
|
@ -1 +0,0 @@
|
|||
import './_entry'
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
.red {
|
||||
color: red;
|
||||
}
|
||||
.green {
|
||||
color: green;
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"isolatedDeclarations": false,
|
||||
"allowJs": true
|
||||
},
|
||||
"include": ["./**/*", "../../packages/*/src"]
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
import { defineConfig } from 'vite'
|
||||
import Inspect from 'vite-plugin-inspect'
|
||||
import { DevPlugin } from './setup/dev'
|
||||
import Vue from '@vitejs/plugin-vue'
|
||||
import * as CompilerSFC from '@vue/compiler-sfc'
|
||||
|
||||
export default defineConfig({
|
||||
clearScreen: false,
|
||||
plugins: [
|
||||
Vue({
|
||||
compiler: CompilerSFC,
|
||||
}),
|
||||
DevPlugin(),
|
||||
Inspect(),
|
||||
],
|
||||
optimizeDeps: {
|
||||
exclude: ['@vueuse/core'],
|
||||
},
|
||||
})
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
import { defineConfig } from 'vite'
|
||||
import Vue from '@vitejs/plugin-vue'
|
||||
import * as CompilerSFC from '@vue/compiler-sfc'
|
||||
|
||||
export default defineConfig({
|
||||
build: {
|
||||
modulePreload: false,
|
||||
target: 'esnext',
|
||||
minify: 'terser',
|
||||
terserOptions: {
|
||||
format: { comments: false },
|
||||
compress: {
|
||||
pure_getters: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
clearScreen: false,
|
||||
plugins: [
|
||||
Vue({
|
||||
compiler: CompilerSFC,
|
||||
features: {
|
||||
optionsAPI: false,
|
||||
},
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
"vite": "catalog:"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vue/repl": "^4.6.1",
|
||||
"@vue/repl": "^4.7.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"jszip": "^3.10.1",
|
||||
"vue": "workspace:*"
|
||||
|
|
|
|||
|
|
@ -1,14 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import Header from './Header.vue'
|
||||
import {
|
||||
Repl,
|
||||
type SFCOptions,
|
||||
useStore,
|
||||
useVueImportMap,
|
||||
StoreState,
|
||||
} from '@vue/repl'
|
||||
import { Repl, useStore, SFCOptions, useVueImportMap } from '@vue/repl'
|
||||
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>>()
|
||||
|
||||
|
|
@ -26,17 +20,13 @@ const initAutoSave: boolean = JSON.parse(
|
|||
)
|
||||
const autoSave = ref(initAutoSave)
|
||||
|
||||
const { vueVersion, productionMode, importMap } = useVueImportMap({
|
||||
runtimeDev: () => {
|
||||
return import.meta.env.PROD
|
||||
? `${location.origin}/vue.runtime-with-vapor.esm-browser.js`
|
||||
: `${location.origin}/src/vue-dev-proxy`
|
||||
},
|
||||
runtimeProd: () => {
|
||||
return import.meta.env.PROD
|
||||
? `${location.origin}/vue.runtime-with-vapor.esm-browser.prod.js`
|
||||
: `${location.origin}/src/vue-dev-proxy-prod`
|
||||
},
|
||||
const { productionMode, vueVersion, importMap } = useVueImportMap({
|
||||
runtimeDev: import.meta.env.PROD
|
||||
? `${location.origin}/vue.runtime.esm-browser.js`
|
||||
: `${location.origin}/src/vue-dev-proxy`,
|
||||
runtimeProd: import.meta.env.PROD
|
||||
? `${location.origin}/vue.runtime.esm-browser.prod.js`
|
||||
: `${location.origin}/src/vue-dev-proxy-prod`,
|
||||
serverRenderer: import.meta.env.PROD
|
||||
? `${location.origin}/server-renderer.esm-browser.js`
|
||||
: `${location.origin}/src/vue-server-renderer-dev-proxy`,
|
||||
|
|
@ -56,8 +46,6 @@ if (hash.startsWith('__SSR__')) {
|
|||
useSSRMode.value = true
|
||||
}
|
||||
|
||||
const files: StoreState['files'] = ref(Object.create(null))
|
||||
|
||||
// enable experimental features
|
||||
const sfcOptions = computed(
|
||||
(): SFCOptions => ({
|
||||
|
|
@ -65,13 +53,11 @@ const sfcOptions = computed(
|
|||
inlineTemplate: productionMode.value,
|
||||
isProd: productionMode.value,
|
||||
propsDestructure: true,
|
||||
// vapor: useVaporMode.value,
|
||||
},
|
||||
style: {
|
||||
isProd: productionMode.value,
|
||||
},
|
||||
template: {
|
||||
// vapor: useVaporMode.value,
|
||||
isProd: productionMode.value,
|
||||
compilerOptions: {
|
||||
isCustomElement: (tag: string) =>
|
||||
|
|
@ -83,9 +69,8 @@ const sfcOptions = computed(
|
|||
|
||||
const store = useStore(
|
||||
{
|
||||
files,
|
||||
vueVersion,
|
||||
builtinImportMap: importMap,
|
||||
vueVersion,
|
||||
sfcOptions,
|
||||
},
|
||||
hash,
|
||||
|
|
@ -130,6 +115,34 @@ onMounted(() => {
|
|||
// @ts-expect-error process shim for old versions of @vue/compiler-sfc dependency
|
||||
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>
|
||||
|
||||
<template>
|
||||
|
|
@ -160,20 +173,7 @@ onMounted(() => {
|
|||
:showOpenSourceMap="true"
|
||||
:autoResize="true"
|
||||
:clearConsole="false"
|
||||
:preview-options="{
|
||||
customCode: {
|
||||
importCode: `import { initCustomFormatter, vaporInteropPlugin } from 'vue'`,
|
||||
useCode: `
|
||||
app.use(vaporInteropPlugin)
|
||||
if (window.devtoolsFormatters) {
|
||||
const index = window.devtoolsFormatters.findIndex((v) => v.__vue_custom_formatter)
|
||||
window.devtoolsFormatters.splice(index, 1)
|
||||
initCustomFormatter()
|
||||
} else {
|
||||
initCustomFormatter()
|
||||
}`,
|
||||
},
|
||||
}"
|
||||
:preview-options="previewOptions"
|
||||
/>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ const emit = defineEmits([
|
|||
'toggle-theme',
|
||||
'toggle-ssr',
|
||||
'toggle-prod',
|
||||
'toggle-vapor',
|
||||
'toggle-autosave',
|
||||
'reload-page',
|
||||
])
|
||||
|
|
@ -216,7 +215,6 @@ h1 img {
|
|||
}
|
||||
|
||||
.toggle-prod span,
|
||||
.toggle-vapor span,
|
||||
.toggle-ssr span,
|
||||
.toggle-autosave span {
|
||||
font-size: 12px;
|
||||
|
|
@ -244,15 +242,6 @@ h1 img {
|
|||
background-color: var(--green);
|
||||
}
|
||||
|
||||
.toggle-vapor span {
|
||||
background-color: var(--btn-bg);
|
||||
}
|
||||
|
||||
.toggle-vapor.enabled span {
|
||||
color: #fff;
|
||||
background-color: var(--green);
|
||||
}
|
||||
|
||||
.toggle-dark svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"vue": "latest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.2.4",
|
||||
"vite": "^6.3.5"
|
||||
"@vitejs/plugin-vue": "^6.0.1",
|
||||
"vite": "^7.1.12"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
// serve vue to the iframe sandbox during dev.
|
||||
export * from 'vue/dist/vue.runtime-with-vapor.esm-browser.prod.js'
|
||||
export * from 'vue/dist/vue.runtime.esm-browser.prod.js'
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
// serve vue to the iframe sandbox during dev.
|
||||
export * from 'vue/dist/vue.runtime-with-vapor.esm-browser.js'
|
||||
export * from 'vue'
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
const msg = ref('Hello World!')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h1>{{ msg }}</h1>
|
||||
</template>
|
||||
|
|
@ -53,8 +53,6 @@ function copyVuePlugin(): Plugin {
|
|||
copyFile(`vue/dist/vue.esm-browser.prod.js`)
|
||||
copyFile(`vue/dist/vue.runtime.esm-browser.js`)
|
||||
copyFile(`vue/dist/vue.runtime.esm-browser.prod.js`)
|
||||
copyFile(`vue/dist/vue.runtime-with-vapor.esm-browser.js`)
|
||||
copyFile(`vue/dist/vue.runtime-with-vapor.esm-browser.prod.js`)
|
||||
copyFile(`server-renderer/dist/server-renderer.esm-browser.js`)
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,7 @@
|
|||
"enableNonBrowserBranches": true
|
||||
},
|
||||
"dependencies": {
|
||||
"@vue/compiler-vapor": "workspace:^",
|
||||
"monaco-editor": "^0.52.2",
|
||||
"monaco-editor": "^0.54.0",
|
||||
"source-map-js": "^1.2.1"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,15 @@
|
|||
import type * as m from 'monaco-editor'
|
||||
import type { CompilerError } from '@vue/compiler-dom'
|
||||
import { compile } from '@vue/compiler-dom'
|
||||
import {
|
||||
type CompilerError,
|
||||
type CompilerOptions,
|
||||
compile as vaporCompile,
|
||||
} from '@vue/compiler-vapor'
|
||||
// import { compile as ssrCompile } from '@vue/compiler-ssr'
|
||||
|
||||
compile,
|
||||
} from '@vue/compiler-dom'
|
||||
import { compile as ssrCompile } from '@vue/compiler-ssr'
|
||||
import {
|
||||
compilerOptions,
|
||||
defaultOptions,
|
||||
initOptions,
|
||||
ssrMode,
|
||||
vaporMode,
|
||||
} from './options'
|
||||
import { toRaw, watchEffect } from '@vue/runtime-dom'
|
||||
import { SourceMapConsumer } from 'source-map-js'
|
||||
|
|
@ -80,16 +77,10 @@ window.init = () => {
|
|||
console.clear()
|
||||
try {
|
||||
const errors: CompilerError[] = []
|
||||
const compileFn = /* ssrMode.value ? ssrCompile : */ (
|
||||
vaporMode.value ? vaporCompile : compile
|
||||
) as typeof vaporCompile
|
||||
const compileFn = ssrMode.value ? ssrCompile : compile
|
||||
const start = performance.now()
|
||||
const { code, ast, map } = compileFn(source, {
|
||||
...compilerOptions,
|
||||
prefixIdentifiers:
|
||||
compilerOptions.prefixIdentifiers ||
|
||||
compilerOptions.mode === 'module' ||
|
||||
compilerOptions.ssr,
|
||||
filename: 'ExampleTemplate.vue',
|
||||
sourceMap: true,
|
||||
onError: err => {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import { createApp, h, reactive, ref } from 'vue'
|
||||
import type { CompilerOptions } from '@vue/compiler-vapor'
|
||||
import type { CompilerOptions } from '@vue/compiler-dom'
|
||||
import { BindingTypes } from '@vue/compiler-core'
|
||||
|
||||
export const ssrMode = ref(false)
|
||||
export const vaporMode = ref(true)
|
||||
|
||||
export const defaultOptions: CompilerOptions = {
|
||||
mode: 'module',
|
||||
|
|
@ -40,11 +39,11 @@ const App = {
|
|||
compilerOptions.prefixIdentifiers || compilerOptions.mode === 'module'
|
||||
|
||||
return [
|
||||
h('h1', `Vue Template Explorer`),
|
||||
h('h1', `Vue 3 Template Explorer`),
|
||||
h(
|
||||
'a',
|
||||
{
|
||||
href: `https://github.com/vuejs/vue/tree/${__COMMIT__}`,
|
||||
href: `https://github.com/vuejs/core/tree/${__COMMIT__}`,
|
||||
target: `_blank`,
|
||||
},
|
||||
`@${__COMMIT__}`,
|
||||
|
|
@ -223,18 +222,6 @@ const App = {
|
|||
}),
|
||||
h('label', { for: 'compat' }, 'v2 compat mode'),
|
||||
]),
|
||||
|
||||
h('li', [
|
||||
h('input', {
|
||||
type: 'checkbox',
|
||||
id: 'vapor',
|
||||
checked: vaporMode.value,
|
||||
onChange(e: Event) {
|
||||
vaporMode.value = (e.target as HTMLInputElement).checked
|
||||
},
|
||||
}),
|
||||
h('label', { for: 'vapor' }, 'vapor'),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@
|
|||
"compilerOptions": {
|
||||
"isolatedDeclarations": false
|
||||
},
|
||||
"include": [".", "../packages/vue/__tests__/e2e/e2eUtils.ts"]
|
||||
"include": ["."]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,195 +0,0 @@
|
|||
import path from 'node:path'
|
||||
import {
|
||||
E2E_TIMEOUT,
|
||||
setupPuppeteer,
|
||||
} from '../../../packages/vue/__tests__/e2e/e2eUtils'
|
||||
import connect from 'connect'
|
||||
import sirv from 'sirv'
|
||||
|
||||
describe('e2e: todomvc', () => {
|
||||
const {
|
||||
page,
|
||||
click,
|
||||
isVisible,
|
||||
count,
|
||||
text,
|
||||
value,
|
||||
isChecked,
|
||||
isFocused,
|
||||
classList,
|
||||
enterValue,
|
||||
clearValue,
|
||||
timeout,
|
||||
} = setupPuppeteer()
|
||||
|
||||
let server: any
|
||||
const port = '8194'
|
||||
beforeAll(() => {
|
||||
server = connect()
|
||||
.use(sirv(path.resolve(import.meta.dirname, '../dist')))
|
||||
.listen(port)
|
||||
process.on('SIGTERM', () => server && server.close())
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
server.close()
|
||||
})
|
||||
|
||||
async function removeItemAt(n: number) {
|
||||
const item = (await page().$('.todo:nth-child(' + n + ')'))!
|
||||
const itemBBox = (await item.boundingBox())!
|
||||
await page().mouse.move(itemBBox.x + 10, itemBBox.y + 10)
|
||||
await click('.todo:nth-child(' + n + ') .destroy')
|
||||
}
|
||||
|
||||
test(
|
||||
'vapor',
|
||||
async () => {
|
||||
const baseUrl = `http://localhost:${port}/todomvc/`
|
||||
await page().goto(baseUrl)
|
||||
|
||||
expect(await isVisible('.main')).toBe(false)
|
||||
expect(await isVisible('.footer')).toBe(false)
|
||||
expect(await count('.filters .selected')).toBe(1)
|
||||
expect(await text('.filters .selected')).toBe('All')
|
||||
expect(await count('.todo')).toBe(0)
|
||||
|
||||
await enterValue('.new-todo', 'test')
|
||||
expect(await count('.todo')).toBe(1)
|
||||
expect(await isVisible('.todo .edit')).toBe(false)
|
||||
expect(await text('.todo label')).toBe('test')
|
||||
expect(await text('.todo-count strong')).toBe('1')
|
||||
expect(await isChecked('.todo .toggle')).toBe(false)
|
||||
expect(await isVisible('.main')).toBe(true)
|
||||
expect(await isVisible('.footer')).toBe(true)
|
||||
expect(await isVisible('.clear-completed')).toBe(false)
|
||||
expect(await value('.new-todo')).toBe('')
|
||||
|
||||
await enterValue('.new-todo', 'test2')
|
||||
expect(await count('.todo')).toBe(2)
|
||||
expect(await text('.todo:nth-child(2) label')).toBe('test2')
|
||||
expect(await text('.todo-count strong')).toBe('2')
|
||||
|
||||
// toggle
|
||||
await click('.todo .toggle')
|
||||
expect(await count('.todo.completed')).toBe(1)
|
||||
expect(await classList('.todo:nth-child(1)')).toContain('completed')
|
||||
expect(await text('.todo-count strong')).toBe('1')
|
||||
expect(await isVisible('.clear-completed')).toBe(true)
|
||||
|
||||
await enterValue('.new-todo', 'test3')
|
||||
expect(await count('.todo')).toBe(3)
|
||||
expect(await text('.todo:nth-child(3) label')).toBe('test3')
|
||||
expect(await text('.todo-count strong')).toBe('2')
|
||||
|
||||
await enterValue('.new-todo', 'test4')
|
||||
await enterValue('.new-todo', 'test5')
|
||||
expect(await count('.todo')).toBe(5)
|
||||
expect(await text('.todo-count strong')).toBe('4')
|
||||
|
||||
// toggle more
|
||||
await click('.todo:nth-child(4) .toggle')
|
||||
await click('.todo:nth-child(5) .toggle')
|
||||
expect(await count('.todo.completed')).toBe(3)
|
||||
expect(await text('.todo-count strong')).toBe('2')
|
||||
|
||||
// remove
|
||||
await removeItemAt(1)
|
||||
expect(await count('.todo')).toBe(4)
|
||||
expect(await count('.todo.completed')).toBe(2)
|
||||
expect(await text('.todo-count strong')).toBe('2')
|
||||
await removeItemAt(2)
|
||||
expect(await count('.todo')).toBe(3)
|
||||
expect(await count('.todo.completed')).toBe(2)
|
||||
expect(await text('.todo-count strong')).toBe('1')
|
||||
|
||||
// remove all
|
||||
await click('.clear-completed')
|
||||
expect(await count('.todo')).toBe(1)
|
||||
expect(await text('.todo label')).toBe('test2')
|
||||
expect(await count('.todo.completed')).toBe(0)
|
||||
expect(await text('.todo-count strong')).toBe('1')
|
||||
expect(await isVisible('.clear-completed')).toBe(false)
|
||||
|
||||
// prepare to test filters
|
||||
await enterValue('.new-todo', 'test')
|
||||
await enterValue('.new-todo', 'test')
|
||||
await click('.todo:nth-child(2) .toggle')
|
||||
await click('.todo:nth-child(3) .toggle')
|
||||
|
||||
// active filter
|
||||
await click('.filters li:nth-child(2) a')
|
||||
await timeout(1)
|
||||
expect(await count('.todo')).toBe(1)
|
||||
expect(await count('.todo.completed')).toBe(0)
|
||||
// add item with filter active
|
||||
await enterValue('.new-todo', 'test')
|
||||
expect(await count('.todo')).toBe(2)
|
||||
|
||||
// completed filter
|
||||
await click('.filters li:nth-child(3) a')
|
||||
await timeout(1)
|
||||
expect(await count('.todo')).toBe(2)
|
||||
expect(await count('.todo.completed')).toBe(2)
|
||||
|
||||
// filter on page load
|
||||
await page().goto(`${baseUrl}#active`)
|
||||
expect(await count('.todo')).toBe(2)
|
||||
expect(await count('.todo.completed')).toBe(0)
|
||||
expect(await text('.todo-count strong')).toBe('2')
|
||||
|
||||
// completed on page load
|
||||
await page().goto(`${baseUrl}#completed`)
|
||||
expect(await count('.todo')).toBe(2)
|
||||
expect(await count('.todo.completed')).toBe(2)
|
||||
expect(await text('.todo-count strong')).toBe('2')
|
||||
|
||||
// toggling with filter active
|
||||
await click('.todo .toggle')
|
||||
expect(await count('.todo')).toBe(1)
|
||||
await click('.filters li:nth-child(2) a')
|
||||
await timeout(1)
|
||||
expect(await count('.todo')).toBe(3)
|
||||
await click('.todo .toggle')
|
||||
expect(await count('.todo')).toBe(2)
|
||||
|
||||
// editing triggered by blur
|
||||
await click('.filters li:nth-child(1) a')
|
||||
await timeout(1)
|
||||
await click('.todo:nth-child(1) label', { clickCount: 2 })
|
||||
expect(await count('.todo.editing')).toBe(1)
|
||||
expect(await isFocused('.todo:nth-child(1) .edit')).toBe(true)
|
||||
await clearValue('.todo:nth-child(1) .edit')
|
||||
await page().type('.todo:nth-child(1) .edit', 'edited!')
|
||||
await click('.new-todo') // blur
|
||||
expect(await count('.todo.editing')).toBe(0)
|
||||
expect(await text('.todo:nth-child(1) label')).toBe('edited!')
|
||||
|
||||
// editing triggered by enter
|
||||
await click('.todo label', { clickCount: 2 })
|
||||
await enterValue('.todo:nth-child(1) .edit', 'edited again!')
|
||||
expect(await count('.todo.editing')).toBe(0)
|
||||
expect(await text('.todo:nth-child(1) label')).toBe('edited again!')
|
||||
|
||||
// cancel
|
||||
await click('.todo label', { clickCount: 2 })
|
||||
await clearValue('.todo:nth-child(1) .edit')
|
||||
await page().type('.todo:nth-child(1) .edit', 'edited!')
|
||||
await page().keyboard.press('Escape')
|
||||
expect(await count('.todo.editing')).toBe(0)
|
||||
expect(await text('.todo:nth-child(1) label')).toBe('edited again!')
|
||||
|
||||
// empty value should remove
|
||||
await click('.todo label', { clickCount: 2 })
|
||||
await enterValue('.todo:nth-child(1) .edit', ' ')
|
||||
expect(await count('.todo')).toBe(3)
|
||||
|
||||
// toggle all
|
||||
await click('.toggle-all+label')
|
||||
expect(await count('.todo.completed')).toBe(3)
|
||||
await click('.toggle-all+label')
|
||||
expect(await count('.todo:not(.completed)')).toBe(3)
|
||||
},
|
||||
E2E_TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
import path from 'node:path'
|
||||
import {
|
||||
E2E_TIMEOUT,
|
||||
setupPuppeteer,
|
||||
} from '../../../packages/vue/__tests__/e2e/e2eUtils'
|
||||
import connect from 'connect'
|
||||
import sirv from 'sirv'
|
||||
|
||||
describe('vdom / vapor interop', () => {
|
||||
const { page, click, text, enterValue } = setupPuppeteer()
|
||||
|
||||
let server: any
|
||||
const port = '8193'
|
||||
beforeAll(() => {
|
||||
server = connect()
|
||||
.use(sirv(path.resolve(import.meta.dirname, '../dist')))
|
||||
.listen(port)
|
||||
process.on('SIGTERM', () => server && server.close())
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
server.close()
|
||||
})
|
||||
|
||||
test(
|
||||
'should work',
|
||||
async () => {
|
||||
const baseUrl = `http://localhost:${port}/interop/`
|
||||
await page().goto(baseUrl)
|
||||
|
||||
expect(await text('.vapor > h2')).toContain('Vapor component in VDOM')
|
||||
|
||||
expect(await text('.vapor-prop')).toContain('hello')
|
||||
|
||||
const t = await text('.vdom-slot-in-vapor-default')
|
||||
expect(t).toContain('slot prop: slot prop')
|
||||
expect(t).toContain('component prop: hello')
|
||||
|
||||
await click('.change-vdom-slot-in-vapor-prop')
|
||||
expect(await text('.vdom-slot-in-vapor-default')).toContain(
|
||||
'slot prop: changed',
|
||||
)
|
||||
|
||||
expect(await text('.vdom-slot-in-vapor-test')).toContain('A test slot')
|
||||
|
||||
await click('.toggle-vdom-slot-in-vapor')
|
||||
expect(await text('.vdom-slot-in-vapor-test')).toContain(
|
||||
'fallback content',
|
||||
)
|
||||
|
||||
await click('.toggle-vdom-slot-in-vapor')
|
||||
expect(await text('.vdom-slot-in-vapor-test')).toContain('A test slot')
|
||||
|
||||
expect(await text('.vdom > h2')).toContain('VDOM component in Vapor')
|
||||
|
||||
expect(await text('.vdom-prop')).toContain('hello')
|
||||
|
||||
const tt = await text('.vapor-slot-in-vdom-default')
|
||||
expect(tt).toContain('slot prop: slot prop')
|
||||
expect(tt).toContain('component prop: hello')
|
||||
|
||||
await click('.change-vapor-slot-in-vdom-prop')
|
||||
expect(await text('.vapor-slot-in-vdom-default')).toContain(
|
||||
'slot prop: changed',
|
||||
)
|
||||
|
||||
expect(await text('.vapor-slot-in-vdom-test')).toContain('fallback')
|
||||
|
||||
await click('.toggle-vapor-slot-in-vdom-default')
|
||||
expect(await text('.vapor-slot-in-vdom-default')).toContain(
|
||||
'default slot fallback',
|
||||
)
|
||||
|
||||
await click('.toggle-vapor-slot-in-vdom-default')
|
||||
|
||||
await enterValue('input', 'bye')
|
||||
expect(await text('.vapor-prop')).toContain('bye')
|
||||
expect(await text('.vdom-slot-in-vapor-default')).toContain('bye')
|
||||
expect(await text('.vdom-prop')).toContain('bye')
|
||||
expect(await text('.vapor-slot-in-vdom-default')).toContain('bye')
|
||||
},
|
||||
E2E_TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
<a href="/interop/">VDOM / Vapor interop</a>
|
||||
<a href="/todomvc/">Vapor TodoMVC</a>
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import VaporComp from './VaporComp.vue'
|
||||
|
||||
const msg = ref('hello')
|
||||
const passSlot = ref(true)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<input v-model="msg" />
|
||||
<button class="toggle-vdom-slot-in-vapor" @click="passSlot = !passSlot">
|
||||
toggle #test slot
|
||||
</button>
|
||||
<VaporComp :msg="msg">
|
||||
<template #default="{ foo }">
|
||||
<div>slot prop: {{ foo }}</div>
|
||||
<div>component prop: {{ msg }}</div>
|
||||
</template>
|
||||
|
||||
<template #test v-if="passSlot">A test slot</template>
|
||||
</VaporComp>
|
||||
</template>
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
<script setup vapor lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import VdomComp from './VdomComp.vue'
|
||||
|
||||
defineProps<{
|
||||
msg: string
|
||||
}>()
|
||||
|
||||
const ok = ref(true)
|
||||
const passSlot = ref(true)
|
||||
const slotProp = ref('slot prop')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="vapor" style="border: 2px solid red; padding: 10px">
|
||||
<h2>This is a Vapor component in VDOM</h2>
|
||||
<p class="vapor-prop">props.msg: {{ msg }}</p>
|
||||
|
||||
<button @click="ok = !ok">Toggle slots</button>
|
||||
|
||||
<div v-if="ok" style="border: 2px solid orange; padding: 10px">
|
||||
<h3>vdom slots in vapor component</h3>
|
||||
<button
|
||||
class="change-vdom-slot-in-vapor-prop"
|
||||
@click="slotProp = 'changed'"
|
||||
>
|
||||
change slot prop
|
||||
</button>
|
||||
<div class="vdom-slot-in-vapor-default">
|
||||
#default: <slot :foo="slotProp" />
|
||||
</div>
|
||||
<div class="vdom-slot-in-vapor-test">
|
||||
#test: <slot name="test">fallback content</slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="toggle-vapor-slot-in-vdom-default"
|
||||
@click="passSlot = !passSlot"
|
||||
>
|
||||
Toggle default slot to vdom
|
||||
</button>
|
||||
<VdomComp :msg="msg">
|
||||
<template #default="{ foo }" v-if="passSlot">
|
||||
<div>slot prop: {{ foo }}</div>
|
||||
<div>component prop: {{ msg }}</div>
|
||||
</template>
|
||||
</VdomComp>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
defineProps<{
|
||||
msg: string
|
||||
}>()
|
||||
|
||||
const bar = ref('slot prop')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="vdom" style="border: 2px solid blue; padding: 10px">
|
||||
<h2>This is a VDOM component in Vapor</h2>
|
||||
<p class="vdom-prop">props.msg: {{ msg }}</p>
|
||||
<div style="border: 2px solid aquamarine; padding: 10px">
|
||||
<h3>vapor slots in vdom</h3>
|
||||
<button class="change-vapor-slot-in-vdom-prop" @click="bar = 'changed'">
|
||||
Change slot prop
|
||||
</button>
|
||||
<div class="vapor-slot-in-vdom-default">
|
||||
#default: <slot :foo="bar">default slot fallback</slot>
|
||||
</div>
|
||||
<div class="vapor-slot-in-vdom-test">
|
||||
#test <slot name="test">fallback</slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
<script type="module" src="./main.ts"></script>
|
||||
<div id="app"></div>
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import { createApp, vaporInteropPlugin } from 'vue'
|
||||
import App from './App.vue'
|
||||
|
||||
createApp(App).use(vaporInteropPlugin).mount('#app')
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"name": "vapor-e2e-test",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/connect": "^3.4.38",
|
||||
"@vitejs/plugin-vue": "catalog:",
|
||||
"connect": "^3.7.0",
|
||||
"sirv": "^2.0.4",
|
||||
"vite": "catalog:",
|
||||
"vue": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,228 +0,0 @@
|
|||
<script setup vapor>
|
||||
import {
|
||||
reactive,
|
||||
computed,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
watchPostEffect,
|
||||
} from 'vue'
|
||||
|
||||
const STORAGE_KEY = 'todos-vuejs-3.x'
|
||||
|
||||
const todoStorage = {
|
||||
fetch() {
|
||||
const todos = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]')
|
||||
todos.forEach((todo, index) => {
|
||||
todo.id = index
|
||||
})
|
||||
todoStorage.uid = todos.length
|
||||
return todos
|
||||
},
|
||||
save(todos) {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(todos))
|
||||
},
|
||||
}
|
||||
|
||||
const filters = {
|
||||
all(todos) {
|
||||
return todos
|
||||
},
|
||||
active(todos) {
|
||||
return todos.filter(todo => {
|
||||
return !todo.completed
|
||||
})
|
||||
},
|
||||
completed(todos) {
|
||||
return todos.filter(function (todo) {
|
||||
return todo.completed
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
function pluralize(n) {
|
||||
return n === 1 ? 'item' : 'items'
|
||||
}
|
||||
|
||||
const state = reactive({
|
||||
todos: todoStorage.fetch(),
|
||||
editedTodo: null,
|
||||
newTodo: '',
|
||||
beforeEditCache: '',
|
||||
visibility: 'all',
|
||||
remaining: computed(() => {
|
||||
return filters.active(state.todos).length
|
||||
}),
|
||||
remainingText: computed(() => {
|
||||
return ` ${pluralize(state.remaining)} left`
|
||||
}),
|
||||
filteredTodos: computed(() => {
|
||||
return filters[state.visibility](state.todos)
|
||||
}),
|
||||
allDone: computed({
|
||||
get: function () {
|
||||
return state.remaining === 0
|
||||
},
|
||||
set: function (value) {
|
||||
state.todos.forEach(todo => {
|
||||
todo.completed = value
|
||||
})
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
watchPostEffect(() => {
|
||||
todoStorage.save(state.todos)
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('hashchange', onHashChange)
|
||||
onHashChange()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('hashchange', onHashChange)
|
||||
})
|
||||
|
||||
function onHashChange() {
|
||||
const visibility = window.location.hash.replace(/#\/?/, '')
|
||||
if (filters[visibility]) {
|
||||
state.visibility = visibility
|
||||
} else {
|
||||
window.location.hash = ''
|
||||
state.visibility = 'all'
|
||||
}
|
||||
}
|
||||
|
||||
function addTodo() {
|
||||
const value = state.newTodo && state.newTodo.trim()
|
||||
if (!value) {
|
||||
return
|
||||
}
|
||||
state.todos.push({
|
||||
id: todoStorage.uid++,
|
||||
title: value,
|
||||
completed: false,
|
||||
})
|
||||
state.newTodo = ''
|
||||
}
|
||||
|
||||
function removeTodo(todo) {
|
||||
state.todos.splice(state.todos.indexOf(todo), 1)
|
||||
}
|
||||
|
||||
function editTodo(todo) {
|
||||
state.beforeEditCache = todo.title
|
||||
state.editedTodo = todo
|
||||
}
|
||||
|
||||
function doneEdit(todo) {
|
||||
if (!state.editedTodo) {
|
||||
return
|
||||
}
|
||||
state.editedTodo = null
|
||||
todo.title = todo.title.trim()
|
||||
if (!todo.title) {
|
||||
removeTodo(todo)
|
||||
}
|
||||
}
|
||||
|
||||
function cancelEdit(todo) {
|
||||
state.editedTodo = null
|
||||
todo.title = state.beforeEditCache
|
||||
}
|
||||
|
||||
function removeCompleted() {
|
||||
state.todos = filters.active(state.todos)
|
||||
}
|
||||
|
||||
// vapor custom directive
|
||||
const vTodoFocus = (el, value) => {
|
||||
watchPostEffect(() => value() && el.focus())
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="todoapp">
|
||||
<header class="header">
|
||||
<h1>todos</h1>
|
||||
<input
|
||||
class="new-todo"
|
||||
autofocus
|
||||
autocomplete="off"
|
||||
placeholder="What needs to be done?"
|
||||
v-model="state.newTodo"
|
||||
@keyup.enter="addTodo"
|
||||
/>
|
||||
</header>
|
||||
<section class="main" v-show="state.todos.length">
|
||||
<input
|
||||
id="toggle-all"
|
||||
class="toggle-all"
|
||||
type="checkbox"
|
||||
v-model="state.allDone"
|
||||
/>
|
||||
<label for="toggle-all">Mark all as complete</label>
|
||||
<ul class="todo-list">
|
||||
<li
|
||||
v-for="todo in state.filteredTodos"
|
||||
class="todo"
|
||||
:key="todo.id"
|
||||
:class="{
|
||||
completed: todo.completed,
|
||||
editing: todo === state.editedTodo,
|
||||
}"
|
||||
>
|
||||
<div class="view">
|
||||
<input class="toggle" type="checkbox" v-model="todo.completed" />
|
||||
<label @dblclick="editTodo(todo)">{{ todo.title }}</label>
|
||||
<button class="destroy" @click="removeTodo(todo)"></button>
|
||||
</div>
|
||||
<input
|
||||
class="edit"
|
||||
type="text"
|
||||
v-model="todo.title"
|
||||
v-todo-focus="todo === state.editedTodo"
|
||||
@blur="doneEdit(todo)"
|
||||
@keyup.enter="doneEdit(todo)"
|
||||
@keyup.escape="cancelEdit(todo)"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
<footer class="footer" v-show="state.todos.length">
|
||||
<span class="todo-count">
|
||||
<strong>{{ state.remaining }}</strong>
|
||||
<span>{{ state.remainingText }}</span>
|
||||
</span>
|
||||
<ul class="filters">
|
||||
<li>
|
||||
<a href="#/all" :class="{ selected: state.visibility === 'all' }"
|
||||
>All</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#/active"
|
||||
:class="{ selected: state.visibility === 'active' }"
|
||||
>Active</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#/completed"
|
||||
:class="{ selected: state.visibility === 'completed' }"
|
||||
>Completed</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<button
|
||||
class="clear-completed"
|
||||
@click="removeCompleted"
|
||||
v-show="state.todos.length > state.remaining"
|
||||
>
|
||||
Clear completed
|
||||
</button>
|
||||
</footer>
|
||||
</section>
|
||||
</template>
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
<script type="module" src="./main.ts"></script>
|
||||
<div id="app"></div>
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
import { createVaporApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import 'todomvc-app-css/index.css'
|
||||
|
||||
createVaporApp(App).mount('#app')
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
import { defineConfig } from 'vite'
|
||||
import Vue from '@vitejs/plugin-vue'
|
||||
import * as CompilerSFC from 'vue/compiler-sfc'
|
||||
import { resolve } from 'node:path'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
Vue({
|
||||
compiler: CompilerSFC,
|
||||
}),
|
||||
],
|
||||
build: {
|
||||
rollupOptions: {
|
||||
input: {
|
||||
interop: resolve(import.meta.dirname, 'interop/index.html'),
|
||||
todomvc: resolve(import.meta.dirname, 'todomvc/index.html'),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
@ -7,9 +7,9 @@ return function render(_ctx, _cache) {
|
|||
with (_ctx) {
|
||||
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 /* CACHED */)
|
||||
])))
|
||||
]))]))
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
|
@ -21,7 +21,7 @@ return function render(_ctx, _cache) {
|
|||
with (_ctx) {
|
||||
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("span"),
|
||||
_createElementVNode("span")
|
||||
|
|
@ -30,7 +30,7 @@ return function render(_ctx, _cache) {
|
|||
_createElementVNode("span"),
|
||||
_createElementVNode("span")
|
||||
], -1 /* CACHED */)
|
||||
])))
|
||||
]))]))
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
|
@ -42,11 +42,11 @@ return function render(_ctx, _cache) {
|
|||
with (_ctx) {
|
||||
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, [
|
||||
_createCommentVNode("comment")
|
||||
], -1 /* CACHED */)
|
||||
])))
|
||||
]))]))
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
|
@ -58,11 +58,11 @@ return function render(_ctx, _cache) {
|
|||
with (_ctx) {
|
||||
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 /* CACHED */),
|
||||
_createTextVNode("foo"),
|
||||
_createTextVNode("foo", -1 /* CACHED */),
|
||||
_createElementVNode("div", null, null, -1 /* CACHED */)
|
||||
])))
|
||||
]))]))
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
|
@ -74,9 +74,9 @@ return function render(_ctx, _cache) {
|
|||
with (_ctx) {
|
||||
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 /* CACHED */)
|
||||
])))
|
||||
]))]))
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
|
@ -147,9 +147,9 @@ return function render(_ctx, _cache) {
|
|||
with (_ctx) {
|
||||
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 /* CACHED */)
|
||||
])))
|
||||
]))]))
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
|
@ -161,9 +161,9 @@ return function render(_ctx, _cache) {
|
|||
with (_ctx) {
|
||||
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 /* CACHED */)
|
||||
])))
|
||||
]))]))
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
|
@ -215,9 +215,9 @@ return function render(_ctx, _cache) {
|
|||
const _directive_foo = _resolveDirective("foo")
|
||||
|
||||
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 /* CACHED */)
|
||||
]))), [
|
||||
]))])), [
|
||||
[_directive_foo]
|
||||
])
|
||||
]))
|
||||
|
|
@ -401,9 +401,9 @@ return function render(_ctx, _cache) {
|
|||
|
||||
return (_openBlock(), _createElementBlock("div", null, [
|
||||
ok
|
||||
? (_openBlock(), _createElementBlock("div", _hoisted_1, _cache[0] || (_cache[0] = [
|
||||
? (_openBlock(), _createElementBlock("div", _hoisted_1, [...(_cache[0] || (_cache[0] = [
|
||||
_createElementVNode("span", null, null, -1 /* CACHED */)
|
||||
])))
|
||||
]))]))
|
||||
: _createCommentVNode("v-if", true)
|
||||
]))
|
||||
}
|
||||
|
|
@ -422,7 +422,7 @@ return function render(_ctx, _cache) {
|
|||
|
||||
return (_openBlock(), _createElementBlock(_Fragment, null, [
|
||||
_createCommentVNode("comment"),
|
||||
_createElementVNode("div", _hoisted_1, _cache[0] || (_cache[0] = [
|
||||
_createElementVNode("div", _hoisted_1, [...(_cache[0] || (_cache[0] = [
|
||||
_createElementVNode("div", { id: "b" }, [
|
||||
_createElementVNode("div", { id: "c" }, [
|
||||
_createElementVNode("div", { id: "d" }, [
|
||||
|
|
@ -430,7 +430,7 @@ return function render(_ctx, _cache) {
|
|||
])
|
||||
])
|
||||
], -1 /* CACHED */)
|
||||
]))
|
||||
]))])
|
||||
], 2112 /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */))
|
||||
}
|
||||
}"
|
||||
|
|
@ -448,9 +448,9 @@ return function render(_ctx, _cache) {
|
|||
|
||||
return (_openBlock(), _createElementBlock("div", null, [
|
||||
(_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 /* CACHED */)
|
||||
])))
|
||||
]))]))
|
||||
}), 256 /* UNKEYED_FRAGMENT */))
|
||||
]))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import { PatchFlags } from '@vue/shared'
|
|||
|
||||
const cachedChildrenArrayMatcher = (
|
||||
tags: string[],
|
||||
needArraySpread = false,
|
||||
needArraySpread = true,
|
||||
) => ({
|
||||
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||
needArraySpread,
|
||||
|
|
@ -170,11 +170,6 @@ describe('compiler: cacheStatic transform', () => {
|
|||
{
|
||||
/* _ slot flag */
|
||||
},
|
||||
{
|
||||
type: NodeTypes.JS_PROPERTY,
|
||||
key: { content: '__' },
|
||||
value: { content: '[0]' },
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
|
|
@ -202,11 +197,6 @@ describe('compiler: cacheStatic transform', () => {
|
|||
{
|
||||
/* _ slot flag */
|
||||
},
|
||||
{
|
||||
type: NodeTypes.JS_PROPERTY,
|
||||
key: { content: '__' },
|
||||
value: { content: '[0]' },
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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`)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import {
|
|||
helperNameMap,
|
||||
} from '../../src/runtimeHelpers'
|
||||
import { transformExpression } from '../../src/transforms/transformExpression'
|
||||
import { transformVBindShorthand } from '../../src/transforms/transformVBindShorthand'
|
||||
|
||||
function parseWithVBind(
|
||||
template: string,
|
||||
|
|
@ -25,6 +26,7 @@ function parseWithVBind(
|
|||
const ast = parse(template)
|
||||
transform(ast, {
|
||||
nodeTransforms: [
|
||||
transformVBindShorthand,
|
||||
...(options.prefixIdentifiers ? [transformExpression] : []),
|
||||
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', () => {
|
||||
const node = parseWithVBind(`<div v-bind:[id]="id"/>`)
|
||||
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 { PatchFlags } from '@vue/shared'
|
||||
import { createObjectMatcher } from '../testUtils'
|
||||
import { transformVBindShorthand } from '../../src/transforms/transformVBindShorthand'
|
||||
|
||||
export function parseWithForTransform(
|
||||
template: string,
|
||||
|
|
@ -32,6 +33,7 @@ export function parseWithForTransform(
|
|||
const ast = parse(template, options)
|
||||
transform(ast, {
|
||||
nodeTransforms: [
|
||||
transformVBindShorthand,
|
||||
transformIf,
|
||||
transformFor,
|
||||
...(options.prefixIdentifiers ? [transformExpression] : []),
|
||||
|
|
|
|||
|
|
@ -17,7 +17,12 @@ import {
|
|||
type VNodeCall,
|
||||
} from '../../src/ast'
|
||||
import { ErrorCodes } from '../../src/errors'
|
||||
import { type CompilerOptions, TO_HANDLERS, generate } from '../../src'
|
||||
import {
|
||||
type CompilerOptions,
|
||||
TO_HANDLERS,
|
||||
generate,
|
||||
transformVBindShorthand,
|
||||
} from '../../src'
|
||||
import {
|
||||
CREATE_COMMENT,
|
||||
FRAGMENT,
|
||||
|
|
@ -35,7 +40,12 @@ function parseWithIfTransform(
|
|||
) {
|
||||
const ast = parse(template, options)
|
||||
transform(ast, {
|
||||
nodeTransforms: [transformIf, transformSlotOutlet, transformElement],
|
||||
nodeTransforms: [
|
||||
transformVBindShorthand,
|
||||
transformIf,
|
||||
transformSlotOutlet,
|
||||
transformElement,
|
||||
],
|
||||
...options,
|
||||
})
|
||||
if (!options.onError) {
|
||||
|
|
@ -209,6 +219,16 @@ describe('compiler: v-if', () => {
|
|||
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', () => {
|
||||
|
|
@ -301,6 +321,25 @@ describe('compiler: v-if', () => {
|
|||
])
|
||||
})
|
||||
|
||||
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,
|
||||
loc: branches[branches.length - 1].loc,
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
test('error on user key', () => {
|
||||
const onError = vi.fn()
|
||||
// dynamic
|
||||
|
|
|
|||
|
|
@ -478,7 +478,10 @@ describe('compiler: transform component slots', () => {
|
|||
})
|
||||
|
||||
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 })
|
||||
let flag: any
|
||||
if (root.children[0].type === NodeTypes.FOR) {
|
||||
|
|
@ -491,8 +494,8 @@ describe('compiler: transform component slots', () => {
|
|||
.children[0] as ComponentNode
|
||||
flag = (innerComp.codegenNode as VNodeCall).patchFlag
|
||||
}
|
||||
if (shouldForce) {
|
||||
expect(flag).toBe(PatchFlags.DYNAMIC_SLOTS)
|
||||
if (expectedPatchFlag) {
|
||||
expect(flag).toBe(expectedPatchFlag)
|
||||
} else {
|
||||
expect(flag).toBeUndefined()
|
||||
}
|
||||
|
|
@ -502,14 +505,13 @@ describe('compiler: transform component slots', () => {
|
|||
`<div v-for="i in list">
|
||||
<Comp v-slot="bar">foo</Comp>
|
||||
</div>`,
|
||||
false,
|
||||
)
|
||||
|
||||
assertDynamicSlots(
|
||||
`<div v-for="i in list">
|
||||
<Comp v-slot="bar">{{ i }}</Comp>
|
||||
</div>`,
|
||||
true,
|
||||
PatchFlags.DYNAMIC_SLOTS,
|
||||
)
|
||||
|
||||
// reference the component's own slot variable should not force dynamic slots
|
||||
|
|
@ -517,14 +519,13 @@ describe('compiler: transform component slots', () => {
|
|||
`<Comp v-slot="foo">
|
||||
<Comp v-slot="bar">{{ bar }}</Comp>
|
||||
</Comp>`,
|
||||
false,
|
||||
)
|
||||
|
||||
assertDynamicSlots(
|
||||
`<Comp v-slot="foo">
|
||||
<Comp v-slot="bar">{{ foo }}</Comp>
|
||||
</Comp>`,
|
||||
true,
|
||||
PatchFlags.DYNAMIC_SLOTS,
|
||||
)
|
||||
|
||||
// #2564
|
||||
|
|
@ -532,14 +533,35 @@ describe('compiler: transform component slots', () => {
|
|||
`<div v-for="i in list">
|
||||
<Comp v-slot="bar"><button @click="fn(i)" /></Comp>
|
||||
</div>`,
|
||||
true,
|
||||
PatchFlags.DYNAMIC_SLOTS,
|
||||
)
|
||||
|
||||
assertDynamicSlots(
|
||||
`<div v-for="i in list">
|
||||
<Comp v-slot="bar"><button @click="fn()" /></Comp>
|
||||
</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,
|
||||
)
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
advancePositionWithClone,
|
||||
|
|
@ -115,3 +120,18 @@ test('toValidAssetId', () => {
|
|||
'_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",
|
||||
"version": "3.6.0-alpha.1",
|
||||
"version": "3.5.24",
|
||||
"description": "@vue/compiler-core",
|
||||
"main": "index.js",
|
||||
"module": "dist/compiler-core.esm-bundler.js",
|
||||
|
|
|
|||
|
|
@ -86,13 +86,6 @@ export interface Position {
|
|||
column: number
|
||||
}
|
||||
|
||||
export type AllNode =
|
||||
| ParentNode
|
||||
| ExpressionNode
|
||||
| TemplateChildNode
|
||||
| AttributeNode
|
||||
| DirectiveNode
|
||||
|
||||
export type ParentNode = RootNode | ElementNode | IfBranchNode | ForNode
|
||||
|
||||
export type ExpressionNode = SimpleExpressionNode | CompoundExpressionNode
|
||||
|
|
|
|||
|
|
@ -10,9 +10,10 @@ import type {
|
|||
Node,
|
||||
ObjectProperty,
|
||||
Program,
|
||||
SwitchCase,
|
||||
SwitchStatement,
|
||||
} from '@babel/types'
|
||||
import { walk } from 'estree-walker'
|
||||
import { type BindingMetadata, BindingTypes } from './options'
|
||||
|
||||
/**
|
||||
* Return value indicates whether the AST walked can be a constant
|
||||
|
|
@ -81,14 +82,31 @@ export function walkIdentifiers(
|
|||
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) {
|
||||
for (const id of extractIdentifiers(node.param)) {
|
||||
markScopeIdentifier(node, id, knownIds)
|
||||
if (node.scopeIds) {
|
||||
node.scopeIds.forEach(id => markKnownIds(id, knownIds))
|
||||
} else {
|
||||
for (const id of extractIdentifiers(node.param)) {
|
||||
markScopeIdentifier(node, id, knownIds)
|
||||
}
|
||||
}
|
||||
} else if (isForStatement(node)) {
|
||||
walkForStatement(node, false, id =>
|
||||
markScopeIdentifier(node, id, knownIds),
|
||||
)
|
||||
if (node.scopeIds) {
|
||||
node.scopeIds.forEach(id => markKnownIds(id, knownIds))
|
||||
} else {
|
||||
walkForStatement(node, false, id =>
|
||||
markScopeIdentifier(node, id, knownIds),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
leave(node: Node & { scopeIds?: Set<string> }, parent: Node | null) {
|
||||
|
|
@ -123,7 +141,7 @@ export function isReferencedIdentifier(
|
|||
return false
|
||||
}
|
||||
|
||||
if (isReferenced(id, parent)) {
|
||||
if (isReferenced(id, parent, parentStack[parentStack.length - 2])) {
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -133,7 +151,8 @@ export function isReferencedIdentifier(
|
|||
case 'AssignmentExpression':
|
||||
case 'AssignmentPattern':
|
||||
return true
|
||||
case 'ObjectPattern':
|
||||
case 'ObjectProperty':
|
||||
return parent.key !== id && isInDestructureAssignment(parent, parentStack)
|
||||
case 'ArrayPattern':
|
||||
return isInDestructureAssignment(parent, parentStack)
|
||||
}
|
||||
|
|
@ -187,10 +206,11 @@ export function walkFunctionParams(
|
|||
}
|
||||
|
||||
export function walkBlockDeclarations(
|
||||
block: BlockStatement | Program,
|
||||
block: BlockStatement | SwitchCase | Program,
|
||||
onIdent: (node: Identifier) => 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.declare) continue
|
||||
for (const decl of stmt.declarations) {
|
||||
|
|
@ -206,6 +226,8 @@ export function walkBlockDeclarations(
|
|||
onIdent(stmt.id)
|
||||
} else if (isForStatement(stmt)) {
|
||||
walkForStatement(stmt, true, onIdent)
|
||||
} else if (stmt.type === 'SwitchStatement') {
|
||||
walkSwitchStatement(stmt, true, onIdent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -239,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(
|
||||
param: Node,
|
||||
nodes: Identifier[] = [],
|
||||
|
|
@ -309,8 +353,8 @@ export const isFunctionType = (node: Node): node is Function => {
|
|||
return /Function(?:Expression|Declaration)$|Method$/.test(node.type)
|
||||
}
|
||||
|
||||
export const isStaticProperty = (node?: Node): node is ObjectProperty =>
|
||||
!!node &&
|
||||
export const isStaticProperty = (node: Node): node is ObjectProperty =>
|
||||
node &&
|
||||
(node.type === 'ObjectProperty' || node.type === 'ObjectMethod') &&
|
||||
!node.computed
|
||||
|
||||
|
|
@ -511,77 +555,3 @@ export function unwrapTSNode(node: Node): Node {
|
|||
return node
|
||||
}
|
||||
}
|
||||
|
||||
export function isStaticNode(node: Node): boolean {
|
||||
node = unwrapTSNode(node)
|
||||
|
||||
switch (node.type) {
|
||||
case 'UnaryExpression': // void 0, !true
|
||||
return isStaticNode(node.argument)
|
||||
|
||||
case 'LogicalExpression': // 1 > 2
|
||||
case 'BinaryExpression': // 1 + 2
|
||||
return isStaticNode(node.left) && isStaticNode(node.right)
|
||||
|
||||
case 'ConditionalExpression': {
|
||||
// 1 ? 2 : 3
|
||||
return (
|
||||
isStaticNode(node.test) &&
|
||||
isStaticNode(node.consequent) &&
|
||||
isStaticNode(node.alternate)
|
||||
)
|
||||
}
|
||||
|
||||
case 'SequenceExpression': // (1, 2)
|
||||
case 'TemplateLiteral': // `foo${1}`
|
||||
return node.expressions.every(expr => isStaticNode(expr))
|
||||
|
||||
case 'ParenthesizedExpression': // (1)
|
||||
return isStaticNode(node.expression)
|
||||
|
||||
case 'StringLiteral':
|
||||
case 'NumericLiteral':
|
||||
case 'BooleanLiteral':
|
||||
case 'NullLiteral':
|
||||
case 'BigIntLiteral':
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
export function isConstantNode(node: Node, bindings: BindingMetadata): boolean {
|
||||
if (isStaticNode(node)) return true
|
||||
|
||||
node = unwrapTSNode(node)
|
||||
switch (node.type) {
|
||||
case 'Identifier':
|
||||
const type = bindings[node.name]
|
||||
return type === BindingTypes.LITERAL_CONST
|
||||
case 'RegExpLiteral':
|
||||
return true
|
||||
case 'ObjectExpression':
|
||||
return node.properties.every(prop => {
|
||||
// { bar() {} } object methods are not considered static nodes
|
||||
if (prop.type === 'ObjectMethod') return false
|
||||
// { ...{ foo: 1 } }
|
||||
if (prop.type === 'SpreadElement')
|
||||
return isConstantNode(prop.argument, bindings)
|
||||
// { foo: 1 }
|
||||
return (
|
||||
(!prop.computed || isConstantNode(prop.key, bindings)) &&
|
||||
isConstantNode(prop.value, bindings)
|
||||
)
|
||||
})
|
||||
case 'ArrayExpression':
|
||||
return node.elements.every(element => {
|
||||
// [1, , 3]
|
||||
if (element === null) return true
|
||||
// [1, ...[2, 3]]
|
||||
if (element.type === 'SpreadElement')
|
||||
return isConstantNode(element.argument, bindings)
|
||||
// [1, 2]
|
||||
return isConstantNode(element, bindings)
|
||||
})
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,38 +105,22 @@ const aliasHelper = (s: symbol) => `${helperNameMap[s]}: _${helperNameMap[s]}`
|
|||
|
||||
type CodegenNode = TemplateChildNode | JSChildNode | SSRCodegenNode
|
||||
|
||||
export interface BaseCodegenResult {
|
||||
export interface CodegenResult {
|
||||
code: string
|
||||
preamble: string
|
||||
ast: unknown
|
||||
map?: RawSourceMap
|
||||
helpers?: Set<string> | Set<symbol>
|
||||
}
|
||||
|
||||
export interface CodegenResult extends BaseCodegenResult {
|
||||
ast: RootNode
|
||||
helpers: Set<symbol>
|
||||
map?: RawSourceMap
|
||||
}
|
||||
|
||||
export enum NewlineType {
|
||||
/** Start with `\n` */
|
||||
enum NewlineType {
|
||||
Start = 0,
|
||||
/** Ends with `\n` */
|
||||
End = -1,
|
||||
/** No `\n` included */
|
||||
None = -2,
|
||||
/** Don't know, calc it */
|
||||
Unknown = -3,
|
||||
}
|
||||
|
||||
export interface CodegenContext
|
||||
extends Omit<
|
||||
Required<CodegenOptions>,
|
||||
| 'bindingMetadata'
|
||||
| 'inline'
|
||||
| 'vaporRuntimeModuleName'
|
||||
| 'expressionPlugins'
|
||||
> {
|
||||
extends Omit<Required<CodegenOptions>, 'bindingMetadata' | 'inline'> {
|
||||
source: string
|
||||
code: string
|
||||
line: number
|
||||
|
|
@ -416,7 +400,6 @@ export function generate(
|
|||
code: context.code,
|
||||
preamble: isSetupInlined ? preambleContext.code : ``,
|
||||
map: context.map ? context.map.toJSON() : undefined,
|
||||
helpers: ast.helpers,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import { transformModel } from './transforms/vModel'
|
|||
import { transformFilter } from './compat/transformFilter'
|
||||
import { ErrorCodes, createCompilerError, defaultOnError } from './errors'
|
||||
import { transformMemo } from './transforms/vMemo'
|
||||
import { transformVBindShorthand } from './transforms/transformVBindShorthand'
|
||||
|
||||
export type TransformPreset = [
|
||||
NodeTransform[],
|
||||
|
|
@ -33,6 +34,7 @@ export function getBaseTransformPreset(
|
|||
): TransformPreset {
|
||||
return [
|
||||
[
|
||||
transformVBindShorthand,
|
||||
transformOnce,
|
||||
transformIf,
|
||||
transformMemo,
|
||||
|
|
|
|||
|
|
@ -17,26 +17,21 @@ export {
|
|||
createTransformContext,
|
||||
traverseNode,
|
||||
createStructuralDirectiveTransform,
|
||||
getSelfName,
|
||||
type NodeTransform,
|
||||
type StructuralDirectiveTransform,
|
||||
type DirectiveTransform,
|
||||
} from './transform'
|
||||
export {
|
||||
generate,
|
||||
NewlineType,
|
||||
type CodegenContext,
|
||||
type CodegenResult,
|
||||
type CodegenSourceMapGenerator,
|
||||
type RawSourceMap,
|
||||
type BaseCodegenResult,
|
||||
} from './codegen'
|
||||
export {
|
||||
ErrorCodes,
|
||||
errorMessages,
|
||||
createCompilerError,
|
||||
defaultOnError,
|
||||
defaultOnWarn,
|
||||
type CoreCompilerError,
|
||||
type CompilerError,
|
||||
} from './errors'
|
||||
|
|
@ -57,7 +52,6 @@ export {
|
|||
transformExpression,
|
||||
processExpression,
|
||||
stringifyExpression,
|
||||
isLiteralWhitelisted,
|
||||
} from './transforms/transformExpression'
|
||||
export {
|
||||
buildSlots,
|
||||
|
|
@ -72,6 +66,7 @@ export {
|
|||
buildDirectiveArgs,
|
||||
type PropsExpression,
|
||||
} from './transforms/transformElement'
|
||||
export { transformVBindShorthand } from './transforms/transformVBindShorthand'
|
||||
export { processSlotOutlet } from './transforms/transformSlotOutlet'
|
||||
export { getConstantType } from './transforms/cacheStatic'
|
||||
export { generateCodeFrame } from '@vue/shared'
|
||||
|
|
@ -81,5 +76,4 @@ export {
|
|||
checkCompatEnabled,
|
||||
warnDeprecation,
|
||||
CompilerDeprecationTypes,
|
||||
type CompilerCompatOptions,
|
||||
} from './compat/compatConfig'
|
||||
|
|
|
|||
|
|
@ -174,12 +174,6 @@ interface SharedTransformCodegenOptions {
|
|||
* @default mode === 'module'
|
||||
*/
|
||||
prefixIdentifiers?: boolean
|
||||
/**
|
||||
* A list of parser plugins to enable for `@babel/parser`, which is used to
|
||||
* parse expressions in bindings and interpolations.
|
||||
* https://babeljs.io/docs/en/next/babel-parser#plugins
|
||||
*/
|
||||
expressionPlugins?: ParserPlugin[]
|
||||
/**
|
||||
* Control whether generate SSR-optimized render functions instead.
|
||||
* The resulting function must be attached to the component via the
|
||||
|
|
@ -278,6 +272,12 @@ export interface TransformOptions
|
|||
* @default false
|
||||
*/
|
||||
cacheHandlers?: boolean
|
||||
/**
|
||||
* A list of parser plugins to enable for `@babel/parser`, which is used to
|
||||
* parse expressions in bindings and interpolations.
|
||||
* https://babeljs.io/docs/en/next/babel-parser#plugins
|
||||
*/
|
||||
expressionPlugins?: ParserPlugin[]
|
||||
/**
|
||||
* SFC scoped styles ID
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ import {
|
|||
isCoreComponent,
|
||||
isSimpleIdentifier,
|
||||
isStaticArgOf,
|
||||
isVPre,
|
||||
} from './utils'
|
||||
import { decodeHTML } from 'entities/lib/decode.js'
|
||||
import {
|
||||
|
|
@ -246,7 +247,7 @@ const tokenizer = new Tokenizer(stack, {
|
|||
ondirarg(start, end) {
|
||||
if (start === end) return
|
||||
const arg = getSlice(start, end)
|
||||
if (inVPre) {
|
||||
if (inVPre && !isVPre(currentProp!)) {
|
||||
;(currentProp as AttributeNode).name += arg
|
||||
setLocEnd((currentProp as AttributeNode).nameLoc, end)
|
||||
} else {
|
||||
|
|
@ -262,7 +263,7 @@ const tokenizer = new Tokenizer(stack, {
|
|||
|
||||
ondirmodifier(start, end) {
|
||||
const mod = getSlice(start, end)
|
||||
if (inVPre) {
|
||||
if (inVPre && !isVPre(currentProp!)) {
|
||||
;(currentProp as AttributeNode).name += '.' + mod
|
||||
setLocEnd((currentProp as AttributeNode).nameLoc, end)
|
||||
} else if ((currentProp as DirectiveNode).name === 'slot') {
|
||||
|
|
@ -1053,7 +1054,7 @@ export function baseParse(input: string, options?: ParserOptions): RootNode {
|
|||
`[@vue/compiler-core] decodeEntities option is passed but will be ` +
|
||||
`ignored in non-browser builds.`,
|
||||
)
|
||||
} else if (__BROWSER__ && !currentOptions.decodeEntities) {
|
||||
} else if (__BROWSER__ && !__TEST__ && !currentOptions.decodeEntities) {
|
||||
throw new Error(
|
||||
`[@vue/compiler-core] decodeEntities option is required in browser builds.`,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -123,11 +123,6 @@ export interface TransformContext
|
|||
filters?: Set<string>
|
||||
}
|
||||
|
||||
export function getSelfName(filename: string): string | null {
|
||||
const nameMatch = filename.replace(/\?.*$/, '').match(/([^/\\]+)\.\w+$/)
|
||||
return nameMatch ? capitalize(camelize(nameMatch[1])) : null
|
||||
}
|
||||
|
||||
export function createTransformContext(
|
||||
root: RootNode,
|
||||
{
|
||||
|
|
@ -155,10 +150,11 @@ export function createTransformContext(
|
|||
compatConfig,
|
||||
}: TransformOptions,
|
||||
): TransformContext {
|
||||
const nameMatch = filename.replace(/\?.*$/, '').match(/([^/\\]+)\.\w+$/)
|
||||
const context: TransformContext = {
|
||||
// options
|
||||
filename,
|
||||
selfName: getSelfName(filename),
|
||||
selfName: nameMatch && capitalize(camelize(nameMatch[1])),
|
||||
prefixIdentifiers,
|
||||
hoistStatic,
|
||||
hmr,
|
||||
|
|
|
|||
|
|
@ -12,19 +12,22 @@ import {
|
|||
type RootNode,
|
||||
type SimpleExpressionNode,
|
||||
type SlotFunctionExpression,
|
||||
type SlotsObjectProperty,
|
||||
type TemplateChildNode,
|
||||
type TemplateNode,
|
||||
type TextCallNode,
|
||||
type VNodeCall,
|
||||
createArrayExpression,
|
||||
createObjectProperty,
|
||||
createSimpleExpression,
|
||||
getVNodeBlockHelper,
|
||||
getVNodeHelper,
|
||||
} from '../ast'
|
||||
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 {
|
||||
GUARD_REACTIVE_PROPS,
|
||||
|
|
@ -109,6 +112,15 @@ function walk(
|
|||
? ConstantTypes.NOT_CONSTANT
|
||||
: getConstantType(child, context)
|
||||
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)
|
||||
continue
|
||||
}
|
||||
|
|
@ -142,7 +154,6 @@ function walk(
|
|||
}
|
||||
|
||||
let cachedAsArray = false
|
||||
const slotCacheKeys = []
|
||||
if (toCache.length === children.length && node.type === NodeTypes.ELEMENT) {
|
||||
if (
|
||||
node.tagType === ElementTypes.ELEMENT &&
|
||||
|
|
@ -166,7 +177,6 @@ function walk(
|
|||
// default slot
|
||||
const slot = getSlotNode(node.codegenNode, 'default')
|
||||
if (slot) {
|
||||
slotCacheKeys.push(context.cached.length)
|
||||
slot.returns = getCacheExpression(
|
||||
createArrayExpression(slot.returns as TemplateChildNode[]),
|
||||
)
|
||||
|
|
@ -190,7 +200,6 @@ function walk(
|
|||
slotName.arg &&
|
||||
getSlotNode(parent.codegenNode, slotName.arg)
|
||||
if (slot) {
|
||||
slotCacheKeys.push(context.cached.length)
|
||||
slot.returns = getCacheExpression(
|
||||
createArrayExpression(slot.returns as TemplateChildNode[]),
|
||||
)
|
||||
|
|
@ -201,39 +210,22 @@ function walk(
|
|||
|
||||
if (!cachedAsArray) {
|
||||
for (const child of toCache) {
|
||||
slotCacheKeys.push(context.cached.length)
|
||||
child.codegenNode = context.cache(child.codegenNode!)
|
||||
}
|
||||
}
|
||||
|
||||
// put the slot cached keys on the slot object, so that the cache
|
||||
// can be removed when component unmounting to prevent memory leaks
|
||||
if (
|
||||
slotCacheKeys.length &&
|
||||
node.type === NodeTypes.ELEMENT &&
|
||||
node.tagType === ElementTypes.COMPONENT &&
|
||||
node.codegenNode &&
|
||||
node.codegenNode.type === NodeTypes.VNODE_CALL &&
|
||||
node.codegenNode.children &&
|
||||
!isArray(node.codegenNode.children) &&
|
||||
node.codegenNode.children.type === NodeTypes.JS_OBJECT_EXPRESSION
|
||||
) {
|
||||
node.codegenNode.children.properties.push(
|
||||
createObjectProperty(
|
||||
`__`,
|
||||
createSimpleExpression(JSON.stringify(slotCacheKeys), false),
|
||||
) as SlotsObjectProperty,
|
||||
)
|
||||
}
|
||||
|
||||
function getCacheExpression(value: JSChildNode): CacheExpression {
|
||||
const exp = context.cache(value)
|
||||
// #6978, #7138, #7114
|
||||
// a cached children array inside v-for can caused HMR errors since
|
||||
// it might be mutated when mounting the first item
|
||||
if (inFor && context.hmr) {
|
||||
exp.needArraySpread = true
|
||||
}
|
||||
// #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
|
||||
return exp
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,8 +44,7 @@ import { parseExpression } from '@babel/parser'
|
|||
import { IS_REF, UNREF } from '../runtimeHelpers'
|
||||
import { BindingTypes } from '../options'
|
||||
|
||||
export const isLiteralWhitelisted: (key: string) => boolean =
|
||||
/*@__PURE__*/ makeMap('true,false,null,this')
|
||||
const isLiteralWhitelisted = /*@__PURE__*/ makeMap('true,false,null,this')
|
||||
|
||||
export const transformExpression: NodeTransform = (node, context) => {
|
||||
if (node.type === NodeTypes.INTERPOLATION) {
|
||||
|
|
|
|||
|
|
@ -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,16 +1,13 @@
|
|||
import type { DirectiveTransform, TransformContext } from '../transform'
|
||||
import type { DirectiveTransform } from '../transform'
|
||||
import {
|
||||
type DirectiveNode,
|
||||
type ExpressionNode,
|
||||
NodeTypes,
|
||||
type SimpleExpressionNode,
|
||||
createObjectProperty,
|
||||
createSimpleExpression,
|
||||
} from '../ast'
|
||||
import { ErrorCodes, createCompilerError } from '../errors'
|
||||
import { camelize } from '@vue/shared'
|
||||
import { CAMELIZE } from '../runtimeHelpers'
|
||||
import { processExpression } from './transformExpression'
|
||||
|
||||
// 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
|
||||
|
|
@ -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) {
|
||||
arg.children.unshift(`(`)
|
||||
arg.children.push(`) || ""`)
|
||||
} else if (!arg.isStatic) {
|
||||
arg.content = `${arg.content} || ""`
|
||||
arg.content = arg.content ? `${arg.content} || ""` : `""`
|
||||
}
|
||||
|
||||
// .sync is replaced by v-model:arg
|
||||
|
|
@ -92,20 +68,7 @@ export const transformBind: DirectiveTransform = (dir, _node, context) => {
|
|||
}
|
||||
|
||||
return {
|
||||
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)
|
||||
props: [createObjectProperty(arg, exp!)],
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ import {
|
|||
import { processExpression } from './transformExpression'
|
||||
import { validateBrowserExpression } from '../validateExpression'
|
||||
import { PatchFlags } from '@vue/shared'
|
||||
import { transformBindShorthand } from './vBind'
|
||||
|
||||
export const transformFor: NodeTransform = createStructuralDirectiveTransform(
|
||||
'for',
|
||||
|
|
@ -64,10 +63,6 @@ export const transformFor: NodeTransform = createStructuralDirectiveTransform(
|
|||
const memo = findDir(node, 'memo')
|
||||
const keyProp = findProp(node, `key`, false, true)
|
||||
const isDirKey = keyProp && keyProp.type === NodeTypes.DIRECTIVE
|
||||
if (isDirKey && !keyProp.exp) {
|
||||
// resolve :key shorthand #10882
|
||||
transformBindShorthand(keyProp, context)
|
||||
}
|
||||
let keyExp =
|
||||
keyProp &&
|
||||
(keyProp.type === NodeTypes.ATTRIBUTE
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ import { findDir, findProp, getMemoedVNodeCall, injectProp } from '../utils'
|
|||
import { PatchFlags } from '@vue/shared'
|
||||
|
||||
export const transformIf: NodeTransform = createStructuralDirectiveTransform(
|
||||
/^(if|else|else-if)$/,
|
||||
/^(?:if|else|else-if)$/,
|
||||
(node, dir, context) => {
|
||||
return processIf(node, dir, context, (ifNode, branch, isRoot) => {
|
||||
// #1587: We need to dynamically increment the key based on the current
|
||||
|
|
@ -141,9 +141,9 @@ export function processIf(
|
|||
}
|
||||
|
||||
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 (
|
||||
dir.name === 'else-if' &&
|
||||
(dir.name === 'else-if' || dir.name === 'else') &&
|
||||
sibling.branches[sibling.branches.length - 1].condition === undefined
|
||||
) {
|
||||
context.onError(
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const seen = new WeakSet()
|
|||
export const transformMemo: NodeTransform = (node, context) => {
|
||||
if (node.type === NodeTypes.ELEMENT) {
|
||||
const dir = findDir(node, 'memo')
|
||||
if (!dir || seen.has(node)) {
|
||||
if (!dir || seen.has(node) || context.inSSR) {
|
||||
return
|
||||
}
|
||||
seen.add(node)
|
||||
|
|
|
|||
|
|
@ -131,9 +131,17 @@ export function buildSlots(
|
|||
// since it likely uses a scope variable.
|
||||
let hasDynamicSlots = context.scopes.vSlot > 0 || context.scopes.vFor > 0
|
||||
// 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) {
|
||||
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.
|
||||
|
|
@ -215,7 +223,7 @@ export function buildSlots(
|
|||
),
|
||||
)
|
||||
} else if (
|
||||
(vElse = findDir(slotElement, /^else(-if)?$/, true /* allowEmpty */))
|
||||
(vElse = findDir(slotElement, /^else(?:-if)?$/, true /* allowEmpty */))
|
||||
) {
|
||||
// find adjacent v-if
|
||||
let j = i
|
||||
|
|
@ -226,7 +234,7 @@ export function buildSlots(
|
|||
break
|
||||
}
|
||||
}
|
||||
if (prev && isTemplateNode(prev) && findDir(prev, /^(else-)?if$/)) {
|
||||
if (prev && isTemplateNode(prev) && findDir(prev, /^(?:else-)?if$/)) {
|
||||
__TEST__ && assert(dynamicSlots.length > 0)
|
||||
// attach this slot to previous conditional
|
||||
let conditional = dynamicSlots[
|
||||
|
|
|
|||
|
|
@ -63,7 +63,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 =>
|
||||
!nonIdentifierRE.test(name)
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ enum MemberExpLexState {
|
|||
inString,
|
||||
}
|
||||
|
||||
const validFirstIdentCharRE = /[A-Za-z_$\xA0-\uFFFF]/
|
||||
export const validFirstIdentCharRE: RegExp = /[A-Za-z_$\xA0-\uFFFF]/
|
||||
const validIdentCharRE = /[\.\?\w$\xA0-\uFFFF]/
|
||||
const whitespaceRE = /\s+[.[]\s*|\s*[.[]\s+/g
|
||||
|
||||
|
|
@ -160,7 +160,7 @@ export const isMemberExpressionBrowser = (exp: ExpressionNode): boolean => {
|
|||
|
||||
export const isMemberExpressionNode: (
|
||||
exp: ExpressionNode,
|
||||
context: Pick<TransformContext, 'expressionPlugins'>,
|
||||
context: TransformContext,
|
||||
) => boolean = __BROWSER__
|
||||
? (NOOP as any)
|
||||
: (exp, context) => {
|
||||
|
|
@ -185,18 +185,18 @@ export const isMemberExpressionNode: (
|
|||
|
||||
export const isMemberExpression: (
|
||||
exp: ExpressionNode,
|
||||
context: Pick<TransformContext, 'expressionPlugins'>,
|
||||
context: TransformContext,
|
||||
) => boolean = __BROWSER__ ? isMemberExpressionBrowser : isMemberExpressionNode
|
||||
|
||||
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 =>
|
||||
fnExpRE.test(getExpSource(exp))
|
||||
|
||||
export const isFnExpressionNode: (
|
||||
exp: ExpressionNode,
|
||||
context: Pick<TransformContext, 'expressionPlugins'>,
|
||||
context: TransformContext,
|
||||
) => boolean = __BROWSER__
|
||||
? (NOOP as any)
|
||||
: (exp, context) => {
|
||||
|
|
@ -227,7 +227,7 @@ export const isFnExpressionNode: (
|
|||
|
||||
export const isFnExpression: (
|
||||
exp: ExpressionNode,
|
||||
context: Pick<TransformContext, 'expressionPlugins'>,
|
||||
context: TransformContext,
|
||||
) => boolean = __BROWSER__ ? isFnExpressionBrowser : isFnExpressionNode
|
||||
|
||||
export function advancePositionWithClone(
|
||||
|
|
@ -279,7 +279,6 @@ export function assert(condition: boolean, msg?: string): void {
|
|||
}
|
||||
}
|
||||
|
||||
/** find directive */
|
||||
export function findDir(
|
||||
node: ElementNode,
|
||||
name: string | RegExp,
|
||||
|
|
@ -344,6 +343,10 @@ export function isText(
|
|||
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 {
|
||||
return p.type === NodeTypes.DIRECTIVE && p.name === 'slot'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,29 @@ exports[`stringify static html > eligible content (elements > 20) + non-eligible
|
|||
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||
|
||||
return function render(_ctx, _cache) {
|
||||
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||
return (_openBlock(), _createElementBlock("div", null, [...(_cache[0] || (_cache[0] = [
|
||||
_createStaticVNode("<span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span>", 20),
|
||||
_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))
|
||||
]))
|
||||
}"
|
||||
`;
|
||||
|
||||
|
|
@ -16,9 +34,9 @@ exports[`stringify static html > escape 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] = [
|
||||
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)
|
||||
])))
|
||||
]))]))
|
||||
}"
|
||||
`;
|
||||
|
||||
|
|
@ -26,9 +44,9 @@ exports[`stringify static html > serializing constant bindings 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] = [
|
||||
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)
|
||||
])))
|
||||
]))]))
|
||||
}"
|
||||
`;
|
||||
|
||||
|
|
@ -36,9 +54,9 @@ 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] = [
|
||||
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)
|
||||
])))
|
||||
]))]))
|
||||
}"
|
||||
`;
|
||||
|
||||
|
|
@ -46,7 +64,7 @@ exports[`stringify static html > should bail for <option> elements with null val
|
|||
"const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||
|
||||
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("option", { value: null }),
|
||||
_createElementVNode("option", { value: "1" }),
|
||||
|
|
@ -55,7 +73,7 @@ return function render(_ctx, _cache) {
|
|||
_createElementVNode("option", { value: "1" }),
|
||||
_createElementVNode("option", { value: "1" })
|
||||
], -1 /* CACHED */)
|
||||
])))
|
||||
]))]))
|
||||
}"
|
||||
`;
|
||||
|
||||
|
|
@ -63,7 +81,7 @@ exports[`stringify static html > should bail for <option> elements with number v
|
|||
"const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||
|
||||
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("option", { value: 1 }),
|
||||
_createElementVNode("option", { value: 1 }),
|
||||
|
|
@ -71,7 +89,7 @@ return function render(_ctx, _cache) {
|
|||
_createElementVNode("option", { value: 1 }),
|
||||
_createElementVNode("option", { value: 1 })
|
||||
], -1 /* CACHED */)
|
||||
])))
|
||||
]))]))
|
||||
}"
|
||||
`;
|
||||
|
||||
|
|
@ -95,7 +113,7 @@ exports[`stringify static html > should bail on bindings that are cached but not
|
|||
"const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||
|
||||
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("span", { class: "foo" }, "foo"),
|
||||
_createElementVNode("span", { class: "foo" }, "foo"),
|
||||
|
|
@ -104,7 +122,7 @@ return function render(_ctx, _cache) {
|
|||
_createElementVNode("span", { class: "foo" }, "foo"),
|
||||
_createElementVNode("img", { src: _imports_0_ })
|
||||
], -1 /* CACHED */)
|
||||
])))
|
||||
]))]))
|
||||
}"
|
||||
`;
|
||||
|
||||
|
|
@ -112,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
|
||||
|
||||
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)
|
||||
])))
|
||||
]))]))
|
||||
}"
|
||||
`;
|
||||
|
||||
|
|
@ -122,9 +140,9 @@ exports[`stringify static html > should work for multiple adjacent nodes 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] = [
|
||||
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)
|
||||
])))
|
||||
]))]))
|
||||
}"
|
||||
`;
|
||||
|
||||
|
|
@ -132,9 +150,9 @@ exports[`stringify static html > should work on eligible content (elements > 20)
|
|||
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||
|
||||
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)
|
||||
])))
|
||||
]))]))
|
||||
}"
|
||||
`;
|
||||
|
||||
|
|
@ -142,9 +160,9 @@ exports[`stringify static html > should work on eligible content (elements with
|
|||
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||
|
||||
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)
|
||||
])))
|
||||
]))]))
|
||||
}"
|
||||
`;
|
||||
|
||||
|
|
@ -152,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
|
||||
|
||||
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)
|
||||
])))
|
||||
]))]))
|
||||
}"
|
||||
`;
|
||||
|
||||
|
|
|
|||
|
|
@ -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`] = `
|
||||
"const _Vue = Vue
|
||||
|
||||
|
|
|
|||
|
|
@ -525,4 +525,14 @@ describe('stringify static html', () => {
|
|||
|
||||
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,
|
||||
baseParse as parse,
|
||||
transform,
|
||||
transformVBindShorthand,
|
||||
} from '@vue/compiler-core'
|
||||
import { transformModel } from '../../src/transforms/vModel'
|
||||
import { transformElement } from '../../../compiler-core/src/transforms/transformElement'
|
||||
|
|
@ -18,7 +19,7 @@ import {
|
|||
function transformWithModel(template: string, options: CompilerOptions = {}) {
|
||||
const ast = parse(template)
|
||||
transform(ast, {
|
||||
nodeTransforms: [transformElement],
|
||||
nodeTransforms: [transformVBindShorthand, transformElement],
|
||||
directiveTransforms: {
|
||||
model: transformModel,
|
||||
},
|
||||
|
|
@ -63,6 +64,14 @@ describe('compiler: transform v-model', () => {
|
|||
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', () => {
|
||||
const root = transformWithModel('<input v-bind="obj" v-model="model" />')
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@vue/compiler-dom",
|
||||
"version": "3.6.0-alpha.1",
|
||||
"version": "3.5.24",
|
||||
"description": "@vue/compiler-dom",
|
||||
"main": "index.js",
|
||||
"module": "dist/compiler-dom.esm-bundler.js",
|
||||
|
|
|
|||
|
|
@ -42,13 +42,13 @@ if (__TEST__) {
|
|||
if (DOMErrorCodes.X_V_HTML_NO_EXPRESSION < ErrorCodes.__EXTEND_POINT__) {
|
||||
throw new Error(
|
||||
`DOMErrorCodes need to be updated to ${
|
||||
ErrorCodes.__EXTEND_POINT__ + 1
|
||||
ErrorCodes.__EXTEND_POINT__
|
||||
} to match extension point from core ErrorCodes.`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export const DOMErrorMessages: Record<DOMErrorCodes, string> = {
|
||||
export const DOMErrorMessages: { [code: number]: string } = {
|
||||
[DOMErrorCodes.X_V_HTML_NO_EXPRESSION]: `v-html is missing expression.`,
|
||||
[DOMErrorCodes.X_V_HTML_WITH_CHILDREN]: `v-html will override element children.`,
|
||||
[DOMErrorCodes.X_V_TEXT_NO_EXPRESSION]: `v-text is missing expression.`,
|
||||
|
|
@ -60,7 +60,4 @@ export const DOMErrorMessages: Record<DOMErrorCodes, string> = {
|
|||
[DOMErrorCodes.X_V_SHOW_NO_EXPRESSION]: `v-show is missing expression.`,
|
||||
[DOMErrorCodes.X_TRANSITION_INVALID_CHILDREN]: `<Transition> expects exactly one child element or component.`,
|
||||
[DOMErrorCodes.X_IGNORED_SIDE_EFFECT_TAG]: `Tags with side effect (<script> and <style>) are ignored in client component templates.`,
|
||||
|
||||
// just to fulfill types
|
||||
[DOMErrorCodes.__EXTEND_POINT__]: ``,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,4 @@ export {
|
|||
DOMErrorCodes,
|
||||
DOMErrorMessages,
|
||||
} from './errors'
|
||||
export { resolveModifiers } from './transforms/vOn'
|
||||
export { isValidHTMLNesting } from './htmlNesting'
|
||||
export * from '@vue/compiler-core'
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue