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

fix(slot): add a function to return the slot fallback content #12014

Merged
merged 2 commits into from Apr 16, 2021

Conversation

posva
Copy link
Member

@posva posva commented Apr 16, 2021

slot fallback content should be evaluated only when the parent is not providing it.

What kind of change does this PR introduce? (check at least one)

  • Bugfix
  • Feature
  • Code style update
  • Refactor
  • Build-related changes
  • Other, please describe:

Does this PR introduce a breaking change? (check one)

  • Yes
  • No

If yes, please describe the impact and migration path for existing applications:

The PR fulfills these requirements:

If adding a new feature, the PR's description includes:

  • A convincing reason for adding this feature (to avoid wasting your time, it's best to open a suggestion issue first and wait for approval before working on it)

Other information:

fixes #10224

zrh122 and others added 2 commits April 16, 2021 17:12
slot fallback content should be evaluated only when the parent is not providing it.
@posva
Copy link
Member Author

posva commented Apr 16, 2021

Sorry for the delay and thanks a lot @zrh122 !

@posva posva merged commit ce457f9 into dev Apr 16, 2021
@posva posva deleted the delay-render-slot-fallback branch April 16, 2021 15:37
@posva posva moved this from In Review to Done in 2.6.13 Apr 16, 2021
@BryanAdamss
Copy link

Its render a empty node with this case;

My rollup project environment

rollup-plugin-vue@5.1.9
vue@2.6.14
vue-template-compiler@2.6.14

My rollup project code

<template>
   <div class="c-Box">
       <slot>
          <h1>this is a title</h1>
       </slot>
   </div>
</temlate>

When i use rollup bundle it and use bundle in demo project(init with vue-cli@2,use vue@2.6.12 and vue-template-compiler@2.6.12 ),slot can not render fallback content,it get a undefined

My demo project code

<template>
   <div class="c-Demo">
        <CBox></CBox>
   </div>
</temlate>

I try to upgrade demo project vue and vue-template-compiler version to 2.6.14(equal rollup project vue version),still not working。

When i reduce rollup project vue and vue-template-compiler version to 2.6.12 ,its working!!!

Did I use it right?

@posva
Copy link
Member Author

posva commented Jun 18, 2021

Templates compiled with 2.6.14 are only compatible with projects running >=2.6.14 while templates compiled with 2.6.12 are compatible with projects running >=2.6.12

@BryanAdamss
Copy link

Templates compiled with 2.6.14 are only compatible with projects running >=2.6.14 while templates compiled with 2.6.12 are compatible with projects running >=2.6.12

got it 👍

@minikinl
Copy link

Templates compiled with 2.6.14 are only compatible with projects running >=2.6.14 while templates compiled with 2.6.12 are compatible with projects running >=2.6.12

The code compiled by the 2.6.13+ compiler will show the slot fallback content as "undefined" when running in
v2.6.12 and below.

截屏2021-07-11 下午9 41 36

The problem is very easy to encounter, especially when develop a vue lib by vue-cli@latest, since CLI tool will install the latest version of vue and vue-template-compiler by default. And it is hard to debug.

In order to fix this problem in the old versions, we can only set the dependency to v2.6.12 and below hardly. eg:

// package.json
{
    "decDependencies": {
        "vue": "2.6.12",
        "vue-template-compiler": "2.6.12"
    }
}

And be very careful to set the version in package-lock.json, because some projects do not have a lock file at all (such as ant-desing-vue), although this is their fault.

In fact, it only needs a little code to be compatible with lower versions, eg:

// src/core/instance/render-helpers/render-slot.js
export function renderSlot (
  name: string,
  fallback: ?Array<VNode>,
  props: ?Object,
  bindObject: ?Object
): ?Array<VNode> {
  // ...
}
renderSlot.delay = true;

// or set  `_delay` prop to all instance
// src/core/instance/render-helpers/index.js
// export function installRenderHelpers (target: any) {
//  ...
//  target._delay = true;
//}

// and
// src/compiler/codegen/index.js:546
function genSlot (el: ASTElement, state: CodegenState): string {
  const slotName = el.slotName || '"default"'
  // if vue runtime supports delay evaluate slot fallback content feature,
  // then return a function as current compiler do,
  // or return a object array as old versions do.
  const children = `
    (function () {
      function fallback() {
        return ${genChildren(el, state)};
      }
      return _t.delay ? fallback : fallback();
    })()
  `;
  let res = `_t(${slotName}, ${children}`
  const attrs = el.attrs || el.dynamicAttrs
    ? genProps((el.attrs || []).concat(el.dynamicAttrs || []).map(attr => ({
        // slot props are camelized
        name: camelize(attr.name),
        value: attr.value,
        dynamic: attr.dynamic
      })))
    : null
  const bind = el.attrsMap['v-bind']
  if (attrs) {
    res += `,${attrs}`
  }
  if (bind) {
    res += `${attrs ? '' : ',null'},${bind}`
  }
  return res + ')'
}

Gist: https://gist.github.com/mozhs/485222d9f51f97136134c461338786e0

@ihepta
Copy link

ihepta commented Aug 4, 2021

for me, when i want to build a library, eg "element-ui/page-header"

// element-ui/packages/page-header/src/main.vue
<template>
  <div class="el-page-header">
    <div class="el-page-header__left" @click="$emit('back')">
      <i class="el-icon-back"></i>
      <div class="el-page-header__title">
        <slot name="title">{{ title }}</slot>
      </div>
    </div>
    <div class="el-page-header__content">
      <slot name="content">{{ content }}</slot>
    </div>
  </div>
</template>
...

the build result diff between use these two version:

"devDependencies": {
    "vue": "2.6.12",
    "vue-template-compiler": "2.6.12"
}
"devDependencies": {
    "vue": "2.6.13",
    "vue-template-compiler": "2.6.13"
}

image

when render the page, it's going wrong!
it render a empty tag, seems that function didn't be called.

image
image

now, I can only set the dependency to v2.6.12.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
No open projects
Development

Successfully merging this pull request may close these issues.

Default slot content should not be evaluated when the parent is providing it
5 participants