Skip to content

Latest commit

 

History

History
714 lines (411 loc) · 9.48 KB

index.mdx

File metadata and controls

714 lines (411 loc) · 9.48 KB

import { themes } from "mdx-deck"; import { dark, highlight } from "@mdx-deck/themes";

import Img from "./components/Img"; import Layout from "./components/Layout"; import Link from "./components/Link"; import Column from "./components/Column";

export const theme = { ...dark, ...highlight, };

<title>How to Build High Performance Website</title> <script async data-api="/_hive" src="/bee.js" />

How to Build High Performance Website

by Ilham Wahabi


About Me

  • Frontend Developer
  • Informatics ITB'16
  • Ex. eHealth, Dekoruma, Chatbiz, Stoqo
  • Github & Twitter

Why Performance Matters?


bad found :(


Aberdeen Group found that a 1s slow down resulted 11% fewer page views, 7% less conversion


Akamai found that 2s delay in web page load time increase bounce rates by 103%


Google found that a 2% slower page resulted in 2% fewer searches, which means 2% fewer ads show


good found :)


A 400ms improvement in performance resulted in a 9% increase in traffic at Yahoo


100ms improvement in performance results in 1% increase in overall revenue at Amazon


Takeaway

Even small improvement have huge effect


3 Aspect of Performance

<Column data={[ { label: "Javascript", img: require("./images/coding.png") }, { label: "Load", img: require("./images/loader.png") }, { label: "Rendering", img: require("./images/render.png") }, ]} />


Steve Golden Rules of Performance


Doing less stuff takes less time


If you can do it later. Do it later


#1 Javascript Performance


<Img src={require("./images/js.png")} />


Try avoid nested function

function cubic(a) {
  // Will parsed repeatedly
  function square(b) {
    return b * b;
  }

  return square(a) * a;
}

Use function consistently

function add(a, b) {
  return a + b;
}

add(1, 2);

add(2, 3); // faster

add("1", "a"); // slow

Takeaways

  • Ship less code

  • Consider type system


Debugging with worsen performance

<Img src={require("./images/performance.png")} style={{ width: "60%", maxWidth: 1080 }} />


Benchmark Javascript Operation with perf.link

<Img src={require("./images/perflink.png")} />


#2 Load Performance


Debugging with slow connection

<Img src={require("./images/network.png")} />


Code splitting


Imagine this scenario

  1. Your website have home page, about page, and register page

  2. User visit your home page

  3. Is user also need to load your about page & register page?


Just load what matters

<Img src={require("./images/codesplitting.png")} />


2 types:

  1. Route based

    • Split route that likely will not visited often
    • Ex: Split career page and about page
  2. Component based

    • Split component that will not used immediately
    • Ex: Split modal and drawer

<template>
  <lazy-modal />
</template>

<script>
/* load even if user will not use */
// import Modal from "./Modal.vue";

/* just load when used */
const LazyModal = () => import("Modal.vue");
export default {
  components: { LazyModal },
};
</script>

Nuxt.js use route-based code splitting as default

<Img src={require("./images/nuxt.png")} />


This is JUST (modern) Javascript


Load Image


Keep small

and

Just load what screen need


<img src="small.jpg" srcset="medium.jpg 500w, large.jpg 1000w" />
  • If your device width is 320px
  • And non retina (1x)
  • Calculation:
    • 500 / 320 = 1.5625
    • 1000 / 320 = 3.125
  • Then your browser will choose medium.jpg
  • Since it nearest >= than 1

  • You need multiple file for one image

  • You need to compress it manually

  • Syntax not too intuitive


Imgix

<Img src={require("./images/imgix.png")} />


http://domain/img.png?auto=compress&w=600&h=400
  • Just need 1 master file

  • No need compress manually

  • And another great feature!

  • official: vue-imgix


How to check package size?


Bundlephobia

<Img src={require("./images/bundlephobia.png")} />


Alternative package

take with grain of salt


dayjs, for momentjs

  • 25x smaller
  • (almost) same API
  • tree-shakeable

redaxios, for axios

  • ~800 byte
  • same API
  • use Fetch
  • tree-shakeable

nanoid, for uuid

  • 6x smaller
  • tree-shakeable
  • side-effect free

lodash-es, for lodash

even better

lodash.[methodName]


Or use it with

import add from "lodash/add";

add(6, 4);

#3 Render Performance


Reflow

  • Blocking operation

  • Consume CPU


Whenever the geometry of an element changes, the browser has to reflow the page

Reflow an element causes a reflow of its parent and children


Cause

  • Changing the font
  • Content changes
  • Add / remove element
  • Add / remove classes
  • Calculating size
  • Changing size / position
  • (Even more...)

How to Avoid?

  • Change classes at the lowest level

  • Avoid repeatedly modifying inline style

  • Avoid table layouts

  • (Even more...)


Do Batch DOM Manipulation

// BAD
parent.append(child1);
parent.append(child2);
// GOOD
fragment.append(child1);
fragment.append(child2);

parent.append(fragment);

Layout Trashing


we update something

then we read something

browser be like

wait, you just changed something before. Let me reflow the page again to get latest value


// BAD
const width1 = element1.offsetWidth;
element1.style.width = width1 * 2;

const width2 = element2.offsetWidth;
element1.style.width = width2 * 2;
// GOOD
const width1 = element1.offsetWidth;
const width2 = element2.offsetWidth;

element1.style.width = width1 * 2;
element2.style.width = width2 * 2;

Solution

Separate read and write


If you can change the visual appearance of an element by adding a CSS class

Do that, you'll avoid accidental trashing


Have long list of data?

<Img src={require("./images/twitter.png")} />


Every time you scroll a long list

There is expensive DOM nodes creation

and

Not visible component still stored in memory


Use vue-virtual-scroller

  • By Vue core team
  • only renders the visible items
  • as the user scrolls,
  • it reuses all components & DOM nodes

Maybe you don't need this?

ever heard of pagination?


Audit


It's an irony


User access our web...

Using low spec device

In slow connection


Meanwhile developer...

Using high spec device

In high speed connection


Auditing Tools


1. Lighthouse

<Img src={require("./images/lighthouse.png")} />


2. Web Vitals

<Img src={require("./images/webvitals.png")} />


3. Measure

<Img src={require("./images/measure.png")} />


4. Pagespeed Insight

<Img src={require("./images/pagespeedinsight.png")} />


5. Testmysite

<Img src={require("./images/testmysite.png")} />


6. Webpagetest

<Img src={require("./images/webpagetest.png")} />


It's Audit Time!


Things not discussed here

  • Performance CSS animation
  • Load font effectively
  • Caching
  • Service Worker
  • Unused code removal
  • Chrome Performance tab
  • Much more...

That's all folks

Any Question?