Performant Components
Through customisation

Maya Shavin
@mayashavin

Sr. Developer @

Sr. Developer @

@mayashavin
Sr. Front-end Developer

Core maintainer @StorefrontUI

Founder @VueJSIsrael
Blogger




🇻🇳
🇮🇱
Nuxt.js Ambassador
Blogger
Maya Shavin
@mayashavin

Sr. Developer @
console.log( )







1200x800
1MB
1200x800
300kB
500x500
crop: thumb
500x500
{gravity: auto}
500x500
Hokusai effect
{radius: max, dpr: auto, art effect: hokusai}
500x500
Stamp effect
{e_red: 50, e_vectorize: 2:0.2 }
https://res.cloudinary.com/mayashavin/image/upload/v1576101486/maya_shavin.jpg
https://res.cloudinary.com/mayashavin/image/upload/w_500,h_500,c_thumb/v1576101486/maya_shavin.jpg
https://.../image/upload/w_500,h_500,c_crop,g_auto/v1576101486/maya_shavin.jpg
https://.../image/upload/w_500,h_500,c_thumb,r_max,dpr_auto,g_auto,e_art:hokusai/v1576101486/maya_shavin.png
https://res.cloudinary.com/mayashavin/image/upload/q_auto/v1576101486/maya_shavin.jpg
https://.../image/upload/w_500,h_500,c_thumb,r_max,dpr_auto,g_auto,e_red:50/e_vectorize:2:0.2/.../maya_shavin.png
Maya Shavin
@mayashavin

Sr. Developer @
UI Components library





Maya Shavin
@mayashavin

Sr. Developer @
Reusable
UI_component_lib.component
Stylable
Customizable
Responsive








Isolate & Testable
Maya Shavin
@mayashavin

Sr. Developer @


Visual consistency
Functional consistency

UI_component_lib.component
UI
UX
Maya Shavin
@mayashavin

Sr. Developer @


Maya Shavin
@mayashavin

Sr. Developer @
Build a good component library
===
Build a design system
That's the talk!
Maya Shavin
@mayashavin

Sr. Developer @
select(UI_component_lib)
Meet the goal
Performance
Customizability
Simplicity
Ease of use
Maya Shavin
@mayashavin

Sr. Developer @
Meet the goal
How do you know what I am looking for?
Maya Shavin
@mayashavin

Sr. Developer @
Define goal
Style guides
Planning
Implementation
Good planning === less breaking changes
Maya Shavin
@mayashavin

Sr. Developer @
StorefrontUI.defineGoals()
PRIORITIZE customization
Code-compatible for ~80% design cases
FOR-EVERY-NEED components?
E-commerce component focus
HAS-EVERYTHING library?
Desktop-then-mobile
Mobile-FIRST
Maya Shavin
@mayashavin

Sr. Developer @
Performance
Faster loading is everything about performance?
Maya Shavin
@mayashavin

Sr. Developer @
console.log(performance)
Delivery
Development
Stand-alone component
Number of props
Dependencies
Implementation direction
Code structure
Simpler structure
Faster development
Faster delivery
Consumed size
Bundling speed
Loading time
Installing effort
Maya Shavin
@mayashavin

Sr. Developer @
Customizability
Are you ready for me to turn component upside down?
Maya Shavin
@mayashavin

Sr. Developer @
console.log(customizability)
Icons
Content design
Out of scope functionality design
Style guides
Component-based








Colors & Themes
Typography
Paddings, margins, sizes


Maya Shavin
@mayashavin

Sr. Developer @
style_guides.customize()

CSS class?

SCSS variables
CSS variables

:root {
// Font Family
--body-font-family-primary: 'Roboto', serif;
--body-font-family-secondary: 'Raleway', sans-serif;
// Font weight
--body-font-weight-primary: 300;
--body-font-weight-secondary: 400;
// Font sizes
--font-size-extra-small: .625rem;
--font-size-small: .75rem;
--font-size-regular: .875rem;
--font-size-big: 1rem;
--font-size-extra-big: 1.125rem;
}

.my-awesome-theme {
--body-font-family-secondary: CURSIVE;
}

Maya Shavin
@mayashavin

Sr. Developer @
component.customize(template)

<SfButton
class="color-primary"
>
Learn More
</SfButton>

