feat(v2): optimize image processing with sharp & lqip (#1663)

* feat(v2): optimize image processing

* cleanup
This commit is contained in:
Endi 2019-07-15 01:28:16 +07:00 committed by Yangshun Tay
parent f77e96d28d
commit bc5bceeb87
15 changed files with 838 additions and 33 deletions

View file

@ -49,8 +49,10 @@
"fs-extra": "^7.0.0", "fs-extra": "^7.0.0",
"globby": "^9.2.0", "globby": "^9.2.0",
"html-webpack-plugin": "^4.0.0-beta.5", "html-webpack-plugin": "^4.0.0-beta.5",
"image-webpack-loader": "^5.0.0",
"import-fresh": "^3.0.0", "import-fresh": "^3.0.0",
"lodash": "^4.17.14", "lodash": "^4.17.14",
"lqip-loader": "^2.2.0",
"mini-css-extract-plugin": "^0.7.0", "mini-css-extract-plugin": "^0.7.0",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"null-loader": "^3.0.0", "null-loader": "^3.0.0",
@ -58,12 +60,16 @@
"portfinder": "^1.0.20", "portfinder": "^1.0.20",
"react-dev-utils": "^9.0.1", "react-dev-utils": "^9.0.1",
"react-helmet": "^6.0.0-beta", "react-helmet": "^6.0.0-beta",
"react-ideal-image": "^0.0.5",
"react-loadable": "^5.5.0", "react-loadable": "^5.5.0",
"react-loadable-ssr-addon": "^0.1.8", "react-loadable-ssr-addon": "^0.1.8",
"react-router": "^5.0.1", "react-router": "^5.0.1",
"react-router-config": "^5.0.1", "react-router-config": "^5.0.1",
"react-router-dom": "^5.0.1", "react-router-dom": "^5.0.1",
"react-waypoint": "8.0.3",
"responsive-loader": "^1.2.0",
"semver": "^6.1.1", "semver": "^6.1.1",
"sharp": "^0.22.1",
"shelljs": "^0.8.3", "shelljs": "^0.8.3",
"static-site-generator-webpack-plugin": "^3.4.2", "static-site-generator-webpack-plugin": "^3.4.2",
"std-env": "^2.2.1", "std-env": "^2.2.1",

View file

@ -0,0 +1,29 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import React from 'react';
import IdealImage from 'react-ideal-image';
function Image(props) {
const {alt, className, img} = props;
return (
<IdealImage
{...props}
alt={alt}
className={className}
height={img.src.height}
placeholder={{lqip: img.preSrc}}
src={img.src.src}
srcSet={img.src.images.map(image => ({
...image,
src: image.path,
}))}
width={img.src.width}
/>
);
}
export default Image;

View file

@ -156,6 +156,20 @@ export function createBaseConfig(
exportOnlyLocals: isServer, exportOnlyLocals: isServer,
}), }),
}, },
{
test: /\.(gif|png|jpe?g)$/i,
use: [
'lqip-loader',
{
loader: 'responsive-loader',
options: {
adapter: require('responsive-loader/sharp'),
sizes: [300, 600, 900, 1200],
},
},
'image-webpack-loader',
],
},
], ],
}, },
plugins: [ plugins: [

View file

Before

Width:  |  Height:  |  Size: 155 KiB

After

Width:  |  Height:  |  Size: 155 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 223 KiB

After

Width:  |  Height:  |  Size: 223 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 200 KiB

After

Width:  |  Height:  |  Size: 200 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 197 KiB

After

Width:  |  Height:  |  Size: 197 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 188 KiB

After

Width:  |  Height:  |  Size: 188 KiB

Before After
Before After

View file

@ -10,7 +10,7 @@ const users = [
{ {
title: 'Channel.js', title: 'Channel.js',
description: 'The missing constructor for creating safe async iterators', description: 'The missing constructor for creating safe async iterators',
preview: '/img/showcase/channeljs.png', preview: require('./showcase/channeljs.png'),
website: 'https://channel.js.org', website: 'https://channel.js.org',
source: 'https://github.com/channeljs/channel', source: 'https://github.com/channeljs/channel',
fbOpenSource: false, fbOpenSource: false,
@ -19,7 +19,7 @@ const users = [
{ {
title: 'Component Kit', title: 'Component Kit',
description: 'A declarative UI framework for iOS', description: 'A declarative UI framework for iOS',
preview: '/img/showcase/componentkit.png', preview: require('./showcase/componentkit.png'),
website: 'https://componentkit.org', website: 'https://componentkit.org',
source: 'https://github.com/facebook/componentkit', source: 'https://github.com/facebook/componentkit',
fbOpenSource: true, fbOpenSource: true,
@ -28,7 +28,7 @@ const users = [
{ {
title: 'Flux', title: 'Flux',
description: 'Application architecture for building user interfaces', description: 'Application architecture for building user interfaces',
preview: '/img/showcase/flux.png', preview: require('./showcase/flux.png'),
website: 'https://facebook.github.io/flux/', website: 'https://facebook.github.io/flux/',
source: 'https://github.com/facebook/flux', source: 'https://github.com/facebook/flux',
fbOpenSource: true, fbOpenSource: true,
@ -37,7 +37,7 @@ const users = [
{ {
title: 'Hermes', title: 'Hermes',
description: 'JavaScript engine optimized for React Native', description: 'JavaScript engine optimized for React Native',
preview: '/img/showcase/hermes.png', preview: require('./showcase/hermes.png'),
website: 'https://hermesengine.dev', website: 'https://hermesengine.dev',
source: 'https://github.com/facebook/hermes', source: 'https://github.com/facebook/hermes',
fbOpenSource: true, fbOpenSource: true,
@ -46,7 +46,7 @@ const users = [
{ {
title: 'uniforms', title: 'uniforms',
description: 'A set of React libraries for building forms', description: 'A set of React libraries for building forms',
preview: '/img/showcase/uniforms.png', preview: require('./showcase/uniforms.png'),
website: 'https://uniforms.tools/', website: 'https://uniforms.tools/',
source: 'https://github.com/vazco/uniforms', source: 'https://github.com/vazco/uniforms',
fbOpenSource: false, fbOpenSource: false,

View file

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Before After
Before After

View file

@ -9,6 +9,7 @@ import React from 'react';
import Link from '@docusaurus/Link'; import Link from '@docusaurus/Link';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import withBaseUrl from '@docusaurus/withBaseUrl'; import withBaseUrl from '@docusaurus/withBaseUrl';
import Image from '@docusaurus/Image';
import Layout from '@theme/Layout'; import Layout from '@theme/Layout';
@ -18,7 +19,7 @@ import styles from './styles.module.css';
const QUOTES = [ const QUOTES = [
{ {
thumbnail: 'img/christopher-chedeau.jpg', thumbnail: require('./christopher-chedeau.jpg'),
name: 'Christopher "vjeux" Chedeau', name: 'Christopher "vjeux" Chedeau',
title: 'Lead Prettier Developer', title: 'Lead Prettier Developer',
text: ( text: (
@ -34,7 +35,7 @@ const QUOTES = [
), ),
}, },
{ {
thumbnail: 'img/hector-ramos.png', thumbnail: require('./hector-ramos.png'),
name: 'Hector Ramos', name: 'Hector Ramos',
title: 'Lead React Native Advocate', title: 'Lead React Native Advocate',
text: ( text: (
@ -47,7 +48,7 @@ const QUOTES = [
), ),
}, },
{ {
thumbnail: 'img/ricky-vetter.jpg', thumbnail: require('./ricky-vetter.jpg'),
name: 'Ricky Vetter', name: 'Ricky Vetter',
title: 'ReasonReact Developer', title: 'ReasonReact Developer',
text: ( text: (
@ -197,10 +198,10 @@ function Home() {
{QUOTES.map(quote => ( {QUOTES.map(quote => (
<div className="col" key={quote.name}> <div className="col" key={quote.name}>
<div className="avatar avatar--vertical margin-bottom--sm"> <div className="avatar avatar--vertical margin-bottom--sm">
<img <Image
alt={quote.name} alt={quote.name}
className="avatar__photo avatar__photo--xl" className="avatar__photo avatar__photo--xl"
src={withBaseUrl(quote.thumbnail)} img={quote.thumbnail}
/> />
<div className="avatar__intro"> <div className="avatar__intro">
<h4 className="avatar__name">{quote.name}</h4> <h4 className="avatar__name">{quote.name}</h4>

View file

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Before After
Before After

View file

@ -6,6 +6,7 @@
*/ */
import React, {useEffect} from 'react'; import React, {useEffect} from 'react';
import Image from '@docusaurus/Image';
import Layout from '@theme/Layout'; import Layout from '@theme/Layout';
import classnames from 'classnames'; import classnames from 'classnames';
@ -42,7 +43,7 @@ function Showcase() {
<div className="col col--4"> <div className="col col--4">
<div className={classnames('card', styles.showcaseUser)}> <div className={classnames('card', styles.showcaseUser)}>
<div className="card__image"> <div className="card__image">
<img src={user.preview} alt={user.title} /> <Image img={user.preview} alt={user.title} />
</div> </div>
<div className="card__body"> <div className="card__body">
<div class="avatar"> <div class="avatar">

798
yarn.lock

File diff suppressed because it is too large Load diff