UNPKG

eleventy-plugin-local-respimg

Version:

Eleventy plugin for optimizing and making responsive local images

177 lines (158 loc) 4.99 kB
/** * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const sharp = require('sharp'); const imagemin = require('imagemin'); const imageminWebP = require('imagemin-webp'); const mozjpeg = require('imagemin-mozjpeg'); const pngquant = require('imagemin-pngquant'); const gif2webp = require('imagemin-gif2webp'); const svgo = require('imagemin-svgo'); const gifResize = require('@gumlet/gif-resize'); const { ensureDirSync } = require('fs-extra'); const path = require('path'); const { writeFile } = require('fs').promises; const util = require('util'); const exec = util.promisify(require('child_process').exec); const { outputURL } = require('./helpers'); /** * * @param {number[]} sizes - An array of widths in px * @param {string} type - file extension * @param {string} src - image source URL * @param {buffer} buff - File buffer * @param {object} config - Config * * @return {Promise[]} */ async function resizeAndOptimize(sizes, type, src, buff, config) { switch (type.mime) { case 'image/gif': { return sizes.map(async size => { const c = config.images.gifresize || {}; const output = await gifResize(Object.assign(c, { width: size }))(buff); const webp = await generateWebp(output, config); const outputDest = outputURL(src, size, type.ext, config.folders.output); const webpDest = outputURL(src, size, 'webp', config.folders.output); return [ { dest: outputDest, buff: output }, { dest: webpDest, buff: webp }, ]; }); } case 'image/jpeg': case 'image/png': { return sizes.map(async size => { let output = await sharp(buff) .resize(size) .toBuffer(); if (process.env.NODE_ENV === 'production') { output = await imagemin.buffer(output, { plugins: [mozjpeg(config.images.mozjpeg || {}), pngquant(config.images.pngquant || {})], }); } const webp = await generateWebp(output, config); const outputDest = outputURL(src, size, type.ext, config.folders.output); const webpDest = outputURL(src, size, 'webp', config.folders.output); return [ { dest: outputDest, buff: output }, { dest: webpDest, buff: webp }, ]; }); } case 'image/svg': { if (process.env.NODE_ENV === 'production') { const output = await imagemin.buffer(buff, { plugins: [svgo(config.images.svgo || {})], }); return [ { dest: path.join(config.folders.output, src), buff: output, }, ]; } else { return [ { dest: path.join(config.folders.output, src), buff, }, ]; } } default: { return [ { dest: path.join(config.folders.output, src), buff, }, ]; } } } /** * * @param {object} f - File to optimize * @param {buffer} f.buff - File buffer * @param {string} f.dest - Destination path * @param {object} config - Config * * @return {buffer<Promise>} */ async function optimizeAdditional(f, config) { ensureDirSync(path.dirname(f.dest)); let output = f.buff; if (process.env.NODE_ENV === 'production') { output = await imagemin.buffer(f.buff, { destination: config.folders.output, plugins: [mozjpeg(config.images.mozjpeg || {}), pngquant(config.images.pngquant || {}), svgo(config.images.svgo || {})], }); } return writeFile(f.dest, output); } /** * * @param {buffer} buff - Input buffer * @param {object} config - Config * * @return {buffer} */ function generateWebp(buff, config) { return imagemin.buffer(buff, { plugins: [imageminWebP(config.images.webp || {}), gif2webp(config.images.gifwebp || {})], }); } /** * * @param {string} src * @param {object} config * @return {Promise} */ async function generateVideo(src, config) { const output = outputURL(src, 'xform', 'mp4', config.folders.output); const input = path.join(config.folders.source, src); const command = `ffmpeg -i ${input} -movflags faststart -filter:v "scale=trunc(iw/2)*2:trunc(ih/2)*2" -pix_fmt yuv420p -y -loglevel error ${output}`; const { stderr } = await exec(command); if (stderr) { return Promise.reject(stderr); } return output; } module.exports = { resizeAndOptimize, optimizeAdditional, generateVideo, generateWebp, };