is the code you don't load
How not to get yelled at by Alex Russell
Environment Edition
Inspector: CSS+JS Coverage
Inspector: CSS Coverage
Lighthouse
Intersection Observer
Intersection Observer: Native DOM API
var iObserver = new IntersectionObserver((entries) => {
// If intersectionRatio is 0, the target is out of view
if (entries[0].intersectionRatio <= 0) return;
loadItems(10);
});
// start observing
iObserver.observe(
document.querySelector('.scrollerFooter')
);
Intersection Observer: react-intersection-observer
import Observer from 'react-intersection-observer'
<Observer>
{(inView) => <h2>{`Header inside viewport ${inView}.`}</h2>}
</Observer>
Service Worker: offline-first pattern
Service Worker: offline-first pattern
Step 1: Configure plugin in webpack.config.js:
// webpack.config.js
var OfflinePlugin = require('offline-plugin');
module.exports = {
// ...
plugins: [
// ... other plugins
// Should usually be last
new OfflinePlugin({
...
})
]
}
Service Worker: offline-first pattern
// main.entry.js
require('offline-plugin/runtime').install();
runtime.install({
onUpdateReady: () => {
// Tells to new SW to take control immediately
runtime.applyUpdate();
},
onUpdated: () => {
// Reload page to load the new version
window.location.reload();
},
onUpdateFailed: () => {
console.log('SW Event:', 'onUpdateFailed');
}
});
Step 2: Add the runtime into your entry file
H2
Server Push
https://jakearchibald.com/2017/h2-push-tougher-than-i-thought/
Tooling Edition
Per entry-point
Dynamic - component-based
webpack-bundle-analyzer: stats.json
669kB
83kB
80kB
489kB
webpack-bundle-analyzer: gzipped
61kB
7kB
47kB
11kB
webpack-bundle-analyzer: parsed
151kB
48kB
209kB
25.4 kB
.babelrc
{
"presets": [
["env", {"modules": false}],
"react",
"stage-2"
],
"plugins": [
"transform-flow-strip-types"
],
"env": {
"browser": {
"presets": [
["env", {
"targets": {"chrome": 57, "firefox": 52, "safari": 10},
"modules": false,
"useBuiltIns": true
}],
"react",
"stage-2"
]
}
}
}
react-loadable
import Loadable from 'react-loadable';
const RadarLoader = Loadable({
loader: () => import(/* webpackChunkName: "radar" */ './radar'),
LoadingComponent: RadarSpinner
});
const RadarSpinner = ({ isLoading, error, pastDelay }: Props) => {
if (isLoading) {
return pastDelay ? <Spinner>Loading...</Spinner> : null;
} else if (error) {
return <div>Error! Component failed to load</div>;
}
return null;
};
export default class extends Component {
render() {
return (
<Container>
<Media query={d.mqs.tablet}>
{matches => (matches ? <RadarLoader /> : null)}
</Media>
</Container>
);
}
}
1
2
react-loadable
let Db = Loadable({
loader: () => import(/* webpackChunkName: "searchdb" */ './db'),
LoadingComponent: DbShim
});
class Search extends Component {
state = {initialised: false, query: ''};
loadDB = () => {
if (this.state.initialised) return;
this.setState({ initialised: true });
Database.preload();
};
updateQuery = (e) => this.setState({ query: e.target.value; });
render() {
const {query} = this.state;
const {cards, submitSearch} = this.props;
return (
<Container>
<Form query={query} onFocus={this.loadDB} onChange={this.updateQuery} />
<Db cards={cards} term={query} onTermUpdated={submitSearch} />
</Container>
);
}
}
3
1
2
preload-webpack-plugin
preload-webpack-plugin
<!DOCTYPE html>
<html lang="en">
<head>
...
<link rel="preload" as="script" href="/js/chunks/radar.js">
<link rel="preload" as="script" href="/js/chunks/root.js">
<link rel="preload" as="script" href="/js/chunks/searchdb.js">
<link rel="preload" as="script" href="/js/chunks/smoothscroll.js">
<style type="text/css">...</style>
<link href="/css/app.css" rel="preload" as="style" onload="this.rel='stylesheet'">
</head>
<body>...</body>
</html>
👇
@oliverturner