From 201c46df07a38f3c2b73f384e8e6846dc62f224e Mon Sep 17 00:00:00 2001 From: edison Date: Tue, 11 Jul 2023 17:13:18 +0800 Subject: [PATCH] fix(ssr): render correct initial selected state for select with v-model (#7432) close #7392 --- .../compiler-ssr/__tests__/ssrVModel.spec.ts | 38 +++++++++++++++++++ .../compiler-ssr/src/transforms/ssrVModel.ts | 33 ++++++++++++++-- .../__tests__/ssrDirectives.spec.ts | 24 ++++++++++++ 3 files changed, 92 insertions(+), 3 deletions(-) diff --git a/packages/compiler-ssr/__tests__/ssrVModel.spec.ts b/packages/compiler-ssr/__tests__/ssrVModel.spec.ts index 3411aa291..5bccbcb78 100644 --- a/packages/compiler-ssr/__tests__/ssrVModel.spec.ts +++ b/packages/compiler-ssr/__tests__/ssrVModel.spec.ts @@ -33,6 +33,44 @@ describe('ssr: v-model', () => { `) }) + test('` + ).code + ).toMatchInlineSnapshot(` + "const { ssrIncludeBooleanAttr: _ssrIncludeBooleanAttr, ssrLooseContain: _ssrLooseContain, ssrLooseEqual: _ssrLooseEqual, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"vue/server-renderer\\") + + return function ssrRender(_ctx, _push, _parent, _attrs) { + _push(\`\`) + }" + `) + + expect( + compileWithWrapper( + `` + ).code + ).toMatchInlineSnapshot(` + "const { ssrIncludeBooleanAttr: _ssrIncludeBooleanAttr, ssrLooseContain: _ssrLooseContain, ssrLooseEqual: _ssrLooseEqual, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"vue/server-renderer\\") + + return function ssrRender(_ctx, _push, _parent, _attrs) { + _push(\`\`) + }" + `) + }) + test('', () => { expect( compileWithWrapper(``).code diff --git a/packages/compiler-ssr/src/transforms/ssrVModel.ts b/packages/compiler-ssr/src/transforms/ssrVModel.ts index 589ef6a86..bd587edcb 100644 --- a/packages/compiler-ssr/src/transforms/ssrVModel.ts +++ b/packages/compiler-ssr/src/transforms/ssrVModel.ts @@ -18,7 +18,8 @@ import { import { SSR_LOOSE_EQUAL, SSR_LOOSE_CONTAIN, - SSR_RENDER_DYNAMIC_MODEL + SSR_RENDER_DYNAMIC_MODEL, + SSR_INCLUDE_BOOLEAN_ATTR } from '../runtimeHelpers' import { DirectiveTransformResult } from 'packages/compiler-core/src/transform' @@ -129,8 +130,34 @@ export const ssrTransformModel: DirectiveTransform = (dir, node, context) => { checkDuplicatedValue() node.children = [createInterpolation(model, model.loc)] } else if (node.tag === 'select') { - // NOOP - // select relies on client-side directive to set initial selected state. + node.children.forEach(option => { + if (option.type === NodeTypes.ELEMENT) { + const plainNode = option as PlainElementNode + if (plainNode.props.findIndex(p => p.name === 'selected') === -1) { + const value = findValueBinding(plainNode) + plainNode.ssrCodegenNode!.elements.push( + createConditionalExpression( + createCallExpression(context.helper(SSR_INCLUDE_BOOLEAN_ATTR), [ + createConditionalExpression( + createCallExpression(`Array.isArray`, [model]), + createCallExpression(context.helper(SSR_LOOSE_CONTAIN), [ + model, + value + ]), + createCallExpression(context.helper(SSR_LOOSE_EQUAL), [ + model, + value + ]) + ) + ]), + createSimpleExpression(' selected', true), + createSimpleExpression('', true), + false /* no newline */ + ) + ) + } + } + }) } else { context.onError( createDOMCompilerError( diff --git a/packages/server-renderer/__tests__/ssrDirectives.spec.ts b/packages/server-renderer/__tests__/ssrDirectives.spec.ts index 102e95d5b..e52ef2db6 100644 --- a/packages/server-renderer/__tests__/ssrDirectives.spec.ts +++ b/packages/server-renderer/__tests__/ssrDirectives.spec.ts @@ -107,6 +107,30 @@ describe('ssr: directives', () => { ).toBe(``) }) + test('select', async () => { + expect( + await renderToString( + createApp({ + data: () => ({ model: 1 }), + template: `` + }) + ) + ).toBe( + `` + ) + + expect( + await renderToString( + createApp({ + data: () => ({ model: [0, 1] }), + template: `` + }) + ) + ).toBe( + `` + ) + }) + test('checkbox', async () => { expect( await renderToString(