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

Support vue-class-component #1476

Closed
pavellzubkov opened this issue Jan 10, 2021 · 19 comments
Closed

Support vue-class-component #1476

pavellzubkov opened this issue Jan 10, 2021 · 19 comments

Comments

@pavellzubkov
Copy link

Is your feature request related to a problem? Please describe.
vite can't build component when using class component. error - expected class, but get const ...

@Djaler
Copy link

Djaler commented Jan 11, 2021

I think this is a problem with https://github.com/underfin/vite-plugin-vue2

@pavellzubkov
Copy link
Author

i've been trying with vue3 and oficial vite vue plugin.

@Djaler
Copy link

Djaler commented Jan 11, 2021

Ok, I just thought the problem is inside vue2 plugin because I saw it in stacktrace

@pavellzubkov
Copy link
Author

May be class api and vue-class-component have type issues and not planned to be supported in vite...

@C0Nd3Mnd
Copy link

Full error (I truncated the paths):

[vite] Internal server error: Transform failed with 1 error:
/truncated_path/src/App.vue:10:0: error: Expected "class" but found "const"
  Plugin: vite:vue
  File: /truncated_path/src/App.vue

  Expected "class" but found "const"
  7  |      HelloWorld
  8  |    }
  9  |  })
     |     ^
  10 |  const _sfc_main = class App extends Vue {}
     |  ^
  11 |

      at failureErrorWithLog (C:\truncated_path\node_modules\esbuild\lib\main.js:969:15)
      at C:\truncated_path\node_modules\esbuild\lib\main.js:852:33
      at handleIncomingPacket (C:\truncated_path\node_modules\esbuild\lib\main.js:566:9)
      at Socket.readFromStdout (C:\truncated_path\node_modules\esbuild\lib\main.js:482:7)
      at Socket.emit (events.js:315:20)
      at addChunk (internal/streams/readable.js:309:12)
      at readableAddChunk (internal/streams/readable.js:284:9)
      at Socket.Readable.push (internal/streams/readable.js:223:10)
      at Pipe.onStreamRead (internal/stream_base_commons.js:188:23)

package.json:

{
  "name": "project_name",
  "version": "0.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vuedx-typecheck . && vite build"
  },
  "dependencies": {
    "vue": "^3.0.5",
    "vue-class-component": "^8.0.0-rc.1"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^1.0.4",
    "@vue/compiler-sfc": "^3.0.5",
    "@vuedx/typecheck": "^0.4.1",
    "@vuedx/typescript-plugin-vue": "^0.4.1",
    "autoprefixer": "^10.2.1",
    "postcss": "^8.2.4",
    "tailwindcss": "^2.0.2",
    "typescript": "^4.1.3",
    "vite": "^2.0.0-beta.12"
  }
}

App.vue:

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <HelloWorld msg="Hello Vue 3 + Vite" />
</template>

<script lang="ts">
import { Vue, Options } from 'vue-class-component'
import HelloWorld from './components/HelloWorld.vue'

@Options({
  components: {
    HelloWorld
  }
})
export default class App extends Vue {}
</script>

It works if you remove the @Options decorator. That's not a solution though.

@alykamb
Copy link
Contributor

alykamb commented Jan 19, 2021

The issue is that vite changes the "export default class" to const _sfc_main, and its not possible to decorate a variable. Thus a workaround is to create the class and export it in another line of code:

@Options({
    components: {HelloWorld}
})
class App extends Vue {}

export default App

@n1kk
Copy link

n1kk commented Jan 25, 2021

Had same issue, tried re-exporting class and now I have this error:

> vite

Optimizable dependencies detected:
vue, vue-class-component, vue-property-decorator
Pre-bundling them to speed up dev server page load...
(this will be run only when your dependencies or config have changed)
 > node_modules/vue-class-component/dist/vue-class-component.esm.js: error: No matching export for import
"default"
    6 │ import Vue from 'vue';
      ╵        ~~~

 > node_modules/vue-property-decorator/lib/index.js: error: No matching export for import "default"
    3 │ import Vue from 'vue';
      ╵        ~~~

