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

@ -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,
};