CSS Code Splitting
TAN LI HAU
Frontend Developer at Shopee
lihautan.com
@import 'typography';
@import 'buttons';
.button {
@include button($radius: 5px);
@include typo-light-1;
}
.button {
border-radius: 5px;
display: block;
background-color: '#ee4d2d';
font-size: 12px;
font-weight: lighter;
color: #ddd;
}
:local {
.button {
color: green;
}
}
import classNames from './style.css';
console.log(classNames.button);
style.css
component.js
.a8eqrd {
color: green;
}
import classNames from './style.css';
console.log(classNames.button);
// 'a8eqrd'
style.css
component.js
+
HOW BIG IS SHOPEE?
> 1K CSS files
and growing...
> 67K lines of CSS
~500KB
~ 4s to download and parse
with SLOW 3G Network
6x CPU slowdown
Downloaded: ~518KB
Unused: ~477KB
(~92%)
Too long to load
Too much to parse
Unused CSS
SO HOW?
switch(url) {
case '/':
return import('./PageHome').then(PageHome => {
// do something
})
case '/campaigns':
return import('./PageCampaign').then(PageCampaign => {
// do something
})
}
Code Splitting
npm install --save-dev mini-css-extract-plugin
plugins: [ new MiniCssExtractPlugin({ filename: "[name].css", chunkFilename: "[id].css" }) ], module: { rules: [ { test: /\.scss$/, use: [ MiniCssExtractPlugin.loader, "css-loader",
"sass-loader",
]
}
]
}
THE RESULT
~ 200ms to download and parse
with SLOW 3G Network
6x CPU slowdown
Downloaded: ~53KB
Unused: ~43KB
(~81%)
PROBLEM #1
Styles broken when user goes from Page XXX to Page YYY
Styles working when user goes directly to Page YYY, only broken when user goes from Page XXX to Page YYY
<html>
<head>
<link rel="stylesheet" type="text/css" href="page-1-style.css" />
<link rel="stylesheet" type="text/css" href="page-2-style.css" />
</head>
<body>
<div class="foo">HELLO WORLD</div>
</body>
</html>
/* page-1-styles.css */
.foo {
color: green;
}
/* page-2-styles.css */
.foo {
color: blue;
}
page1 → page2
<head>
<link rel="stylesheet" type="text/css" href="page-1-style.css" />
<link rel="stylesheet" type="text/css" href="page-2-style.css" />
</head>
page2 → page1
<head>
<link rel="stylesheet" type="text/css" href="page-2-style.css" />
<link rel="stylesheet" type="text/css" href="page-1-style.css" />
</head>
function ensureCss(href) {
const existingLinkTags = document.getElementsByTagName("link");
for(let i = 0; i < existingLinkTags.length; i++) {
if (tag.rel === 'stylesheet' && tag.getAttribute("href") === href) {
return;
}
}
const linkTag = document.createElement('link');
linkTag.rel = "stylesheet";
linkTag.type = "text/css";
linkTag.href = href;
const head = document.getElementsByTagName("head")[0];
head.appendChild(linkTag);
}
// somewhere in your application code
// when you write
import './styles.scss';
// webpack's mini-css-extract-plugin transform it into
ensureCss('https://shopee.sg/page-1-style.css');
/* page-1-styles.css */
.page-1 .foo {
color: green;
}
/* page-2-styles.css */
.page-2 .foo {
color: blue;
}
<div class="class-a class-b">
HELLO WORLD
</div>
/* styles.css */
.class-b {
color: green;
}
.class-a {
color: blue;
}
import styles from './styles.scss';
function MyComponent({ className }) {
return <div className={styles.classA + ' ' + className}>Hello World</div>;
}
/* styles.scss */
:local {
.classA {
color: blue;
}
}
ensureCss('https://shopee.sg/76ab609c.css');
const styles = { classA: 'c8e4436e' };
function MyComponent({ className }) {
return <div className={styles.classA + ' ' + className}>Hello World</div>;
}
/* 76ab609c.css */
.c8e4436e {
color: blue;
}
ensureCss('https://shopee.sg/76ab609c.css');
const styles = { classA: 'c8e4436e' };
function MyComponent({ className }) {
return <div className={styles.classA + ' ' + className}>Hello World</div>;
}
<MyComponent className="classB" />
// ↓↓↓↓↓↓↓↓↓↓↓↓↓
<div class="c8e4436e classB">Hello World</div>
<div class="c8e4436e classB">Hello World</div>
/* 76ab609c.css */
.c8e4436e {
color: blue;
}
/* 41c877ed.css */
.classB {
color: green;
}
<div class="c8e4436e classB">Hello World</div>
/* 76ab609c.css */
.c8e4436e {
color: blue;
}
/* 41c877ed.css */
.classB.classB {
color: green;
}
PROBLEM #2
Server-Side Rendering Not Working
function ensureCss(href) {
const existingLinkTags = document.getElementsByTagName("link");
for(let i = 0; i < existingLinkTags.length; i++) {
if (tag.rel === 'stylesheet' && tag.getAttribute("href") === href) {
return;
}
}
const linkTag = document.createElement('link');
linkTag.rel = "stylesheet";
linkTag.type = "text/css";
linkTag.href = href;
const head = document.getElementsByTagName("head")[0];
head.appendChild(linkTag);
}
CSS Code Splitting
By Li Hau Tan
CSS Code Splitting
- 2,995