<SfButton
class="color-primary"
icon="chevron-right"
icon-pos="left"
>
Learn More
</SfButton>
<SfButton
class="color-primary"
icon="chevron-right"
icon-pos="left"
icon-color="red"
@on-icon-click="onIconClick"
>
Learn More
</SfButton>
<SfButton
class="color-primary"
icon="chevron-right"
icon-pos="left"
icon-size="lg"
>
Learn More
</SfButton>
<SfButton
class="color-primary"
>
<SfIcon
icon="chevron_right"
size="xxs"
color="white"/>
Learn More
</SfButton>
<button
class="sf-button"
v-bind="$attrs"
:disabled="disabled"
v-on="$listeners"
>
<!--@slot Use this slot to place content inside the button.-->
<slot />
</button>
Cover MOST COMMON use cases
(~80% users)
Use <slot> for 20% left
SfButton.vue
Endless props !== cover ALL cases
Maya Shavin
@mayashavin

Sr. Developer @
component.customize(icon)
Single color
SVG paths
Minimal form
Scale in size
<svg aria-hidden="true" focusable="false" data-prefix="fas"
data-icon="cloud" class="svg-inline--fa fa-cloud fa-w-20"
role="img" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 640 512"
>
<path
fill="currentColor"
d="M537.6 226.6c4.1-10.7 6.4-22.4 6.4-34.6 0-53-43-96-96-96-19.7
0-38.1 6-53.3 16.2C367 64.2 315.3 32 256 32c-88.4 0-160 71.6-160
160 0 2.7.1 5.4.2 8.1C40.2 219.8 0 273.2 0 336c0 79.5 64.5 144
144 144h368c70.7 0 128-57.3 128-128 0-61.9-44-113.6-102.4-125.4z">
</path>
</svg>
<SfIcon
icon="home"
size="lg"
color="primary"
/>

<SfIcon
icon="M537.6 226.6c4.1-10.7 6.4-22.4 6.4-34.6 0-53-43-96-96-96-19.7
0-38.1 6-53.3 16.2C367 64.2 315.3 32 256 32c-88.4 0-160 71.6-160
160 0 2.7.1 5.4.2 8.1C40.2 219.8 0 273.2 0 336c0 79.5 64.5 144
144 144h368c70.7 0 128-57.3 128-128 0-61.9-44-113.6-102.4-125.4z"
viewBox="0 0 640 512"
size="lg"
color="primary"
/>
<SfIcon
icon="M537.6 226.6c4.1-10.7 6.4-22.4 6.4-34.6 0-53-43-96-96-96-19.7
0-38.1 6-53.3 16.2C367 64.2 315.3 32 256 32c-88.4 0-160 71.6-160
160 0 2.7.1 5.4.2 8.1C40.2 219.8 0 273.2 0 336c0 79.5 64.5 144
144 144h368c70.7 0 128-57.3 128-128 0-61.9-44-113.6-102.4-125.4z"
viewBox="0 0 640 512"
size="lg"
color="#7714b3"
/>
<SfIcon
icon="M537.6 226.6c4.1-10.7 6.4-22.4 6.4-34.6 0-53-43-96-96-96-19.7
0-38.1 6-53.3 16.2C367 64.2 315.3 32 256 32c-88.4 0-160 71.6-160
160 0 2.7.1 5.4.2 8.1C40.2 219.8 0 273.2 0 336c0 79.5 64.5 144
144 144h368c70.7 0 128-57.3 128-128 0-61.9-44-113.6-102.4-125.4z"
viewBox="0 0 640 512"
size="10rem"
color="#7714b3"
/>

