From d5dbd27193eee5fe401d3b85b6c5ddef5cd42b9d Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 26 Jun 2020 14:23:50 -0400 Subject: [PATCH] fix(ssr): handle fallthrough attrs in ssr compile output --- packages/compiler-core/src/codegen.ts | 2 +- .../__tests__/ssrComponent.spec.ts | 50 +-- .../compiler-ssr/__tests__/ssrElement.spec.ts | 205 +++++----- .../compiler-ssr/__tests__/ssrPortal.spec.ts | 30 +- .../compiler-ssr/__tests__/ssrScopeId.spec.ts | 19 +- .../__tests__/ssrSlotOutlet.spec.ts | 10 +- .../__tests__/ssrSuspense.spec.ts | 4 +- .../compiler-ssr/__tests__/ssrText.spec.ts | 10 +- .../compiler-ssr/__tests__/ssrVFor.spec.ts | 14 +- .../compiler-ssr/__tests__/ssrVIf.spec.ts | 63 +-- .../compiler-ssr/__tests__/ssrVModel.spec.ts | 166 +++++--- .../compiler-ssr/__tests__/ssrVShow.spec.ts | 114 ++++-- packages/compiler-ssr/__tests__/utils.ts | 14 +- packages/compiler-ssr/src/index.ts | 2 + .../transforms/ssrInjectFallthroughAttrs.ts | 52 +++ .../src/transforms/ssrTransformElement.ts | 362 +++++++++--------- packages/runtime-core/src/componentOptions.ts | 3 +- packages/runtime-core/src/vnode.ts | 3 +- .../__tests__/renderToString.spec.ts | 54 +-- .../__tests__/ssrAttrFallthrough.spec.ts | 78 ++++ packages/server-renderer/src/render.ts | 5 +- 21 files changed, 774 insertions(+), 486 deletions(-) create mode 100644 packages/compiler-ssr/src/transforms/ssrInjectFallthroughAttrs.ts create mode 100644 packages/server-renderer/__tests__/ssrAttrFallthrough.spec.ts diff --git a/packages/compiler-core/src/codegen.ts b/packages/compiler-core/src/codegen.ts index b213eec0ff7..e71810fc958 100644 --- a/packages/compiler-core/src/codegen.ts +++ b/packages/compiler-core/src/codegen.ts @@ -210,7 +210,7 @@ export function generate( if (!ssr) { push(`function render(_ctx, _cache) {`) } else { - push(`function ssrRender(_ctx, _push, _parent) {`) + push(`function ssrRender(_ctx, _push, _parent, _attrs) {`) } indent() diff --git a/packages/compiler-ssr/__tests__/ssrComponent.spec.ts b/packages/compiler-ssr/__tests__/ssrComponent.spec.ts index 8c5fb0d868b..4076749321a 100644 --- a/packages/compiler-ssr/__tests__/ssrComponent.spec.ts +++ b/packages/compiler-ssr/__tests__/ssrComponent.spec.ts @@ -3,16 +3,16 @@ import { compile } from '../src' describe('ssr: components', () => { test('basic', () => { expect(compile(``).code).toMatchInlineSnapshot(` - "const { resolveComponent: _resolveComponent } = require(\\"vue\\") + "const { resolveComponent: _resolveComponent, mergeProps: _mergeProps } = require(\\"vue\\") const { ssrRenderComponent: _ssrRenderComponent } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { const _component_foo = _resolveComponent(\\"foo\\") - _push(_ssrRenderComponent(_component_foo, { + _push(_ssrRenderComponent(_component_foo, _mergeProps({ id: \\"a\\", prop: _ctx.b - }, null, _parent)) + }, _attrs), null, _parent)) }" `) }) @@ -20,21 +20,21 @@ describe('ssr: components', () => { test('dynamic component', () => { expect(compile(``).code) .toMatchInlineSnapshot(` - "const { resolveDynamicComponent: _resolveDynamicComponent } = require(\\"vue\\") + "const { resolveDynamicComponent: _resolveDynamicComponent, mergeProps: _mergeProps } = require(\\"vue\\") const { ssrRenderComponent: _ssrRenderComponent } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { - _push(_ssrRenderComponent(_resolveDynamicComponent(\\"foo\\"), { prop: \\"b\\" }, null, _parent)) + return function ssrRender(_ctx, _push, _parent, _attrs) { + _push(_ssrRenderComponent(_resolveDynamicComponent(\\"foo\\"), _mergeProps({ prop: \\"b\\" }, _attrs), null, _parent)) }" `) expect(compile(``).code) .toMatchInlineSnapshot(` - "const { resolveDynamicComponent: _resolveDynamicComponent } = require(\\"vue\\") + "const { resolveDynamicComponent: _resolveDynamicComponent, mergeProps: _mergeProps } = require(\\"vue\\") const { ssrRenderComponent: _ssrRenderComponent } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { - _push(_ssrRenderComponent(_resolveDynamicComponent(_ctx.foo), { prop: \\"b\\" }, null, _parent)) + return function ssrRender(_ctx, _push, _parent, _attrs) { + _push(_ssrRenderComponent(_resolveDynamicComponent(_ctx.foo), _mergeProps({ prop: \\"b\\" }, _attrs), null, _parent)) }" `) }) @@ -45,10 +45,10 @@ describe('ssr: components', () => { "const { resolveComponent: _resolveComponent, withCtx: _withCtx, createVNode: _createVNode, createTextVNode: _createTextVNode } = require(\\"vue\\") const { ssrRenderComponent: _ssrRenderComponent } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { const _component_foo = _resolveComponent(\\"foo\\") - _push(_ssrRenderComponent(_component_foo, null, { + _push(_ssrRenderComponent(_component_foo, _attrs, { default: _withCtx((_, _push, _parent, _scopeId) => { if (_push) { _push(\`hello\`) @@ -71,10 +71,10 @@ describe('ssr: components', () => { "const { resolveComponent: _resolveComponent, withCtx: _withCtx, toDisplayString: _toDisplayString, createTextVNode: _createTextVNode } = require(\\"vue\\") const { ssrRenderComponent: _ssrRenderComponent, ssrInterpolate: _ssrInterpolate } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { const _component_foo = _resolveComponent(\\"foo\\") - _push(_ssrRenderComponent(_component_foo, null, { + _push(_ssrRenderComponent(_component_foo, _attrs, { default: _withCtx(({ msg }, _push, _parent, _scopeId) => { if (_push) { _push(\`\${_ssrInterpolate(msg + _ctx.outer)}\`) @@ -100,10 +100,10 @@ describe('ssr: components', () => { "const { resolveComponent: _resolveComponent, withCtx: _withCtx, createTextVNode: _createTextVNode } = require(\\"vue\\") const { ssrRenderComponent: _ssrRenderComponent } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { const _component_foo = _resolveComponent(\\"foo\\") - _push(_ssrRenderComponent(_component_foo, null, { + _push(_ssrRenderComponent(_component_foo, _attrs, { default: _withCtx((_, _push, _parent, _scopeId) => { if (_push) { _push(\`foo\`) @@ -137,10 +137,10 @@ describe('ssr: components', () => { "const { resolveComponent: _resolveComponent, withCtx: _withCtx, createTextVNode: _createTextVNode, createSlots: _createSlots } = require(\\"vue\\") const { ssrRenderComponent: _ssrRenderComponent } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { const _component_foo = _resolveComponent(\\"foo\\") - _push(_ssrRenderComponent(_component_foo, null, _createSlots({ _: 1 }, [ + _push(_ssrRenderComponent(_component_foo, _attrs, _createSlots({ _: 1 }, [ (_ctx.ok) ? { name: \\"named\\", @@ -169,10 +169,10 @@ describe('ssr: components', () => { "const { resolveComponent: _resolveComponent, withCtx: _withCtx, toDisplayString: _toDisplayString, createTextVNode: _createTextVNode, renderList: _renderList, createSlots: _createSlots } = require(\\"vue\\") const { ssrRenderComponent: _ssrRenderComponent, ssrInterpolate: _ssrInterpolate } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { const _component_foo = _resolveComponent(\\"foo\\") - _push(_ssrRenderComponent(_component_foo, null, _createSlots({ _: 1 }, [ + _push(_ssrRenderComponent(_component_foo, _attrs, _createSlots({ _: 1 }, [ _renderList(_ctx.names, (key) => { return { name: key, @@ -210,10 +210,10 @@ describe('ssr: components', () => { "const { resolveComponent: _resolveComponent, withCtx: _withCtx, renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createBlock: _createBlock, createVNode: _createVNode, createCommentVNode: _createCommentVNode } = require(\\"vue\\") const { ssrRenderComponent: _ssrRenderComponent, ssrRenderList: _ssrRenderList } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { const _component_foo = _resolveComponent(\\"foo\\") - _push(_ssrRenderComponent(_component_foo, null, { + _push(_ssrRenderComponent(_component_foo, _attrs, { foo: _withCtx(({ list }, _push, _parent, _scopeId) => { if (_push) { if (_ctx.ok) { @@ -270,7 +270,7 @@ describe('ssr: components', () => { expect(compile(`
`).code) .toMatchInlineSnapshot(` " - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { _push(\`
\`) }" `) @@ -278,7 +278,7 @@ describe('ssr: components', () => { expect(compile(`
`).code) .toMatchInlineSnapshot(` " - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { _push(\`
\`) }" `) @@ -288,7 +288,7 @@ describe('ssr: components', () => { "const { resolveComponent: _resolveComponent } = require(\\"vue\\") const { ssrRenderComponent: _ssrRenderComponent } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { const _component_foo = _resolveComponent(\\"foo\\") _push(_ssrRenderComponent(_component_foo, null, null, _parent)) diff --git a/packages/compiler-ssr/__tests__/ssrElement.spec.ts b/packages/compiler-ssr/__tests__/ssrElement.spec.ts index a3181f4e663..55eaa50647c 100644 --- a/packages/compiler-ssr/__tests__/ssrElement.spec.ts +++ b/packages/compiler-ssr/__tests__/ssrElement.spec.ts @@ -23,23 +23,28 @@ describe('ssr: element', () => { describe('children override', () => { test('v-html', () => { - expect(getCompiledString(`
`)).toMatchInlineSnapshot( - `"\`
\${_ctx.foo}
\`"` - ) + expect(getCompiledString(`
`)).toMatchInlineSnapshot(` + "\`
\${ + _ctx.foo + }
\`" + `) }) test('v-text', () => { - expect(getCompiledString(`
`)).toMatchInlineSnapshot( - `"\`
\${_ssrInterpolate(_ctx.foo)}
\`"` - ) + expect(getCompiledString(`
`)).toMatchInlineSnapshot(` + "\`
\${ + _ssrInterpolate(_ctx.foo) + }
\`" + `) }) test('\`"` - ) + expect(getCompiledString(`\`" + `) }) test('`).code) .toMatchInlineSnapshot(` - "const { ssrRenderAttrs: _ssrRenderAttrs, ssrInterpolate: _ssrInterpolate } = require(\\"@vue/server-renderer\\") + "const { mergeProps: _mergeProps } = require(\\"vue\\") + const { ssrRenderAttrs: _ssrRenderAttrs, ssrInterpolate: _ssrInterpolate } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { let _temp0 _push(\`\${ _ssrInterpolate((\\"value\\" in _temp0) ? _temp0.value : \\"fallback\\") }\`) @@ -71,10 +77,11 @@ describe('ssr: element', () => { isCustomElement: () => true }).code ).toMatchInlineSnapshot(` - "const { ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") + "const { mergeProps: _mergeProps } = require(\\"vue\\") + const { ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { - _push(\`\`) + return function ssrRender(_ctx, _push, _parent, _attrs) { + _push(\`\`) }" `) }) @@ -88,107 +95,126 @@ describe('ssr: element', () => { }) test('v-bind:class', () => { - expect( - getCompiledString(`
`) - ).toMatchInlineSnapshot( - `"\`
\`"` - ) + expect(getCompiledString(`
`)) + .toMatchInlineSnapshot(` + "\`
\`" + `) }) test('static class + v-bind:class', () => { - expect( - getCompiledString(`
`) - ).toMatchInlineSnapshot( - `"\`
\`"` - ) + expect(getCompiledString(`
`)) + .toMatchInlineSnapshot(` + "\`
\`" + `) }) test('v-bind:style', () => { - expect( - getCompiledString(`
`) - ).toMatchInlineSnapshot( - `"\`
\`"` - ) + expect(getCompiledString(`
`)) + .toMatchInlineSnapshot(` + "\`
\`" + `) }) test('static style + v-bind:style', () => { - expect( - getCompiledString(`
`) - ).toMatchInlineSnapshot( - `"\`
\`"` - ) + expect(getCompiledString(`
`)) + .toMatchInlineSnapshot(` + "\`
\`" + `) }) test('v-bind:key (boolean)', () => { - expect( - getCompiledString(``) - ).toMatchInlineSnapshot( - `"\`\`"` - ) + expect(getCompiledString(``)) + .toMatchInlineSnapshot(` + "\`\`" + `) }) test('v-bind:key (non-boolean)', () => { - expect( - getCompiledString(`
`) - ).toMatchInlineSnapshot( - `"\`
\`"` - ) + expect(getCompiledString(`
`)) + .toMatchInlineSnapshot(` + "\`
\`" + `) }) test('v-bind:[key]', () => { - expect( - getCompiledString(`
`) - ).toMatchInlineSnapshot( - `"\`
\`"` - ) + expect(getCompiledString(`
`)) + .toMatchInlineSnapshot(` + "\`
\`" + `) expect(getCompiledString(`
`)) .toMatchInlineSnapshot(` - "\`
\`" + "\`
\`" `) expect(getCompiledString(`
`)) .toMatchInlineSnapshot(` - "\`\`" + "\`\`" `) }) test('v-bind="obj"', () => { - expect( - getCompiledString(`
`) - ).toMatchInlineSnapshot(`"\`\`"`) + expect(getCompiledString(`
`)) + .toMatchInlineSnapshot(` + "\`\`" + `) - expect( - getCompiledString(`
`) - ).toMatchInlineSnapshot( - `"\`\`"` - ) + expect(getCompiledString(`
`)) + .toMatchInlineSnapshot(` + "\`\`" + `) - expect( - getCompiledString(`
`) - ).toMatchInlineSnapshot( - `"\`\`"` - ) + expect(getCompiledString(`
`)) + .toMatchInlineSnapshot(` + "\`\`" + `) // dynamic key + v-bind="object" - expect( - getCompiledString(`
`) - ).toMatchInlineSnapshot( - `"\`\`"` - ) + expect(getCompiledString(`
`)) + .toMatchInlineSnapshot(` + "\`\`" + `) // should merge class and :class expect(getCompiledString(`
`)) .toMatchInlineSnapshot(` - "\`\`" + "\`\`" `) // should merge style and :style @@ -197,9 +223,11 @@ describe('ssr: element', () => { `
` ) ).toMatchInlineSnapshot(` - "\`\`" + "\`\`" `) }) @@ -210,9 +238,12 @@ describe('ssr: element', () => { expect( getCompiledString(`
`) ).toMatchInlineSnapshot(`"\`
\`"`) - expect( - getCompiledString(`
`) - ).toMatchInlineSnapshot(`"\`
\`"`) + expect(getCompiledString(`
`)) + .toMatchInlineSnapshot(` + "\`
\`" + `) }) }) }) diff --git a/packages/compiler-ssr/__tests__/ssrPortal.spec.ts b/packages/compiler-ssr/__tests__/ssrPortal.spec.ts index 36d6138d3aa..e5a6bad1289 100644 --- a/packages/compiler-ssr/__tests__/ssrPortal.spec.ts +++ b/packages/compiler-ssr/__tests__/ssrPortal.spec.ts @@ -6,7 +6,7 @@ describe('ssr compile: teleport', () => { .toMatchInlineSnapshot(` "const { ssrRenderTeleport: _ssrRenderTeleport } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { _ssrRenderTeleport(_push, (_push) => { _push(\`
\`) }, _ctx.target, false, _parent) @@ -18,26 +18,26 @@ describe('ssr compile: teleport', () => { expect( compile(`
`).code ).toMatchInlineSnapshot(` - "const { ssrRenderTeleport: _ssrRenderTeleport } = require(\\"@vue/server-renderer\\") + "const { ssrRenderTeleport: _ssrRenderTeleport } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { - _ssrRenderTeleport(_push, (_push) => { - _push(\`
\`) - }, _ctx.target, true, _parent) - }" - `) + return function ssrRender(_ctx, _push, _parent, _attrs) { + _ssrRenderTeleport(_push, (_push) => { + _push(\`
\`) + }, _ctx.target, true, _parent) + }" + `) expect( compile(`
`) .code ).toMatchInlineSnapshot(` - "const { ssrRenderTeleport: _ssrRenderTeleport } = require(\\"@vue/server-renderer\\") + "const { ssrRenderTeleport: _ssrRenderTeleport } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { - _ssrRenderTeleport(_push, (_push) => { - _push(\`
\`) - }, _ctx.target, _ctx.foo, _parent) - }" - `) + return function ssrRender(_ctx, _push, _parent, _attrs) { + _ssrRenderTeleport(_push, (_push) => { + _push(\`
\`) + }, _ctx.target, _ctx.foo, _parent) + }" + `) }) }) diff --git a/packages/compiler-ssr/__tests__/ssrScopeId.spec.ts b/packages/compiler-ssr/__tests__/ssrScopeId.spec.ts index 64bb12f116a..a2a6452a741 100644 --- a/packages/compiler-ssr/__tests__/ssrScopeId.spec.ts +++ b/packages/compiler-ssr/__tests__/ssrScopeId.spec.ts @@ -9,9 +9,10 @@ describe('ssr: scopeId', () => { scopeId }).code ).toMatchInlineSnapshot(` - " - return function ssrRender(_ctx, _push, _parent) { - _push(\`
hello
\`) + "const { ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") + + return function ssrRender(_ctx, _push, _parent, _attrs) { + _push(\`hello
\`) }" `) }) @@ -26,10 +27,10 @@ describe('ssr: scopeId', () => { "const { resolveComponent: _resolveComponent, withCtx: _withCtx, createTextVNode: _createTextVNode } = require(\\"vue\\") const { ssrRenderComponent: _ssrRenderComponent } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { const _component_foo = _resolveComponent(\\"foo\\") - _push(_ssrRenderComponent(_component_foo, null, { + _push(_ssrRenderComponent(_component_foo, _attrs, { default: _withCtx((_, _push, _parent, _scopeId) => { if (_push) { _push(\`foo\`) @@ -54,10 +55,10 @@ describe('ssr: scopeId', () => { "const { resolveComponent: _resolveComponent, withCtx: _withCtx, createVNode: _createVNode } = require(\\"vue\\") const { ssrRenderComponent: _ssrRenderComponent } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { const _component_foo = _resolveComponent(\\"foo\\") - _push(_ssrRenderComponent(_component_foo, null, { + _push(_ssrRenderComponent(_component_foo, _attrs, { default: _withCtx((_, _push, _parent, _scopeId) => { if (_push) { _push(\`hello\`) @@ -82,11 +83,11 @@ describe('ssr: scopeId', () => { "const { resolveComponent: _resolveComponent, withCtx: _withCtx, createVNode: _createVNode } = require(\\"vue\\") const { ssrRenderComponent: _ssrRenderComponent } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { const _component_foo = _resolveComponent(\\"foo\\") const _component_bar = _resolveComponent(\\"bar\\") - _push(_ssrRenderComponent(_component_foo, null, { + _push(_ssrRenderComponent(_component_foo, _attrs, { default: _withCtx((_, _push, _parent, _scopeId) => { if (_push) { _push(\`hello\`) diff --git a/packages/compiler-ssr/__tests__/ssrSlotOutlet.spec.ts b/packages/compiler-ssr/__tests__/ssrSlotOutlet.spec.ts index 4d6d7e7e3be..668a80e8789 100644 --- a/packages/compiler-ssr/__tests__/ssrSlotOutlet.spec.ts +++ b/packages/compiler-ssr/__tests__/ssrSlotOutlet.spec.ts @@ -5,7 +5,7 @@ describe('ssr: ', () => { expect(compile(``).code).toMatchInlineSnapshot(` "const { ssrRenderSlot: _ssrRenderSlot } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { _ssrRenderSlot(_ctx.$slots, \\"default\\", {}, null, _push, _parent) }" `) @@ -15,7 +15,7 @@ describe('ssr: ', () => { expect(compile(``).code).toMatchInlineSnapshot(` "const { ssrRenderSlot: _ssrRenderSlot } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { _ssrRenderSlot(_ctx.$slots, \\"foo\\", {}, null, _push, _parent) }" `) @@ -25,7 +25,7 @@ describe('ssr: ', () => { expect(compile(``).code).toMatchInlineSnapshot(` "const { ssrRenderSlot: _ssrRenderSlot } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { _ssrRenderSlot(_ctx.$slots, _ctx.bar.baz, {}, null, _push, _parent) }" `) @@ -36,7 +36,7 @@ describe('ssr: ', () => { .toMatchInlineSnapshot(` "const { ssrRenderSlot: _ssrRenderSlot } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { _ssrRenderSlot(_ctx.$slots, \\"foo\\", { p: 1, bar: \\"2\\" @@ -50,7 +50,7 @@ describe('ssr: ', () => { .toMatchInlineSnapshot(` "const { ssrRenderSlot: _ssrRenderSlot, ssrInterpolate: _ssrInterpolate } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { _ssrRenderSlot(_ctx.$slots, \\"default\\", {}, () => { _push(\`some \${_ssrInterpolate(_ctx.fallback)} content\`) }, _push, _parent) diff --git a/packages/compiler-ssr/__tests__/ssrSuspense.spec.ts b/packages/compiler-ssr/__tests__/ssrSuspense.spec.ts index db60f5e2321..e85269f462b 100644 --- a/packages/compiler-ssr/__tests__/ssrSuspense.spec.ts +++ b/packages/compiler-ssr/__tests__/ssrSuspense.spec.ts @@ -6,7 +6,7 @@ describe('ssr compile: suspense', () => { "const { resolveComponent: _resolveComponent, withCtx: _withCtx } = require(\\"vue\\") const { ssrRenderComponent: _ssrRenderComponent, ssrRenderSuspense: _ssrRenderSuspense } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { const _component_foo = _resolveComponent(\\"foo\\") _ssrRenderSuspense(_push, { @@ -33,7 +33,7 @@ describe('ssr compile: suspense', () => { "const { resolveComponent: _resolveComponent, withCtx: _withCtx } = require(\\"vue\\") const { ssrRenderComponent: _ssrRenderComponent, ssrRenderSuspense: _ssrRenderSuspense } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { const _component_foo = _resolveComponent(\\"foo\\") _ssrRenderSuspense(_push, { diff --git a/packages/compiler-ssr/__tests__/ssrText.spec.ts b/packages/compiler-ssr/__tests__/ssrText.spec.ts index 37c9646d272..6ecadc6dbb1 100644 --- a/packages/compiler-ssr/__tests__/ssrText.spec.ts +++ b/packages/compiler-ssr/__tests__/ssrText.spec.ts @@ -45,7 +45,7 @@ describe('ssr: text', () => { expect(compile(`foo {{ bar }} baz`).code).toMatchInlineSnapshot(` "const { ssrInterpolate: _ssrInterpolate } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { _push(\`foo \${_ssrInterpolate(_ctx.bar)} baz\`) }" `) @@ -56,10 +56,12 @@ describe('ssr: text', () => { compile(`
{{ foo }} barbaz {{ qux }}
`) .code ).toMatchInlineSnapshot(` - "const { ssrInterpolate: _ssrInterpolate } = require(\\"@vue/server-renderer\\") + "const { ssrRenderAttrs: _ssrRenderAttrs, ssrInterpolate: _ssrInterpolate } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { - _push(\`
\${ + return function ssrRender(_ctx, _push, _parent, _attrs) { + _push(\`\${ _ssrInterpolate(_ctx.foo) } barbaz \${ _ssrInterpolate(_ctx.qux) diff --git a/packages/compiler-ssr/__tests__/ssrVFor.spec.ts b/packages/compiler-ssr/__tests__/ssrVFor.spec.ts index d599bc1ae49..87d0243d735 100644 --- a/packages/compiler-ssr/__tests__/ssrVFor.spec.ts +++ b/packages/compiler-ssr/__tests__/ssrVFor.spec.ts @@ -5,7 +5,7 @@ describe('ssr: v-for', () => { expect(compile(`
`).code).toMatchInlineSnapshot(` "const { ssrRenderList: _ssrRenderList } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { _push(\`\`) _ssrRenderList(_ctx.list, (i) => { _push(\`
\`) @@ -20,7 +20,7 @@ describe('ssr: v-for', () => { .toMatchInlineSnapshot(` "const { ssrRenderList: _ssrRenderList } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { _push(\`\`) _ssrRenderList(_ctx.list, (i) => { _push(\`
foobar
\`) @@ -40,7 +40,7 @@ describe('ssr: v-for', () => { ).toMatchInlineSnapshot(` "const { ssrInterpolate: _ssrInterpolate, ssrRenderList: _ssrRenderList } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { _push(\`\`) _ssrRenderList(_ctx.list, (row, i) => { _push(\`
\`) @@ -63,7 +63,7 @@ describe('ssr: v-for', () => { .toMatchInlineSnapshot(` "const { ssrInterpolate: _ssrInterpolate, ssrRenderList: _ssrRenderList } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { _push(\`\`) _ssrRenderList(_ctx.list, (i) => { _push(\`\${_ssrInterpolate(i)}\`) @@ -80,7 +80,7 @@ describe('ssr: v-for', () => { ).toMatchInlineSnapshot(` "const { ssrInterpolate: _ssrInterpolate, ssrRenderList: _ssrRenderList } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { _push(\`\`) _ssrRenderList(_ctx.list, (i) => { _push(\`\${_ssrInterpolate(i)}\`) @@ -98,7 +98,7 @@ describe('ssr: v-for', () => { ).toMatchInlineSnapshot(` "const { ssrInterpolate: _ssrInterpolate, ssrRenderList: _ssrRenderList } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { _push(\`\`) _ssrRenderList(_ctx.list, (i) => { _push(\`\${ @@ -122,7 +122,7 @@ describe('ssr: v-for', () => { expect(code).toMatchInlineSnapshot(` "const { ssrInterpolate: _ssrInterpolate, ssrRenderList: _ssrRenderList } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { _push(\`\`) _ssrRenderList(_ctx.list, ({ foo }, index) => { _push(\`
\${_ssrInterpolate(foo + _ctx.bar + index)}
\`) diff --git a/packages/compiler-ssr/__tests__/ssrVIf.spec.ts b/packages/compiler-ssr/__tests__/ssrVIf.spec.ts index 51a3d78fe6b..b64df0c21d2 100644 --- a/packages/compiler-ssr/__tests__/ssrVIf.spec.ts +++ b/packages/compiler-ssr/__tests__/ssrVIf.spec.ts @@ -3,10 +3,11 @@ import { compile } from '../src' describe('ssr: v-if', () => { test('basic', () => { expect(compile(`
`).code).toMatchInlineSnapshot(` - " - return function ssrRender(_ctx, _push, _parent) { + "const { ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") + + return function ssrRender(_ctx, _push, _parent, _attrs) { if (_ctx.foo) { - _push(\`
\`) + _push(\`
\`) } else { _push(\`\`) } @@ -17,10 +18,11 @@ describe('ssr: v-if', () => { test('with nested content', () => { expect(compile(`
hellook
`).code) .toMatchInlineSnapshot(` - " - return function ssrRender(_ctx, _push, _parent) { + "const { ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") + + return function ssrRender(_ctx, _push, _parent, _attrs) { if (_ctx.foo) { - _push(\`
hellook
\`) + _push(\`hellook
\`) } else { _push(\`\`) } @@ -31,12 +33,13 @@ describe('ssr: v-if', () => { test('v-if + v-else', () => { expect(compile(`
`).code) .toMatchInlineSnapshot(` - " - return function ssrRender(_ctx, _push, _parent) { + "const { ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") + + return function ssrRender(_ctx, _push, _parent, _attrs) { if (_ctx.foo) { - _push(\`
\`) + _push(\`
\`) } else { - _push(\`\`) + _push(\`
\`) } }" `) @@ -45,12 +48,13 @@ describe('ssr: v-if', () => { test('v-if + v-else-if', () => { expect(compile(`
`).code) .toMatchInlineSnapshot(` - " - return function ssrRender(_ctx, _push, _parent) { + "const { ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") + + return function ssrRender(_ctx, _push, _parent, _attrs) { if (_ctx.foo) { - _push(\`
\`) + _push(\`
\`) } else if (_ctx.bar) { - _push(\`\`) + _push(\`
\`) } else { _push(\`\`) } @@ -61,14 +65,15 @@ describe('ssr: v-if', () => { test('v-if + v-else-if + v-else', () => { expect(compile(`

`).code) .toMatchInlineSnapshot(` - " - return function ssrRender(_ctx, _push, _parent) { + "const { ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") + + return function ssrRender(_ctx, _push, _parent, _attrs) { if (_ctx.foo) { - _push(\`

\`) + _push(\`
\`) } else if (_ctx.bar) { - _push(\`\`) + _push(\`\`) } else { - _push(\`

\`) + _push(\`

\`) } }" `) @@ -78,7 +83,7 @@ describe('ssr: v-if', () => { expect(compile(``).code) .toMatchInlineSnapshot(` " - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { if (_ctx.foo) { _push(\`hello\`) } else { @@ -92,10 +97,11 @@ describe('ssr: v-if', () => { // single element should not wrap with fragment expect(compile(``).code) .toMatchInlineSnapshot(` - " - return function ssrRender(_ctx, _push, _parent) { + "const { ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") + + return function ssrRender(_ctx, _push, _parent, _attrs) { if (_ctx.foo) { - _push(\`
hi
\`) + _push(\`hi
\`) } else { _push(\`\`) } @@ -108,7 +114,7 @@ describe('ssr: v-if', () => { compile(``).code ).toMatchInlineSnapshot(` " - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { if (_ctx.foo) { _push(\`
hi
ho
\`) } else { @@ -124,7 +130,7 @@ describe('ssr: v-if', () => { ).toMatchInlineSnapshot(` "const { ssrRenderList: _ssrRenderList } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { if (_ctx.foo) { _push(\`\`) _ssrRenderList(_ctx.list, (i) => { @@ -144,12 +150,13 @@ describe('ssr: v-if', () => { `
` ).code ).toMatchInlineSnapshot(` - " - return function ssrRender(_ctx, _push, _parent) { + "const { ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") + + return function ssrRender(_ctx, _push, _parent, _attrs) { if (_ctx.foo) { _push(\`
hi
ho
\`) } else { - _push(\`
\`) + _push(\`
\`) } }" `) diff --git a/packages/compiler-ssr/__tests__/ssrVModel.spec.ts b/packages/compiler-ssr/__tests__/ssrVModel.spec.ts index 151eaa79da8..18a03b115f4 100644 --- a/packages/compiler-ssr/__tests__/ssrVModel.spec.ts +++ b/packages/compiler-ssr/__tests__/ssrVModel.spec.ts @@ -1,136 +1,186 @@ import { compile } from '../src' +function compileWithWrapper(src: string) { + return compile(`
${src}
`) +} + describe('ssr: v-model', () => { test(' (text types)', () => { - expect(compile(``).code).toMatchInlineSnapshot(` - "const { ssrRenderAttr: _ssrRenderAttr } = require(\\"@vue/server-renderer\\") + expect(compileWithWrapper(``).code) + .toMatchInlineSnapshot(` + "const { ssrRenderAttr: _ssrRenderAttr, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { - _push(\`\`) + return function ssrRender(_ctx, _push, _parent, _attrs) { + _push(\`
\`) }" `) - expect(compile(``).code) + expect(compileWithWrapper(``).code) .toMatchInlineSnapshot(` - "const { ssrRenderAttr: _ssrRenderAttr } = require(\\"@vue/server-renderer\\") + "const { ssrRenderAttr: _ssrRenderAttr, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { - _push(\`\`) + return function ssrRender(_ctx, _push, _parent, _attrs) { + _push(\`
\`) }" `) }) test('', () => { - expect(compile(``).code) - .toMatchInlineSnapshot(` - "const { ssrLooseEqual: _ssrLooseEqual } = require(\\"@vue/server-renderer\\") - - return function ssrRender(_ctx, _push, _parent) { - _push(\`\`) + expect( + compileWithWrapper(``).code + ).toMatchInlineSnapshot(` + "const { ssrLooseEqual: _ssrLooseEqual, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") + + return function ssrRender(_ctx, _push, _parent, _attrs) { + _push(\`\`) }" `) }) test(' { - expect(compile(``).code) + expect(compileWithWrapper(``).code) .toMatchInlineSnapshot(` - "const { ssrLooseContain: _ssrLooseContain } = require(\\"@vue/server-renderer\\") - - return function ssrRender(_ctx, _push, _parent) { - _push(\`\`) + "const { ssrLooseContain: _ssrLooseContain, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") + + return function ssrRender(_ctx, _push, _parent, _attrs) { + _push(\`\`) }" `) - expect(compile(``).code) - .toMatchInlineSnapshot(` - "const { ssrLooseContain: _ssrLooseContain } = require(\\"@vue/server-renderer\\") - - return function ssrRender(_ctx, _push, _parent) { - _push(\`\`) + expect( + compileWithWrapper(``) + .code + ).toMatchInlineSnapshot(` + "const { ssrLooseContain: _ssrLooseContain, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") + + return function ssrRender(_ctx, _push, _parent, _attrs) { + _push(\`\`) }" `) }) test('`).code) + expect(compileWithWrapper(``).code) .toMatchInlineSnapshot(` - "const { ssrInterpolate: _ssrInterpolate } = require(\\"@vue/server-renderer\\") - - return function ssrRender(_ctx, _push, _parent) { - _push(\`\`) + "const { ssrRenderAttrs: _ssrRenderAttrs, ssrInterpolate: _ssrInterpolate } = require(\\"@vue/server-renderer\\") + + return function ssrRender(_ctx, _push, _parent, _attrs) { + _push(\`\`) }" `) }) test('', () => { - expect(compile(``).code) + expect(compileWithWrapper(``).code) .toMatchInlineSnapshot(` - "const { ssrRenderAttr: _ssrRenderAttr, ssrRenderDynamicModel: _ssrRenderDynamicModel } = require(\\"@vue/server-renderer\\") + "const { ssrRenderAttr: _ssrRenderAttr, ssrRenderDynamicModel: _ssrRenderDynamicModel, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { - _push(\`\`) + }>\`) }" `) - expect(compile(``).code) - .toMatchInlineSnapshot(` - "const { ssrRenderAttr: _ssrRenderAttr, ssrRenderDynamicModel: _ssrRenderDynamicModel } = require(\\"@vue/server-renderer\\") + expect( + compileWithWrapper(``).code + ).toMatchInlineSnapshot(` + "const { ssrRenderAttr: _ssrRenderAttr, ssrRenderDynamicModel: _ssrRenderDynamicModel, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { - _push(\`\`) + } value=\\"bar\\">\`) }" `) - expect(compile(``).code) - .toMatchInlineSnapshot(` - "const { ssrRenderAttr: _ssrRenderAttr, ssrRenderDynamicModel: _ssrRenderDynamicModel } = require(\\"@vue/server-renderer\\") + expect( + compileWithWrapper(``).code + ).toMatchInlineSnapshot(` + "const { ssrRenderAttr: _ssrRenderAttr, ssrRenderDynamicModel: _ssrRenderDynamicModel, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { - _push(\`\`) + }>\`) }" `) }) test('', () => { - expect(compile(``).code) + expect(compileWithWrapper(``).code) .toMatchInlineSnapshot(` "const { mergeProps: _mergeProps } = require(\\"vue\\") const { ssrRenderAttrs: _ssrRenderAttrs, ssrGetDynamicModelProps: _ssrGetDynamicModelProps } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { let _temp0 - _push(\`\`) + _push(\`\`) }" `) - expect(compile(``).code) - .toMatchInlineSnapshot(` + expect( + compileWithWrapper(``) + .code + ).toMatchInlineSnapshot(` "const { mergeProps: _mergeProps } = require(\\"vue\\") const { ssrRenderAttrs: _ssrRenderAttrs, ssrGetDynamicModelProps: _ssrGetDynamicModelProps } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { + return function ssrRender(_ctx, _push, _parent, _attrs) { let _temp0 - _push(\`\`) + _push(\`\`) }" `) }) diff --git a/packages/compiler-ssr/__tests__/ssrVShow.spec.ts b/packages/compiler-ssr/__tests__/ssrVShow.spec.ts index 8a99a52c7d3..e28014d9356 100644 --- a/packages/compiler-ssr/__tests__/ssrVShow.spec.ts +++ b/packages/compiler-ssr/__tests__/ssrVShow.spec.ts @@ -1,78 +1,118 @@ import { compile } from '../src' +function compileWithWrapper(src: string) { + return compile(`
${src}
`) +} + describe('ssr: v-show', () => { - test('basic', () => { + test('basic as root', () => { expect(compile(`
`).code).toMatchInlineSnapshot(` - "const { ssrRenderStyle: _ssrRenderStyle } = require(\\"@vue/server-renderer\\") + "const { mergeProps: _mergeProps } = require(\\"vue\\") + const { ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") + + return function ssrRender(_ctx, _push, _parent, _attrs) { + _push(\`
\`) + }" + `) + }) + + test('basic', () => { + expect(compileWithWrapper(`
`).code) + .toMatchInlineSnapshot(` + "const { ssrRenderStyle: _ssrRenderStyle, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { - _push(\`
\`) + return function ssrRender(_ctx, _push, _parent, _attrs) { + _push(\`
\`) }" `) }) test('with static style', () => { - expect(compile(`
`).code) + expect(compileWithWrapper(`
`).code) .toMatchInlineSnapshot(` - "const { ssrRenderStyle: _ssrRenderStyle } = require(\\"@vue/server-renderer\\") + "const { ssrRenderStyle: _ssrRenderStyle, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { - _push(\`
\`) + return function ssrRender(_ctx, _push, _parent, _attrs) { + _push(\`
\`) }" `) }) test('with dynamic style', () => { - expect(compile(`
`).code) - .toMatchInlineSnapshot(` - "const { ssrRenderStyle: _ssrRenderStyle } = require(\\"@vue/server-renderer\\") + expect( + compileWithWrapper(`
`).code + ).toMatchInlineSnapshot(` + "const { ssrRenderStyle: _ssrRenderStyle, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { - _push(\`
\`) + return function ssrRender(_ctx, _push, _parent, _attrs) { + _push(\`
\`) }" `) }) test('with static + dynamic style', () => { expect( - compile(`
`) - .code + compileWithWrapper( + `
` + ).code ).toMatchInlineSnapshot(` - "const { ssrRenderStyle: _ssrRenderStyle } = require(\\"@vue/server-renderer\\") + "const { ssrRenderStyle: _ssrRenderStyle, ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { - _push(\`
\`) + return function ssrRender(_ctx, _push, _parent, _attrs) { + _push(\`
\`) }" `) }) test('with v-bind', () => { expect( - compile( + compileWithWrapper( `
` ).code ).toMatchInlineSnapshot(` "const { mergeProps: _mergeProps } = require(\\"vue\\") const { ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") - return function ssrRender(_ctx, _push, _parent) { - _push(\`
\`) + return function ssrRender(_ctx, _push, _parent, _attrs) { + _push(\`
\`) }" `) }) diff --git a/packages/compiler-ssr/__tests__/utils.ts b/packages/compiler-ssr/__tests__/utils.ts index cc3cd45ba28..08dec4debec 100644 --- a/packages/compiler-ssr/__tests__/utils.ts +++ b/packages/compiler-ssr/__tests__/utils.ts @@ -1,5 +1,17 @@ import { compile } from '../src' export function getCompiledString(src: string): string { - return compile(src).code.match(/_push\(([^]*)\)/)![1] + // Wrap src template in a root div so that it doesn't get injected + // fallthrough attr. This results in less noise in generated snapshots + // but also means this util can only be used for non-root cases. + const { code } = compile(`
${src}
`) + const match = code.match( + /_push\(\`([^]*)<\/div>\`\)/ + ) + + if (!match) { + throw new Error(`Unexpected compile result:\n${code}`) + } + + return `\`${match[1]}\`` } diff --git a/packages/compiler-ssr/src/index.ts b/packages/compiler-ssr/src/index.ts index 2edb97915d8..02153773b64 100644 --- a/packages/compiler-ssr/src/index.ts +++ b/packages/compiler-ssr/src/index.ts @@ -23,6 +23,7 @@ import { ssrTransformIf } from './transforms/ssrVIf' import { ssrTransformFor } from './transforms/ssrVFor' import { ssrTransformModel } from './transforms/ssrVModel' import { ssrTransformShow } from './transforms/ssrVShow' +import { ssrInjectFallthroughAttrs } from './transforms/ssrInjectFallthroughAttrs' export function compile( template: string, @@ -55,6 +56,7 @@ export function compile( trackVForSlotScopes, transformExpression, ssrTransformSlotOutlet, + ssrInjectFallthroughAttrs, ssrTransformElement, ssrTransformComponent, trackSlotScopes, diff --git a/packages/compiler-ssr/src/transforms/ssrInjectFallthroughAttrs.ts b/packages/compiler-ssr/src/transforms/ssrInjectFallthroughAttrs.ts new file mode 100644 index 00000000000..01ca66f50f5 --- /dev/null +++ b/packages/compiler-ssr/src/transforms/ssrInjectFallthroughAttrs.ts @@ -0,0 +1,52 @@ +import { + NodeTransform, + NodeTypes, + ElementTypes, + locStub, + createSimpleExpression, + RootNode, + TemplateChildNode, + ParentNode, + findDir +} from '@vue/compiler-dom' + +const hasSingleChild = (node: ParentNode): boolean => + node.children.filter(n => n.type !== NodeTypes.COMMENT).length === 1 + +export const ssrInjectFallthroughAttrs: NodeTransform = (node, context) => { + // _attrs is provided as a function argument. + // mark it as a known identifier so that it doesn't get prefixed by + // transformExpression. + if (node.type === NodeTypes.ROOT) { + context.identifiers._attrs = 1 + } + + const parent = context.parent + if (!parent || parent.type !== NodeTypes.ROOT) { + return + } + + if (node.type === NodeTypes.IF_BRANCH && hasSingleChild(node)) { + injectFallthroughAttrs(node.children[0]) + } else if (hasSingleChild(parent)) { + injectFallthroughAttrs(node) + } +} + +function injectFallthroughAttrs(node: RootNode | TemplateChildNode) { + if ( + node.type === NodeTypes.ELEMENT && + (node.tagType === ElementTypes.ELEMENT || + node.tagType === ElementTypes.COMPONENT) && + !findDir(node, 'for') + ) { + node.props.push({ + type: NodeTypes.DIRECTIVE, + name: 'bind', + arg: undefined, + exp: createSimpleExpression(`_attrs`, false), + modifiers: [], + loc: locStub + }) + } +} diff --git a/packages/compiler-ssr/src/transforms/ssrTransformElement.ts b/packages/compiler-ssr/src/transforms/ssrTransformElement.ts index d56315d4363..21c231e85fc 100644 --- a/packages/compiler-ssr/src/transforms/ssrTransformElement.ts +++ b/packages/compiler-ssr/src/transforms/ssrTransformElement.ts @@ -23,7 +23,8 @@ import { hasDynamicKeyVBind, MERGE_PROPS, isBindKey, - createSequenceExpression + createSequenceExpression, + InterpolationNode } from '@vue/compiler-dom' import { escapeHtml, @@ -53,30 +54,40 @@ const rawChildrenMap = new WeakMap< export const ssrTransformElement: NodeTransform = (node, context) => { if ( - node.type === NodeTypes.ELEMENT && - node.tagType === ElementTypes.ELEMENT + node.type !== NodeTypes.ELEMENT || + node.tagType !== ElementTypes.ELEMENT ) { - return function ssrPostTransformElement() { - // element - // generate the template literal representing the open tag. - const openTag: TemplateLiteral['elements'] = [`<${node.tag}`] - // some tags need to be pasesd to runtime for special checks - const needTagForRuntime = - node.tag === 'textarea' || node.tag.indexOf('-') > 0 + return + } - // v-bind="obj" or v-bind:[key] can potentially overwrite other static - // attrs and can affect final rendering result, so when they are present - // we need to bail out to full `renderAttrs` - const hasDynamicVBind = hasDynamicKeyVBind(node) - if (hasDynamicVBind) { - const { props } = buildProps(node, context, node.props, true /* ssr */) - if (props) { - const propsExp = createCallExpression( - context.helper(SSR_RENDER_ATTRS), - [props] - ) + return function ssrPostTransformElement() { + // element + // generate the template literal representing the open tag. + const openTag: TemplateLiteral['elements'] = [`<${node.tag}`] + // some tags need to be pasesd to runtime for special checks + const needTagForRuntime = + node.tag === 'textarea' || node.tag.indexOf('-') > 0 - if (node.tag === 'textarea') { + // v-bind="obj" or v-bind:[key] can potentially overwrite other static + // attrs and can affect final rendering result, so when they are present + // we need to bail out to full `renderAttrs` + const hasDynamicVBind = hasDynamicKeyVBind(node) + if (hasDynamicVBind) { + const { props } = buildProps(node, context, node.props, true /* ssr */) + if (props) { + const propsExp = createCallExpression( + context.helper(SSR_RENDER_ATTRS), + [props] + ) + + if (node.tag === 'textarea') { + const existingText = node.children[0] as + | TextNode + | InterpolationNode + | undefined + // If interpolation, this is dynamic