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" />by Ilham Wahabi
- Frontend Developer
- Informatics ITB'16
- Ex. eHealth, Dekoruma, Chatbiz, Stoqo
- Github & Twitter
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
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
<Column data={[ { label: "Javascript", img: require("./images/coding.png") }, { label: "Load", img: require("./images/loader.png") }, { label: "Rendering", img: require("./images/render.png") }, ]} />
<Img src={require("./images/js.png")} />
function cubic(a) {
// Will parsed repeatedly
function square(b) {
return b * b;
}
return square(a) * a;
}
function add(a, b) {
return a + b;
}
add(1, 2);
add(2, 3); // faster
add("1", "a"); // slow
-
Ship less code
-
Consider type system
<Img src={require("./images/performance.png")} style={{ width: "60%", maxWidth: 1080 }} />
<Img src={require("./images/perflink.png")} />
<Img src={require("./images/network.png")} />
-
Your website have home page, about page, and register page
-
User visit your home page
-
Is user also need to load your about page & register page?
<Img src={require("./images/codesplitting.png")} />
-
Route based
- Split route that likely will not visited often
- Ex: Split career page and about page
-
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>
<Img src={require("./images/nuxt.png")} />
<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
<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
<Img src={require("./images/bundlephobia.png")} />
take with grain of salt
- 25x smaller
- (almost) same API
- tree-shakeable
- ~800 byte
- same API
- use Fetch
- tree-shakeable
- 6x smaller
- tree-shakeable
- side-effect free
even better
import add from "lodash/add";
add(6, 4);
-
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
- Changing the font
- Content changes
- Add / remove element
- Add / remove classes
- Calculating size
- Changing size / position
- (Even more...)
-
Change classes at the lowest level
-
Avoid repeatedly modifying inline style
-
Avoid table layouts
-
(Even more...)
// BAD
parent.append(child1);
parent.append(child2);
// GOOD
fragment.append(child1);
fragment.append(child2);
parent.append(fragment);
we update something
then we read something
browser be like
// 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;
If you can change the visual appearance of an element by adding a CSS class
Do that, you'll avoid accidental trashing
<Img src={require("./images/twitter.png")} />
- By Vue core team
- only renders the visible items
- as the user scrolls,
- it reuses all components & DOM nodes
<Img src={require("./images/lighthouse.png")} />
<Img src={require("./images/webvitals.png")} />
<Img src={require("./images/measure.png")} />
<Img src={require("./images/pagespeedinsight.png")} />
<Img src={require("./images/testmysite.png")} />
<Img src={require("./images/webpagetest.png")} />
- Performance CSS animation
- Load font effectively
- Caching
- Service Worker
- Unused code removal
- Chrome Performance tab
- Much more...