<svg viewBox="0 0 14 10" preserveAspectRatio="none">
<path d="M11.8125 9.8125H2.1875C1.46289 9.8125 0.875 9.22461
0.875 8.5V1.5C0.875 0.775388 1.46289 0.1875 2.1875
0.1875H11.8125C12.5371 0.1875 13.125 0.775388 13.125
1.5V8.5C13.125 9.22461 12.5371 9.8125 11.8125 9.8125ZM2.1875
1.0625C1.94578 1.0625 1.75 1.25828 1.75 1.5V8.5C1.75 8.61594
1.79594 8.7275 1.87797 8.80953C1.96 8.89156 2.07156 8.93749
2.18749 8.93749H11.8125C11.9284 8.93749 12.04 8.89156 12.122
8.80953C12.2041 8.72749 12.25 8.61593 12.25 8.5V1.5C12.25 1.38406
12.2041 1.2725 12.122 1.19047C12.04 1.10844 11.9284 1.06251
11.8125 1.06251L2.1875 1.0625Z"
style="height: 100%;"></path>
<path d="M7.00088 5.21008C6.71158 5.21063 6.42995 5.11492 6.20025
4.93883L1.33959 1.19817C1.14763 1.05051 1.111 0.775439 1.25865
0.583485C1.40631 0.391531 1.68138 0.354893 1.87334 0.502549L6.734
4.24321C6.8915 4.36407 7.11025 4.36407 7.26775 4.24321L12.1284
0.502549C12.3204 0.354891 12.5954 0.391533 12.7431 0.583485C12.8907
0.775438 12.8541 1.05051 12.6622 1.19817L7.80149 4.93883C7.57181
5.11492 7.29017 5.21062 7.00086 5.21008H7.00088Z"
style="height: 100%;"></path>
</svg>
<SfIcon
:icon="[
`M11.8125 9.8125H2.1875C1.46289 9.8125 0.875 9.22461 0.875 8.5V1.5C0.875
0.775388 1.46289 0.1875 2.1875 0.1875H11.8125C12.5371 0.1875 13.125
0.775388 13.125 1.5V8.5C13.125 9.22461 12.5371 9.8125 11.8125 9.8125ZM2.1875
1.0625C1.94578 1.0625 1.75 1.25828 1.75 1.5V8.5C1.75 8.61594 1.79594 8.7275
1.87797 8.80953C1.96 8.89156 2.07156 8.93749 2.18749 8.93749H11.8125C11.9284
8.93749 12.04 8.89156 12.122 8.80953C12.2041 8.72749 12.25 8.61593 12.25
8.5V1.5C12.25 1.38406 12.2041 1.2725 12.122 1.19047C12.04 1.10844 11.9284
1.06251 11.8125 1.06251L2.1875 1.0625Z`,
`M7.00088 5.21008C6.71158 5.21063 6.42995 5.11492 6.20025 4.93883L1.33959
1.19817C1.14763 1.05051 1.111 0.775439 1.25865 0.583485C1.40631 0.391531
1.68138 0.354893 1.87334 0.502549L6.734 4.24321C6.8915 4.36407 7.11025
4.36407 7.26775 4.24321L12.1284 0.502549C12.3204 0.354891 12.5954 0.391533
12.7431 0.583485C12.8907 0.775438 12.8541 1.05051 12.6622 1.19817L7.80149
4.93883C7.57181 5.11492 7.29017 5.21062 7.00086 5.21008H7.00088Z`
]"
color="black"
size="lg"
viewBow="0 0 24 24"
/>
Maya Shavin
@mayashavin

Sr. Developer @
component.customize(functionality)



Maya Shavin
@mayashavin

Sr. Developer @
Ease of use
You have 5 mins to make me happy when trying it
Maya Shavin
@mayashavin

Sr. Developer @
StorefrontUI.deliver()
Bundled code
Raw-source code
Include the WHOLE library in production bundle
NO CONTROL over bundled code and CSS code (SCSS variables, polyfills)

import Vue from 'vue';
import StorefrontUI from '@storefront-ui/vue';
Vue.use(StorefrontUI);
import SfAccordion from "../SfAccordion.vue"
import SfAddToCart from "../SfAddToCart.vue"
import SfAlert from "../SfAlert.vue"
import SfArrow from "../SfArrow.vue"
/*...*/
export default {
install: function(Vue) {
Vue.component('SfAccordion', SfAccordion);
Vue.component('SfAddToCart', SfAddToCart);
Vue.component('SfAlert', SfAlert);
Vue.component('SfArrow', SfArrow);
/*...*/
}
}
import { SfButton } from '@storefront-ui/vue';
export default {
component: {
SfButton,
},
data() {
return { /*...*/ }
}
}
NOT WORKING on browser as-is
FULL CONTROL on bundled code
NEED bundle tool (webpack) to compile
FULL TREE-SHAKING for optimization
EVERYONE uses Webpack (kindof)
main.js
Product.vue
Maya Shavin
@mayashavin

