New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

grunt-responsive-images-extender

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

grunt-responsive-images-extender - npm Package Compare versions

Comparing version 0.1.0 to 1.0.0

38

Gruntfile.js

@@ -38,3 +38,24 @@ /*

options: {
useSizes: true
sizes: [{
selector: '.fig-hero img',
sizeList: [{
cond: 'max-width: 30em',
size: '100vw'
},{
cond: 'max-width: 50em',
size: '50vw'
},{
cond: 'default',
size: 'calc(33vw - 100px)'
}]
},{
selector: '[alt]',
sizeList: [{
cond: 'max-width: 20em',
size: '80vw'
},{
cond: 'default',
size: '90vw'
}]
}]
},

@@ -61,3 +82,3 @@ files: {

options: {
useSizes: true,
ignore: ['.ignore-me'],
srcset: [{

@@ -79,2 +100,15 @@ suffix: '-200',

value: '2x'
}],
sizes: [{
selector: '.fig-hero img',
sizeList: [{
cond: 'max-width: 30em',
size: '100vw'
},{
cond: 'max-width: 50em',
size: '50vw'
},{
cond: 'default',
size: 'calc(33vw - 100px)'
}]
}]

@@ -81,0 +115,0 @@ },

{
"name": "grunt-responsive-images-extender",
"description": "Extend HTML image tags with srcset and sizes attributes to leverage native responsive images.",
"version": "0.1.0",
"version": "1.0.0",
"homepage": "https://github.com/smaxtastic/grunt-responsive-images-extender",

@@ -40,4 +40,18 @@ "author": {

"keywords": [
"gruntplugin", "grunt", "responsive", "img", "image", "images", "extend", "convert", "converter", "srcset", "sizes", "responsivedesign"
]
}
"gruntplugin",
"grunt",
"responsive",
"img",
"image",
"images",
"extend",
"convert",
"converter",
"srcset",
"sizes",
"responsivedesign"
],
"dependencies": {
"cheerio": "^0.17.0"
}
}

@@ -28,2 +28,4 @@ # grunt-responsive-images-extender

This plugin uses [Cheerio](https://github.com/cheeriojs/cheerio) to traverse and modify the DOM.
In your project's Gruntfile, add a section named `responsive_images_extender` to the data object passed into `grunt.initConfig()`.

@@ -52,17 +54,36 @@

* **options.useSizes**<br>
*Type:* `Boolean`<br>
*Default:* `false`<br>
Determines whether a `sizes` attribute is added. If set to `true`, the `options.sizes` array is used to build the attribute value.
* **options.sizes**<br>
*Type:* `Array`<br>
*Default:* `[{cond: 'max-width: 30em', size: '100vw'}, {cond: 'max-width: 50em', size: '50vw'}, {cond: 'default', size: 'calc(33vw - 100px)'}]`<br>
*Default:* none<br>
An array of objects containing the conditions and sizes of our size tableau. The default values are adopted from said [article by Yoav Weiss](https://dev.opera.com/articles/native-responsive-images/).
An array of objects containing the selectors (standard CSS selectors, like `.some-class`, `#an-id` or `img[src^="http://"]`) and their respective size tableau. An example could look like this:
```js
sizes: [{
selector: '#post-header',
sizeList: [{
cond: 'max-width: 30em',
size: '100vw'
},{
cond: 'max-width: 50em',
size: '50vw'
},{
cond: 'default',
size: 'calc(33vw - 100px)'
}]
},{
selector: '.hero img',
sizeList: [{
cond: 'max-width: 20em',
size: '80vw'
},{
cond: 'default',
size: '90vw'
}]
}]
```
If you want to set a default size value, make sure to set the condition to `default` and add the object at the end of the array. Otherwise the default value renders the following media conditions obsolete, since the browser walks through the list specified in `sizes` and looks for the first matching one.
This array is optional and only used when `options.useSizes` is set to `true`. Otherwise the browser assumes the size `100vw` for all images.
This array is optional and without specifying one the browser assumes the size `100vw` for all images.

@@ -75,6 +96,12 @@ * **options.srcsetRetina**<br>

* **options.ignore**<br>
*Type:* `Array`<br>
*Default:* `[]`<br>
An array of selectors you want to ignore.
### Usage Examples
#### Default Options
Using the default options will make the task search for HTML `<img>` tags that have no `width` or `srcset` attribute already. Once found
Using the default options will make the task search for HTML `<img>` tags that have no `width` or `srcset` attribute already.

@@ -121,3 +148,2 @@ ```js

options: {
useSizes: true,
srcset: [{

@@ -139,2 +165,15 @@ suffix: '-200',

value: '2x'
}],
sizes: [{
selector: '.article-img',
sizeList: [{
cond: 'max-width: 30em',
size: '100vw'
},{
cond: 'max-width: 50em',
size: '50vw'
},{
cond: 'default',
size: 'calc(33vw - 100px)'
}]
}]

@@ -156,3 +195,3 @@ },

```html
<img alt="A simple image" src="simple.jpg" title="A simple image">
<img alt="A simple image" src="simple.jpg" class="article-img">

@@ -165,3 +204,3 @@ <img src="non_responsive.png" width="150">

```html
<img alt="A simple image" src="simple.jpg"
<img alt="A simple image" src="simple.jpg" class=".article-img"
srcset="simple-200.jpg 200w,

@@ -172,11 +211,30 @@ simple-400.jpg 400w,

(max-width: 50em) 50vw,
calc(33vw - 100px)"
title="A simple image">
calc(33vw - 100px)">
<img src="non_responsive.png"
<img src="non_responsive.png" width="150"
srcset="non_responsive_x1.5.png 1.5x,
non_responsive_x2.png 2x"
width="150">
non_responsive_x2.png 2x">
```
#### Ignoring images
Sometimes you want to exclude certain images from the algorithm. You can achieve this with the `ignore` option:
```js
grunt.initConfig({
responsive_images_extender: {
ignoring: {
options: {
ignore: ['.icons', '#logo', 'figure img']
},
files: [{
expand: true,
src: ['**/*.{html,htm,php}'],
cwd: 'src/',
dest: 'build/'
}]
}
}
});
```
Please see this task's [Gruntfile](https://github.com/smaxtastic/grunt-responsive-images-extender/blob/master/Gruntfile.js) for more usage examples.

@@ -199,4 +257,9 @@

*0.0.1*
*1.0.0*
* The `sizes` option allows users to specify multiple sizes for different selectors, for example for hero images, article images or icons.
* Added the `ignore` option.
*0.1.0*
* Initial commit and first version

119

tasks/responsive_images_extender.js

@@ -7,2 +7,7 @@ /*

* Licensed under the MIT license.
*
* Extend HTML image tags with srcset and sizes attributes to leverage native responsive images.
*
* @author Stephan Max (http://twitter.com/smaxtastic)
* @version 0.1.0
*/

@@ -13,15 +18,7 @@

module.exports = function(grunt) {
var cheerio = require('cheerio');
var DEFAULT_OPTIONS = {
useSizes: false,
sizes: [{
cond: 'max-width: 30em',
size: '100vw'
},{
cond: 'max-width: 50em',
size: '50vw'
},{
cond: 'default',
size: 'calc(33vw - 100px)'
}],
ignore: [],
srcset: [{

@@ -40,5 +37,5 @@ suffix: '-small',

grunt.registerMultiTask('responsive_images_extender', 'Extend HTML image tags with srcset and sizes attributes to leverage native responsive images.', function() {
var numOfFiles = this.files.length;
var options = this.options(DEFAULT_OPTIONS);
var processedImgs = 0;
var numOfFiles = this.files.length,
options = this.options(DEFAULT_OPTIONS),
processedImages = 0;

@@ -54,23 +51,9 @@ function buildAttributeList(optionList, buildAttribute) {

function parseAndExtendImg(content, options) {
var numberOfMatches = 0;
var findImg = /(<img[^>]+src=")(.+)(\.[^"]+)("[^>]*>)/gi;
var $ = cheerio.load(content),
images = $('img:not(' + options.ignore.join(', ') + ')');
content = content.replace(findImg, function(match, front, filePath, fileExt, remainder) {
images.each(function() {
var separatorPos, filePath, fileExt,
image = $(this);
var sources, sizes;
function buildReplacement(srcset, sizes) {
var replacement = front + filePath + fileExt;
if (typeof srcset !== 'undefined') {
replacement += '" srcset="' + srcset;
}
if (typeof sizes !== 'undefined') {
replacement += '" sizes="' + sizes;
}
return replacement + remainder;
}
function buildSrc(option) {

@@ -89,6 +72,7 @@ return filePath + option.suffix + fileExt + ' ' + option.value;

var retinaReady = 'srcsetRetina' in options;
var isNonResponsive = match.indexOf('width') !== -1;
var hasSrcset = match.indexOf('srcset') !== -1;
var hasSizes = match.indexOf('sizes') !== -1;
var retinaReady = 'srcsetRetina' in options,
useSizes = 'sizes' in options,
isNonResponsive = image.attr('width') !== undefined,
hasSrcset = image.attr('srcset') !== undefined,
hasSizes = image.attr('sizes') !== undefined;

@@ -99,42 +83,41 @@ // Don't process <img> tags unnecessarily

(!isNonResponsive && hasSrcset && hasSizes) ||
(hasSrcset && !options.useSizes)) {
return match;
(hasSrcset && !useSizes)) {
return;
}
filePath = image.attr('src');
if (filePath === undefined) {
grunt.log.verbose.error('Found an image without a source: ' + $.html(image));
return;
}
separatorPos = filePath.lastIndexOf('.');
fileExt = filePath.slice(separatorPos);
filePath = filePath.slice(0, separatorPos);
if (isNonResponsive) {
sources = buildAttributeList(options.srcsetRetina, buildSrc);
grunt.log.verbose.ok(
'Detected width attribute for ' + filePath + fileExt +
' (not responsive, but retina-ready)'
);
image.attr('srcset', buildAttributeList(options.srcsetRetina, buildSrc));
grunt.log.verbose.ok('Detected width attribute for ' + filePath + fileExt + ' (not responsive, but retina-ready)');
}
else {
if (!hasSrcset) {
sources = buildAttributeList(options.srcset, buildSrc);
grunt.log.verbose.ok(
'Extend ' + filePath + fileExt + ' with srcset attribute'
);
image.attr('srcset', buildAttributeList(options.srcset, buildSrc));
grunt.log.verbose.ok('Extend ' + filePath + fileExt + ' with srcset attribute');
}
if (!hasSizes && options.useSizes) {
sizes = buildAttributeList(options.sizes, buildSize);
grunt.log.verbose.ok(
'Extend ' + filePath + fileExt + ' with sizes attribute'
);
if (!hasSizes && useSizes) {
options.sizes.some(function (s) {
if (image.is(s.selector)) {
image.attr('sizes', buildAttributeList(s.sizeList, buildSize));
grunt.log.verbose.ok('Extend ' + filePath + fileExt + ' with sizes attribute (selector: ' + s.selector + ')');
return true;
}
});
}
}
numberOfMatches++;
return buildReplacement(sources, sizes);
});
return {content: content, count: numberOfMatches};
return {content: $.html(), count: images.length};
}
grunt.log.writeln(
'Found ' +
numOfFiles.toString().cyan + ' ' +
grunt.util.pluralize(numOfFiles, 'file/files')
);
grunt.log.writeln('Found ' + numOfFiles.toString().cyan + ' ' + grunt.util.pluralize(numOfFiles, 'file/files'));

@@ -146,14 +129,8 @@ this.files.forEach(function(f) {

grunt.file.write(f.dest, result.content);
processedImgs += result.count;
processedImages += result.count;
});
grunt.log.writeln(
'Processed ' +
processedImgs.toString().cyan +
' <img> ' +
grunt.util.pluralize(processedImgs, 'tag/tags')
);
grunt.log.writeln('Processed ' + processedImages.toString().cyan + ' <img> ' + grunt.util.pluralize(processedImages, 'tag/tags'));
});
};

@@ -5,25 +5,4 @@ 'use strict';

/*
======== A Handy Little Nodeunit Reference ========
https://github.com/caolan/nodeunit
Test methods:
test.expect(numAssertions)
test.done()
Test assertions:
test.ok(value, [message])
test.equal(actual, expected, [message])
test.notEqual(actual, expected, [message])
test.deepEqual(actual, expected, [message])
test.notDeepEqual(actual, expected, [message])
test.strictEqual(actual, expected, [message])
test.notStrictEqual(actual, expected, [message])
test.throws(block, [error], [message])
test.doesNotThrow(block, [error], [message])
test.ifError(value)
*/
exports.responsive_images_extender = {
setUp: function(done) {
// setup here if necessary
done();

@@ -36,3 +15,3 @@ },

var expected = grunt.file.read('test/expected/default_options');
test.equal(actual, expected, 'should describe what the default behavior is.');
test.equal(actual, expected, 'Should describe what the default behavior is.');

@@ -46,3 +25,3 @@ test.done();

var expected = grunt.file.read('test/expected/retina');
test.equal(actual, expected, 'should describe what the retina behavior is.');
test.equal(actual, expected, 'Should describe what the retina behavior is.');

@@ -56,3 +35,3 @@ test.done();

var expected = grunt.file.read('test/expected/use_sizes');
test.equal(actual, expected, 'should describe what the sizes attribute behavior is.');
test.equal(actual, expected, 'Should describe what the sizes attribute behavior is.');

@@ -66,3 +45,3 @@ test.done();

var expected = grunt.file.read('test/expected/all');
test.equal(actual, expected, 'should describe what the complete behavior is.');
test.equal(actual, expected, 'Should describe what the complete behavior is.');

@@ -69,0 +48,0 @@ test.done();

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc