diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 34307d8af13..aad4afa132a 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -1,18 +1,17 @@ { $schema: 'https://docs.renovatebot.com/renovate-schema.json', - extends: ['config:base', 'schedule:weekly', 'group:allNonMajor'], + extends: ['config:recommended', 'schedule:weekly', 'group:allNonMajor'], labels: ['dependencies'], ignorePaths: ['**/__tests__/**'], rangeStrategy: 'bump', packageRules: [ { - depTypeList: ['peerDependencies'], + matchDepTypes: ['peerDependencies'], enabled: false, }, { groupName: 'test', - matchPackageNames: ['vitest', 'jsdom', 'puppeteer'], - matchPackagePrefixes: ['@vitest'], + matchPackageNames: ['vitest', 'jsdom', 'puppeteer', '@vitest{/,}**'], }, { groupName: 'playground', @@ -23,18 +22,28 @@ }, { groupName: 'compiler', - matchPackageNames: ['magic-string'], - matchPackagePrefixes: ['@babel', 'postcss'], + matchPackageNames: ['magic-string', '@babel{/,}**', 'postcss{/,}**'], }, { groupName: 'build', - matchPackageNames: ['vite', '@swc/core'], - matchPackagePrefixes: ['rollup', 'esbuild', '@rollup', '@vitejs'], + matchPackageNames: [ + 'vite', + '@swc/core', + 'rollup{/,}**', + 'esbuild{/,}**', + '@rollup{/,}**', + '@vitejs{/,}**', + ], }, { groupName: 'lint', - matchPackageNames: ['simple-git-hooks', 'lint-staged'], - matchPackagePrefixes: ['typescript-eslint', 'eslint', 'prettier'], + matchPackageNames: [ + 'simple-git-hooks', + 'lint-staged', + 'typescript-eslint{/,}**', + 'eslint{/,}**', + 'prettier{/,}**', + ], }, ], ignoreDeps: [ @@ -58,5 +67,9 @@ // pinned // only used in example for e2e tests 'marked', + + // pinned, 5.0+ has exports issues + // https://github.com/vuejs/core/issues/11603 + 'entities', ], } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d9145507f3b..c8c217f62c4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,6 +3,8 @@ on: push: branches: - '**' + tags: + - '!**' pull_request: branches: - main @@ -12,3 +14,29 @@ jobs: test: if: ${{ ! startsWith(github.event.head_commit.message, 'release:') && (github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository) }} uses: ./.github/workflows/test.yml + + continuous-release: + if: github.repository == 'vuejs/core' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.node-version' + registry-url: 'https://registry.npmjs.org' + cache: 'pnpm' + + - name: Install deps + run: pnpm install + + - name: Build + run: pnpm build --withTypes + + - name: Release + run: pnpx pkg-pr-new publish --compact --pnpm './packages/*' diff --git a/.github/workflows/close-cant-reproduce-issues.yml b/.github/workflows/close-cant-reproduce-issues.yml new file mode 100644 index 00000000000..8fb48f842d8 --- /dev/null +++ b/.github/workflows/close-cant-reproduce-issues.yml @@ -0,0 +1,21 @@ +name: Auto close issues with "can't reproduce" label + +on: + schedule: + - cron: '0 0 * * *' + +permissions: + issues: write + +jobs: + close-issues: + if: github.repository == 'vuejs/core' + runs-on: ubuntu-latest + steps: + - name: can't reproduce + uses: actions-cool/issues-helper@v3 + with: + actions: 'close-issues' + token: ${{ secrets.GITHUB_TOKEN }} + labels: "can't reproduce" + inactive-day: 3 diff --git a/.github/workflows/ecosystem-ci-trigger.yml b/.github/workflows/ecosystem-ci-trigger.yml index 25adf7c85f4..b3e963ececa 100644 --- a/.github/workflows/ecosystem-ci-trigger.yml +++ b/.github/workflows/ecosystem-ci-trigger.yml @@ -9,7 +9,8 @@ jobs: runs-on: ubuntu-latest if: github.repository == 'vuejs/core' && github.event.issue.pull_request && startsWith(github.event.comment.body, '/ecosystem-ci run') steps: - - uses: actions/github-script@v7 + - name: Check user permission + uses: actions/github-script@v7 with: script: | const user = context.payload.sender.login @@ -43,7 +44,8 @@ jobs: }) throw new Error('not allowed') } - - uses: actions/github-script@v7 + - name: Get PR info + uses: actions/github-script@v7 id: get-pr-data with: script: | @@ -56,9 +58,11 @@ jobs: return { num: context.issue.number, branchName: pr.head.ref, - repo: pr.head.repo.full_name + repo: pr.head.repo.full_name, + commit: pr.head.sha } - - uses: actions/github-script@v7 + - name: Trigger run + uses: actions/github-script@v7 id: trigger env: COMMENT: ${{ github.event.comment.body }} @@ -80,6 +84,7 @@ jobs: prNumber: '' + prData.num, branchName: prData.branchName, repo: prData.repo, - suite: suite === '' ? '-' : suite + suite: suite === '' ? '-' : suite, + commit: prData.commit } }) diff --git a/.github/workflows/size-data.yml b/.github/workflows/size-data.yml index 3cd6cbfdf95..7f8bf7b08ca 100644 --- a/.github/workflows/size-data.yml +++ b/.github/workflows/size-data.yml @@ -18,6 +18,7 @@ env: jobs: upload: + if: github.repository == 'vuejs/core' runs-on: ubuntu-latest steps: diff --git a/.github/workflows/size-report.yml b/.github/workflows/size-report.yml index 32e96dc64a5..f9d2052b69c 100644 --- a/.github/workflows/size-report.yml +++ b/.github/workflows/size-report.yml @@ -18,6 +18,7 @@ jobs: size-report: runs-on: ubuntu-latest if: > + github.repository == 'vuejs/core' && github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' steps: @@ -65,7 +66,7 @@ jobs: if_no_artifact_found: warn - name: Prepare report - run: pnpm tsx scripts/size-report.ts > size-report.md + run: node scripts/size-report.js > size-report.md - name: Read Size Report id: size-report diff --git a/.github/workflows/upload-packages.yml b/.github/workflows/upload-packages.yml deleted file mode 100644 index 6c2bfa8c571..00000000000 --- a/.github/workflows/upload-packages.yml +++ /dev/null @@ -1,42 +0,0 @@ -# upload built packages as artifacts for faster ecosystem-ci -name: upload-built-packages - -on: - workflow_run: - workflows: ['ci'] - branches: [main, minor] - types: - - completed - -jobs: - build-and-upload: - if: > - github.repository == 'vuejs/core' && - github.event.workflow_run.event == 'push' && - github.event.workflow_run.conclusion == 'success' - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Install pnpm - uses: pnpm/action-setup@v4 - - - name: Install Node.js - uses: actions/setup-node@v4 - with: - node-version-file: '.node-version' - registry-url: 'https://registry.npmjs.org' - cache: 'pnpm' - - - name: Install deps - run: pnpm install - - - name: Build - run: pnpm build --withTypes - - - name: Upload - uses: actions/upload-artifact@v4 - with: - name: packages - path: packages/*/dist/* diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000000..91ebd56925c --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["vitest.explorer"] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 1dcc2819c28..302428290b9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,5 +13,6 @@ }, "[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode" - } + }, + "editor.formatOnSave": true } diff --git a/.well-known/funding-manifest-urls b/.well-known/funding-manifest-urls new file mode 100644 index 00000000000..f26079d4138 --- /dev/null +++ b/.well-known/funding-manifest-urls @@ -0,0 +1 @@ +https://vuejs.org/funding.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 54d83073cd9..d45ad1087b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,382 @@ +## [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) +* **reactiivty:** 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 `, { + parseMode: 'html', + }) + expect((ast3.children[0] as ElementNode).children).toMatchObject([ + { + type: NodeTypes.ELEMENT, + children: [ + { + type: NodeTypes.TEXT, + content: `{{ foo `, + }, + ], + }, + ]) }) test('self-closing v-pre', () => { @@ -2176,6 +2369,7 @@ describe('compiler: parse', () => { test('should remove leading newline character immediately following the pre element start tag', () => { const ast = parse(`
\n  foo  bar  
`, { isPreTag: tag => tag === 'pre', + isIgnoreNewlineTag: tag => tag === 'pre', }) expect(ast.children).toHaveLength(1) const preElement = ast.children[0] as ElementNode diff --git a/packages/compiler-core/__tests__/testUtils.ts b/packages/compiler-core/__tests__/testUtils.ts index 9618a482add..a2525e0cab9 100644 --- a/packages/compiler-core/__tests__/testUtils.ts +++ b/packages/compiler-core/__tests__/testUtils.ts @@ -3,6 +3,8 @@ import { ElementTypes, Namespaces, NodeTypes, + type Property, + type SimpleExpressionNode, type VNodeCall, locStub, } from '../src' @@ -22,7 +24,10 @@ const bracketsRE = /^\[|\]$/g // e.g. // - createObjectMatcher({ 'foo': '[bar]' }) matches { foo: bar } // - createObjectMatcher({ '[foo]': 'bar' }) matches { [foo]: "bar" } -export function createObjectMatcher(obj: Record) { +export function createObjectMatcher(obj: Record): { + type: NodeTypes + properties: Partial[] +} { return { type: NodeTypes.JS_OBJECT_EXPRESSION, properties: Object.keys(obj).map(key => ({ @@ -31,7 +36,7 @@ export function createObjectMatcher(obj: Record) { type: NodeTypes.SIMPLE_EXPRESSION, content: key.replace(bracketsRE, ''), isStatic: !leadingBracketRE.test(key), - }, + } as SimpleExpressionNode, value: isString(obj[key]) ? { type: NodeTypes.SIMPLE_EXPRESSION, @@ -78,7 +83,7 @@ type Flags = PatchFlags | ShapeFlags export function genFlagText( flag: Flags | Flags[], names: { [k: number]: string } = PatchFlagNames, -) { +): string { if (isArray(flag)) { let f = 0 flag.forEach(ff => { diff --git a/packages/compiler-core/__tests__/transforms/__snapshots__/cacheStatic.spec.ts.snap b/packages/compiler-core/__tests__/transforms/__snapshots__/cacheStatic.spec.ts.snap index 8d0305ee354..375a0c8674a 100644 --- a/packages/compiler-core/__tests__/transforms/__snapshots__/cacheStatic.spec.ts.snap +++ b/packages/compiler-core/__tests__/transforms/__snapshots__/cacheStatic.spec.ts.snap @@ -191,7 +191,7 @@ exports[`compiler: cacheStatic transform > prefixIdentifiers > hoist class with const { createElementVNode: _createElementVNode } = _Vue const _hoisted_1 = { - class: /*#__PURE__*/_normalizeClass({ foo: true }) + class: /*@__PURE__*/_normalizeClass({ foo: true }) } return function render(_ctx, _cache) { diff --git a/packages/compiler-core/__tests__/transforms/__snapshots__/vMemo.spec.ts.snap b/packages/compiler-core/__tests__/transforms/__snapshots__/vMemo.spec.ts.snap index 220bc177418..86e0b3d2fd5 100644 --- a/packages/compiler-core/__tests__/transforms/__snapshots__/vMemo.spec.ts.snap +++ b/packages/compiler-core/__tests__/transforms/__snapshots__/vMemo.spec.ts.snap @@ -1,5 +1,23 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`compiler: v-memo transform > element v-for key expression prefixing + v-memo 1`] = ` +"import { renderList as _renderList, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock, isMemoSame as _isMemoSame, withMemo as _withMemo } from "vue" + +export function render(_ctx, _cache) { + return (_openBlock(), _createElementBlock("div", null, [ + (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.tableData, (data, __, ___, _cached) => { + const _memo = (_ctx.getLetter(data)) + if (_cached && _cached.key === _ctx.getId(data) && _isMemoSame(_cached, _memo)) return _cached + const _item = (_openBlock(), _createElementBlock("span", { + key: _ctx.getId(data) + })) + _item.memo = _memo + return _item + }, _cache, 0), 128 /* KEYED_FRAGMENT */)) + ])) +}" +`; + exports[`compiler: v-memo transform > on component 1`] = ` "import { resolveComponent as _resolveComponent, createVNode as _createVNode, withMemo as _withMemo, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue" diff --git a/packages/compiler-core/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap b/packages/compiler-core/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap index 3d13c4066d9..6660865a523 100644 --- a/packages/compiler-core/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap +++ b/packages/compiler-core/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap @@ -8,7 +8,7 @@ return function render(_ctx, _cache) { const { setBlockTracking: _setBlockTracking, createElementVNode: _createElementVNode } = _Vue return _cache[0] || ( - _setBlockTracking(-1), + _setBlockTracking(-1, true), (_cache[0] = _createElementVNode("div", { id: foo }, null, 8 /* PROPS */, ["id"])).cacheIndex = 0, _setBlockTracking(1), _cache[0] @@ -28,7 +28,7 @@ return function render(_ctx, _cache) { return (_openBlock(), _createElementBlock("div", null, [ _cache[0] || ( - _setBlockTracking(-1), + _setBlockTracking(-1, true), (_cache[0] = _createVNode(_component_Comp, { id: foo }, null, 8 /* PROPS */, ["id"])).cacheIndex = 0, _setBlockTracking(1), _cache[0] @@ -47,7 +47,7 @@ return function render(_ctx, _cache) { return (_openBlock(), _createElementBlock("div", null, [ _cache[0] || ( - _setBlockTracking(-1), + _setBlockTracking(-1, true), (_cache[0] = _createElementVNode("div", { id: foo }, null, 8 /* PROPS */, ["id"])).cacheIndex = 0, _setBlockTracking(1), _cache[0] @@ -66,7 +66,7 @@ return function render(_ctx, _cache) { return (_openBlock(), _createElementBlock("div", null, [ _cache[0] || ( - _setBlockTracking(-1), + _setBlockTracking(-1, true), (_cache[0] = _renderSlot($slots, "default")).cacheIndex = 0, _setBlockTracking(1), _cache[0] @@ -85,7 +85,7 @@ return function render(_ctx, _cache) { return (_openBlock(), _createElementBlock("div", null, [ _cache[0] || ( - _setBlockTracking(-1), + _setBlockTracking(-1, true), (_cache[0] = _createElementVNode("div")).cacheIndex = 0, _setBlockTracking(1), _cache[0] diff --git a/packages/compiler-core/__tests__/transforms/vFor.spec.ts b/packages/compiler-core/__tests__/transforms/vFor.spec.ts index d0e95fcbcb3..fead2476ac5 100644 --- a/packages/compiler-core/__tests__/transforms/vFor.spec.ts +++ b/packages/compiler-core/__tests__/transforms/vFor.spec.ts @@ -13,6 +13,7 @@ import { type ForNode, type InterpolationNode, NodeTypes, + type RootNode, type SimpleExpressionNode, } from '../../src/ast' import { ErrorCodes } from '../../src/errors' @@ -24,7 +25,10 @@ import { createObjectMatcher } from '../testUtils' export function parseWithForTransform( template: string, options: CompilerOptions = {}, -) { +): { + root: RootNode + node: ForNode & { codegenNode: ForCodegenNode } +} { const ast = parse(template, options) transform(ast, { nodeTransforms: [ diff --git a/packages/compiler-core/__tests__/transforms/vMemo.spec.ts b/packages/compiler-core/__tests__/transforms/vMemo.spec.ts index 85769e6e977..41e7d922ebe 100644 --- a/packages/compiler-core/__tests__/transforms/vMemo.spec.ts +++ b/packages/compiler-core/__tests__/transforms/vMemo.spec.ts @@ -53,4 +53,12 @@ describe('compiler: v-memo transform', () => { ), ).toMatchSnapshot() }) + + test('element v-for key expression prefixing + v-memo', () => { + expect( + compile( + ``, + ), + ).toMatchSnapshot() + }) }) diff --git a/packages/compiler-core/__tests__/transforms/vOn.spec.ts b/packages/compiler-core/__tests__/transforms/vOn.spec.ts index 66097f29f0f..9fda0259585 100644 --- a/packages/compiler-core/__tests__/transforms/vOn.spec.ts +++ b/packages/compiler-core/__tests__/transforms/vOn.spec.ts @@ -285,6 +285,21 @@ describe('compiler: transform v-on', () => { }, ], }) + + const { node: node2 } = parseWithVOn( + `
`, + ) + expect((node2.codegenNode as VNodeCall).props).toMatchObject({ + properties: [ + { + key: { content: `onClick` }, + value: { + type: NodeTypes.SIMPLE_EXPRESSION, + content: `(e: (number | string)[]) => foo(e)`, + }, + }, + ], + }) }) test('should NOT wrap as function if expression is already function expression (async)', () => { diff --git a/packages/compiler-core/__tests__/utils.spec.ts b/packages/compiler-core/__tests__/utils.spec.ts index 506aa86982e..2d377a271ac 100644 --- a/packages/compiler-core/__tests__/utils.spec.ts +++ b/packages/compiler-core/__tests__/utils.spec.ts @@ -1,5 +1,5 @@ -import type { TransformContext } from '../src' -import type { Position } from '../src/ast' +import type { ExpressionNode, TransformContext } from '../src' +import { type Position, createSimpleExpression } from '../src/ast' import { advancePositionWithClone, isMemberExpressionBrowser, @@ -41,7 +41,8 @@ describe('advancePositionWithClone', () => { }) describe('isMemberExpression', () => { - function commonAssertions(fn: (str: string) => boolean) { + function commonAssertions(raw: (exp: ExpressionNode) => boolean) { + const fn = (str: string) => raw(createSimpleExpression(str)) // should work expect(fn('obj.foo')).toBe(true) expect(fn('obj[foo]')).toBe(true) @@ -78,13 +79,16 @@ describe('isMemberExpression', () => { test('browser', () => { commonAssertions(isMemberExpressionBrowser) - expect(isMemberExpressionBrowser('123[a]')).toBe(false) + expect(isMemberExpressionBrowser(createSimpleExpression('123[a]'))).toBe( + false, + ) }) test('node', () => { const ctx = { expressionPlugins: ['typescript'] } as any as TransformContext - const fn = (str: string) => isMemberExpressionNode(str, ctx) - commonAssertions(fn) + const fn = (str: string) => + isMemberExpressionNode(createSimpleExpression(str), ctx) + commonAssertions(exp => isMemberExpressionNode(exp, ctx)) // TS-specific checks expect(fn('foo as string')).toBe(true) diff --git a/packages/compiler-core/package.json b/packages/compiler-core/package.json index 4172a3919f1..d2f474c5983 100644 --- a/packages/compiler-core/package.json +++ b/packages/compiler-core/package.json @@ -1,6 +1,6 @@ { "name": "@vue/compiler-core", - "version": "3.5.0-beta.1", + "version": "3.5.13", "description": "@vue/compiler-core", "main": "index.js", "module": "dist/compiler-core.esm-bundler.js", @@ -48,7 +48,7 @@ "dependencies": { "@babel/parser": "catalog:", "@vue/shared": "workspace:*", - "entities": "^5.0.0", + "entities": "^4.5.0", "estree-walker": "catalog:", "source-map-js": "catalog:" }, diff --git a/packages/compiler-core/src/ast.ts b/packages/compiler-core/src/ast.ts index 8116f532b79..2d6df9d9010 100644 --- a/packages/compiler-core/src/ast.ts +++ b/packages/compiler-core/src/ast.ts @@ -203,7 +203,7 @@ export interface DirectiveNode extends Node { rawName?: string exp: ExpressionNode | undefined arg: ExpressionNode | undefined - modifiers: string[] + modifiers: SimpleExpressionNode[] /** * optional property to cache the expression parse result for v-for */ @@ -418,6 +418,7 @@ export interface CacheExpression extends Node { index: number value: JSChildNode needPauseTracking: boolean + inVOnce: boolean needArraySpread: boolean } @@ -774,12 +775,14 @@ export function createCacheExpression( index: number, value: JSChildNode, needPauseTracking: boolean = false, + inVOnce: boolean = false, ): CacheExpression { return { type: NodeTypes.JS_CACHE_EXPRESSION, index, value, needPauseTracking: needPauseTracking, + inVOnce, needArraySpread: false, loc: locStub, } diff --git a/packages/compiler-core/src/codegen.ts b/packages/compiler-core/src/codegen.ts index 2798ce989da..70116cfb61a 100644 --- a/packages/compiler-core/src/codegen.ts +++ b/packages/compiler-core/src/codegen.ts @@ -99,7 +99,7 @@ interface MappingItem { name: string | null } -const PURE_ANNOTATION = `/*#__PURE__*/` +const PURE_ANNOTATION = `/*@__PURE__*/` const aliasHelper = (s: symbol) => `${helperNameMap[s]}: _${helperNameMap[s]}` @@ -725,7 +725,7 @@ function genNode(node: CodegenNode | symbol | string, context: CodegenContext) { !__BROWSER__ && genReturnStatement(node, context) break - /* istanbul ignore next */ + /* v8 ignore start */ case NodeTypes.IF_BRANCH: // noop break @@ -736,6 +736,7 @@ function genNode(node: CodegenNode | symbol | string, context: CodegenContext) { const exhaustiveCheck: never = node return exhaustiveCheck } + /* v8 ignore stop */ } } @@ -1016,7 +1017,9 @@ function genCacheExpression(node: CacheExpression, context: CodegenContext) { push(`_cache[${node.index}] || (`) if (needPauseTracking) { indent() - push(`${helper(SET_BLOCK_TRACKING)}(-1),`) + push(`${helper(SET_BLOCK_TRACKING)}(-1`) + if (node.inVOnce) push(`, true`) + push(`),`) newline() push(`(`) } diff --git a/packages/compiler-core/src/compile.ts b/packages/compiler-core/src/compile.ts index 854c2bc6d69..a697c9d22e6 100644 --- a/packages/compiler-core/src/compile.ts +++ b/packages/compiler-core/src/compile.ts @@ -68,7 +68,7 @@ export function baseCompile( ): CodegenResult { const onError = options.onError || defaultOnError const isModuleMode = options.mode === 'module' - /* istanbul ignore if */ + /* v8 ignore start */ if (__BROWSER__) { if (options.prefixIdentifiers === true) { onError(createCompilerError(ErrorCodes.X_PREFIX_ID_NOT_SUPPORTED)) @@ -76,6 +76,7 @@ export function baseCompile( onError(createCompilerError(ErrorCodes.X_MODULE_MODE_NOT_SUPPORTED)) } } + /* v8 ignore stop */ const prefixIdentifiers = !__BROWSER__ && (options.prefixIdentifiers === true || isModuleMode) diff --git a/packages/compiler-core/src/options.ts b/packages/compiler-core/src/options.ts index 16b35d3ee85..1de865f42eb 100644 --- a/packages/compiler-core/src/options.ts +++ b/packages/compiler-core/src/options.ts @@ -52,6 +52,11 @@ export interface ParserOptions * e.g. elements that should preserve whitespace inside, e.g. `
`
    */
   isPreTag?: (tag: string) => boolean
+  /**
+   * Elements that should ignore the first newline token per parinsg spec
+   * e.g. `', parserOptions)
+      const element = ast.children[0] as ElementNode
+      const text = element.children[0] as TextNode
+      expect(element.children.length).toBe(1)
+      expect(text).toStrictEqual({
+        type: NodeTypes.TEXT,
+        content: 'hello',
+        loc: {
+          start: { offset: 10, line: 1, column: 11 },
+          end: { offset: 16, line: 2, column: 6 },
+          source: '\nhello',
+        },
+      })
+    })
+
     test('should not treat Uppercase component as special tag', () => {
       const ast = parse(
         '',
diff --git a/packages/compiler-dom/__tests__/transforms/__snapshots__/stringifyStatic.spec.ts.snap b/packages/compiler-dom/__tests__/transforms/__snapshots__/stringifyStatic.spec.ts.snap
index f55c27a9c6e..2ed15ef5e62 100644
--- a/packages/compiler-dom/__tests__/transforms/__snapshots__/stringifyStatic.spec.ts.snap
+++ b/packages/compiler-dom/__tests__/transforms/__snapshots__/stringifyStatic.spec.ts.snap
@@ -1,5 +1,17 @@
 // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
+exports[`stringify static html > eligible content (elements > 20) + non-eligible content 1`] = `
+"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
+
+return function render(_ctx, _cache) {
+  return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
+    _createStaticVNode("", 20),
+    _createElementVNode("div", { key: "1" }, "1", -1 /* HOISTED */),
+    _createStaticVNode("", 20)
+  ])))
+}"
+`;
+
 exports[`stringify static html > escape 1`] = `
 "const { toDisplayString: _toDisplayString, normalizeClass: _normalizeClass, createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
 
@@ -20,6 +32,33 @@ return function render(_ctx, _cache) {
 }"
 `;
 
+exports[`stringify static html > serializing template string style 1`] = `
+"const { toDisplayString: _toDisplayString, normalizeClass: _normalizeClass, createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
+
+return function render(_ctx, _cache) {
+  return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
+    _createStaticVNode("
1 + false1 + false1 + false1 + false1 + false
", 1) + ]))) +}" +`; + +exports[`stringify static html > should bail for