@yyx990803
Copy link
Member

@n1kk Vue 3 doesn't have a default export. Looks like you are using vue-class-component v7 which is for Vue 2.

@n1kk
Copy link

n1kk commented Jan 26, 2021

Thanks @yyx990803, updating to beta v8 of vue-class-component helped with first error, the issue vue-property-decorator is still there. They don't have a vue3 version ready yet, so I guess it's not possible to use property decorators for now.

@C0Nd3Mnd
Copy link

They don't have a vue3 version ready yet, so I guess it's not possible to use property decorators for now.

I thought most (if not all) of the functionality of vue-property-decorator is available in vue-class-component now, making it no longer necessary.

@n1kk
Copy link

n1kk commented Jan 26, 2021

I thought most (if not all) of the functionality of vue-property-decorator is available in vue-class-component now, making it no longer necessary.

Is it? They don't have the docs for the new version yet. At least I couldn't find it.

@C0Nd3Mnd
Copy link

@n1kk This is part of the vue-class-component.d.ts file (8.0.0-rc1):

// ...
export declare function prop<T>(options: PropOptionsWithDefault<T>): WithDefault<T>;

export declare function prop<T>(options: PropOptionsWithRequired<T>): T;

export declare function prop<T>(options: Prop<T>): T | undefined;

export declare interface PropOptions<T = any, D = T> {
    type?: PropType<T> | true | null;
    required?: boolean;
    default?: D | DefaultFactory<D> | null | undefined | object;
    validator?(value: unknown): boolean;
}

export declare interface PropOptionsWithDefault<T, D = T> extends PropOptions<T, D> {
    default: PropOptions<T, D>['default'];
}

export declare interface PropOptionsWithRequired<T, D = T> extends PropOptions<T, D> {
    required: true;
}

export declare type PublicProps = VNodeProps & AllowedComponentProps & ComponentCustomProps;
// ...

It doesn't contain any comments and I haven't played around with it a lot yet, but I'd imagine you'd use it somewhat like this:

import { Vue, prop } from 'vue-class-component'

class MyComponent extends Vue {
  @prop({
    type: String,
    required: false,
    default: ''
  })
  private example!: string
}

However, when using it with vite, it compiles fine, but I get this error in Chromium:

Uncaught TypeError: decorator is not a function
    at __decorate (MyComponent.vue:7)
    at MyComponent.vue:23

Not sure if I'm using it completely wrong or if vite just doesn't support it properly yet.

@alykamb
Copy link
Contributor

alykamb commented Jan 26, 2021

@n1kk This is part of the vue-class-component.d.ts file (8.0.0-rc1):

// ...
export declare function prop<T>(options: PropOptionsWithDefault<T>): WithDefault<T>;

export declare function prop<T>(options: PropOptionsWithRequired<T>): T;

export declare function prop<T>(options: Prop<T>): T | undefined;

export declare interface PropOptions<T = any, D = T> {
    type?: PropType<T> | true | null;
    required?: boolean;
    default?: D | DefaultFactory<D> | null | undefined | object;
    validator?(value: unknown): boolean;
}

export declare interface PropOptionsWithDefault<T, D = T> extends PropOptions<T, D> {
    default: PropOptions<T, D>['default'];
}

export declare interface PropOptionsWithRequired<T, D = T> extends PropOptions<T, D> {
    required: true;
}

export declare type PublicProps = VNodeProps & AllowedComponentProps & ComponentCustomProps;
// ...

It doesn't contain any comments and I haven't played around with it a lot yet, but I'd imagine you'd use it somewhat like this:

import { Vue, prop } from 'vue-class-component'

class MyComponent extends Vue {
  @prop({
    type: String,
    required: false,
    default: ''
  })
  private example!: string
}

However, when using it with vite, it compiles fine, but I get this error in Chromium:

Uncaught TypeError: decorator is not a function
    at __decorate (MyComponent.vue:7)
    at MyComponent.vue:23

Not sure if I'm using it completely wrong or if vite just doesn't support it properly yet.

