From 6f8e15bdf8f1fefc8d06c0e0fb8f48a9d8dc859d Mon Sep 17 00:00:00 2001 From: biodiscus Date: Wed, 18 Oct 2023 11:12:54 +0200 Subject: [PATCH] release v2.15.0 - feat: add `parsedValue` argument as an array of parsed filenames w/o URL query, in the `filter()` function of the `sources` - fix(BREAKING CHANGE): for `srcset` attribute the type of the `value` argument is now `string` (was as `Array`), in the `filter()` function of the `sources`, #36\ Note: for `srcset` attribute you can use the `parsedValue` as an array instead of the `value`, the `value` contains now an original string - docs: fix attributes type --- CHANGELOG.md | 9 ++-- README.md | 30 ++++++----- package.json | 2 +- src/Common/HtmlParser.js | 14 ++--- .../webpack.config.js | 10 ---- .../expected/assets/img/apple.02a7c382.png | Bin .../expected/assets/img/fig.c6809878.png | Bin .../expected/assets/img/fig2.c6809878.png | Bin .../expected/assets/img/fig3.c6809878.png | Bin .../expected/index.html | 12 +++++ .../src/index.html | 12 +++++ .../webpack.config.js | 50 ++++++++++++++++++ .../expected/assets/img/apple.02a7c382.png | Bin .../expected/assets/video/video.697ef306.mp4 | Bin .../expected/index.html | 0 .../src/index.html | 0 .../webpack.config.js | 0 .../expected/assets/img/apple.02a7c382.png | Bin 0 -> 1779 bytes .../expected/assets/img/fig.c6809878.png | Bin 0 -> 1635 bytes .../expected/assets/img/fig2.c6809878.png | Bin 0 -> 1635 bytes .../expected/assets/img/fig3.c6809878.png | Bin 0 -> 1635 bytes .../expected/assets/img/kiwi.da3e3cc9.png | Bin .../expected/assets/img/lemon.7b66be8e.png | Bin .../expected/assets/img/melon.a92cb911.png | Bin .../expected/assets/img/plum.d39e7174.png | Bin .../expected/index.html | 0 .../src/index.html | 0 .../webpack.config.js | 4 +- .../expected/assets/img/apple-60w.png | Bin 0 -> 484 bytes .../expected/assets/img/apple-70w.png | Bin 0 -> 548 bytes .../expected/pages/home.html | 2 +- .../src/views/index.html | 2 +- .../webpack.config.js | 1 + test/integration.test.js | 7 ++- test/unit.test.js | 39 ++++++++------ types.d.ts | 32 ++++++----- 36 files changed, 160 insertions(+), 66 deletions(-) rename test/cases/{loader-option-sources-attrs-filter-property => loader-option-sources-filter-parsedValues}/expected/assets/img/apple.02a7c382.png (100%) rename test/cases/{loader-option-sources-attrs-filter => loader-option-sources-filter-parsedValues}/expected/assets/img/fig.c6809878.png (100%) rename test/cases/{loader-option-sources-attrs-filter => loader-option-sources-filter-parsedValues}/expected/assets/img/fig2.c6809878.png (100%) rename test/cases/{loader-option-sources-attrs-filter => loader-option-sources-filter-parsedValues}/expected/assets/img/fig3.c6809878.png (100%) create mode 100644 test/cases/loader-option-sources-filter-parsedValues/expected/index.html create mode 100644 test/cases/loader-option-sources-filter-parsedValues/src/index.html create mode 100644 test/cases/loader-option-sources-filter-parsedValues/webpack.config.js rename test/cases/{loader-option-sources-attrs-filter => loader-option-sources-filter-property}/expected/assets/img/apple.02a7c382.png (100%) rename test/cases/{loader-option-sources-attrs-filter-property => loader-option-sources-filter-property}/expected/assets/video/video.697ef306.mp4 (100%) rename test/cases/{loader-option-sources-attrs-filter-property => loader-option-sources-filter-property}/expected/index.html (100%) rename test/cases/{loader-option-sources-attrs-filter-property => loader-option-sources-filter-property}/src/index.html (100%) rename test/cases/{loader-option-sources-attrs-filter-property => loader-option-sources-filter-property}/webpack.config.js (100%) create mode 100644 test/cases/loader-option-sources-filter/expected/assets/img/apple.02a7c382.png create mode 100644 test/cases/loader-option-sources-filter/expected/assets/img/fig.c6809878.png create mode 100644 test/cases/loader-option-sources-filter/expected/assets/img/fig2.c6809878.png create mode 100644 test/cases/loader-option-sources-filter/expected/assets/img/fig3.c6809878.png rename test/cases/{loader-option-sources-attrs-filter => loader-option-sources-filter}/expected/assets/img/kiwi.da3e3cc9.png (100%) rename test/cases/{loader-option-sources-attrs-filter => loader-option-sources-filter}/expected/assets/img/lemon.7b66be8e.png (100%) rename test/cases/{loader-option-sources-attrs-filter => loader-option-sources-filter}/expected/assets/img/melon.a92cb911.png (100%) rename test/cases/{loader-option-sources-attrs-filter => loader-option-sources-filter}/expected/assets/img/plum.d39e7174.png (100%) rename test/cases/{loader-option-sources-attrs-filter => loader-option-sources-filter}/expected/index.html (100%) rename test/cases/{loader-option-sources-attrs-filter => loader-option-sources-filter}/src/index.html (100%) rename test/cases/{loader-option-sources-attrs-filter => loader-option-sources-filter}/webpack.config.js (92%) create mode 100644 test/cases/responsive-images-html-css/expected/assets/img/apple-60w.png create mode 100644 test/cases/responsive-images-html-css/expected/assets/img/apple-70w.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 83c157a1..22130b99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,11 @@ # Change log -## 2.14.5 (2023-10-17) +## 2.15.0 (2023-10-18) -- fix: correct the type of the `value` argument in the `filter()` function of the `sources` loader option +- feat: add `parsedValue` argument as an array of parsed filenames w/o URL query, in the `filter()` function of the `sources` +- fix(BREAKING CHANGE): for `srcset` attribute the type of the `value` argument is now `string` (was as `Array`), in the `filter()` function of the `sources`\ + Note: for `srcset` attribute you can use the `parsedValue` as an array instead of the `value`, the `value` contains now an original string +- docs: fix attributes type ## 2.14.4 (2023-10-12) @@ -20,7 +23,7 @@ - fix: pass correct entry data in the template when the same template used for many pages with different data, in `serve` mode ## 2.14.1 (2023-09-24) -- + - fix: remove unused `isEntry` property from the `info` argument of the `postprocess` callback the `isEntry` property was always true, because template is defined as an entrypoint - chore: code cleanup diff --git a/README.md b/README.md index cf383fb8..ccffa379 100644 --- a/README.md +++ b/README.md @@ -641,7 +641,7 @@ The plugin automatically extracts JS and CSS whose source files are specified in ```ts type EntryObject = { - [key: string]: EntryDescription | string; + [name: string]: EntryDescription | string; }; ``` @@ -681,7 +681,7 @@ type EntryDescription = { /** * The template data. */ - data?: { [k: string]: any } | string; + data?: { [key: string]: any } | string; }; type FilenameTemplate = @@ -1330,7 +1330,7 @@ type Preload = Array<{ as?: string; rel?: string; type?: string; - attributes?: { [k: string]: string | boolean }; + attributes?: { [attributeName: string]: string | boolean }; }>; ``` @@ -2008,8 +2008,9 @@ type Sources = filter?: (props: { tag: string; attribute: string; - value: string | Array; - attributes: { [k: string]: string }; + value: string; + parsedValue: Array; + attributes: { [attributeName: string]: string }; resourcePath: string; }) => boolean | undefined; }>; @@ -2071,10 +2072,15 @@ The argument is an object containing the properties: - `tag: string` - a name of the HTML tag - `attribute: string` - a name of the HTML attribute -- `value: string | Array` - a value of the HTML attribute;\ - for `srcset` the `value` argument is an array of parsed filenames,\ - an original srcset value as string is available via `attributes.srcset` -- `attributes: string` - all attributes of the tag +- `value: string` - an original value of the HTML attribute +- `parsedValue: Array` - an array of filenames w/o URL query, parsed in the value\ + it's useful for the `srcset` attribute containing many image files, e.g.: + ```html + + ``` + the `parsedValue` for the `src` is `['image.png']`, the array with one parsed filename\ + the `parsedValue` for the `srcset` is `['image1.png', 'image2.png']` +- `attributes: { [attributeName: string]: string }` - all attributes of the tag - `resourcePath: string` - a path of the HTML template The processing of an attribute can be ignored by returning `false`. @@ -2259,7 +2265,7 @@ type BeforePreprocessor = | false | (( template: string, - loaderContext: LoaderContext & { data: { [k: string]: any } | string } + loaderContext: LoaderContext & { data: { [key: string]: any } | string } ) => string | undefined); ``` @@ -2311,7 +2317,7 @@ type Preprocessor = | 'nunjucks' | (( template: string, - loaderContext: LoaderContext & { data: { [k: string]: any } | string } + loaderContext: LoaderContext & { data: { [key: string]: any } | string } ) => string | Promise | undefined); ``` @@ -2391,7 +2397,7 @@ To use any templating engine, you can define the `preprocessor` as a function. ```ts type Preprocessor = ( template: string, - loaderContext: LoaderContext & { data: { [k: string]: any } | string } + loaderContext: LoaderContext & { data: { [key: string]: any } | string } ) => string | Promise | undefined; ``` diff --git a/package.json b/package.json index d10ee8b5..99a290b2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "html-bundler-webpack-plugin", - "version": "2.14.5", + "version": "2.15.0", "description": "HTML bundler plugin for webpack handles a template as an entry point, extracts CSS and JS from their sources referenced in HTML, supports template engines like Eta, EJS, Handlebars, Nunjucks.", "keywords": [ "html", diff --git a/src/Common/HtmlParser.js b/src/Common/HtmlParser.js index f4ff7a40..1cb0e1cc 100644 --- a/src/Common/HtmlParser.js +++ b/src/Common/HtmlParser.js @@ -143,14 +143,14 @@ class HtmlParser { let res = true; if (filter) { - let value = parsedAttr.value; + const { value, parsedValue } = parsedAttr; // when is the filter defined, parse all attributes once if (!attrs) { attrs = this.parseAttrAll(source); } - res = filter({ tag, attribute, value, attributes: attrs, resourcePath }) !== false; + res = filter({ tag, attribute, value, parsedValue, attributes: attrs, resourcePath }) !== false; } if (res === true) { @@ -223,7 +223,7 @@ class HtmlParser { * @param {string} attr The attribute to parse value. * @param {string} type The type of attribute value. * @param {Number} offset The absolute tag offset in the content. - * @return {{attr: string, attrs?: Array, value: string|Array, startPos: number, endPos: number}|boolean} + * @return {{attr: string, attrs?: Array, value: string, parsedValue: Array, startPos: number, endPos: number}|boolean} */ static parseAttr(content, attr, type = 'asset', offset = 0) { const open = `${attr}="`; @@ -248,14 +248,15 @@ class HtmlParser { return { attr, attrs, - value: values, + value, + parsedValue: values, startPos, endPos, offset, }; } - return { type, attr, value, startPos, endPos, offset }; + return { type, attr, value, parsedValue: [value.split('?', 1)[0]], startPos, endPos, offset }; } /** @@ -282,6 +283,7 @@ class HtmlParser { // support for 'responsive-loader' value, e.g.: image.png?{sizes: [100,200,300], format: 'jpg'} if (srcsetValue.indexOf('?{') > 0) { return { + // TODO: parse this complex non-standard use case values: [srcsetValue], attrs: [ { type, attr: 'srcset', value: srcsetValue, startPos: valueOffset, endPos: valueOffset + lastPos, offset }, @@ -309,7 +311,7 @@ class HtmlParser { endPos = currentPos; } - values.push(value); + values.push(value.split('?', 1)[0]); attrs.push({ type, diff --git a/test/cases/loader-option-sources-attrs/webpack.config.js b/test/cases/loader-option-sources-attrs/webpack.config.js index 199de746..6ef4cd98 100644 --- a/test/cases/loader-option-sources-attrs/webpack.config.js +++ b/test/cases/loader-option-sources-attrs/webpack.config.js @@ -30,16 +30,6 @@ module.exports = { tag: 'img-ng', attributes: ['data-src-one', 'data-src-two'], }, - // TODO: in next major version - // - change the value as original string - // - add the values argument containing array of parsed in srcset filenames - // { - // tag: 'img', - // attributes: ['srcset'], - // filter: ({ attribute, value, values }) => { - // console.log('\n### ATTR: ', { attribute, value, values }); - // }, - // }, { tag: 'link', attributes: ['data-source'], diff --git a/test/cases/loader-option-sources-attrs-filter-property/expected/assets/img/apple.02a7c382.png b/test/cases/loader-option-sources-filter-parsedValues/expected/assets/img/apple.02a7c382.png similarity index 100% rename from test/cases/loader-option-sources-attrs-filter-property/expected/assets/img/apple.02a7c382.png rename to test/cases/loader-option-sources-filter-parsedValues/expected/assets/img/apple.02a7c382.png diff --git a/test/cases/loader-option-sources-attrs-filter/expected/assets/img/fig.c6809878.png b/test/cases/loader-option-sources-filter-parsedValues/expected/assets/img/fig.c6809878.png similarity index 100% rename from test/cases/loader-option-sources-attrs-filter/expected/assets/img/fig.c6809878.png rename to test/cases/loader-option-sources-filter-parsedValues/expected/assets/img/fig.c6809878.png diff --git a/test/cases/loader-option-sources-attrs-filter/expected/assets/img/fig2.c6809878.png b/test/cases/loader-option-sources-filter-parsedValues/expected/assets/img/fig2.c6809878.png similarity index 100% rename from test/cases/loader-option-sources-attrs-filter/expected/assets/img/fig2.c6809878.png rename to test/cases/loader-option-sources-filter-parsedValues/expected/assets/img/fig2.c6809878.png diff --git a/test/cases/loader-option-sources-attrs-filter/expected/assets/img/fig3.c6809878.png b/test/cases/loader-option-sources-filter-parsedValues/expected/assets/img/fig3.c6809878.png similarity index 100% rename from test/cases/loader-option-sources-attrs-filter/expected/assets/img/fig3.c6809878.png rename to test/cases/loader-option-sources-filter-parsedValues/expected/assets/img/fig3.c6809878.png diff --git a/test/cases/loader-option-sources-filter-parsedValues/expected/index.html b/test/cases/loader-option-sources-filter-parsedValues/expected/index.html new file mode 100644 index 00000000..d5053010 --- /dev/null +++ b/test/cases/loader-option-sources-filter-parsedValues/expected/index.html @@ -0,0 +1,12 @@ + + + + Test + + + + + + + + \ No newline at end of file diff --git a/test/cases/loader-option-sources-filter-parsedValues/src/index.html b/test/cases/loader-option-sources-filter-parsedValues/src/index.html new file mode 100644 index 00000000..a742092a --- /dev/null +++ b/test/cases/loader-option-sources-filter-parsedValues/src/index.html @@ -0,0 +1,12 @@ + + + + Test + + + + + + + + \ No newline at end of file diff --git a/test/cases/loader-option-sources-filter-parsedValues/webpack.config.js b/test/cases/loader-option-sources-filter-parsedValues/webpack.config.js new file mode 100644 index 00000000..d0813435 --- /dev/null +++ b/test/cases/loader-option-sources-filter-parsedValues/webpack.config.js @@ -0,0 +1,50 @@ +const path = require('path'); +const HtmlBundlerPlugin = require('../../../'); + +module.exports = { + mode: 'production', + + output: { + path: path.join(__dirname, 'dist/'), + }, + + resolve: { + alias: { + '@images': path.join(__dirname, '../../fixtures/images'), + }, + }, + + plugins: [ + new HtmlBundlerPlugin({ + entry: { + index: './src/index.html', + }, + loaderOptions: { + sources: [ + { + tag: 'img', + attributes: ['data-srcset'], + // test parsedValue + filter: ({ attribute, value, parsedValue }) => { + //console.log('\n### filter attributes: ', { attribute, value, parsedValue }); + if (attribute === 'src' && parsedValue.includes('@images/pear.png')) return false; + if (attribute === 'data-srcset' && parsedValue.includes('@images/lemon.png')) return false; + }, + }, + ], + }, + }), + ], + + module: { + rules: [ + { + test: /\.(png|jpe?g|ico|svg)$/, + type: 'asset/resource', + generator: { + filename: 'assets/img/[name].[hash:8][ext][query]', + }, + }, + ], + }, +}; diff --git a/test/cases/loader-option-sources-attrs-filter/expected/assets/img/apple.02a7c382.png b/test/cases/loader-option-sources-filter-property/expected/assets/img/apple.02a7c382.png similarity index 100% rename from test/cases/loader-option-sources-attrs-filter/expected/assets/img/apple.02a7c382.png rename to test/cases/loader-option-sources-filter-property/expected/assets/img/apple.02a7c382.png diff --git a/test/cases/loader-option-sources-attrs-filter-property/expected/assets/video/video.697ef306.mp4 b/test/cases/loader-option-sources-filter-property/expected/assets/video/video.697ef306.mp4 similarity index 100% rename from test/cases/loader-option-sources-attrs-filter-property/expected/assets/video/video.697ef306.mp4 rename to test/cases/loader-option-sources-filter-property/expected/assets/video/video.697ef306.mp4 diff --git a/test/cases/loader-option-sources-attrs-filter-property/expected/index.html b/test/cases/loader-option-sources-filter-property/expected/index.html similarity index 100% rename from test/cases/loader-option-sources-attrs-filter-property/expected/index.html rename to test/cases/loader-option-sources-filter-property/expected/index.html diff --git a/test/cases/loader-option-sources-attrs-filter-property/src/index.html b/test/cases/loader-option-sources-filter-property/src/index.html similarity index 100% rename from test/cases/loader-option-sources-attrs-filter-property/src/index.html rename to test/cases/loader-option-sources-filter-property/src/index.html diff --git a/test/cases/loader-option-sources-attrs-filter-property/webpack.config.js b/test/cases/loader-option-sources-filter-property/webpack.config.js similarity index 100% rename from test/cases/loader-option-sources-attrs-filter-property/webpack.config.js rename to test/cases/loader-option-sources-filter-property/webpack.config.js diff --git a/test/cases/loader-option-sources-filter/expected/assets/img/apple.02a7c382.png b/test/cases/loader-option-sources-filter/expected/assets/img/apple.02a7c382.png new file mode 100644 index 0000000000000000000000000000000000000000..c3b5ce07f66020372ad9fffeff0bdb9111cf21cf GIT binary patch literal 1779 zcmV004pr0{{R3_H{EN0001KP)t-s*4Eb7 z*Vpv)^!4@i_xJbO+S=yk=JxjX^78W4)z$3m?BL+w+9>~<>ln$WQr zd70F6ds2)6;~=3cz?Gthpc%ww1cTgMkI!%%pAq5?K+9i~j}e+11Ra1V4Ohiu)~5|0 z)&LQ?tjSmCYIOicWr9~|#Ew(ml8C!4FdW15`*G z5LrPGSnt%NANl2lj=N2PdFNoc*dJ-S4?2O0?UJ^`Fz_4|pcBSZx8#w4Zrd!%Q!N81giFl=h+ifFP0`&zK!G@*?zjk6lYpiM54!R5 zujv6XoZ8nx>T{cRJ`C|7zmALGzI`J9*FSJ5ycba#$@0X27`yE&A%6d$f%^|q>Nqro zULTGF?1*5}%O|WCQ{GF`xYvi{Jh|JL(p8k{ddwn>vCyCp8lAa7p|5b$DJ{$*#$weK&Fz(}f`mZAF^x@di zOcW|}>~%c_oBosP^x^37pt3hU-#hr;{8z=W!-tcOsA*3}-1J{X*zUvea}x5l@PCea z_}=_i5w`kJW7-)UYE9X^?mK$9Hvc_?-{wP|d9k(ksEneyy^*d7Q=9*)7`FIOZ|MW= zvixY<=W7!6E!(vDuOd|YPzO+C1X+X-InGC|NpAOFMHr#UBREWb{*$5^!noO376I(> z-!q2c?L7mFtPl42PXZcY_C~l&iu?RmW%<_h;oN{j{U^m@h-yBZ9dMxkD#Em$<=Im_ z(0@{IKAaNJQf#Aq;J*UI5p8+;6f+R(;GM*}NOkQq|4G$+I2j=03(d=^e(gj5JqcfY zI2oXo@NvU+_u8R;=s&5N52pgO4kib5wx{aDf9k&{AoF1+eK-Z6@Sofpzmz^4=|3s^ zRKK|%px~1q|H5O4NBgf7ofNR}pClAM#3TJT3n2GjwV`7e+=nd7qx?5HV9kG0+=nQ# z4Gle)lC=R}{U^nI2zq=I0@nOj5gzpTrUPvHPfGVN+9ZHV|Bcbzoe5CozcB(b6QI(6 zUj*3Zzpnrs?!V)0ANyxsG513|aU-!T_F9&J+sw`K$pDA?FJr&YI_H=b_mGGa(amxR z$ZE0+xtGzn}M1$5!$|3!#df6Jh($0lcHqeiVj95-%Y|BVG=W^1Y|v&%DE( zL3w;Hl<*L}mdl#Ml&Y-K z4{&9`j#D2UN^VqHRs&+t02~*=PZa6_vaW7sX#rw5CH~Ah1TY>D_^#pH0zJUx^aIq@ zCxE6MOn=h6Pv0Lw`U&7;SvaoU5WsVp;xL=>#SyjS`b8(8b(Qm@FyAb!yzEq+Vmzw` zcu%1f5WBRhzBpg0#>vUX`^EV>bjHgIHGaqIy8wHgJ()>#ZX7*r0HSQw zSG0?>XYGIpgO!CV#?Y}-tNSHKwbR+b@lat{{T)J Vs6AcRANBwM002ovPDHLkV1iIdiy8m` literal 0 HcmV?d00001 diff --git a/test/cases/loader-option-sources-filter/expected/assets/img/fig.c6809878.png b/test/cases/loader-option-sources-filter/expected/assets/img/fig.c6809878.png new file mode 100644 index 0000000000000000000000000000000000000000..f28a1eb9f4ee0779df428a85636b478f7cfcd1d0 GIT binary patch literal 1635 zcmV-p2AuhcP)004pr0{{R3_H{EN0001KP)t-s*4Eba z^z_%)*Y)-F^78W9+S=yk=JxjX)z#Ja_xJ4V?BL+w+1c6SgDC-=jZ3^>+9+1>G1II?(XjG?d{^?;^gGy;o;%l-rn2W+uz^c+}zyg=;-nB@k8>G zdjJ3hwMj%lRCt{2oQaOJDj0@Aw4YS!R_*e4pZmYagH~!)a08c<^qpkVIHo@H@mK`0 z2v#1nG(cB=fV%ks>gETin;)QV6o3TJ9s(2y|LFvzfX~U*n>*LtA;kRP-GC&0Fyx~7 zV=-^r(Zm!e^)GAzxFT%t*Na%MpntWN<3p~yOY*(*z%77r(ZCCw#I9Q$l%3U0Om?5$ku`HZMRE7)3i^QnyeHe4lQ?fe%kqd4 z&~}P{!b)NG#Nzx6{O`?DK;+o-!e#lp7jpFhWD5Y=?>6oS==d;q=rF)VDmb8te}Ix` z0}|}}K5lMb95C;A$nkKw1wnA#Z0*KX`NDu%!hcRwbVkwb!2d{_*XD}>QfhBle*IAN zme%7$C4+~>0O5~cWV<<^TYOU8r|1bs1KJ*H#M$Npm{kDcOOww<&!bT|9l%sF2IWnC z#iq}bk$}GE$^hLcHGL+J1l+1dQJ!oXKoVMH5ZL5}C0W|(;W!7w76-e%;(NsG-GB2|o}h_=*iRLo6}KNy_$T)7 z^l;osl6?-!Cu*FqwH_b;#QvQgj_gTNbx+dK!ot6ju-(IPfYiRp3mBzcd>{Wx!d4H* zUd_ajw2i&CPrBCQ^dz8;kJ#`jYTU&Ft$hAkc%y`p9v9dX^il2Gm8_%VsynE1cP z9efS{Nm(4dZ2f=&qn9qxp+lKikQt{9jAm@v$+p)TBpno62FAt3Y z;!Aej@Cd&<)PeqqR6H~Vi1$_o=my8~pC9Vq2atQ12oFsF=KhI$0q&nTI5HkVZaJ z$=ZP5{)uo8L66TMV8y?ZaIeQ_4zTW@i0)!EBY;x>hUIy}XXKrl^C)HjW&RCI2>6Bm zK{64b)W0FI0P}aa@0zz=i~y?q>mLTT>My#02K+3xC%q#482dB>8*p;j&V|6khzp^+tTQ zQowADcIbouL?!@RR(*^P+nkT_MI4HS6f^)QI!V3~=>hVtZsKSGQaE0A6KC(kctFVR z8crS11Dr2EK-~-hv>f03O7pI)zk+NC;NQG(S;9Vm_o9iTWWonWVco%zES?-vJ90@5ujcb}cFNNwe0?fK&CGIZ$cftp>*1*DTa*w+!&0VRO*!xe{>9{2zHeKYIH4^THh hK;8TRb+dZF{{Z&_oNfX_A&me4002ovPDHLkV1i@;TTcK0 literal 0 HcmV?d00001 diff --git a/test/cases/loader-option-sources-filter/expected/assets/img/fig2.c6809878.png b/test/cases/loader-option-sources-filter/expected/assets/img/fig2.c6809878.png new file mode 100644 index 0000000000000000000000000000000000000000..f28a1eb9f4ee0779df428a85636b478f7cfcd1d0 GIT binary patch literal 1635 zcmV-p2AuhcP)004pr0{{R3_H{EN0001KP)t-s*4Eba z^z_%)*Y)-F^78W9+S=yk=JxjX)z#Ja_xJ4V?BL+w+1c6SgDC-=jZ3^>+9+1>G1II?(XjG?d{^?;^gGy;o;%l-rn2W+uz^c+}zyg=;-nB@k8>G zdjJ3hwMj%lRCt{2oQaOJDj0@Aw4YS!R_*e4pZmYagH~!)a08c<^qpkVIHo@H@mK`0 z2v#1nG(cB=fV%ks>gETin;)QV6o3TJ9s(2y|LFvzfX~U*n>*LtA;kRP-GC&0Fyx~7 zV=-^r(Zm!e^)GAzxFT%t*Na%MpntWN<3p~yOY*(*z%77r(ZCCw#I9Q$l%3U0Om?5$ku`HZMRE7)3i^QnyeHe4lQ?fe%kqd4 z&~}P{!b)NG#Nzx6{O`?DK;+o-!e#lp7jpFhWD5Y=?>6oS==d;q=rF)VDmb8te}Ix` z0}|}}K5lMb95C;A$nkKw1wnA#Z0*KX`NDu%!hcRwbVkwb!2d{_*XD}>QfhBle*IAN zme%7$C4+~>0O5~cWV<<^TYOU8r|1bs1KJ*H#M$Npm{kDcOOww<&!bT|9l%sF2IWnC z#iq}bk$}GE$^hLcHGL+J1l+1dQJ!oXKoVMH5ZL5}C0W|(;W!7w76-e%;(NsG-GB2|o}h_=*iRLo6}KNy_$T)7 z^l;osl6?-!Cu*FqwH_b;#QvQgj_gTNbx+dK!ot6ju-(IPfYiRp3mBzcd>{Wx!d4H* zUd_ajw2i&CPrBCQ^dz8;kJ#`jYTU&Ft$hAkc%y`p9v9dX^il2Gm8_%VsynE1cP z9efS{Nm(4dZ2f=&qn9qxp+lKikQt{9jAm@v$+p)TBpno62FAt3Y z;!Aej@Cd&<)PeqqR6H~Vi1$_o=my8~pC9Vq2atQ12oFsF=KhI$0q&nTI5HkVZaJ z$=ZP5{)uo8L66TMV8y?ZaIeQ_4zTW@i0)!EBY;x>hUIy}XXKrl^C)HjW&RCI2>6Bm zK{64b)W0FI0P}aa@0zz=i~y?q>mLTT>My#02K+3xC%q#482dB>8*p;j&V|6khzp^+tTQ zQowADcIbouL?!@RR(*^P+nkT_MI4HS6f^)QI!V3~=>hVtZsKSGQaE0A6KC(kctFVR z8crS11Dr2EK-~-hv>f03O7pI)zk+NC;NQG(S;9Vm_o9iTWWonWVco%zES?-vJ90@5ujcb}cFNNwe0?fK&CGIZ$cftp>*1*DTa*w+!&0VRO*!xe{>9{2zHeKYIH4^THh hK;8TRb+dZF{{Z&_oNfX_A&me4002ovPDHLkV1i@;TTcK0 literal 0 HcmV?d00001 diff --git a/test/cases/loader-option-sources-filter/expected/assets/img/fig3.c6809878.png b/test/cases/loader-option-sources-filter/expected/assets/img/fig3.c6809878.png new file mode 100644 index 0000000000000000000000000000000000000000..f28a1eb9f4ee0779df428a85636b478f7cfcd1d0 GIT binary patch literal 1635 zcmV-p2AuhcP)004pr0{{R3_H{EN0001KP)t-s*4Eba z^z_%)*Y)-F^78W9+S=yk=JxjX)z#Ja_xJ4V?BL+w+1c6SgDC-=jZ3^>+9+1>G1II?(XjG?d{^?;^gGy;o;%l-rn2W+uz^c+}zyg=;-nB@k8>G zdjJ3hwMj%lRCt{2oQaOJDj0@Aw4YS!R_*e4pZmYagH~!)a08c<^qpkVIHo@H@mK`0 z2v#1nG(cB=fV%ks>gETin;)QV6o3TJ9s(2y|LFvzfX~U*n>*LtA;kRP-GC&0Fyx~7 zV=-^r(Zm!e^)GAzxFT%t*Na%MpntWN<3p~yOY*(*z%77r(ZCCw#I9Q$l%3U0Om?5$ku`HZMRE7)3i^QnyeHe4lQ?fe%kqd4 z&~}P{!b)NG#Nzx6{O`?DK;+o-!e#lp7jpFhWD5Y=?>6oS==d;q=rF)VDmb8te}Ix` z0}|}}K5lMb95C;A$nkKw1wnA#Z0*KX`NDu%!hcRwbVkwb!2d{_*XD}>QfhBle*IAN zme%7$C4+~>0O5~cWV<<^TYOU8r|1bs1KJ*H#M$Npm{kDcOOww<&!bT|9l%sF2IWnC z#iq}bk$}GE$^hLcHGL+J1l+1dQJ!oXKoVMH5ZL5}C0W|(;W!7w76-e%;(NsG-GB2|o}h_=*iRLo6}KNy_$T)7 z^l;osl6?-!Cu*FqwH_b;#QvQgj_gTNbx+dK!ot6ju-(IPfYiRp3mBzcd>{Wx!d4H* zUd_ajw2i&CPrBCQ^dz8;kJ#`jYTU&Ft$hAkc%y`p9v9dX^il2Gm8_%VsynE1cP z9efS{Nm(4dZ2f=&qn9qxp+lKikQt{9jAm@v$+p)TBpno62FAt3Y z;!Aej@Cd&<)PeqqR6H~Vi1$_o=my8~pC9Vq2atQ12oFsF=KhI$0q&nTI5HkVZaJ z$=ZP5{)uo8L66TMV8y?ZaIeQ_4zTW@i0)!EBY;x>hUIy}XXKrl^C)HjW&RCI2>6Bm zK{64b)W0FI0P}aa@0zz=i~y?q>mLTT>My#02K+3xC%q#482dB>8*p;j&V|6khzp^+tTQ zQowADcIbouL?!@RR(*^P+nkT_MI4HS6f^)QI!V3~=>hVtZsKSGQaE0A6KC(kctFVR z8crS11Dr2EK-~-hv>f03O7pI)zk+NC;NQG(S;9Vm_o9iTWWonWVco%zES?-vJ90@5ujcb}cFNNwe0?fK&CGIZ$cftp>*1*DTa*w+!&0VRO*!xe{>9{2zHeKYIH4^THh hK;8TRb+dZF{{Z&_oNfX_A&me4002ovPDHLkV1i@;TTcK0 literal 0 HcmV?d00001 diff --git a/test/cases/loader-option-sources-attrs-filter/expected/assets/img/kiwi.da3e3cc9.png b/test/cases/loader-option-sources-filter/expected/assets/img/kiwi.da3e3cc9.png similarity index 100% rename from test/cases/loader-option-sources-attrs-filter/expected/assets/img/kiwi.da3e3cc9.png rename to test/cases/loader-option-sources-filter/expected/assets/img/kiwi.da3e3cc9.png diff --git a/test/cases/loader-option-sources-attrs-filter/expected/assets/img/lemon.7b66be8e.png b/test/cases/loader-option-sources-filter/expected/assets/img/lemon.7b66be8e.png similarity index 100% rename from test/cases/loader-option-sources-attrs-filter/expected/assets/img/lemon.7b66be8e.png rename to test/cases/loader-option-sources-filter/expected/assets/img/lemon.7b66be8e.png diff --git a/test/cases/loader-option-sources-attrs-filter/expected/assets/img/melon.a92cb911.png b/test/cases/loader-option-sources-filter/expected/assets/img/melon.a92cb911.png similarity index 100% rename from test/cases/loader-option-sources-attrs-filter/expected/assets/img/melon.a92cb911.png rename to test/cases/loader-option-sources-filter/expected/assets/img/melon.a92cb911.png diff --git a/test/cases/loader-option-sources-attrs-filter/expected/assets/img/plum.d39e7174.png b/test/cases/loader-option-sources-filter/expected/assets/img/plum.d39e7174.png similarity index 100% rename from test/cases/loader-option-sources-attrs-filter/expected/assets/img/plum.d39e7174.png rename to test/cases/loader-option-sources-filter/expected/assets/img/plum.d39e7174.png diff --git a/test/cases/loader-option-sources-attrs-filter/expected/index.html b/test/cases/loader-option-sources-filter/expected/index.html similarity index 100% rename from test/cases/loader-option-sources-attrs-filter/expected/index.html rename to test/cases/loader-option-sources-filter/expected/index.html diff --git a/test/cases/loader-option-sources-attrs-filter/src/index.html b/test/cases/loader-option-sources-filter/src/index.html similarity index 100% rename from test/cases/loader-option-sources-attrs-filter/src/index.html rename to test/cases/loader-option-sources-filter/src/index.html diff --git a/test/cases/loader-option-sources-attrs-filter/webpack.config.js b/test/cases/loader-option-sources-filter/webpack.config.js similarity index 92% rename from test/cases/loader-option-sources-attrs-filter/webpack.config.js rename to test/cases/loader-option-sources-filter/webpack.config.js index b2de5031..4fa46a33 100644 --- a/test/cases/loader-option-sources-attrs-filter/webpack.config.js +++ b/test/cases/loader-option-sources-filter/webpack.config.js @@ -48,9 +48,9 @@ module.exports = { // add filter to default tag { tag: 'img', - filter: ({ tag, attribute, value, attributes, resourcePath }) => { + filter: ({ tag, attribute, value, parsedValue, attributes, resourcePath }) => { if (attribute === 'src' && !value.endsWith('lemon.png')) return false; - if (attribute === 'srcset' && !value.find((item) => item.endsWith('fig3.png'))) return false; + if (attribute === 'srcset' && !parsedValue.find((item) => item.endsWith('fig3.png'))) return false; }, }, diff --git a/test/cases/responsive-images-html-css/expected/assets/img/apple-60w.png b/test/cases/responsive-images-html-css/expected/assets/img/apple-60w.png new file mode 100644 index 0000000000000000000000000000000000000000..faa6b905fefd0ece8b512e6d07b754ffc127fba8 GIT binary patch literal 484 zcmV8}fgPYiX|5rYRpAIUZbld54o;HoH9}Y=iJ&u1REJlwd-+9^{rY<@bbpEN#Hd4kZrwf(w;z@ z*25kT<0*e$mRl$L861rWpAg@ z@-V2ovec+uGjHJ9qC9=8a~Wt3r0000y`kobrAIy^kSTa7%hHknEQRq59!BE?A9BGKT^M~o4 zpI%nQcx4B3#U>V#F!b=SMsAShXIL;Mn8%F7^YNOzPA+Iku!@Rljk8NB!oY|ZL$zlSQl$YP!Yxig8)ojVv(x|nh;zE?nu zDQnC#ue5EQo^fl;;%QFq#iphhP1KAc=0#F8qNZ*dF9riOkPwh?gipFTrtOiMkp>YM z+>0M*EN-sFN#^%6ll$9mt-Fj3wq(RT4V z#V|HpV#cui--Cl#?D{%t%G^-Vl18pwY^v3cm6YkI$ZWb3_lR^!pSdW m&8ydkw-&y}$gB6ix&8psIu4!5bxmUc0000Home - +
diff --git a/test/cases/responsive-images-html-css/src/views/index.html b/test/cases/responsive-images-html-css/src/views/index.html index 70371264..d37efddb 100644 --- a/test/cases/responsive-images-html-css/src/views/index.html +++ b/test/cases/responsive-images-html-css/src/views/index.html @@ -13,7 +13,7 @@

