feat(v2): optimize image processing with sharp & lqip (#1663)
* feat(v2): optimize image processing * cleanup
|
@ -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",
|
||||||
|
|
29
packages/docusaurus/src/client/exports/Image.js
Normal 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;
|
|
@ -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: [
|
||||||
|
|
Before Width: | Height: | Size: 155 KiB After Width: | Height: | Size: 155 KiB |
Before Width: | Height: | Size: 223 KiB After Width: | Height: | Size: 223 KiB |
Before Width: | Height: | Size: 200 KiB After Width: | Height: | Size: 200 KiB |
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 197 KiB |
Before Width: | Height: | Size: 188 KiB After Width: | Height: | Size: 188 KiB |
|
@ -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,
|
||||||
|
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 9.4 KiB |
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
@ -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>
|
||||||
|
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
|
@ -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">
|
||||||
|
|