Skip to content

[compiler-sfc] inconsistent behavior with vue2 when parsing empty blocks #2463

Closed
@meteorlxy

Description

@meteorlxy

Version

3.0.2

Reproduction link

https://codesandbox.io/s/autumn-wildflower-cqpew?file=/src/index.ts

Steps to reproduce

import { parse } from "@vue/compiler-sfc";
import { parse as parse2 } from "@vue/component-compiler-utils";

const source = `\
<template></template>
<script></script>
<style></style>
`;

const vue3 = parse(source);

console.log("vue3", vue3.descriptor);

// template: null
// script: null
// style: []

const vue2 = parse2({
  source,
  compiler: require("vue-template-compiler")
});

console.log("vue2", vue2);

// template: { ... }
// script: { ... }
// style: [{ ... }]

What is expected?

Consistent with vue2, get the descriptor of empty block.

What is actually happening?

The descriptor of empty block is null.

Related issues

Explanation

It seems to be intended as the tests show:

https://github.com/vuejs/vue-next/blob/f4621ff5ee4abe924d985177956af3ddc9bb378f/packages/compiler-sfc/__tests__/parse.spec.ts#L114-L119

However, it may cause some breakings in SFC:

  • An empty <template> block means it should render empty string, which is different from no <template> block.
  • If @vue/compiler-sfc return null for empty <template>, it's difficult for vue-loader / rollup-plugin-vue to determine if the SFC has <template> block or not.

In fact, the only difference is a runtime warning during development:

https://github.com/vuejs/vue-next/blob/288c764e5279ccef63e0ef304d4250f5ad935a46/packages/runtime-core/src/component.ts#L711

IMO:

  • An empty <template> block is intended by user, which should not be warned.
  • No <template> block might be a fault, which should be warned.

Questions / Discussion

As we do not have a full specification for vue SFC, some edge cases are not so specific, and the behavior of vue-loader / rollup-plugin-vue / other implementations can be inconsistent.

Here are some edge cases that might need to be determined:

Case A: SFC has both <template> and script.render:

<template>
  <div></div>
</template>

<script>
export default {
  render() {}
}
</script>

Which is expected?

  • replace script.render with <template>
  • use script.render

Current behavior of vue-loader and rollup-plugin-vue is the first one.

Case B: SFC has empty <template> and script.render:

<template></template>

<script>
export default {
  render() {}
}
</script>

Which is expected?

  • replace script.render with empty <template>
  • use script.render

This is affected by this issue.

Case C: SFC has empty <template>, but does not have script.render:

<template></template>

<script>
export default {
  // no render()
}
</script>

Which is expected?

  • replace script.render with empty <template>
  • replace script.render with a NOOP as default render
  • keep it undefined (will print a runtime warning)

This is affected by this issue.

Case D: SFC does not have <template> nor script.render:

<script>
export default {
  // no render()
}
</script>

Which is expected?

  • replace script.render with a NOOP as default render
  • keep it undefined (will print a runtime warning)

@yyx990803 @sodatea @znck

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions