Standardization for developing pyeongyang UI with reasonable performance approach
Before Continue to the content make sure you already read and understand this following concept or tutorials
- Common
- Naming
- CSS
- VueJs
- Commit Message Standardization
//bad approach
<template>
<div>
<div class="header"><div class="header__left">Logo</div><div class="header__right">User</div></div>
</div>
</template>
//good approach
<template>
<div>
<div class="header">
<div class="header__left">Logo</div>
<div class="header__right">User</div>
</div>
</div>
</template>
//bad approach
export default {
name: 'test',
props: {
students: {
type: Array,
default: []
}
},
computed: {
goodStudents () {
return this.students.length > 0 && this.students.filter(student => { return student.score > 7 && student.extracurricular > 2})
}
}
}
//good approach
export default {
name: 'test',
props: {
students: {
type: Array,
default: []
}
},
computed: {
goodStudents () {
return this.students.length > 0 && this.students.filter(student => {
return student.score > 7 && student.extracurricular > 2
})
}
}
}
//best approach
export default {
name: 'test',
props: {
students: {
type: Array,
default: []
}
},
computed: {
goodStudents () {
return this.students.length > 0 &&
this.students.filter(student => {
return student.score > 7 &&
student.extracurricular > 2
})
}
}
}
//bad approach
const variable1 = {name : 'cat'}
const variable2 = variable1
const variable3 = ['lucky', 'cat']
const variable5 = variable3
//good approach
const variable1 = {name : 'cat'}
const variable2 = Object.assign({}, variable1)
const variable3 = ['lucky', 'cat']
const variable5 = variable3.slice(0)
//best approach
const variable1 = {name : 'cat'}
const variable2 = {...variable1}
const variable3 = ['lucky', 'cat']
const variable5 = [...variable3]
Reduce image until it's very small with tinypng.com Reduce svg size with https://jakearchibald.github.io/svgomg/ with compression level 2
Vue Component name
Reference: https://vuejs.org/v2/style-guide/#Multi-word-component-names-essential
<ComponentName /> // If you don't give any attribute use self closing tag
<ComponentName
:title="title"
></ComponentName>
export default {
name: 'ComponentName',
}
Vue Props name
<ComponentName
:component-props="data"> //use kebab case for props name
></ComponentName>
export default {
name: 'ComponentName',
props: {
componentProps: { // use camelCase
type: 'Object', //better define the props type
default: () => ({}) // better give default value for props
}
}
}
In Pyeongyang UI we are agreed to use scss
// bad approach
.header {}
.header__left {}
.header__middle {}
.header__middle__search {}
.header__right {}
// bad approach
.header {}
.left {}
.middle {}
.middle .search {}
.right {}
// good approach
.header {
&__left {}
&__middle {
&__search {}
}
&__right {}
}
// best approach
//break the chain if you're already inside element
.header {
&__left {}
&__middle {
.search {}
}
&__right {}
}
Use VueJs files template by this following order
<template>
</template>
//use external javascript from js folder
<script src="./js/${fileName}"></script>
//use scss style and scoped the style
<style lang="scss" scoped></style>
Use Javascript template by this following order. use as needed. No need create all this lifecycle Hooks!
export default {
name: 'App',
components: {},
props: {},
data () {
return {}
},
beforeCreate(){},
created () {
//Will be execute before the UI being rendered
//Used for important API Calls
},
beforeMount (){},
mounted () {
//Will be execute After the UI being rendered
//Used for DOM manipulation and less important API Calls
},
computed: {},
methods: {},
watch: {},
beforeDestroy: {},
destroyed: {}
}
Use Async import for all component (Code Splitting Approach)
const TestComponent = () => import(
/* webpackChunkName: "c-test-component"*/ '@/components/TestComponent.vue')
export default {
name: 'Test',
components: {
TestComponent
},
}
Import only spesific function you want to use (Tree Shaking Approach)
import { currencyFormat } from '@/utils'
export default {
name: 'App',
data() {
return {
price: 1000
}
},
computed: {
priceInIdr() {
return currencyFormat(this.price)
}
}
}
This filter feature will be deprecated in Vue 3 versions
Reference: https://eslint.vuejs.org/rules/no-deprecated-filter.html
Better using utils instead filter
import { currencyFormat } from '@/filters'
export default {
name: 'App',
data() {
return {
price: 1000
}
},
filters: {
currencyFormat
},
}
<template>
<div>{{ price | currencyFormat }}</div>
</template>
How To use it
- Read supportsWebP variable from pyeongyang main store
- Add util with name "asset.js"
import store from '@/store'
function akamaiImage (url) {
if (!url) return
if (!store.getters.supportsWebP || url.indexOf('.gif') > -1) return url
const prefix = url.indexOf('?') > -1 ? '&' : '?'
return url + prefix + 'output-format=webp'
}
export { akamaiImage }
- Add mixins with name "akamai-image-mixin.js"
import { akamaiImage } from '@/util/asset'
export default {
methods: {
akamaiImage
}
}
- Add to mixins to your component Js
import AkamaiImageMixin from '@/mixins/akamai-image-mixin'
mixins: [
AkamaiImageMixin
]
- Use It in your template vue
<lazy-image
class="lazy-image"
:lazy-src="akamaiImage(test.imageUrl)"
/>
${Type} - {Subject}
${Body}
${Reference}
This should be filled by type of your task
- feature: add new feature
- bugfix: a bug fixing
- test: unit test improvement
- config: updating depedencies or build configuration
Essence description about your task
To explain something about the task or explain how you doing this task
For external when doing the task
feature - product review detail implementation
register new routes for review detail page,
add new pages component for review detail,
breakdown each content into smaller components (review info, review rating, review other product)
create interaction with lazy load component using intersection observer
https://app.zeplin.io/project/123123
https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
https://stackoverflow.com/questions/43663665/what-is-the-use-case-of-intersectionobserver
bugfix - fixing broken image in my review page if backend didn't return the correct image url
add blibli.com default image if the image is not found
config - Add vue-cat-carousel and vue-h-zoom library
add vue-cat-carousel for product review page in other review component
add vue-h-zoom for my review page in zoomable review image component
https://www.npmjs.com/package/vue-cat-carousel