Make your VueJS code look more fabulous with class decorator (part 1)

Khai Bui,VueJSTip

Look at VueJS community and decorator apply

The debate between the options API and the compositions API in VueJS has been a hot topic among the developer community since the release of the compositions API in Vue 3.0. Both approaches have their own unique benefits and drawbacks, and choosing the right one will have a big impact on the contribution of your team.

Today, I will intro with you to another way to build Vue project look cooler with class setup and decorator as functionality support. Moreover, we can taste the mixing of traditional javascript class style and compositions API in your Vue 3.0 projects.

Create VueJS project

npm init vue@latest
 Project name:  <your-project-name>
 Add TypeScript?  No / Yes
 Add JSX Support?  No / Yes
 Add Vue Router for Single Page Application development?  No / Yes
 Add Pinia for state management?  No / Yes
 Add Vitest for Unit testing?  No / Yes
 Add an End-to-End Testing Solution?  No / Cypress / Playwright
 Add ESLint for code quality?  No / Yes
 Add Prettier for code formatting?  No / Yes
 
Scaffolding project in ./<your-project-name>...
Done.
> cd <your-project-name>
> npm install
> npm run dev

In official documents of Vue community provide us with some recommendations for using a more modern Vue style in compositions API:

You should now have your first Vue project running! Note that the example components in the generated project are written using the Composition API and <script setup>, rather than the Options API.

Using decorator by vue-facing-decorator

The library is designed for Vue 3 to write Vue components in classes. Works on TypeScript and decorator.

  • The community desired Vue class component with typescript decorators.
  • Safety. Transform es class to Vue options API according to specifications.
  • Performance. Once transform on project loading, ready for everywhere.
  • Support ES class inherit, Vue extends, and Vue mixins.

Add to a project right now by using the command to download the package from NPM:

npm i vue-facing-decorator

Enable experimentalDecorators in tsconfig.json in the project root directory:

{
  "compilerOptions": {
    "experimentalDecorators": true
  }
}

How to use it?

Define a class component

The simplest class component must extend Vue base class and be decorated by Component from this workspace.

import { Component, Vue } from 'vue-facing-decorator'
 
@Component
class MyComponent extends Vue {}

In Vue single-file components

<template>
  <div></div>
</template>
<script lang="ts">
// DO NOT USE <script setup>
 
// Vue options API
/*
import { defineComponent } from "vue";
export default defineComponent({});
*/
 
// Class component
import { Component, Vue } from "vue-facing-decorator";
@Component
export default class MyComponent extends Vue {}
</script>

In separated files with TSX

If you don't want to use single-file components, this is another choice. It use .ts file to define component and import template from .tsx file.

Component.render.tsx
import type Comp from './Comp'
import Style from './style.css'
export default function render(this: Comp) {
  return (
    <div class={Style.root} onClick={this.onClick}>
      {this.counter}
    </div>
  )
}
Component.ts
import { Component, Base } from 'vue-facing-decorator'
import render from './Comp.render'
 
@Component({ render })
export default class Component extends Base {
  counter = 1
 
  onClick() {
    this.counter++
  }
}
style.css
.root {
  background-color: red;
}

The features and performances

@Component decorator

Use the decorator Component to decorate a class that extends from Vue base class.

import { Component, Vue } from 'vue-facing-decorator'
 
@Component({
  ...options, // option here
})
export default class MyComponentWithOptions extends Vue {}

You can find out further detail about options API via official documents:

@Property decorator

In a class component, we could define data of Vue options API as class properties directly. This repo will analyze properties and transform them as the return value of data function.

import { Component, Vue } from 'vue-facing-decorator'
 
@Component
export default class MyComponent extends Vue {
  property = 'property value'
}

@Method decorator

In a class component, we could define methods of vue options API as class methods directly. This repo will analyze methods and transform them into methods options.

import { Component, Vue } from 'vue-facing-decorator'
 
@Component
export default class MyComponent extends Vue {
  method() {
    console.log('This is method! ')
  }
}

@Hook decorator

Class component supports almost all lifecycle hooks in vanilla Vue. Write them as class methods directly. Hooks won't be transformed into methods.

import { Component, Vue } from 'vue-facing-decorator'
 
@Component
export default class MyComponent extends Vue {
  mounted() {}
}

Vue has many built-in hooks for life-cycle as the internal hook. It can not be replaced by override. Your custom hook name must have a different name from that one.

;[
  'beforeCreate',
  'created',
  'beforeMount',
  'mounted',
  'beforeUpdate',
  'updated',
  'activated',
  'deactivated',
  'beforeDestroy',
  'beforeUnmount',
  'destroyed',
  'unmounted',
  'renderTracked',
  'renderTriggered',
  'errorCaptured',
  'serverPrefetch',
  'render',
]

Component props decorator

Use Prop decorator to define a property in Vue's props.

import { Prop, Component, Vue } from 'vue-facing-decorator'
 
@Component
export default class MyComponent extends Vue {
  @Prop
  isOpen?: boolean
}

This decorator can expand to more functionality as validation and type support. You can find out further detail about options API via official documents:

Accessor decorator

Property getters will be transformed into { computed: { get: Foo } }

import { Component, Vue } from 'vue-facing-decorator'
 
@Component
export default class MyComponent extends Vue {
  name = 'Michael Jackson'
 
  get getter() {
    return this.name
  }
 
  set setter(name: string) {
    this.name = name
  }
}

Event decorator

We could define a method that triggers a Vue event by Emit decorator. The decorator received an optional event name parameter. Event will be triggered with this name and the method returned value. If the event name parameter is omitted, use the method's name by default.

import { Emit, Component, Vue } from 'vue-facing-decorator'
 
@Component
export default class MyComponent extends Vue {
  @Emit
  triggerMethodNameEvent() {
    return 'triggerMethodNameEvent value'
  }
 
  @Emit('SpecifiedName')
  triggerSpecifiedNameEvent() {
    return 'triggerSpecifiedNameEvent value'
  }
}

If one event method returns a promise, Event will be triggered after the promise is resolved with the promise value.

import { Emit, Component, Vue } from 'vue-facing-decorator'
 
@Component
export default class MyComponent extends Vue {
  @Emit
  triggerAsyncEvent() {
    return new Promise((resolver) => {
      setTimeout(() => {
        resolver('value')
      }, 1000)
    })
  }
}

Reference decorator

Use Ref decorator to define a property getter this.$refs[name] on Vue component instance. The reference name is the name of the property.

import { Ref, Component, Vue } from 'vue-facing-decorator'
 
@Component
export default class MyComponent extends Vue {
  @Ref
  readonly refEl!: HTMLDivElement
}

@Watch decorator

Use Watch decorator to define a watcher in Vue's watch.

The first parameter is the name watched. Same as Vue watch, the watcher receives two parameters: new value and old value.

import { Watch, Component, Vue } from 'vue-facing-decorator'
 
@Component
export default class MyComponent extends Vue {
  property = 'value'
 
  @Watch('property')
  propertyWatcher(newValue: string, oldValue: string) {}
}

You can find out further detail about options API via official documents:

Conclusion

I introduced you to how to make your Vue code by other styles based on using vue-facing-decorator support. I will have completed decorator styling for store management by Vuex module decorator in the next article. See you soon!

Reference resources

Vue-facing-decorator documentation

© Bùi Quốc Khải.