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(plugin-vue): use __vccOpts for vue-class-component #5374

Merged
merged 5 commits into from
Nov 9, 2021

Conversation

borkeszmate
Copy link
Contributor

@borkeszmate borkeszmate commented Oct 21, 2021

Description

We use Vite with Vue 3 and Vue Class Component in class-style syntax.

Since vitejs/plugin-vue 1.8.1 version our apps broke with empty screen showing the following warning on the console: Component is missing template or render function.

The problem is linked to the _sfc_main variable located in packages/plugin-vue/src/main.ts.

Since class-style components utilize export default class {...} so that the value of the _sfc_main variable becomes the exported class itself, while using regular Vue component syntax it should be an object.

let scriptCode = `const _sfc_main = {}`
let map: RawSourceMap | SourceMap | undefined

const script = resolveScript(descriptor, options, ssr)

if (script) {
    // If the script is js/ts and has no external src, it can be directly placed
    // in the main module.
    if ((!script.lang || script.lang === 'ts') && !script.src) {
      scriptCode = compiler.rewriteDefault(
        script.content,
        '_sfc_main',
        script.lang === 'ts'
          ? ['typescript']
          : script.lang === 'tsx'
          ? ['typescript', 'jsx']
          : undefined
      )
      map = script.map
    } else {
      if (script.src) {
        await linkSrcToDescriptor(script.src, descriptor, pluginContext)
      }
      const src = script.src || descriptor.filename
      const langFallback = (script.src && path.extname(src).slice(1)) || 'js'
      const attrsQuery = attrsToQuery(script.attrs, langFallback)
      const srcQuery = script.src ? `&src` : ``
      const query = `?vue&type=script${srcQuery}${attrsQuery}`
      const request = JSON.stringify(src + query)
      scriptCode =
        `import _sfc_main from ${request}\n` + `export * from ${request}` // support named exports
    }

The freshly introduced helper function in packages/plugin-vue/src/helper.ts tries to set values on the _sfc_main variable (assuming it's an object, althougt in this case it's a class) declared in attachedProps like this:

export default (sfc, props) => {

  if (typeof sfc === 'function' ) {
    sfc = {};
  }

  for (const [key, val] of props) {
    sfc[key] = val
  }

  return sfc;
}

Since _sfc_main passed as an argument is a js class, properties are not set corrently. As render function is not present on _sfc_main, __VUE_HMR_RUNTIME__.createRecord(_sfc_main.__hmrId, _sfc_main) leads to HMR error causing an empty page.

This little PR modifies the helper function and checks if _sfc_main is a class and if so, it sets its value to and empty object, thus render function is set correctly.

Fixing this Vue Class Component related issue would be highly desired and appreciated by merging this PR or by other solution since most of our mid-sized projects rely on class based Vue.

Thank you!

Additional context

none

Reproduction

The malfunction can be easily reproduced from the following issue: #5352
or https://github.com/borkeszmate/vite-vue-plugin-bug (navigate to about)


What is the purpose of this pull request?

  • Bug fix
  • New Feature
  • Documentation update
  • Other

Before submitting the PR, please make sure you do the following

  • Read the Contributing Guidelines.
  • Read the Pull Request Guidelines and follow the Commit Convention.
  • Check that there isn't already a PR that solves the problem the same way to avoid creating a duplicate.
  • Provide a description in this PR that addresses what the PR is solving, or reference the issue that it solves (e.g. fixes #123).
  • Ideally, include relevant tests that fail without this PR but pass with it.

@borkeszmate borkeszmate changed the title fix(plugin-vue) vue-class-component - Component is missing template or render function. fix(plugin-vue): vue-class-component - Component is missing template or render function. Oct 22, 2021
@calebeaires
Copy link

This is highly desired.

Shinigami92
Shinigami92 previously approved these changes Nov 2, 2021
@borkeszmate
Copy link
Contributor Author

@sodatea, please take it as a friendly enquiry. When could you take a quick look at this little PR? :)

Copy link
Member

@haoqunjiang haoqunjiang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@patak-dev patak-dev changed the title fix(plugin-vue): vue-class-component - Component is missing template or render function. fix(plugin-vue): use __vccOpts for vue-class-component Nov 9, 2021
@patak-dev patak-dev merged commit c4f9db2 into vitejs:main Nov 9, 2021
@alykamb
Copy link
Contributor

alykamb commented Nov 17, 2021

Hi, thanks for the fix, will it take long to be deployed to npm?

@haoqunjiang
Copy link
Member

It's already in 2.7 beta.

@alykamb
Copy link
Contributor

alykamb commented Nov 17, 2021

I meant the package plugin-vue, or these changes can be imported from vite directly as well?

@haoqunjiang
Copy link
Member

Oh sorry, I didn't realize that. It shall be available soon in the coming releases.

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

Successfully merging this pull request may close these issues.

6 participants