Skip to content

Commit

Permalink
Merge pull request #4130 from kkukelka/chore/update-style-guide
Browse files Browse the repository at this point in the history
chore: update styleguide with info about composition api
  • Loading branch information
vikiival authored Oct 19, 2022
2 parents c734cb1 + 06d79d9 commit 073214f
Showing 1 changed file with 74 additions and 55 deletions.
129 changes: 74 additions & 55 deletions STYLE_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,34 +20,76 @@ With a few exceptions, code and comments should be written in **English** only.

## SFC Conventions
### Skeleton
99% of the time your SCSS should be **scoped**, so it won't bleed outside of your component and pollute the global namespace!
99% of the time your SCSS should be **scoped**, which makes sure your CSS won't bleed outside of your component and pollute the global namespace!
```vue
<template>
<div>
...
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'nuxt-property-decorator'
import { ComponentOne } from '@/components/ComponentOne.vue'
<script lang="ts" setup>
...
</script>
<style scoped lang="scss"></style>
```

### Composition API
Since we want to upgrade to Nuxt 3 in the near future, we should pre-emptively work towards a compatible codebase, such that the transition will be as smooth as possible. Therefore, every new feature is required to be written in the new **Composition API** and should follow the following recommendations:

```vue
<script lang="ts" setup>
import { computed, reactive, ref, onMounted, watch } from 'vue'
import type { CarouselNFT } from '@/components/base/types'
// declaring props
const props = defineProps<{
nfts: CarouselNFT[]
}>()
interface InterfaceName {
property: type
// reactive state
const count = ref(0)
// functions that mutate state and trigger updates
function increment() {
count.value++
}
@Component({
components: {
ComponentOne
},
const author = reactive({
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
})
// a computed ref
const publishedBooksMessage = computed(() => {
return author.books.length > 0 ? 'Yes' : 'No'
})
watch(count, (newCount) => {
console.log(`count is ${newCount}`)
})
// lifecycle hooks
onMounted(() => {
console.log(`The initial count is ${count.value}.`)
})
export default class ComponentName extends Vue {}
</script>
<style scoped lang="scss"></style>
<template>
<button @click="increment">Count is: {{ count }}</button>
</template>
```
For more details make sure to checkout [Vue's official documentation](https://vuejs.org/guide/introduction.html).

### Property Decorators

### Property Decorators DEPRECATED! (only use this syntax for maintenance reasons)
We rely on the package 'nuxt-property-decorator', hence, we urge you to comply with the [Nuxt Class Component Syntax](https://github.com/nuxt-community/nuxt-property-decorator/)
```typescript
import {
Expand Down Expand Up @@ -90,32 +132,19 @@ Use shorthands for vue attributes

### Fetching Data
Though we haven't yet transitioned most of our data fetching logic to Nuxt lifecycles, the following syntax should be considered best practice:
#### Composition API
```typescript
// pages
import { Component } from 'nuxt-property-decorator'

@Component({
async asyncData({ app, $config, params }) {
const res = await app?.apolloProvider?.clients[$config.prefix].query({
query: queryGql,
variables: {
id: params.id
},
})

return {
data: res.data,
total: res.total,
}
}
// useGraphql is a composable function that is auto-imported without having to use an explicit import statement
// you can then call a specific GraphQL query like this in any of your SFCs
const { data } = useGraphql({
queryName: 'buyEventByProfile',
variables: {
id: address,
},
})
export default class ClassName extends Vue {
data?: Type
total?: Type

[...]
}
```
For reference you can take a look at `useCarousel.ts` and its usage throughout the app. It will show you how to best abstract such calls into its own [composables](https://vuejs.org/guide/reusability/composables.html), which is one of the core concepts behind the Composition API.


### Reusability Through Abstraction
If your component will be used on several occasions in many different contexts, you should think about how you pass data to your components and how events are handled.
Expand All @@ -135,27 +164,17 @@ Regarding event handling, you should always aim to emit events happening in your

Make reusable components as generic as possible. Therefore, the naming should only imply the functionality of the component itself and not what it does in the given context.
```vue
<script lang="ts">
import { Component, Prop, Vue } from 'nuxt-property-decorator'
import { ListItem } from '@/components/ListItem.vue'
<script lang="ts" setup>
// List.vue
import { computed } from 'vue'
import ListItem from './ListItem.vue'
import type { IListItem } from '@/components/base/types'
interface IListItem {
name: string,
text?: string,
}
const props = defineProps<{
items: IListItem[]
}>()
@Component({
components: {
ListItem
},
})
export default class List extends Vue {
@Prop({ type: Array, default: () => [] }) items!: IListItem[]
get getItemsWithText(): IListItem[] {
return this.items.filter(item => item.text) || []
}
}
const getItemsWithText = computed(() => props.items.filter(item => item.text) || [])
</script>
```

Expand Down

0 comments on commit 073214f

Please sign in to comment.