I could be wrong, but I don't think those prop types are for decorators. I managed to get it working with https://github.com/calebeaires/vue-decorator

@C0Nd3Mnd
Copy link

I was talking nonsense then, I was just assuming that's how it might work.

Thanks for the heads-up.

@yyx990803
Copy link
Member

As of @vitejs/plugin-vue@1.1.3 the following should work as expected:

<template>
  <div>{{ count }}</div>
  <button @click="increment">+1</button>
</template>

<script lang="ts">
import { Vue, Options } from 'vue-class-component'

// Component definition
@Options({
  // Define component options
  watch: {
    count: value => {
      console.log(value)
    }
  }
})
export default class Counter extends Vue {
  // The behavior in class is the same as the current
  count = 0

  increment() {
    this.count++
  }
}
</script>

@biggestcookie
Copy link

As of @vitejs/plugin-vue@1.1.3 the following should work as expected:

Using the example, I seem to be running into an error if I don't include @Options.

<template>
  <div>{{ count }}</div>
  <button @click="increment">+1</button>
</template>

<script lang="ts">
import { Vue } from "vue-class-component";

export default class App extends Vue {
  count = 0;

  increment() {
    this.count++;
  }
}
</script>
[plugin:vite:vue] Transform failed with 1 error:
/src/App.vue:2:41: error: Expected ";" but found "class"
/src/App.vue:2:41
Expected ";" but found "class"
1  |  
2  |  import { Vue } from "vue-class-component"class App extends Vue {
   |                                           ^
3  |    count = 0;

package.json:

"dependencies": {
    "vue": "^3.0.5",
    "vue-class-component": "^8.0.0-rc.1",
    "vue-router": "^4.0.4"
},
"devDependencies": {
    "@types/node": "^14.14.32",
    "@typescript-eslint/eslint-plugin": "^4.17.0",
    "@typescript-eslint/parser": "^4.17.0",
    "@vitejs/plugin-vue": "^1.1.5",
    "@vue/compiler-sfc": "^3.0.7",
    "@vue/eslint-config-prettier": "^6.0.0",
    "@vue/eslint-config-typescript": "^7.0.0",
    "@vuedx/typecheck": "^0.6.0",
    "@vuedx/typescript-plugin-vue": "^0.6.0",
    "eslint": "^7.21.0",
    "eslint-plugin-prettier": "^3.3.1",
    "eslint-plugin-vue": "^7.6.0",
    "prettier": "^2.2.1",
    "sass": "^1.32.8",
    "typescript": "^4.2.3",
    "vite": "^2.0.5"
}

@alykamb
Copy link
Contributor

alykamb commented Mar 9, 2021

It also happens if extending mixins instead of Vue directly:

import { mixins } from 'vue-class-component'

import { Input } from './input'

export default class FormDatepicker extends mixins(Input) {}

The workaround still works, move the export default to another line of code:

import { mixins } from 'vue-class-component'

import { Input } from './input'

class FormDatepicker extends mixins(Input) {}
export default FormDatepicker

The issue was not happening in version 2.0.0-beta.69, but happens in 2.0.5

@charles-allen
Copy link

Likewise it seems Vite clashes with vue-class-component's MyClass extends Vue.with(Props) syntax.

Perhaps a different issue because it doesn't work on any of 2.0.0-beta.69, 2.0.5, 2.3.6, and sadly splitting export default doesn't seem to fix it:

Works (all versions):

@Options({ props: { slug: String } })
class Event extends Vue {
  slug!: string
  ...
}
export default Event

Doesn't work (all versions) -- does work with Webpack

class Event extends Vue.with(class {
  slug!: string
}) {
  ...
}
export default Event

@github-actions
Copy link

This issue has been locked since it has been closed for more than 14 days.

If you have found a concrete bug or regression related to it, please open a new bug report with a reproduction against the latest Vite version. If you have any other comments you should join the chat at Vite Land or create a new discussion.

@github-actions github-actions bot locked and limited conversation to collaborators Jul 16, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants