UNPKG

responsive-loader

Version:
137 lines (115 loc) 4.82 kB
const path = require('path'); const loaderUtils = require('loader-utils'); const jimp = require('jimp'); const queue = require('d3-queue').queue; const MIMES = { 'jpg': 'image/jpeg', 'jpeg': 'image/jpeg', 'png': 'image/png' }; module.exports = function loader(content) { this.cacheable && this.cacheable(); const loaderCallback = this.async(); const query = loaderUtils.parseQuery(this.query); const options = this.options.responsiveLoader || {}; const sizes = query.sizes || query.size || options.sizes || [Number.MAX_SAFE_INTEGER]; const name = query.name || options.name || '[hash]-[width].'; const outputContext = query.context || options.context || ''; const outputPlaceholder = query.placeholder || query.placeholder !== false && options.placeholder || false; const placeholderSize = query.placeholderSize || options.placeholderSize || 40; // JPEG compression const quality = parseInt(query.quality, 10) || options.quality || 95; // Useful when converting from PNG to JPG const background = parseInt(query.background, 16) || options.background || 0xFFFFFFFF; // Specify ext to convert to another format const ext = query.ext || path.extname(this.resourcePath).replace(/\./, ''); const mime = MIMES[ext]; const loaderContext = this; if (!sizes) { return loaderCallback(null, content); } if (!mime) { return loaderCallback(new Error('No mime type for file with extension ' + ext + 'supported')); } if (options.pass) { // emit original content only const f = loaderUtils.interpolateName(loaderContext, '[hash].[ext]', {context: outputContext, content: content}); loaderContext.emitFile(f, content); const p = '__webpack_public_path__ + ' + JSON.stringify(f); return loaderCallback(null, 'module.exports = {srcSet:' + p + ',images:[{path:' + p + ',width:1}],src: ' + p + ',toString:function(){return ' + p + '}};'); } return jimp.read(loaderContext.resourcePath, (err, img) => { if (err) { return loaderCallback(err); } function resizeImage(width, queueCallback) { img .clone() .resize(width, jimp.AUTO) .quality(quality) .background(background) .getBuffer(mime, function resizeCallback(queueErr, buf) { if (err) { return queueCallback(queueErr); } const fileName = loaderUtils.interpolateName(loaderContext, name + ext, { context: outputContext, content: buf }).replace(/\[width\]/ig, width); loaderContext.emitFile(fileName, buf); return queueCallback(null, { src: '__webpack_public_path__ + ' + JSON.stringify(fileName + ' ' + width + 'w'), path: '__webpack_public_path__ + ' + JSON.stringify(fileName), width: width, height: this.bitmap.height }); }); } const q = queue(); const widthsToGenerate = new Set(); (Array.isArray(sizes) ? sizes : [sizes]).forEach((size) => { const width = Math.min(img.bitmap.width, parseInt(size, 10)); // Only resize images if they aren't an exact copy of one already being resized... if (!widthsToGenerate.has(width)) { widthsToGenerate.add(width); q.defer(resizeImage, width); } }); if (outputPlaceholder) { q.defer(function generatePlaceholder(queueCallback) { img .clone() .resize(placeholderSize, jimp.AUTO) .quality(quality) .background(background) .getBuffer(mime, function resizeCallback(queueErr, buf) { if (err) { return queueCallback(queueErr); } const placeholder = buf.toString('base64'); return queueCallback(null, JSON.stringify('data:' + (mime ? mime + ';' : '') + 'base64,' + placeholder)); }); }); } return q.awaitAll((queueErr, files) => { 'use strict'; // eslint-disable-line let placeholder; if (outputPlaceholder) { placeholder = files.pop(); } const srcset = files.map(f => f.src).join('+","+'); const images = files.map(f => '{path:' + f.path + ',width:' + f.width + ',height:' + f.height + '}').join(','); const firstImage = files[0]; loaderCallback(null, 'module.exports = {' + 'srcSet:' + srcset + ',' + 'images:[' + images + '],' + 'src:' + firstImage.path + ',' + 'toString:function(){return ' + firstImage.path + '},' + 'placeholder: ' + placeholder + ',' + 'width:' + firstImage.width + ',' + 'height:' + firstImage.height + '};'); }); }); }; module.exports.raw = true; // get buffer stream instead of utf8 string