fix(compiler-ssr): expand v-model `option` selected inclusion logic
close #13436
Expand cases under which the selected attribute is added onto an option tag in SSR:
- Consider text nodes/interpolations as direct children of the
option - Consider
v-text
An additional side effect of this PR is to fix the current behavior showcased by this playground example, which I believe to be a bug: link
Example
const app = createSSRApp({
setup() {
const r = ref('asdf')
const val = 'asdf'
return { r, val }
},
template: `
<select v-model="r">
<option>{{ val }}</option>
<option>fdsa</option>
</select>
`
})
// SSR output: <select><option selected>asdf</option><option>fdsa</option></select>
Summary by CodeRabbit
-
New Features
- Improved SSR handling for select v-model so option values resolve from plain text, interpolations, v-text, loops, slots, templates and nested content.
-
Bug Fixes
- More reliable selected-state computation in SSR for single and multiple select scenarios, including when option values are derived rather than explicitly bound.
-
Tests
- Added extensive SSR tests covering many select/v-model permutations and mixed option content.
Walkthrough
Reworks SSR v-model option value extraction to derive values from bound attributes, text directives, or collapsed text/interpolations; adds collapse utility; updates selected-state codegen; and adds extensive SSR tests for
Changes
| Cohort / File(s) | Summary |
|---|---|
SSR v-model transformpackages/compiler-ssr/src/transforms/ssrVModel.ts |
Adds internal OptionValue type and findOptionValue() to resolve option values from value bindings, v-text, or collapsed text/interpolations; introduces collapseTextBetweenComments(); updates imports (TemplateLiteral, TextNode, createTemplateLiteral, findDir); and adjusts selected-state SSR codegen to use the derived value source. |
SSR compiler testspackages/compiler-ssr/__tests__/ssrVModel.spec.ts |
Adds many new SSR unit tests and inline snapshots covering options with literal text, trimmed/spaced text, interpolations, v-text, v-for, slots/content, optgroups, and template/conditional combinations to validate option value derivation and selected logic. |
SSR renderer testspackages/server-renderer/__tests__/ssrDirectives.spec.ts |
Adds two tests verifying interpolation and v-text inside <option> render expected text and selected state in SSR output. |
Sequence Diagram(s)
sequenceDiagram
autonumber
participant Template as Template (AST)
participant Compiler as SSR Compiler
participant Transform as ssrVModel Transform
participant Helper as Utilities (collapseTextBetweenComments)
participant Codegen as SSR Codegen
participant Runtime as SSR Helpers
Template->>Compiler: parse -> AST
Compiler->>Transform: apply v-model transform on <select>/<option>
Transform->>Transform: findOptionValue()\n- if `value` binding -> use bound expr\n- else if `v-text` dir -> use text expr\n- else -> call Helper to collapse TEXT/INTERPOLATION/COMMENT\nHelper-->>Transform: sequence or TemplateLiteral value
Transform->>Codegen: emit selected logic using derived value\nCodegen->>Runtime: reference _ssrLooseContain/_ssrLooseEqual helpers
Note right of Runtime: Helpers evaluate at render time to set `selected`
Estimated code review effort
π― 3 (Moderate) | β±οΈ ~25 minutes
Possibly related PRs
- vuejs/core#13487 β Modifies the same
packages/compiler-ssr/src/transforms/ssrVModel.tsarea to improve SSR handling of<select>/<option>value extraction and child processing.
Suggested labels
ready to merge, :hammer: p3-minor-bug
Poem
Iβm a rabbit in the build, nibbling bits of text,
I fold interpolations, chase comments next.
Value bound or written, I tuck it neatβ
Then hop to mark the selected seat. πβ¨
Pre-merge checks and finishing touches
β Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | β οΈ Warning | Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. | You can run @coderabbitai generate docstrings to improve docstring coverage. |
β Passed checks (4 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | β Passed | Check skipped - CodeRabbitβs high-level summary is enabled. |
| Title Check | β Passed | The title clearly and concisely describes the primary change of expanding the SSR v-model option selection logic in the compiler-ssr transform, directly reflecting the key modifications without extraneous details. |
| Linked Issues Check | β Passed | The PR implements the fix from issue #13436 by introducing a findOptionValue function that derives option values from text nodes, interpolations, and v-text directives and updates the SSR selected-attribute logic accordingly, with matching tests covering the specified scenarios. |
| Out of Scope Changes Check | β Passed | All changes pertain exclusively to enhancing SSR v-model option selection and related tests, and no unrelated features or code areas have been modified. |
β¨ Finishing touches
- [ ] π Generate docstrings
π§ͺ Generate unit tests (beta)
- [ ] Create PR with unit tests
- [ ] Post copyable unit tests in a comment
π Recent review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
π₯ Commits
Reviewing files that changed from the base of the PR and between 15d6f922df89216b4a0455559329d8721fcff644 and cced68b97d8c5c8f43f3f9dbcfc133b02c9f65b0.
π Files selected for processing (3)
packages/compiler-ssr/__tests__/ssrVModel.spec.ts(1 hunks)packages/compiler-ssr/src/transforms/ssrVModel.ts(4 hunks)packages/server-renderer/__tests__/ssrDirectives.spec.ts(1 hunks)
π§ Files skipped from review as they are similar to previous changes (1)
- packages/compiler-ssr/tests/ssrVModel.spec.ts
π§° Additional context used
𧬠Code graph analysis (1)
packages/compiler-ssr/src/transforms/ssrVModel.ts (2)
packages/compiler-core/src/ast.ts (7)
PlainElementNode(140-149)ExpressionNode(91-91)TemplateLiteral(449-452)createSimpleExpression(685-698)createTemplateLiteral(801-809)TemplateChildNode(93-102)TextNode(176-179)packages/compiler-core/src/utils.ts (2)
findProp(299-320)findDir(282-297)
β° Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: test / unit-test-windows
- GitHub Check: test / e2e-test
- GitHub Check: Redirect rules
- GitHub Check: Header rules
- GitHub Check: Pages changed
π Additional comments (2)
packages/server-renderer/__tests__/ssrDirectives.spec.ts (1)
125-145: LGTM! Excellent test coverage for the new option value derivation logic.The new test cases properly validate:
- Interpolation within option text (f{{ zero }}o β "f0o")
- v-text directive bindings (opt1Val β "foo", opt2Val β "bar")
Both scenarios confirm that SSR correctly marks options as selected when the derived text content matches the v-model value.
packages/compiler-ssr/src/transforms/ssrVModel.ts (1)
259-295: LGTM! Clean implementation of text node collapsing.The
collapseTextBetweenCommentsutility correctly:
- Merges adjacent text nodes
- Handles spacing between merged nodes (removes duplicate spaces at boundaries)
- Skips comment nodes
- Preserves non-text nodes in sequence
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
Size Report
Bundles
| File | Size | Gzip | Brotli |
|---|---|---|---|
| runtime-dom.global.prod.js | 102 kB | 38.6 kB | 34.8 kB |
| vue.global.prod.js | 160 kB | 58.7 kB | 52.2 kB |
Usages
| Name | Size | Gzip | Brotli |
|---|---|---|---|
| createApp (CAPI only) | 46.7 kB | 18.3 kB | 16.7 kB |
| createApp | 54.7 kB | 21.3 kB | 19.5 kB |
| createSSRApp | 58.9 kB | 23 kB | 21 kB |
| defineCustomElement | 60 kB | 23 kB | 21 kB |
| overall | 68.8 kB | 26.5 kB | 24.2 kB |
@vue/compiler-core
npm i https://pkg.pr.new/@vue/compiler-core@13963
@vue/compiler-dom
npm i https://pkg.pr.new/@vue/compiler-dom@13963
@vue/compiler-sfc
npm i https://pkg.pr.new/@vue/compiler-sfc@13963
@vue/compiler-ssr
npm i https://pkg.pr.new/@vue/compiler-ssr@13963
@vue/reactivity
npm i https://pkg.pr.new/@vue/reactivity@13963
@vue/runtime-core
npm i https://pkg.pr.new/@vue/runtime-core@13963
@vue/runtime-dom
npm i https://pkg.pr.new/@vue/runtime-dom@13963
@vue/server-renderer
npm i https://pkg.pr.new/@vue/server-renderer@13963
@vue/shared
npm i https://pkg.pr.new/@vue/shared@13963
vue
npm i https://pkg.pr.new/vue@13963
@vue/compat
npm i https://pkg.pr.new/@vue/compat@13963
commit: cced68b
The following example has a bug Playground with this PR
@edison1105 updated!