Sr. Developer @
StorefrontUI.organize_code()
Template
Stand-alone blocks
BEM convention
CSS selectors?
Props?
Clear & concise names
Slot
Scoped slot
<div :class="`sf-alert--${type}`" class="sf-alert">
<!--@slot Custom alert icon.
Slot content will replace default icon <SfIcon/> tag.-->
<slot name="icon" v-bind="{ icon }">
<SfIcon :icon="icon"
size="24px"
color="white"
class="sf-alert__icon" />
</slot>
<!--@slot Custom message .
Slot content will replace default message <span> tag.-->
<slot name="message" v-bind="{ message }">
<span v-if="message"
class="sf-alert__message">
{{ message }}
</span>
</slot>
</div>
<div :class="`sf-alert--${type}`" class="sf-alert">
<!--@slot Custom alert icon.
Slot content will replace default icon <SfIcon/> tag.-->
<slot name="icon" v-bind="{ icon }">
<SfIcon :icon="icon"
size="24px"
color="white"
class="sf-alert__icon" />
</slot>
<!--@slot Custom message .
Slot content will replace default message <span> tag.-->
<slot name="message" v-bind="{ message }">
<span v-if="message"
class="sf-alert__message">
{{ message }}
</span>
</slot>
</div>
<div :class="`sf-alert--${type}`" class="sf-alert">
<!--@slot Custom alert icon.
Slot content will replace default icon <SfIcon/> tag.-->
<slot name="icon" v-bind="{ icon }">
<SfIcon :icon="icon"
size="24px"
color="white"
class="sf-alert__icon" />
</slot>
<!--@slot Custom message .
Slot content will replace default message <span> tag.-->
<slot name="message" v-bind="{ message }">
<span v-if="message"
class="sf-alert__message">
{{ message }}
</span>
</slot>
</div>
props: {
/**
* Message that will be displayed in Alert.
*/
message: {
type: String,
default: ""
},
/**
* Alert type ("secondary", "info", "success",
* "warning", "danger").
* Check "Knobs" section to see how they look like.
*/
type: {
type: String,
default: "secondary",
validator: function(value) {
/*..*/
}
}
}
Maya Shavin
@mayashavin

Sr. Developer @
StorefrontUI.integrate()
Static-site generator support
Server-side rendering support
Client side rendering




Maya Shavin
@mayashavin

Sr. Developer @
StorefrontUI.document()
HOW good about the component?
HOW to use a component?
See (Play) to BELIEVE

HOW to set up?
HOW to contribute?
Are you the ONE?


AUTOMATE, AUTOMATE and AUTOMATE your documentation!
Maya Shavin
@mayashavin

Sr. Developer @

Traverse directory

Extract markdown & SCSS/CSS variables (REGEX)

Fill in placeholders in final generated docs
Auto-generate process
Maya Shavin
@mayashavin

Sr. Developer @
Simplicity
Is your library simple enough for me to use?
Maya Shavin
@mayashavin

Sr. Developer @

Maya Shavin
@mayashavin

Sr. Developer @
What's else?
Any other tips? Who are you? Demo?
Maya Shavin
@mayashavin

Sr. Developer @
console.log(Other_Tips)
Lazy-load whenever and wherever possible
Adopt external optimized solution (images handling)
Think developer first (developer === user)
Maya Shavin
@mayashavin

Sr. Developer @
console.log(Storefront UI)
FIRST component library for E-commerce
100% customizable design system
FULL tree-shakable support
Performance oriented
MOBILE-first design

Maya Shavin
@mayashavin

Sr. Developer @
console.log(Storefront UI.team)

Filip Rakowski
Founder
@Vue-Storefront

Eduard Dopler
Sr. Developer

Maya Shavin
Sr. FE Developer

Nicolò Maria Mezzopera
Sr. FE Developer
Cloudinary
IFM Electronics
Gitlab/Vue-leaflet

Leonardo Matos
CEO
E-com Club

Przemysław Spaczek
FE Developer
DivanteLtd
Maya Shavin
@mayashavin

Sr. Developer @
console.log(Storefront UI.team)

Anna Musiał
Jr. FE Developer

Marta Radziszewska
FE Developer
DivanteLtd
DivanteLtd
Maya Shavin
@mayashavin

Sr. Developer @
StorefrontUI.demo()




Maya Shavin
@mayashavin

Sr. Developer @
StorefrontUI.next()


DEMOs


Stable release
Production-ready
Stable style-guides
A11y compliance
Maya Shavin
@mayashavin

Sr. Developer @
Support StorefrontUI
Give us a ⭐
Contribute
Join our team
Maya Shavin
@mayashavin

Sr. Developer @
THANK YOU


Performant Components through customization
By Maya Shavin
Performant Components through customization
Most current UI libraries provide great user experience with a vast of components. But when it comes to heavy customization and non-standard scenarios, especially for E-Commerce, they become hard to manage, scale or even slow down performance. How to create a UI library that provides users the most possible freedom in customizing components, while keeping our performance and scalability to the fullest? How much customization freedom is enough? What other lessons learned, during building StorefrontUI, that can help other Vue developers in building their own system. Demo github: https://github.com/mayashavin/storefrontui-demo-store Demo site: https://storefrontui-demo-store.now.sh/
- 2,550