Skip to content
Merged
2 changes: 1 addition & 1 deletion example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
Чтобы запустить этот пример,
нужно предварительно запустить imgproxy локально на 8080 порту командой
`docker run -e IMGPROXY_MAX_SRC_RESOLUTION=40 -p 8080:8080 -it darthsim/imgproxy`,
затем выполнить `npm run run-example` из корня проекта
затем выполнить `npm run dev` из корня проекта
и открыть в браузере http://localhost:8081/.
25 changes: 24 additions & 1 deletion example/react-entry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,58 @@ import React from 'react';
import ReactDOM from 'react-dom';
import { PictureSmart } from '../src/react';
import { backgroundCssSmart } from '../src/utils/backgroundCss';
import { getOriginal } from '../src/utils';

// Adds 'webp' class to html element if the browser supports webp.
import '../src/utils/webpDetector'
import '../src/utils/webpDetector';

const oneImageForAllBreakpoints = require.context('./images/oneImageForAllBreakpoints');
const differentBreakpoints = require.context('./images/differentBreakpoints');

const imageWithoutResize = require.context('./images/oneImageForAllBreakpoints?dontresize');

const myImageData = require('./images/oneImageForAllBreakpoints/all.png');
const myImageWithoutResizeData = require('./images/oneImageForAllBreakpoints/all.png?dontresize');

// Usage example getOriginal ()
console.log(getOriginal(myImageData));
console.log(getOriginal(myImageWithoutResizeData));

ReactDOM.render(
<div>
<h1>Example usage of csssr.images</h1>

<h2>As picture tag</h2>

<h3>One image for all resolutions</h3>
<PictureSmart requireImages={oneImageForAllBreakpoints} alt="One image for all resolutions" />

<h3>Image with different breakpoints</h3>
<PictureSmart requireImages={differentBreakpoints} alt="Image with different breakpoints" />

<h3>Image without resize</h3>
<PictureSmart requireImages={imageWithoutResize} alt="Image without resize" />

<h2>As background css</h2>

<h3>One image for all resolutions</h3>
<div className="one-image-for-all-resolutions" style={{ width: '100%', height: '100%' }}>
One image for all resolutions on background
</div>
<style>{backgroundCssSmart('.one-image-for-all-resolutions', oneImageForAllBreakpoints)}</style>

<h3>Different breakpoints</h3>
<div className="different-breakpoints" style={{ width: '100%', height: '100%' }}>
Image with different breakpoints on background
</div>
<style>{backgroundCssSmart('.different-breakpoints', differentBreakpoints)}</style>

<h3>Image without resize</h3>

<div className="image-without-resize" style={{ width: '100%', height: '100%' }}>
Image without resize on background
</div>
<style>{backgroundCssSmart('.image-without-resize', imageWithoutResize)}</style>
</div>,
document.getElementById('app'),
);
83 changes: 50 additions & 33 deletions example/webpack.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,52 @@
import path from 'path';
import webpack from 'webpack';
import ip from 'ip';
import { Plugin } from '../src/webpack';
import { Dpr } from '../src/types';

const handleImagesForOriginalPixelRatio = (originalPixelRatio: Dpr) => {
return {
use: [
{
loader: path.resolve(__dirname, '../src/index.ts'),
options: {
breakpoints: [
{
name: 'mobile',
maxWidth: 767,
},
{
name: 'tablet',
minWidth: 768,
maxWidth: 1279,
},
{
name: 'desktop',
minWidth: 1280,
},
],
imgproxy: {
disable: false,
imagesHost: process.env.HOST || `http://${ip.address()}:8081`,
host: process.env.IMGPROXY_HOST || 'http://localhost:8080',
},
originalPixelRatio,
},
},
{
loader: 'file-loader',
options: {
publicPath: '/build',
name:
process.env.NODE_ENV === 'development'
? '[path][name].[ext]'
: '[path][name]-[hash:8].[ext]',
esModule: false,
},
},
],
};
};

