Skip to content

Commit 1ac0cbd

Browse files
committed
fix: apply the encoding specified in the query to the data URL of an SVG for files imported in JS, #154
1 parent e73c73d commit 1ac0cbd

24 files changed

Lines changed: 390 additions & 96 deletions

CHANGELOG.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
# Changelog
22

3-
## 4.19.0-beta.0
3+
## 4.19.0-beta.3
4+
5+
- fix: apply the encoding specified in the query to the data URL of an SVG for files imported in JS
6+
```js
7+
import svg from './icons.svg?inline=base64'; // <= use exactly this encoding, independ how is specified anywhere global
8+
```
9+
10+
## 4.19.0-beta.0 - 4.19.0-beta.2
411

512
### 🔥 BREAKING CHANGES by inlining SVG only
613

package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "html-bundler-webpack-plugin",
3-
"version": "4.19.0-beta.2",
3+
"version": "4.19.0-beta.3",
44
"description": "Generates complete single-page or multi-page website from source assets. Build-in support for Markdown, Eta, EJS, Handlebars, Nunjucks, Pug. Alternative to html-webpack-plugin.",
55
"keywords": [
66
"html",
@@ -150,7 +150,7 @@
150150
},
151151
"dependencies": {
152152
"@types/html-minifier-terser": "^7.0.2",
153-
"ansis": "3.16.0",
153+
"ansis": "4.0.0-beta.1",
154154
"enhanced-resolve": ">=5.7.0",
155155
"eta": "^3.5.0",
156156
"html-minifier-terser": "^7.2.0"

src/Common/HtmlParser.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,26 @@ const isLinkScript = (attrs) => {
135135
return false;
136136
};
137137

138+
/**
139+
* Parse tag attributes in a tag string.
140+
*
141+
* The string must contains only tag string with attributes, e.g.:
142+
* `<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16px' height='16px'>`
143+
*
144+
* @param {string} string
145+
* @returns {Object<key: string, value: string>} The parsed attributes as the object key:value.
146+
*/
147+
const parseTagAttributes = (string) => {
148+
const matches = string.matchAll(/(\S+)=["'](.+?)["']/gm);
149+
let attrs = {};
150+
151+
for (const [, key, val] of matches) {
152+
attrs[key] = val;
153+
}
154+
155+
return attrs;
156+
};
157+
138158
class HtmlParser {
139159
/**
140160
* Parse values of tag attributes.
@@ -523,4 +543,4 @@ class HtmlParser {
523543
}
524544
}
525545

526-
module.exports = { HtmlParser, comparePos };
546+
module.exports = { HtmlParser, comparePos, parseTagAttributes };

src/Plugin/AssetCompiler.js

Lines changed: 64 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -736,9 +736,10 @@ class AssetCompiler {
736736
let encoding = 'base64'; // default encoding for all resources
737737
let hasInlineQuery = getQueryParam(resource, 'inline') != null;
738738
let isInlineSvg = false;
739+
let svgOptions;
739740

740741
if (this.assetInline.isSvgFile(resource)) {
741-
const svgOptions = this.pluginOption.getInlineSvgOptions(resource, createData);
742+
svgOptions = this.pluginOption.getInlineSvgOptions(resource, createData);
742743

743744
isInlineSvg = svgOptions != null;
744745
encoding = svgOptions?.encoding;
@@ -747,7 +748,7 @@ class AssetCompiler {
747748
// query `?inline`
748749
if (hasInlineQuery || isInlineSvg) {
749750
this.setAssetModuleTypeInline(createData);
750-
this.setAssetModuleEncoding(createData, encoding);
751+
this.setAssetModuleEncoding(createData, encoding, hasInlineQuery, svgOptions);
751752
}
752753
}
753754

@@ -816,8 +817,10 @@ class AssetCompiler {
816817
*
817818
* @param {Object} module
818819
* @param {'base64' | false} encoding
820+
* @param {boolean} hasInlineQuery
821+
* @param {Object | null} svgOptions
819822
*/
820-
setAssetModuleEncoding(module, encoding) {
823+
setAssetModuleEncoding(module, encoding, hasInlineQuery, svgOptions) {
821824
if (this.IS_WEBPACK_VERSION_LOWER_5_96_0) {
822825
// TODO: refactor into Exceptions
823826
throw new Error(`\nThe support for the \`?inline\` query for assets is available since Webpack >= 5.96.`);
@@ -832,15 +835,38 @@ class AssetCompiler {
832835
const publicPath = module.generator.publicPath;
833836
const outputPath = module.generator.outputPath;
834837
const emit = module.generator.emit;
838+
const issuer = module.resourceResolveData?.context?.issuer;
839+
const isIssuerScript = this.pluginOption.isScript(issuer || '');
835840
let dataUrlOptions;
836841

837842
if (dataUrlOptionsType === 'function') {
838843
dataUrlOptions = moduleDataUrlOptions;
844+
if (isIssuerScript) {
845+
dataUrlOptions = (...args) => {
846+
// extra processes SVG loaded in a JS file, because it will not be processed in renderManifest
847+
let res = moduleDataUrlOptions(...args);
848+
let normalized = this.assetInline.normalizeEncoding(res, svgOptions);
849+
850+
// TODO: research why is called double (perhaps the JS file (issuer) is called double)
851+
// console.log(
852+
// ' ====> INJECTION: ',
853+
// { isIssuerScript, resource: module.resource, svgOptions, normalized },
854+
// res,
855+
// args
856+
// );
857+
858+
return normalized.dataUrl;
859+
};
860+
} else {
861+
dataUrlOptions = moduleDataUrlOptions;
862+
}
839863
} else {
840864
dataUrlOptions = dataUrlOptionsType === 'object' ? { ...moduleDataUrlOptions } : {};
841865
dataUrlOptions.encoding = assetEncoding;
842866
}
843867

868+
//console.log('*** saveData: ', { resource: module.resource, encoding, dataUrlOptions }, '\n');
869+
844870
module.generator = new AssetGenerator(moduleGraph, dataUrlOptions, filename, publicPath, outputPath, emit);
845871
}
846872

@@ -1040,7 +1066,11 @@ class AssetCompiler {
10401066
*
10411067
* @param {Object} module The Webpack module.
10421068
*/
1043-
afterBuildModule(module) {}
1069+
afterBuildModule(module) {
1070+
// if (module.resource.includes('&js')) {
1071+
// console.log('*** afterBuildModule: ', module);
1072+
// }
1073+
}
10441074

10451075
/**
10461076
* @param {Array<Object>} result
@@ -1107,34 +1137,38 @@ class AssetCompiler {
11071137
moduleType = buildInfo.dataUrl === true ? ASSET_MODULE_TYPE_INLINE : ASSET_MODULE_TYPE_RESOURCE;
11081138
}
11091139

1110-
if (this.assetInline.isSvgFile(resource) && this.pluginOption.isInlineSvg(resource)) {
1111-
this.assetInline.saveData(entry, chunk, module, codeGenerationResults, moduleType);
1112-
}
1113-
1114-
switch (moduleType) {
1115-
case JAVASCRIPT_MODULE_TYPE_AUTO:
1116-
const assetModule = this.createAssetModule(entry, chunk, module);
1140+
let svgOption = null;
11171141

1118-
if (assetModule == null) continue;
1119-
if (assetModule === false) return;
1120-
1121-
assetModules.add(assetModule);
1122-
break;
1123-
case ASSET_MODULE_TYPE_RESOURCE:
1124-
// resource required in the template or in the CSS via url()
1125-
this.assetResource.saveData(module);
1126-
break;
1127-
case ASSET_MODULE_TYPE_INLINE:
1128-
this.assetInline.saveData(entry, chunk, module, codeGenerationResults, moduleType);
1129-
break;
1130-
case ASSET_MODULE_TYPE_SOURCE:
1131-
// support the source type for SVG only
1132-
if (this.assetInline.isSvgFile(resource)) {
1142+
// TODO: refactor
1143+
if (this.assetInline.isSvgFile(resource) && this.pluginOption.isInlineSvg(resource)) {
1144+
svgOption = this.pluginOption.getInlineSvgOptions(resource, module);
1145+
this.assetInline.saveData(entry, chunk, module, codeGenerationResults, moduleType, svgOption);
1146+
} else {
1147+
switch (moduleType) {
1148+
case JAVASCRIPT_MODULE_TYPE_AUTO:
1149+
const assetModule = this.createAssetModule(entry, chunk, module);
1150+
1151+
if (assetModule == null) continue;
1152+
if (assetModule === false) return;
1153+
1154+
assetModules.add(assetModule);
1155+
break;
1156+
case ASSET_MODULE_TYPE_RESOURCE:
1157+
// resource required in the template or in the CSS via url()
1158+
this.assetResource.saveData(module);
1159+
break;
1160+
case ASSET_MODULE_TYPE_INLINE:
11331161
this.assetInline.saveData(entry, chunk, module, codeGenerationResults, moduleType);
1134-
}
1135-
break;
1136-
default:
1137-
// do nothing
1162+
break;
1163+
case ASSET_MODULE_TYPE_SOURCE:
1164+
// support the source type for SVG only
1165+
if (this.assetInline.isSvgFile(resource)) {
1166+
this.assetInline.saveData(entry, chunk, module, codeGenerationResults, moduleType);
1167+
}
1168+
break;
1169+
default:
1170+
// do nothing
1171+
}
11381172
}
11391173
}
11401174

0 commit comments

Comments
 (0)