@automattic/jetpack-image-guide 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -8
- package/build/MeasurableImage.d.ts +8 -4
- package/build/find-image-elements.d.ts +2 -1
- package/build/index.asset.php +1 -1
- package/build/index.js +1 -1
- package/package.json +10 -5
- package/src/MeasurableImage.ts +13 -8
- package/src/find-image-elements.ts +10 -5
package/CHANGELOG.md
CHANGED
|
@@ -5,25 +5,37 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [0.
|
|
8
|
+
## [0.4.0] - 2023-06-23
|
|
9
|
+
### Added
|
|
10
|
+
- Jetpack Boost: add a proxy to Image Guide so it can load remote images. [#31145]
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- Improved image url validation for background image source. [#31410]
|
|
14
|
+
|
|
15
|
+
## 0.3.0 - 2023-05-11
|
|
16
|
+
### Changed
|
|
17
|
+
- Set `exports` in package.json. This will break directly requiring files from within the package in environments that respect `exports`. [#30313]
|
|
18
|
+
- Updated package dependencies. [#30264] [#30265] [#30294]
|
|
19
|
+
|
|
20
|
+
## 0.2.1 - 2023-04-06
|
|
9
21
|
### Changed
|
|
10
22
|
- Updated package dependencies. [#28609]
|
|
11
23
|
|
|
12
|
-
##
|
|
24
|
+
## 0.2.0 - 2023-01-19
|
|
13
25
|
### Changed
|
|
14
26
|
- Bundle the package to make it easy to consume [#28429]
|
|
15
27
|
|
|
16
28
|
### Fixed
|
|
17
29
|
- Clean up JavaScript eslint issues. [#28441]
|
|
18
30
|
|
|
19
|
-
##
|
|
31
|
+
## 0.1.2 - 2023-01-17
|
|
20
32
|
### Added
|
|
21
33
|
- Fixed an issue that would break the release process [#28186]
|
|
22
34
|
|
|
23
35
|
### Fixed
|
|
24
36
|
- Adding prepare script back to package.json, was needed for an ESlint test [#28103]
|
|
25
37
|
|
|
26
|
-
##
|
|
38
|
+
## 0.1.1 - 2022-12-26
|
|
27
39
|
### Added
|
|
28
40
|
- Turn on auto-publish [#28032]
|
|
29
41
|
|
|
@@ -37,7 +49,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
37
49
|
### Removed
|
|
38
50
|
- Minor package.json change - removing private entry.
|
|
39
51
|
|
|
40
|
-
[0.
|
|
41
|
-
[0.2.0]: https://github.com/Automattic/jetpack-image-guide/compare/v0.1.2...v0.2.0
|
|
42
|
-
[0.1.2]: https://github.com/Automattic/jetpack-image-guide/compare/v0.1.1...v0.1.2
|
|
43
|
-
[0.1.1]: https://github.com/Automattic/jetpack-image-guide/compare/v0.1.0...v0.1.1
|
|
52
|
+
[0.4.0]: https://github.com/Automattic/jetpack-image-guide/compare/v0.3.0...v0.4.0
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
1
|
+
export type SourceCallbackFn = (node: HTMLElement) => string | null;
|
|
2
|
+
export type Dimensions = {
|
|
3
3
|
width: number;
|
|
4
4
|
height: number;
|
|
5
5
|
};
|
|
6
|
-
export
|
|
6
|
+
export type Weight = {
|
|
7
7
|
weight: number;
|
|
8
8
|
};
|
|
9
|
+
type FetchFn = (input: URL | RequestInfo, init?: RequestInit) => Promise<Response>;
|
|
9
10
|
/**
|
|
10
11
|
* A class that represents a DOM Element that
|
|
11
12
|
* has an image that should be measured and
|
|
@@ -14,13 +15,15 @@ export declare type Weight = {
|
|
|
14
15
|
export declare class MeasurableImage {
|
|
15
16
|
readonly node: HTMLElement | HTMLImageElement;
|
|
16
17
|
private getURLCallback;
|
|
18
|
+
fetch: ((input: URL | RequestInfo, init?: RequestInit) => Promise<Response>) & typeof fetch;
|
|
17
19
|
/**
|
|
18
20
|
* Constructor.
|
|
19
21
|
*
|
|
20
22
|
* @param {HTMLElement | HTMLImageElement} node - The DOM Element that contains the image.
|
|
21
23
|
* @param {SourceCallbackFn} getURL - A function that takes in the node and returns the URL of the image.
|
|
24
|
+
* @param {FetchFn} fetchFn - A function that fetches a URL and returns a Promise.
|
|
22
25
|
*/
|
|
23
|
-
constructor(node: HTMLElement | HTMLImageElement, getURL: SourceCallbackFn);
|
|
26
|
+
constructor(node: HTMLElement | HTMLImageElement, getURL: SourceCallbackFn, fetchFn?: FetchFn);
|
|
24
27
|
getURL(): string;
|
|
25
28
|
getSizeOnPage(): {
|
|
26
29
|
width: number;
|
|
@@ -59,3 +62,4 @@ export declare class MeasurableImage {
|
|
|
59
62
|
*/
|
|
60
63
|
private fetchFileDimensions;
|
|
61
64
|
}
|
|
65
|
+
export {};
|
|
@@ -25,6 +25,7 @@ export declare function backgroundImageSource(node: HTMLElement): string;
|
|
|
25
25
|
* and remove any nodes that can't be measured.
|
|
26
26
|
*
|
|
27
27
|
* @param {Element[]} domNodes - A list of nodes to measure
|
|
28
|
+
* @param {(input: string, init?: Array) => Promise<Response>} fetchFn - A function that fetches a URL and returns a Promise.
|
|
28
29
|
* @returns {MeasurableImage[]} - A list of MeasurableImage objects.
|
|
29
30
|
*/
|
|
30
|
-
export declare function getMeasurableImages(domNodes: Element[]): MeasurableImage[];
|
|
31
|
+
export declare function getMeasurableImages(domNodes: Element[], fetchFn?: typeof fetch): MeasurableImage[];
|
package/build/index.asset.php
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<?php return array('dependencies' => array(), 'version' => '
|
|
1
|
+
<?php return array('dependencies' => array(), 'version' => '8823cb077090bda601fc');
|
package/build/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ImageGuideLibrary=e():t.ImageGuideLibrary=e()}(self,(()=>(()=>{"use strict";var t={38:(t,e,n)=>{n.d(e,{z:()=>i});var r=function(t,e,n,r){return new(n||(n=Promise))((function(o,i){function u(t){try{c(r.next(t))}catch(t){i(t)}}function a(t){try{c(r.throw(t))}catch(t){i(t)}}function c(t){var e;t.done?o(t.value):(e=t.value,e instanceof n?e:new n((function(t){t(e)}))).then(u,a)}c((r=r.apply(t,e||[])).next())}))},o=function(t,e){var n,r,o,i,u={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:a(0),throw:a(1),return:a(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function a(
|
|
1
|
+
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ImageGuideLibrary=e():t.ImageGuideLibrary=e()}(self,(()=>(()=>{"use strict";var t={38:(t,e,n)=>{n.d(e,{z:()=>i});var r=function(t,e,n,r){return new(n||(n=Promise))((function(o,i){function u(t){try{c(r.next(t))}catch(t){i(t)}}function a(t){try{c(r.throw(t))}catch(t){i(t)}}function c(t){var e;t.done?o(t.value):(e=t.value,e instanceof n?e:new n((function(t){t(e)}))).then(u,a)}c((r=r.apply(t,e||[])).next())}))},o=function(t,e){var n,r,o,i,u={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return i={next:a(0),throw:a(1),return:a(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function a(a){return function(c){return function(a){if(n)throw new TypeError("Generator is already executing.");for(;i&&(i=0,a[0]&&(u=0)),u;)try{if(n=1,r&&(o=2&a[0]?r.return:a[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,a[1])).done)return o;switch(r=0,o&&(a=[2&a[0],o.value]),a[0]){case 0:case 1:o=a;break;case 4:return u.label++,{value:a[1],done:!1};case 5:u.label++,r=a[1],a=[0];continue;case 7:a=u.ops.pop(),u.trys.pop();continue;default:if(!(o=u.trys,(o=o.length>0&&o[o.length-1])||6!==a[0]&&2!==a[0])){u=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]<o[3])){u.label=a[1];break}if(6===a[0]&&u.label<o[1]){u.label=o[1],o=a;break}if(o&&u.label<o[2]){u.label=o[2],u.ops.push(a);break}o[2]&&u.ops.pop(),u.trys.pop();continue}a=e.call(t,u)}catch(t){a=[6,t],r=0}finally{n=o=0}if(5&a[0])throw a[1];return{value:a[0]?a[1]:void 0,done:!0}}([a,c])}}},i=function(){function t(t,e,n){void 0===n&&(n=fetch),this.fetch=window.fetch,this.node=t,this.getURLCallback=e,this.fetch=n}return t.prototype.getURL=function(){return this.getURLCallback(this.node)},t.prototype.getSizeOnPage=function(){var t=this.node.getBoundingClientRect(),e=t.width,n=t.height;return{width:Math.round(e),height:Math.round(n)}},t.prototype.getFileSize=function(t){return r(this,void 0,void 0,(function(){var e,n,r,i,u;return o(this,(function(o){switch(o.label){case 0:return[4,Promise.all([this.fetchFileWeight(t),this.fetchFileDimensions(t)])];case 1:return e=o.sent(),n=e[0],r=e[1],i=r.width,u=r.height,[2,{width:i,height:u,weight:n}]}}))}))},t.prototype.getPotentialSavings=function(t,e){var n=this.getOversizedRatio(t,e);return n<=1?null:Math.round(t.weight-t.weight/n)},t.prototype.getExpectedSize=function(t){var e=window.devicePixelRatio||1;return{width:Math.round(t.width*e),height:Math.round(t.height*e)}},t.prototype.getOversizedRatio=function(t,e){var n=this.getExpectedSize(e),r=n.width,o=n.height;return t.width*t.height/(r*o)},t.prototype.fetchFileWeight=function(t){return r(this,void 0,void 0,(function(){var e;return o(this,(function(n){switch(n.label){case 0:return[4,this.fetch(t)];case 1:return(e=n.sent()).url?[2,parseInt(e.headers.get("content-length"),10)/1024]:(console.log("Can't get image size for ".concat(t," likely due to a CORS error.")),[2,-1])}}))}))},t.prototype.fetchFileDimensions=function(t){return r(this,void 0,void 0,(function(){var e;return o(this,(function(n){return(e=new Image).src=t,[2,new Promise((function(t){e.onload=function(){t({width:Math.round(e.width),height:Math.round(e.height)})},e.onerror=function(){t({width:-1,height:-1})}}))]}))}))},t}()},705:(t,e,n)=>{n.d(e,{RK:()=>u});var r=n(38);function o(t){return a(t.currentSrc)?t.currentSrc:a(t.src)?t.src:null}function i(t){var e=getComputedStyle(t).backgroundImage.match(/url\(\s*(['"])(.*?)\1\s*\)/i),n=window.location.href.split("#")[0];return e&&e[2]&&e[2]!==n&&a(e[2])?e[2]:null}function u(t,e){return void 0===e&&(e=fetch),function(t){return t.filter((function(t){return t instanceof HTMLImageElement||t instanceof HTMLElement&&"none"!==getComputedStyle(t).backgroundImage}))}(t).map((function(t){return t instanceof HTMLImageElement?new r.z(t,o,e):t instanceof HTMLElement&&i(t)?new r.z(t,i):null})).filter((function(t){return null!==t}))}function a(t){if(t.startsWith("/"))return!t.split("?")[0].endsWith(".svg");try{var e=new URL(t);return"http:"===e.protocol||"https:"===e.protocol}catch(t){return!1}}}},e={};function n(r){var o=e[r];if(void 0!==o)return o.exports;var i=e[r]={exports:{}};return t[r](i,i.exports,n),i.exports}n.d=(t,e)=>{for(var r in e)n.o(e,r)&&!n.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:e[r]})},n.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),n.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var r={};return(()=>{n.r(r),n.d(r,{MeasurableImage:()=>t.z,getMeasurableImages:()=>e.RK});var t=n(38),e=n(705)})(),r})()));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/jetpack-image-guide",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Go through the dom to analyze image size on screen vs actual file size.",
|
|
5
5
|
"homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/image-guide/#readme",
|
|
6
6
|
"type": "module",
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
"license": "GPL-2.0-or-later",
|
|
16
16
|
"author": "Automattic",
|
|
17
17
|
"scripts": {
|
|
18
|
-
"prepare": "[ -e ./build/index.js ] || pnpm build",
|
|
19
18
|
"build": "pnpm run clean && webpack",
|
|
20
19
|
"clean": "rm -rf build/",
|
|
21
20
|
"watch": "pnpm run build && pnpm webpack watch",
|
|
@@ -23,14 +22,20 @@
|
|
|
23
22
|
},
|
|
24
23
|
"devDependencies": {
|
|
25
24
|
"@automattic/jetpack-webpack-config": "workspace:*",
|
|
26
|
-
"@typescript-eslint/parser": "5.
|
|
27
|
-
"eslint": "8.
|
|
25
|
+
"@typescript-eslint/parser": "5.59.0",
|
|
26
|
+
"eslint": "8.39.0",
|
|
28
27
|
"jest": "29.4.3",
|
|
29
28
|
"ts-loader": "9.4.2",
|
|
30
|
-
"typescript": "
|
|
29
|
+
"typescript": "5.0.4",
|
|
31
30
|
"webpack": "5.76.0",
|
|
32
31
|
"webpack-cli": "4.9.1"
|
|
33
32
|
},
|
|
33
|
+
"exports": {
|
|
34
|
+
".": {
|
|
35
|
+
"types": "./build/index.d.ts",
|
|
36
|
+
"default": "./build/index.js"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
34
39
|
"main": "./build/index.js",
|
|
35
40
|
"types": "./build/index.d.ts"
|
|
36
41
|
}
|
package/src/MeasurableImage.ts
CHANGED
|
@@ -2,6 +2,8 @@ export type SourceCallbackFn = ( node: HTMLElement ) => string | null;
|
|
|
2
2
|
export type Dimensions = { width: number; height: number };
|
|
3
3
|
export type Weight = { weight: number };
|
|
4
4
|
|
|
5
|
+
type FetchFn = ( input: URL | RequestInfo, init?: RequestInit ) => Promise< Response >;
|
|
6
|
+
|
|
5
7
|
/**
|
|
6
8
|
* A class that represents a DOM Element that
|
|
7
9
|
* has an image that should be measured and
|
|
@@ -11,15 +13,23 @@ export class MeasurableImage {
|
|
|
11
13
|
readonly node: HTMLElement | HTMLImageElement;
|
|
12
14
|
private getURLCallback: SourceCallbackFn;
|
|
13
15
|
|
|
16
|
+
public fetch = window.fetch;
|
|
17
|
+
|
|
14
18
|
/**
|
|
15
19
|
* Constructor.
|
|
16
20
|
*
|
|
17
21
|
* @param {HTMLElement | HTMLImageElement} node - The DOM Element that contains the image.
|
|
18
22
|
* @param {SourceCallbackFn} getURL - A function that takes in the node and returns the URL of the image.
|
|
23
|
+
* @param {FetchFn} fetchFn - A function that fetches a URL and returns a Promise.
|
|
19
24
|
*/
|
|
20
|
-
constructor(
|
|
25
|
+
constructor(
|
|
26
|
+
node: HTMLElement | HTMLImageElement,
|
|
27
|
+
getURL: SourceCallbackFn,
|
|
28
|
+
fetchFn: FetchFn = fetch
|
|
29
|
+
) {
|
|
21
30
|
this.node = node;
|
|
22
31
|
this.getURLCallback = getURL;
|
|
32
|
+
this.fetch = fetchFn;
|
|
23
33
|
}
|
|
24
34
|
|
|
25
35
|
public getURL() {
|
|
@@ -83,19 +93,14 @@ export class MeasurableImage {
|
|
|
83
93
|
* @param {string} url - string The URL of the image.
|
|
84
94
|
*/
|
|
85
95
|
private async fetchFileWeight( url: string ) {
|
|
86
|
-
const response = await fetch( url
|
|
96
|
+
const response = await this.fetch( url );
|
|
87
97
|
if ( ! response.url ) {
|
|
88
98
|
// eslint-disable-next-line no-console
|
|
89
99
|
console.log( `Can't get image size for ${ url } likely due to a CORS error.` );
|
|
90
100
|
return -1;
|
|
91
101
|
}
|
|
92
102
|
|
|
93
|
-
|
|
94
|
-
if ( size ) {
|
|
95
|
-
return parseInt( size, 10 ) / 1024;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return -1;
|
|
103
|
+
return parseInt( response.headers.get( 'content-length' ), 10 ) / 1024;
|
|
99
104
|
}
|
|
100
105
|
|
|
101
106
|
/**
|
|
@@ -44,9 +44,13 @@ export function imageTagSource( node: HTMLImageElement ) {
|
|
|
44
44
|
*/
|
|
45
45
|
export function backgroundImageSource( node: HTMLElement ) {
|
|
46
46
|
const src = getComputedStyle( node ).backgroundImage;
|
|
47
|
-
const url = src.match( /url\(
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
const url = src.match( /url\(\s*(['"])(.*?)\1\s*\)/i );
|
|
48
|
+
|
|
49
|
+
// If background image is `url('')`, the computed value becomes the current page URL. So we need to check for that.
|
|
50
|
+
const currentUrlWithoutHash = window.location.href.split( '#' )[ 0 ];
|
|
51
|
+
|
|
52
|
+
if ( url && url[ 2 ] && url[ 2 ] !== currentUrlWithoutHash && imageLikeURL( url[ 2 ] ) ) {
|
|
53
|
+
return url[ 2 ];
|
|
50
54
|
}
|
|
51
55
|
return null;
|
|
52
56
|
}
|
|
@@ -56,14 +60,15 @@ export function backgroundImageSource( node: HTMLElement ) {
|
|
|
56
60
|
* and remove any nodes that can't be measured.
|
|
57
61
|
*
|
|
58
62
|
* @param {Element[]} domNodes - A list of nodes to measure
|
|
63
|
+
* @param {(input: string, init?: Array) => Promise<Response>} fetchFn - A function that fetches a URL and returns a Promise.
|
|
59
64
|
* @returns {MeasurableImage[]} - A list of MeasurableImage objects.
|
|
60
65
|
*/
|
|
61
|
-
export function getMeasurableImages( domNodes: Element[] ): MeasurableImage[] {
|
|
66
|
+
export function getMeasurableImages( domNodes: Element[], fetchFn = fetch ): MeasurableImage[] {
|
|
62
67
|
const nodes = findMeasurableElements( domNodes );
|
|
63
68
|
return nodes
|
|
64
69
|
.map( node => {
|
|
65
70
|
if ( node instanceof HTMLImageElement ) {
|
|
66
|
-
return new MeasurableImage( node, imageTagSource );
|
|
71
|
+
return new MeasurableImage( node, imageTagSource, fetchFn );
|
|
67
72
|
} else if ( node instanceof HTMLElement ) {
|
|
68
73
|
if ( ! backgroundImageSource( node ) ) {
|
|
69
74
|
/**
|