Home

- +
diff --git a/test/cases/responsive-images-html-css/webpack.config.js b/test/cases/responsive-images-html-css/webpack.config.js index 332a8a44..8479e263 100644 --- a/test/cases/responsive-images-html-css/webpack.config.js +++ b/test/cases/responsive-images-html-css/webpack.config.js @@ -20,6 +20,7 @@ module.exports = { plugins: [ new HtmlBundlerPlugin({ entry: { + // test a relative image path 'pages/home': './src/views/index.html', }, js: { diff --git a/test/integration.test.js b/test/integration.test.js index 6bccf624..cb4dc4b7 100644 --- a/test/integration.test.js +++ b/test/integration.test.js @@ -129,9 +129,12 @@ describe('plugin minify option', () => { describe('loader options common', () => { test('defaults, when in module.rules is not defined', () => compareFiles('loader-option-defaults')); test('disable parsing for all tags and attributes', () => compareFiles('loader-option-sources-false')); + test('add custom tags and attributes', () => compareFiles('loader-option-sources-attrs')); - test('filter tags and attributes', () => compareFiles('loader-option-sources-attrs-filter')); - test('filter property attribute', () => compareFiles('loader-option-sources-attrs-filter-property')); + test('filter tags and attributes', () => compareFiles('loader-option-sources-filter')); + test('filter property attribute', () => compareFiles('loader-option-sources-filter-property')); + test('filter, parsedValues', () => compareFiles('loader-option-sources-filter-parsedValues')); + test('preprocessor by defaults', () => compareFiles('loader-option-preprocessor-default')); test('preprocessor disabled', () => compareFiles('loader-option-preprocessor-disabled')); test('preprocessor null', () => compareFiles('loader-option-preprocessor-return-null')); diff --git a/test/unit.test.js b/test/unit.test.js index 8f985ac6..3f287275 100644 --- a/test/unit.test.js +++ b/test/unit.test.js @@ -171,40 +171,44 @@ describe('parse attributes unit tests', () => { endPos: 10, offset: 0, value: '', + parsedValue: [''], }; return expect(received).toEqual(expected); }); test('parseAttr value', () => { - const source = ''; + const source = ''; const received = HtmlParser.parseAttr(source, 'src', 'asset', 0); const expected = { type: 'asset', attr: 'src', startPos: 10, - endPos: 18, + endPos: 27, offset: 0, - value: 'img1.png', + value: 'img1.png?size=800', + parsedValue: ['img1.png'], }; return expect(received).toEqual(expected); }); test('parseSrcset single value', () => { - const source = ''; + const source = ''; const received = HtmlParser.parseAttr(source, 'srcset', 'asset'); const expected = { attr: 'srcset', startPos: 16, - endPos: 24, + endPos: 38, offset: 0, - value: ['img1.png'], + value: 'img1.png?size=200 w200', + parsedValue: ['img1.png'], attrs: [ { type: 'asset', attr: 'srcset', - value: 'img1.png', + // TODO: test with a plugin which resizes images via a query param + value: 'img1.png?size=200', startPos: 16, - endPos: 24, + endPos: 33, offset: 0, }, ], @@ -220,7 +224,8 @@ describe('parse attributes unit tests', () => { startPos: 28, endPos: 66, offset: 0, - value: ['img1.png', 'img2.png', 'img3.png'], + value: 'img1.png, img2.png 100w, img3.png 1.5x', + parsedValue: ['img1.png', 'img2.png', 'img3.png'], attrs: [ { type: 'asset', attr: 'srcset', startPos: 28, endPos: 36, offset: 0, value: 'img1.png' }, { type: 'asset', attr: 'srcset', startPos: 38, endPos: 46, offset: 0, value: 'img2.png' }, @@ -273,6 +278,7 @@ describe('parse tags unit tests', () => { type: 'asset', attr: 'src', value: 'img1.png', + parsedValue: ['img1.png'], startPos: 10, endPos: 18, offset: 0, @@ -285,22 +291,23 @@ describe('parse tags unit tests', () => { }); test('parseTag img with srcset', () => { - const html = `
logo
`; + const html = `
logo
`; // test sorting of parsed attrs, filter const received = HtmlParser.parseTag(html, { tag: 'img', attributes: ['srcset', 'src'] }); const expected = [ { tag: 'img', - source: 'logo', + source: 'logo', type: 'asset', startPos: 5, - endPos: 58, + endPos: 69, parsedAttrs: [ { type: 'asset', attr: 'src', value: 'img1.png', + parsedValue: ['img1.png'], startPos: 10, endPos: 18, offset: 5, @@ -308,17 +315,17 @@ describe('parse tags unit tests', () => { { type: 'asset', attr: 'srcset', - value: '1.png', + value: '1.png?s=200', startPos: 39, - endPos: 44, + endPos: 50, offset: 5, }, { type: 'asset', attr: 'srcset', value: '2.png', - startPos: 46, - endPos: 51, + startPos: 57, + endPos: 62, offset: 5, }, ], diff --git a/types.d.ts b/types.d.ts index 37ddb8d9..1e37a68c 100644 --- a/types.d.ts +++ b/types.d.ts @@ -42,11 +42,11 @@ declare namespace HtmlBundlerPlugin { * The references to LoaderOptions. * It's syntactic "sugar" to avoid the complicated structure of options. */ - data?: { [k: string]: any } | string; + data?: { [key: string]: any } | string; beforePreprocessor?: BeforePreprocessor; preprocessor?: Preprocessor; preprocessorOptions?: Object; - // postprocess of rendered template + // postprocess of rendered template, called after js template was compiled into html postprocess?: Postprocess; // generates preload link tags for assets preload?: Preload; @@ -109,7 +109,7 @@ type EntryDescription = { */ import: string; /** - * Specifies the filename of the output file on disk. You must **not** specify an absolute path here, but the path may contain folders separated by '/'! The specified path is joined with the value of the 'output.path' option to determine the location on disk. + * The output filename template. */ filename?: FilenameTemplate; /** @@ -122,7 +122,7 @@ type EntryDescription = { * The template data passed to the preprocessor as an object, or the path to a file that exports the data as an object. * If the value is string, it should be an absolute or relative path to a JSON/JS file. */ -type Data = { [k: string]: any } | string; +type Data = { [key: string]: any } | string; type JsOptions = { filename?: FilenameTemplate; @@ -159,7 +159,9 @@ type IntegrityOptions = { type HashFunctions = 'sha256' | 'sha384' | 'sha512'; /** - * Specifies the filename template of output files on disk. You must **not** specify an absolute path here, but the path may contain folders separated by '/'! The specified path is joined with the value of the 'output.path' option to determine the location on disk. + * Specifies the filename template of output files on disk. + * You must **not** specify an absolute path here, but the path may contain folders separated by '/'! + * The specified path is joined with the value of the 'output.path' option to determine the location on the disk. */ type FilenameTemplate = string | ((pathData: PathData, assetInfo?: AssetInfo) => string); @@ -167,7 +169,7 @@ type BeforePreprocessor = | false | (( template: string, - loaderContext: LoaderContext & { data: { [k: string]: any } | string } + loaderContext: LoaderContext & { data: { [key: string]: any } | string } ) => string | undefined); type Preprocessor = @@ -178,15 +180,18 @@ type Preprocessor = | 'nunjucks' | (( template: string, - loaderContext: LoaderContext & { data: { [k: string]: any } | string } + loaderContext: LoaderContext & { data: { [key: string]: any } | string } ) => string | Promise | undefined); /** - * Called after the template has been rendered, but not yet finalized, + * Called after the template has been compiled into html string, but not yet finalized, * before the split chunks and inline assets are injected. */ -type Postprocess = (content: string, info: TemplateInfo, compilation: Compilation) => string | undefined; +type Postprocess = (content: string, templateInfo: TemplateInfo, compilation: Compilation) => string | undefined; +/** + * The object is argument of the postprocess hook. + */ type TemplateInfo = { verbose: boolean; filename: string | ((pathData: PathData) => string); @@ -200,7 +205,7 @@ type Preload = Array<{ as?: string; rel?: string; type?: string; - attributes?: { [k: string]: string | boolean }; + attributes?: { [attributeName: string]: string | boolean }; }>; type Sources = @@ -211,8 +216,11 @@ type Sources = filter?: (props: { tag: string; attribute: string; - value: string | Array; - attributes: { [k: string]: string }; + // original value string + value: string; + // parsed value, useful for srcset attribute with many filenames + parsedValue: Array; + attributes: { [attributeName: string]: string }; resourcePath: string; }) => boolean | undefined; }>;