refactor(v2): import lqip-loader, fix build on Node 13 (#2544)

This commit is contained in:
Bartosz Kaszubowski 2020-04-05 20:55:36 +02:00 committed by GitHub
parent 6a20183a68
commit 980f1041dc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 344 additions and 41 deletions

View file

@ -79,16 +79,13 @@
"lint-staged": {
"*.{js,jsx}": [
"yarn lint --fix",
"yarn prettier",
"git add"
"yarn prettier"
],
"*.{ts,tsx}": [
"yarn prettier",
"git add"
"yarn prettier"
],
"*.md": [
"yarn prettier-docs",
"git add"
"yarn prettier-docs"
]
},
"husky": {

View file

@ -15,11 +15,11 @@
"fs-extra": "^9.0.0"
},
"dependencies": {
"@endiliey/lqip-loader": "^3.0.2",
"@docusaurus/lqip-loader": "^2.0.0-alpha.50",
"@endiliey/react-ideal-image": "^0.0.11",
"@endiliey/responsive-loader": "^1.3.2",
"react-waypoint": "^9.0.2",
"sharp": "^0.22.1"
"sharp": "^0.25.2"
},
"peerDependencies": {
"@docusaurus/core": "^2.0.0",

View file

@ -27,7 +27,7 @@ export default function (_context: LoadContext, options: PluginOptions) {
{
test: /\.(png|jpe?g|gif)$/i,
use: [
'@endiliey/lqip-loader',
'@docusaurus/lqip-loader',
{
loader: '@endiliey/responsive-loader',
options: {

View file

@ -0,0 +1,89 @@
## lqip-loader: low quality images placeholders for webpack
### Installation
```
npm install --save-dev @docusaurus/lqip-loader
```
### Example
Generating Base64 & dominant colours palette for a jpeg image imported in your JS bundle:
> The large image file will be emitted & only 400byte of Base64 (if set to true in the loader options) will be bundled.
`webpack.config.js`
```json
{
/**
* OPTION A:
* default file-loader fallback
**/
test: /\.jpe?g$/,
loaders: [
{
loader: '@docusaurus/lqip-loader',
options: {
path: '/media', // your image going to be in media folder in the output dir
name: '[name].[ext]', // you can use [hash].[ext] too if you wish,
base64: true, // default: true, gives the base64 encoded image
palette: true // default: false, gives the dominant colours palette
}
}
]
/**
* OPTION B:
* Chained with your own url-loader or file-loader
**/
test: /\.(png|jpe?g)$/,
loaders: [
{
loader: '@docusaurus/lqip-loader',
options: {
base64: true,
palette: false
}
},
{
loader: 'url-loader',
options: {
limit: 8000
}
}
]
}
```
`your-app-module.js`
```js
import banner from './images/banner.jpg';
console.log(banner.preSrc);
// outputs: "data:image/jpeg;base64,/9j/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhY....
// the object will have palette property, array will be sorted from most dominant colour to the least
console.log(banner.palette); // [ '#628792', '#bed4d5', '#5d4340', '#ba454d', '#c5dce4', '#551f24' ]
console.log(banner.src); // that's the original image URL to load later!
```
### Important note
To save memory and improve GPU performance, browsers (including Chrome started from 61.0.3163.38) will now render a slightly more crisp or pixelated Base64 encoded images. If you want the blur to be very intense (smooth), here's a fix!
```css
img {
filter: blur(25px);
}
```
More history about the issue can be [found here](https://bugs.chromium.org/p/chromium/issues/detail?id=771110#c3) and [here](https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/6L_3ZZeuA0M).
Alternatively, you can fill the container with a really cheap colour or gradient from the amazing palette we provide.
### Credits
This package has been imported from [`@endiliey/lqip-loader`](https://github.com/endiliey/lqip-loader) which was a fork of original [`lqip-loader`](https://github.com/zouhir/lqip-loader) created exclusively for Docusaurus.

View file

@ -0,0 +1,22 @@
{
"name": "@docusaurus/lqip-loader",
"version": "2.0.0-alpha.50",
"description": "Low Quality Image Placeholders (LQIP) loader for webpack",
"main": "src/index.js",
"publishConfig": {
"access": "public"
},
"license": "MIT",
"dependencies": {
"loader-utils": "^1.2.3",
"lodash.sortby": "^4.7.0",
"node-vibrant": "^3.1.5"
},
"peerDependencies": {
"file-loader": "*",
"sharp": "*"
},
"engines": {
"node": ">=10.9.0"
}
}

View file

@ -0,0 +1,77 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const loaderUtils = require('loader-utils');
const lqip = require('./lqip');
module.exports = function (contentBuffer) {
if (this.cacheable) {
this.cacheable();
}
const callback = this.async();
const imgPath = this.resourcePath;
const config = loaderUtils.getOptions(this) || {};
config.base64 = 'base64' in config ? config.base64 : true;
config.palette = 'palette' in config ? config.palette : false;
let content = contentBuffer.toString('utf8');
const contentIsUrlExport = /^module.exports = "data:(.*)base64,(.*)/.test(
content,
);
const contentIsFileExport = /^module.exports = (.*)/.test(content);
let source = '';
const SOURCE_CHUNK = 1;
if (contentIsUrlExport) {
source = content.match(/^module.exports = (.*)/)[SOURCE_CHUNK];
} else {
if (!contentIsFileExport) {
// eslint-disable-next-line global-require
const fileLoader = require('file-loader');
content = fileLoader.call(this, contentBuffer);
}
source = content.match(/^module.exports = (.*);/)[SOURCE_CHUNK];
}
const outputPromises = [];
if (config.base64 === true) {
outputPromises.push(lqip.base64(imgPath));
} else {
outputPromises.push(null);
}
// color palette generation is set to false by default
// since it is little bit slower than base64 generation
if (config.palette === true) {
outputPromises.push(lqip.palette(imgPath));
} else {
outputPromises.push(null);
}
Promise.all(outputPromises)
.then((data) => {
if (data) {
const [preSrc, palette] = data;
const param1 = preSrc ? `, "preSrc": ${JSON.stringify(preSrc)}` : '';
const param2 = palette ? `, "palette": ${JSON.stringify(palette)}` : '';
const result = `module.exports = {"src":${source}${param1}${param2}};`;
callback(null, result);
} else {
callback('ERROR', null);
}
})
.catch((error) => {
console.error(error);
callback(error, null);
});
};
module.exports.raw = true;

View file

@ -0,0 +1,75 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const Vibrant = require('node-vibrant');
const path = require('path');
const sharp = require('sharp');
const {version} = require('../package.json');
const {toPalette, toBase64} = require('./utils');
const ERROR_EXT = `Error: Input file is missing or uses unsupported image format, lqip v${version}`;
const SUPPORTED_MIMES = {
jpeg: 'image/jpeg',
jpg: 'image/jpeg',
png: 'image/png',
};
const base64 = (file) => {
return new Promise((resolve, reject) => {
let extension = path.extname(file) || '';
extension = extension.split('.').pop();
if (!SUPPORTED_MIMES[extension]) {
return reject(ERROR_EXT);
}
return sharp(file)
.resize(10)
.toBuffer()
.then((data) => {
if (data) {
return resolve(toBase64(SUPPORTED_MIMES[extension], data));
}
return reject(
new Error('Unhandled promise rejection in base64 promise'),
);
})
.catch((err) => {
return reject(err);
});
});
};
const palette = (file) => {
return new Promise((resolve, reject) => {
const vibrant = new Vibrant(file, {});
vibrant
.getPalette()
.then((pal) => {
if (pal) {
return resolve(toPalette(pal));
}
return reject(
new Error('Unhandled promise rejection in colorPalette', pal),
);
})
.catch((err) => {
return reject(err);
});
});
};
process.on('unhandledRejection', (up) => {
throw up;
});
module.exports = {
base64,
palette,
};

View file

@ -0,0 +1,49 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const sortBy = require('lodash.sortby');
/**
* toBase64
* @description it returns a Base64 image string with required formatting
* to work on the web (<img src=".." /> or in CSS url('..'))
*
* @param extension: image file extension
* @param data: base64 string
* @returns {string}
*/
const toBase64 = (extMimeType, data) => {
return `data:${extMimeType};base64,${data.toString('base64')}`;
};
/**
* toPalette
* @description takes a color swatch object, converts it to an array & returns
* only hex color
*
* @param swatch
* @returns {{palette: Array}}
*/
const toPalette = (swatch) => {
let palette = Object.keys(swatch).reduce((result, key) => {
if (swatch[key] !== null) {
result.push({
popularity: swatch[key].getPopulation(),
hex: swatch[key].getHex(),
});
}
return result;
}, []);
palette = sortBy(palette, ['popularity']);
palette = palette.map((color) => color.hex).reverse();
return palette;
};
module.exports = {
toBase64,
toPalette,
};

View file

@ -1057,16 +1057,6 @@
resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7"
integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==
"@endiliey/lqip-loader@^3.0.2":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@endiliey/lqip-loader/-/lqip-loader-3.0.2.tgz#00f4aebe7d4205b741f913644dee831a689f4fcc"
integrity sha512-Kx8te/ZrXR1EqNxBn4hfBHlVCCovm8Fu1fTpYjLSIvcGSEC2+OYFgT7dwPzvh7HyADhMl3lizOgtWbDhtM5djA==
dependencies:
loader-utils "^1.2.3"
lodash.sortby "^4.7.0"
node-vibrant "^3.1.4"
sharp "^0.22.1"
"@endiliey/react-ideal-image@^0.0.11":
version "0.0.11"
resolved "https://registry.yarnpkg.com/@endiliey/react-ideal-image/-/react-ideal-image-0.0.11.tgz#dc3803d04e1409cf88efa4bba0f67667807bdf27"
@ -4865,7 +4855,7 @@ color-string@^1.5.2:
color-name "^1.0.0"
simple-swizzle "^0.2.2"
color@^3.0.0, color@^3.1.1, color@^3.1.2:
color@^3.0.0, color@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/color/-/color-3.1.2.tgz#68148e7f85d41ad7649c5fa8c8106f098d229e10"
integrity sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg==
@ -7431,11 +7421,6 @@ fs-constants@^1.0.0:
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
fs-copy-file-sync@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/fs-copy-file-sync/-/fs-copy-file-sync-1.1.1.tgz#11bf32c096c10d126e5f6b36d06eece776062918"
integrity sha512-2QY5eeqVv4m2PfyMiEuy9adxNP+ajf+8AR05cEi+OAzPcOj90hvFImeZhTmKLBgSd9EvG33jsD7ZRxsx9dThkQ==
fs-extra@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
@ -11430,7 +11415,7 @@ mz@^2.4.0, mz@^2.5.0:
object-assign "^4.0.1"
thenify-all "^1.0.0"
nan@^2.12.1, nan@^2.13.2:
nan@^2.12.1:
version "2.14.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
@ -11510,6 +11495,11 @@ node-abi@^2.7.0:
dependencies:
semver "^5.4.1"
node-addon-api@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.0.tgz#f9afb8d777a91525244b01775ea0ddbe1125483b"
integrity sha512-ASCL5U13as7HhOExbT6OlWJJUV/lLzL2voOSP1UVehpRD8FbSrSDjfScK/KwAvVTI5AS6r4VwbOMlIqtvRidnA==
node-emoji@^1.10.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.10.0.tgz#8886abd25d9c7bb61802a658523d1f8d2a89b2da"
@ -11630,7 +11620,7 @@ node-releases@^1.1.53:
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.53.tgz#2d821bfa499ed7c5dffc5e2f28c88e78a08ee3f4"
integrity sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ==
node-vibrant@^3.1.4:
node-vibrant@^3.1.5:
version "3.1.5"
resolved "https://registry.yarnpkg.com/node-vibrant/-/node-vibrant-3.1.5.tgz#8729bf35aabd54cd2eccbfadf22124ab4e1305b0"
integrity sha512-Gk+iyBzPSN1SF5qL818QaBtuA38206Z8iPNa0PcLUPyIbZL4+i14VmYxkGCL0n/5Q1721CRSktqtACgkx7Qodg==
@ -13423,7 +13413,7 @@ postcss@^7.0.1, postcss@^7.0.16, postcss@^7.0.17, postcss@^7.0.23, postcss@^7.0.
source-map "^0.6.1"
supports-color "^6.1.0"
prebuild-install@^5.3.0:
prebuild-install@^5.3.3:
version "5.3.3"
resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.3.3.tgz#ef4052baac60d465f5ba6bf003c9c1de79b9da8e"
integrity sha512-GV+nsUXuPW2p8Zy7SarF/2W/oiK8bFQgJcncoJ0d7kRpekEA0ftChjfEaF9/Y+QJEc/wFR7RAEa8lYByuUIe2g==
@ -15057,6 +15047,11 @@ semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.1.3:
version "7.1.3"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.1.3.tgz#e4345ce73071c53f336445cfc19efb1c311df2a6"
integrity sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA==
send@0.17.1:
version "0.17.1"
resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
@ -15161,20 +15156,19 @@ shallowequal@^1.0.1:
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==
sharp@^0.22.1:
version "0.22.1"
resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.22.1.tgz#a67c0e75567f03dd5a7861b901fec04072c5b0f4"
integrity sha512-lXzSk/FL5b/MpWrT1pQZneKe25stVjEbl6uhhJcTULm7PhmJgKKRbTDM/vtjyUuC/RLqL2PRyC4rpKwbv3soEw==
sharp@^0.25.2:
version "0.25.2"
resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.25.2.tgz#f9003d73be50e9265e98f79f04fe53d8c66a3967"
integrity sha512-l1GN0kFNtJr3U9i9pt7a+vo2Ij0xv4tTKDIPx8W6G9WELhPwrMyZZJKAAQNBSI785XB4uZfS5Wpz8C9jWV4AFQ==
dependencies:
color "^3.1.1"
color "^3.1.2"
detect-libc "^1.0.3"
fs-copy-file-sync "^1.1.1"
nan "^2.13.2"
node-addon-api "^2.0.0"
npmlog "^4.1.2"
prebuild-install "^5.3.0"
semver "^6.0.0"
simple-get "^3.0.3"
tar "^4.4.8"
prebuild-install "^5.3.3"
semver "^7.1.3"
simple-get "^3.1.0"
tar "^6.0.1"
tunnel-agent "^0.6.0"
shebang-command@^1.2.0:
@ -15238,7 +15232,7 @@ simple-concat@^1.0.0:
resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6"
integrity sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=
simple-get@^3.0.3:
simple-get@^3.0.3, simple-get@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.1.0.tgz#b45be062435e50d159540b576202ceec40b9c6b3"
integrity sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==
@ -16138,7 +16132,7 @@ tar@^4.4.10, tar@^4.4.12, tar@^4.4.8:
safe-buffer "^5.1.2"
yallist "^3.0.3"
tar@^6.0.0:
tar@^6.0.0, tar@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/tar/-/tar-6.0.1.tgz#7b3bd6c313cb6e0153770108f8d70ac298607efa"
integrity sha512-bKhKrrz2FJJj5s7wynxy/fyxpE0CmCjmOQ1KV4KkgXFWOgoIT/NbTMnB1n+LFNrNk0SSBVGGxcK5AGsyC+pW5Q==