const config: webpack.Configuration = {
mode: 'production',
Expand All @@ -23,42 +69,13 @@ const config: webpack.Configuration = {
},
{
test: /\.(jpe?g|png|gif)$/,
use: [
oneOf: [
{
loader: path.resolve(__dirname, '../src/index.ts'),
options: {
breakpoints: [
{
name: 'mobile',
maxWidth: 767,
},
{
name: 'tablet',
minWidth: 768,
maxWidth: 1279,
},
{
name: 'desktop',
minWidth: 1280,
},
],
imgproxy: {
disable: false,
imagesHost: process.env.HOST || 'http://192.168.1.134:8081',
host: process.env.IMGPROXY_HOST || 'http://localhost:8080',
},
},
resourceQuery: /dontresize/,
...handleImagesForOriginalPixelRatio('1x'),
},
{
loader: 'file-loader',
options: {
publicPath: '/build',
name:
process.env.NODE_ENV === 'development'
? '[path][name].[ext]'
: '[path][name]-[hash:8].[ext]',
esModule: false,
},
...handleImagesForOriginalPixelRatio('3x'),
},
],
},
Expand Down
17 changes: 15 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
"eslint-plugin-react": "^7.20.3",
"file-loader": "^6.0.0",
"http-server": "^0.12.3",
"jest": "^26.1.0",
"ip": "^1.1.5",
"jest": "^26.0.1",
"loader-utils": "^2.0.0",
"prettier": "^2.0.5",
"ts-jest": "^26.1.3",
Expand All @@ -49,6 +50,7 @@
"webpack-cli": "^3.3.12"
},
"dependencies": {
"@types/ip": "^1.1.0",
"imgproxy": "^0.1.2",
"react": "^16.13.1",
"react-dom": "^16.13.1"
Expand Down
10 changes: 9 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
export type Dpr = '1x' | '2x' | '3x';

export type CompressionRatio = {
'1x': number;
'2x'?: number;
'3x'?: number;
};

export type SrcSet = {
[dpr in Dpr]: string;
'1x': string;
'2x'?: string;
'3x'?: string;
};

export type ExtensionSrcSet = {
Expand Down
31 changes: 31 additions & 0 deletions src/utils/__tests__/backgroundCss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -397,3 +397,34 @@ test('backgroundCss multiple breakpoints, png and webp', () => {
}
}`);
});

test('backgroundCss all breakpoints, png and webp, one pixel ratio', () => {
expect(
backgroundCss('.my-selector', [
{
breakpointMedia: null,
srcSets: [
{
extension: 'png',
srcSet: {
'1x': '/mobile.all.1x.png',
},
},
{
extension: 'webp',
srcSet: {
'1x': '/mobile.all.1x.webp',
},
},
],
},
]),
).toBeSameCss(`
.my-selector {
background-image: url(/mobile.all.1x.png);
}
html.webp .my-selector {
background-image: url(/mobile.all.1x.webp);
}
`);
});
17 changes: 17 additions & 0 deletions src/utils/__tests__/getCompressionRatio.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { getCompressionRatio } from '../index';

test('Pixel ratios 1x', () => {
expect(getCompressionRatio(['1x'])).toStrictEqual({ '1x': 0 });
});

test('Pixel ratios 1x, 2x', () => {
expect(getCompressionRatio(['1x', '2x'])).toStrictEqual({ '1x': 0.5, '2x': 0 });
});

test('Pixel ratios 1x, 2x, 3x', () => {
expect(getCompressionRatio(['1x', '2x', '3x'])).toStrictEqual({
'1x': 0.33333,
'2x': 0.66667,
'3x': 0,
});
});
24 changes: 19 additions & 5 deletions src/utils/backgroundCss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,31 @@ const srcSetCss = (selector: string, sources: ExtensionSrcSet[]): string => {
(acc, source) => {
const finalSelector = getSelector(selector, source.extension);
acc['1x'].push(`${finalSelector} { background-image: url(${source.srcSet['1x']}); }`);
acc['2x'].push(`${finalSelector} { background-image: url(${source.srcSet['2x']}); }`);
acc['3x'].push(`${finalSelector} { background-image: url(${source.srcSet['3x']}); }`);
source.srcSet['2x'] &&
acc['2x'].push(`${finalSelector} { background-image: url(${source.srcSet['2x']}); }`);
source.srcSet['3x'] &&
acc['3x'].push(`${finalSelector} { background-image: url(${source.srcSet['3x']}); }`);
return acc;
},
{ '1x': [], '2x': [], '3x': [] },
);

return `
${result['1x'].join(' ')}
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { ${result['2x'].join(' ')} }
@media (-webkit-min-device-pixel-ratio: 3), (min-resolution: 288dpi) { ${result['3x'].join(' ')} }
${result['1x'].join(' ')}
${
result['2x'].length
? `@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { ${result['2x'].join(
' ',
)} }`
: ''
}
${
result['3x'].length
? ` @media (-webkit-min-device-pixel-ratio: 3), (min-resolution: 288dpi) { ${result[
'3x'
].join(' ')} }`
: ''
}
`;
};

Expand Down
15 changes: 15 additions & 0 deletions src/utils/getCompressionRatio.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Dpr, CompressionRatio } from '../types';

export const getCompressionRatio = (pixelRatios: Dpr[]): CompressionRatio => {
Comment thread
vkosinov marked this conversation as resolved.
const length = pixelRatios.length;

return pixelRatios.reduce((acc, item, index) => {
if (index + 1 === length) {
acc[item] = 0;
return acc;
}

acc[item] = Number(((index + 1) / length).toFixed(5));
return acc;
}, {} as CompressionRatio);
};
7 changes: 5 additions & 2 deletions src/utils/getOriginal.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { BreakpointSource } from '../types';

export const getOriginal = (source: BreakpointSource): string =>
source.srcSets[source.srcSets.length - 1].srcSet['3x'];
export const getOriginal = (source: BreakpointSource): string => {
const srcSet = source.srcSets[source.srcSets.length - 1].srcSet;

return srcSet['3x'] || srcSet['2x'] || srcSet['1x'];
};
12 changes: 12 additions & 0 deletions src/utils/getPixelRatios.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Dpr } from '../types';

export const getPixelRatios = (originalPixelRatio: Dpr): Dpr[] => {
switch (originalPixelRatio) {
case '1x':
return ['1x'];
case '2x':
return ['1x', '2x'];
case '3x':
return ['1x', '2x', '3x'];
}
};
2 changes: 2 additions & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ export { getBreakpointMedia } from './getBreakpointMedia';
export { getSrcSetString } from './getSrcSetString';
export { getSources } from './getSources';
export { getOriginal } from './getOriginal';
export { getPixelRatios } from './getPixelRatios';
export { getCompressionRatio } from './getCompressionRatio';
16 changes: 9 additions & 7 deletions src/utils/webpDetector.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
// https://stackoverflow.com/a/27232658

const canUseWebp = (): boolean => {
const canvas = document.createElement('canvas')
canvas.width = canvas.height = 1
return Boolean(canvas.toDataURL &&
canvas.toDataURL('image/webp') &&
canvas.toDataURL('image/webp').indexOf('image/webp') === 5)
}
const canvas = document.createElement('canvas');
canvas.width = canvas.height = 1;
return Boolean(
canvas.toDataURL &&
canvas.toDataURL('image/webp') &&
canvas.toDataURL('image/webp').indexOf('image/webp') === 5,
);
};

if (canUseWebp()) {
document.documentElement.classList.add('webp')
document.documentElement.classList.add('webp');
}
Loading