Skip to content

Commit

Permalink
⚡ perf(carousel): improve LCP (#1513)
Browse files Browse the repository at this point in the history
* Create PR for #1501

* chore: improve performance of carousel

* chore: fix safari

* chore: fix safari

* fix: improve perf of tabs

* chore: improve visual tests

* chore: format files

* chore: increase wait for visual

* update base images

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Gery Hirschfeld <[email protected]>
Co-authored-by: hirsch88 <[email protected]>
  • Loading branch information
3 people authored Nov 22, 2024
1 parent 124a196 commit c36b407
Show file tree
Hide file tree
Showing 27 changed files with 244 additions and 82 deletions.
5 changes: 5 additions & 0 deletions .changeset/gentle-insects-kneel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@baloise/ds-core': patch
---

**carousel**: load images and controls after largest content paint
5 changes: 5 additions & 0 deletions .changeset/giant-walls-cry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@baloise/ds-core': patch
---

**button**: load icons and spinner after largest content paint
5 changes: 5 additions & 0 deletions .changeset/good-bulldogs-change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@baloise/ds-core': patch
---

**icon**: load icon after largest content paint
5 changes: 5 additions & 0 deletions .changeset/lucky-trains-drive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@baloise/ds-core': patch
---

**stage**: load image after largest content paint
5 changes: 5 additions & 0 deletions .changeset/silver-ads-bake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@baloise/ds-core': patch
---

**tabs**: improve performace for tabs rendering
5 changes: 5 additions & 0 deletions .changeset/smart-countries-smile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@baloise/ds-core': minor
---

**core**: add new css helper classes .lcp-wait to hide an element until largest content paint is reached
2 changes: 1 addition & 1 deletion e2e/cypress/e2e/visual/bal-hint.visual.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ describe('bal-hint', () => {
})

context('mobile', () => {
beforeEach(() => cy.platform('mobile').wait(100))
beforeEach(() => cy.platform('mobile').wait(200))

it('basic component', () => {
cy.getByTestId('basic').testVisual('hint-basic-mobile')
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions packages/core/src/components/bal-app/bal-app.sass
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,14 @@
.bal-app
position: relative
display: block

.lcp-wait
opacity: 0
visibility: hidden
display: none

.lcp-ready
.lcp-wait
opacity: inherit
visibility: inherit
display: inherit
11 changes: 9 additions & 2 deletions packages/core/src/components/bal-app/bal-app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Component, Host, h, Prop, Method, Element } from '@stencil/core'
import { balBrowser } from '../../utils/browser'
import { balDevice } from '../../utils/device'
import { updateBalAnimated } from '../../utils/config'
import { debounce, rIC } from '../../utils/helpers'
import { debounce, rIC, rLCP } from '../../utils/helpers'
import { Loggable, Logger, LogInstance } from '../../utils/log'
import { startFocusVisible } from '../../utils/focus-visible'

Expand Down Expand Up @@ -43,10 +43,17 @@ export class App implements Loggable {
}

componentDidLoad() {
rIC(async () => {
rIC(() => {
this.ready = true
startFocusVisible()
})

rLCP(() => {
if (balBrowser.hasDocument && balBrowser.hasWindow) {
const doc = document.documentElement
doc.classList.add('lcp-ready')
}
})
}

disconnectedCallback() {
Expand Down
66 changes: 48 additions & 18 deletions packages/core/src/components/bal-button/bal-button.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
import { Component, h, Prop, Host, Event, EventEmitter, ComponentInterface, Listen, Element } from '@stencil/core'
import {
Component,
h,
Prop,
Host,
Event,
EventEmitter,
ComponentInterface,
Listen,
Element,
State,
} from '@stencil/core'
import { Attributes, inheritAttributes } from '../../utils/attributes'
import { rLCP } from '../../utils/helpers'

@Component({
tag: 'bal-button',
Expand All @@ -10,6 +22,8 @@ export class Button implements ComponentInterface {

@Element() el!: HTMLElement

@State() isLargestContentPaintDone = false

/**
* The color to use from your application's color palette.
*/
Expand Down Expand Up @@ -163,6 +177,10 @@ export class Button implements ComponentInterface {
}
}

componentDidLoad(): void {
rLCP(() => (this.isLargestContentPaintDone = true))
}

componentWillLoad() {
this.inheritAttributes = inheritAttributes(this.el, [
'title',
Expand Down Expand Up @@ -310,15 +328,23 @@ export class Button implements ComponentInterface {
data-testid="bal-button"
{...ariaAttributes}
>
<bal-spinner color={spinnerColor()} small {...this.loadingAttrs} deactivated={!this.loading} />
<bal-icon
{...this.leftIconAttrs}
class={this.square ? '' : 'icon-left'}
name={this.icon}
size={this.square ? this.size : 'small'}
turn={this.iconTurn}
inverted={this.isIconInverted}
/>
{this.isLargestContentPaintDone && this.loading ? (
<bal-spinner color={spinnerColor()} small {...this.loadingAttrs} deactivated={!this.loading} />
) : (
''
)}
{this.isLargestContentPaintDone && this.icon ? (
<bal-icon
{...this.leftIconAttrs}
class={this.square ? '' : 'icon-left'}
name={this.icon}
size={this.square ? this.size : 'small'}
turn={this.iconTurn}
inverted={this.isIconInverted}
/>
) : (
''
)}
<span
class={{
'button-label': true,
Expand All @@ -330,14 +356,18 @@ export class Button implements ComponentInterface {
>
<slot />
</span>
<bal-icon
{...this.leftRightAttrs}
class="icon-right"
name={this.iconRight}
size={'small'}
turn={this.iconTurn}
inverted={this.isIconInverted}
/>
{this.isLargestContentPaintDone && this.iconRight ? (
<bal-icon
{...this.leftRightAttrs}
class="icon-right"
name={this.iconRight}
size={'small'}
turn={this.iconTurn}
inverted={this.isIconInverted}
/>
) : (
''
)}
</TagType>
</Host>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
import { Component, ComponentInterface, h, Host, Method, Element, Prop, Event, EventEmitter } from '@stencil/core'
import {
Component,
ComponentInterface,
h,
Host,
Method,
Element,
Prop,
Event,
EventEmitter,
State,
} from '@stencil/core'
import { BEM } from '../../../utils/bem'
import { BalCarouselItemData } from '../bal-carousel.type'
import { Attributes } from '../../../interfaces'
import { waitAfterFramePaint } from '../../../utils/helpers'
import { rLCP, waitAfterFramePaint } from '../../../utils/helpers'
import { inheritAttributes } from '../../../utils/attributes'

@Component({
Expand All @@ -14,6 +25,8 @@ export class CarouselItem implements ComponentInterface {

@Element() el!: HTMLElement

@State() isLargestContentfulPaintDone = false

/**
* Src path to the image
*/
Expand Down Expand Up @@ -89,6 +102,17 @@ export class CarouselItem implements ComponentInterface {
*/
@Event() balBlur!: EventEmitter<BalEvents.BalCarouselItemBlurDetail>

/**
* LIFECYCLE
* ------------------------------------------------------
*/

componentDidLoad(): void {
rLCP(() => {
this.isLargestContentfulPaintDone = true
})
}

componentWillLoad() {
this.imageInheritAttributes = inheritAttributes(this.el, ['alt'])
}
Expand Down Expand Up @@ -131,7 +155,7 @@ export class CarouselItem implements ComponentInterface {
if (!isProduct) {
return (
<Host role={this.htmlRole} class={{ ...itemEl.class() }}>
{this.src !== undefined ? (
{this.isLargestContentfulPaintDone && this.src !== undefined ? (
<img draggable={false} onDragStart={() => false} src={this.src} {...this.imageInheritAttributes} />
) : (
''
Expand Down Expand Up @@ -169,10 +193,9 @@ export class CarouselItem implements ComponentInterface {
onClick={this.onClick}
ref={el => (this.buttonEl = el)}
>
{this.src !== undefined ? (
{this.isLargestContentfulPaintDone && this.src !== undefined ? (
<img
class={{ ...image.class() }}
loading="lazy"
draggable={false}
onDragStart={() => false}
aria-hidden="true"
Expand Down
29 changes: 19 additions & 10 deletions packages/core/src/components/bal-carousel/bal-carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
State,
Listen,
} from '@stencil/core'
import { raf } from '../../utils/helpers'
import { debounce, raf, rLCP } from '../../utils/helpers'
import { BEM } from '../../utils/bem'
import { BalSlide, ControlItem } from './bal-carousel.type'
import { TabControl } from './controls/tab-control'
Expand Down Expand Up @@ -44,6 +44,7 @@ export class Carousel
private carouselId = `bal-carousel-${CarouselIds++}`
private carouselContainerId = `bal-carousel-${CarouselIds++}-container`

@State() isLargestContentfulPaintDone = false
@State() isLastSlideVisible = true
@State() isMobile = balBreakpoints.isMobile
@State() language: BalLanguage = defaultConfig.language
Expand Down Expand Up @@ -132,6 +133,12 @@ export class Carousel
* ------------------------------------------------------
*/

componentDidLoad(): void {
rLCP(() => {
this.isLargestContentfulPaintDone = true
})
}

/**
* LISTENERS
* ------------------------------------------------------
Expand Down Expand Up @@ -332,11 +339,13 @@ export class Carousel
return undefined
}

private async itemsChanged() {
const activeSlide = await this.buildSlide(this.value)

if (activeSlide) {
this.animate(activeSlide.transformActive, false)
private itemsChanged = debounce(() => this.itemsChangedInternal(), 100)
private async itemsChangedInternal() {
if (this.isLargestContentfulPaintDone) {
const activeSlide = await this.buildSlide(this.value)
if (activeSlide) {
this.animate(activeSlide.transformActive, false)
}
}
}

Expand Down Expand Up @@ -442,7 +451,7 @@ export class Carousel
...block.modifier(`controls-${this.controls}`).class(),
}}
>
{this.controls === 'tabs' ? (
{this.isLargestContentfulPaintDone && this.controls === 'tabs' ? (
<TabControl
value={this.value}
items={controlItems}
Expand Down Expand Up @@ -492,7 +501,7 @@ export class Carousel
</div>
</div>

{this.controls === 'dots' ? (
{this.isLargestContentfulPaintDone && this.controls === 'dots' ? (
<DotControl
value={this.value}
items={controlItems}
Expand All @@ -503,7 +512,7 @@ export class Carousel
''
)}

{this.controls === 'large' ? (
{this.isLargestContentfulPaintDone && this.controls === 'large' ? (
<LargeControl
isFirst={this.isFirst()}
isLast={this.isLast()}
Expand All @@ -519,7 +528,7 @@ export class Carousel
''
)}

{this.controls === 'small' ? (
{this.isLargestContentfulPaintDone && this.controls === 'small' ? (
<SmallControl
isFirst={this.isFirst()}
isLast={this.isLast()}
Expand Down
Loading

0 comments on commit c36b407

Please sign in to comment.