-
Notifications
You must be signed in to change notification settings - Fork 74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Output placeholder image as data URI #16
Changes from all commits
5b9f01d
f1814e1
b551b67
ed151da
a85bea3
1dd0c0d
d382f3d
579a9d5
1888075
0934e9a
7a60f5c
281a0f2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,10 +22,10 @@ const responsiveImage = require('responsive?sizes[]=100,sizes[]=200,sizes[]=300! | |
// responsiveImage.images => [{height: 50, path: '2fefae46cb857bc750fa5e5eed4a0cde-100.jpg', width: 100}, {height: 100, path: '2fefae46cb857bc750fa5e5eed4a0cde-200.jpg', width: 200}, {height: 150, path: '2fefae46cb857bc750fa5e5eed4a0cde-300.jpg', width: 300}] | ||
// responsiveImage.src => '2fefae46cb857bc750fa5e5eed4a0cde-100.jpg' | ||
// responsiveImage.toString() => '2fefae46cb857bc750fa5e5eed4a0cde-100.jpg' | ||
React.render(<img srcSet={responsiveImage.srcSet} src={responsiveImage.src} />, el); | ||
ReactDOM.render(<img srcSet={responsiveImage.srcSet} src={responsiveImage.src} />, el); | ||
|
||
// Or you can just use it as props, `srcSet` and `src` will be set properly | ||
React.render(<img {...responsiveImage} />, el); | ||
ReactDOM.render(<img {...responsiveImage} />, el); | ||
``` | ||
|
||
Or use it in CSS (only the first resized image will be used, if you use multiple `sizes`): | ||
|
@@ -38,13 +38,32 @@ Or use it in CSS (only the first resized image will be used, if you use multiple | |
} | ||
``` | ||
|
||
```js | ||
// Outputs placeholder image as a data URI, and three images with 100, 200, and 300px widths | ||
const responsiveImage = require('responsive?placeholder=true&sizes[]=100,sizes[]=200,sizes[]=300!myImage.jpg'); | ||
|
||
// responsiveImage.placeholder => 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAIBAQE…' | ||
ReactDOM.render( | ||
<div style={{ | ||
height: responsiveImage.height, | ||
width: responsiveImage.width, | ||
backgroundSize: 'cover', | ||
backgroundImage: 'url("' + responsiveImage.placeholder + '")' | ||
}}> | ||
<img src={responsiveImage.src} srcSet={responsiveImage.srcSet} /> | ||
</div>, el); | ||
``` | ||
|
||
|
||
### Options | ||
|
||
- `sizes: array`: specify all widths you want to use; if a specified size exceeds the original image's width, the latter will be used (i.e. images won't be scaled up). You may also declare a default `sizes` array in `responsiveLoader` in your `webpack.config.js`. | ||
- `size: integer`: specify one width you want to use; if the specified size exceeds the original image's width, the latter will be used (i.e. images won't be scaled up) | ||
- `quality: integer`: JPEG compression quality; defaults to `95` | ||
- `ext: string`: either `png`, `jpg`, or `gif`; use to convert to another format; defaults to original file's extension | ||
- `background: hex`: Background fill when converting transparent to opaque images; defaults to `0xFFFFFFFF` (note: make sure this is a valid hex number) | ||
- `sizes: array` — specify all widths you want to use; if a specified size exceeds the original image's width, the latter will be used (i.e. images won't be scaled up). You may also declare a default `sizes` array in `responsiveLoader` in your `webpack.config.js`. | ||
- `size: integer` — specify one width you want to use; if the specified size exceeds the original image's width, the latter will be used (i.e. images won't be scaled up) | ||
- `quality: integer` — JPEG compression quality; defaults to `95` | ||
- `ext: string` — either `png`, `jpg`, or `gif`; use to convert to another format; defaults to original file's extension | ||
- `background: hex` — Background fill when converting transparent to opaque images; defaults to `0xFFFFFFFF` (note: make sure this is a valid hex number) | ||
- `placeholder: bool` — A true or false value to specify wether to output a placeholder image as a data URI. (Defaults to `false`) | ||
- `placeholderSize: integer` — A number value specifying the width of the placeholder image, if enabled with the option above. (Defaults to `40`) | ||
|
||
|
||
### Examples | ||
|
@@ -62,7 +81,9 @@ module.exports = { | |
]} | ||
}, | ||
responsiveLoader: { | ||
sizes: [300, 600, 1200, 2000] | ||
sizes: [300, 600, 1200, 2000], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. webpack 2 doesn't allow this, options should be passed to the plugin afaik. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I haven't really worked with v2 much and will leave updating documentation to someone more knowledgable. We would need to show examples for both versions, as webpack 2 isn't officially out yet. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Basically this, but yeah it's probably for another PR: https://webpack.js.org/how-to/upgrade-from-webpack-1/#loaderoptionplugin-context |
||
placeholder: true, | ||
placeholderSize: 50 | ||
} | ||
} | ||
``` | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,8 @@ module.exports = function loader(content) { | |
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 | ||
|
@@ -87,14 +89,46 @@ module.exports = function loader(content) { | |
} | ||
}); | ||
|
||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is 'use strict' necessary? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe I was getting the following error in older versions of node, complaining about use of
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But not with node >= 4, no? If we want to support older versions (I don't really 😁 ), we should add tests for those too in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thought so too, but it was failing with v4 and v5, only passed with v6. |
||
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 firstImagePath = files[0].path; | ||
|
||
loaderCallback(null, 'module.exports = {srcSet:' + srcset + ',images:[' + images + '],src:' + firstImagePath + ',toString:function(){return ' + firstImagePath + '}};'); | ||
const firstImage = files[0]; | ||
|
||
loaderCallback(null, 'module.exports = {' + | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, still too jet lagged. I've added the original image dimensions to the output. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this be the dimensions of the first resized image to align it with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now that would make sense, wouldn't it 😅 |
||
'srcSet:' + srcset + ',' + | ||
'images:[' + images + '],' + | ||
'src:' + firstImage.path + ',' + | ||
'toString:function(){return ' + firstImage.path + '},' + | ||
'placeholder: ' + placeholder + ',' + | ||
'width:' + firstImage.width + ',' + | ||
'height:' + firstImage.height + | ||
'};'); | ||
}); | ||
}); | ||
}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe an example using
import
as well?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the syntax for using query configuration with
import
? Is it the same?Otherwise I'd rather keep this consistent with the rest of the examples, and create them with the Webpack v2 documentation update.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes sounds reasonable :)