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,424