Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ScopeIds not working on router-view in SSR after upgrading from vue@3.0.7 #3513

Closed
Olli1080 opened this issue Mar 29, 2021 · 8 comments
Closed
Labels
❗ p4-important Priority 4: this fixes bugs that violate documented behavior, or significantly improves perf. 🐞 bug Something isn't working scope: ssr

Comments

@Olli1080
Copy link

Version

3.0.9

Reproduction link

https://github.com/Olli1080/vue-3-ssr-reproduction

Steps to reproduce

Run
npm i
npm start

Open browser on localhost:3000

What is expected?

The scopeId should be applied to the router-view and the header causing the content background to be limegreen

What is actually happening?

The background is white and the scopeId is only missing on the router-view item in the dom.

The background changes to limegreen after navigation
with the scopeId applied


Ran into this after upgrading from vue@3.0.7 to vue@3.0.8 and vue@3.0.9

@HcySunYang HcySunYang added 🐞 bug Something isn't working ❗ p4-important Priority 4: this fixes bugs that violate documented behavior, or significantly improves perf. labels Mar 30, 2021
@HcySunYang
Copy link
Member

HcySunYang commented Mar 30, 2021

A hint, this problem occurs when rendering components with manually written render function between ssr optimized components. E.g.

ComA is scoped, and SSR-optimized:

const _withId =_withScopeId("scope-id")

const CompA = {
  ssrRender = _withId((_ctx, _push, _parent, _attrs) => {
    const RouterView = _resolveComponent("RouterView")
    // Render the <RouterView> component
    _push(_ssrRenderComponent(RouterView, _attrs, null, _parent))
  })
}

RouterView has a hand-written render function:

const RouterView = {
  render() { return h(ViewComp) }
}

ViewComp is also optimized by SSR:

const ViewComp = {
  ssrRender(_ctx, _push, _parent, _attrs) {
    _push(`<p${_attrs}></p>`)
  }
}

This issue occurs in the renderComponentSubTree function, alternating rendering of SSR-optimized and non-SSR-optimized components will break the inheritance of scopeId.

Edit: The following test case can be used as a minimum reproduction:

  test('repro', async () => {
    const Child = {
      ssrRender: (ctx: any, push: any, parent: any, attrs: any) => {
        push(`<div${ssrRenderAttrs(attrs)}></div>`)
      }
    }

    const Middle = {
      render() {
        return h(Child)
      }
    }

    const Comp = {
      __scopeId: 'parent',
      ssrRender: (ctx: any, push: any, parent: any) => {
        push(ssrRenderComponent(Middle, null, null, parent))
      }
    }

    const result = await renderToString(createApp(Comp)) // output: `<div></div>`
    expect(result).toBe(`<div parent></div>`)
  })

@HcySunYang
Copy link
Member

The resolveScopeId function is also problematic. When a component is SSR-optimized, it will no longer have subTree, this will cause the inheritance of scopeId to be broken, the following example can be used to reproduce:

const Child = {
  render() {
    return h('div')
  }
}

const Comp2 = {
  __scopeId: 'parent2',
  ssrRender: (ctx: any, push: any, parent: any) => {
    push(ssrRenderComponent(Child, null, null, parent))
  }
}

const Comp = {
  __scopeId: 'parent',
  ssrRender: (ctx: any, push: any, parent: any) => {
    push(ssrRenderComponent(Comp2, null, null, parent))
  }
}

async function run () {
  // Should output: `<div parent parent2></div>`
  // Actual behavior: `<div parent2></div>`
  console.log(await renderToString(createApp(Comp)))
}
run()

@HcySunYang
Copy link
Member

I have some ideas, and that requires changes to the compiler, but it has a relatively large impact.....

@posva
Copy link
Member

posva commented Mar 30, 2021

@HcySunYang Maybe I could manually add the compiler hints to the render functions to vue router.

@cexbrayat
Copy link
Member

@HcySunYang I suspect we found a similar issue on VTU-next

This template <transition><div></div></transition> (note the lack of content in the div) throws:

Uncaught TypeError: children is null
    filterSingleRoot https://sfc.vuejs.org/vue.runtime.esm-browser.js:2171
    setScopeId https://sfc.vuejs.org/vue.runtime.esm-browser.js:5079
    mountElement https://sfc.vuejs.org/vue.runtime.esm-browser.js:5032

See https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHRlbXBsYXRlPlxuXHQ8dHJhbnNpdGlvbj48ZGl2PjwvZGl2PjwvdHJhbnNpdGlvbj5cbjwvdGVtcGxhdGU+In0=

Is this the same root cause, or should I open a different issue?

@yyx990803
Copy link
Member

@cexbrayat that's a runtime error, definitely a different issue.

@yyx990803
Copy link
Member

yyx990803 commented Mar 30, 2021

@HcySunYang your case in #3513 (comment) won't happen because SSR-optimized HOC components pass attrs down:

const Comp = {
  __scopeId: 'parent',
-  ssrRender: (ctx: any, push: any, parent: any) => {
-    push(ssrRenderComponent(Comp2, null, null, parent))
+  ssrRender: (ctx: any, push: any, parent: any, attrs: any) => {
+    push(ssrRenderComponent(Comp2, attrs, null, parent))
  }
}

playground link (see SSR output)

@yyx990803
Copy link
Member

@cexbrayat the bug you mentioned is fixed in 9cf7525

@github-actions github-actions bot locked and limited conversation to collaborators Oct 22, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
❗ p4-important Priority 4: this fixes bugs that violate documented behavior, or significantly improves perf. 🐞 bug Something isn't working scope: ssr
Projects
None yet
Development

No branches or pull requests

5 participants