Skip to content

Commit e773d40

Browse files
Merge pull request #29 from davidpelayo/master
Ability to load image resources from an URL
2 parents a2cc94a + 77d24a6 commit e773d40

10 files changed

Lines changed: 328 additions & 41 deletions

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## v2.2.0
2+
3+
* _Ability added to load SVGs from an URL (`<img inline src="https://host.com/image.svg">`)._
4+
15
## v2.0.1
26

37
* added `inlineAll` option to inline all svgs the parser finds

README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ If an alias was in place for the images directory, i.e.
124124
```
125125
Then the svg can be inlined with: `<img inline src="~img/icons.svg">`. This method would require the use of **loaders** on your templates as shown above in point 2.
126126

127+
#### Incorrect file paths or URLs
128+
If for any reason the path to a local SVG file is incorrect, or the file fails to be read, or an image retrieved with an URL fails to download, the webpack build process will fail with an error, like `ENOENT`.
129+
127130
#### Duplicated attributes
128131
All the attributes of a `<img/>` element excepting `src` and `inline` will be copied to the inlined `<svg/>` element. Attributes like `id` or `class` will be copied to the resulting root of the `<svg/>` element and if the original SVG file already had these attributes they will be duplicated (and not replaced) on the resulting `<svg/>` element, though the attributes coming from the `<img/>` will appear first and [any subsequent duplicated attribute from the original SVG will be ignored by the browser](https://stackoverflow.com/questions/26341507/can-an-html-element-have-the-same-attribute-twice).
129132

@@ -185,7 +188,15 @@ The plugin accepts three options:
185188
</div>
186189
```
187190

188-
- `svgoConfig`: to configure SVGO (module used to optimise your SVGs), add an `svgoConfig` object to your `html-webpack-plugin` config:
191+
- `allowFromUrl`: defaults to `false`. It allows to use SVG images coming from an URL online in addition to local files. For example:
192+
193+
```html
194+
<div>
195+
<img inline src="https://badge.fury.io/js/html-webpack-inline-svg-plugin.svg"> <!-- it will be inlined from the online SVG -->
196+
</div>
197+
```
198+
199+
- `svgoConfig`: defaults to `undefinded`. to configure SVGO (module used to optimise your SVGs), add an `svgoConfig` object to your `html-webpack-plugin` config:
189200

190201
```javascript
191202
plugins: [

index.js

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const fs = require('fs')
88
const SVGO = require('svgo')
99
const svgoDefaultConfig = require(path.resolve(__dirname, 'svgo-config.js'))
1010
const HtmlWebpackPlugin = require('html-webpack-plugin')
11+
const axios = require('axios')
1112

1213

1314
/**
@@ -20,6 +21,7 @@ class HtmlWebpackInlineSVGPlugin {
2021

2122
this.runPreEmit = _.get(options, 'runPreEmit', false)
2223
this.inlineAll = _.get(options, 'inlineAll', false)
24+
this.allowFromUrl = _.get(options, 'allowFromUrl', false)
2325
this.userConfig = ''
2426
this.outputPath = ''
2527

@@ -412,7 +414,6 @@ class HtmlWebpackInlineSVGPlugin {
412414
|| _.filter(node.attrs, { name: 'inline' }).length)
413415
&& this.getImagesSrc(node))
414416

415-
416417
}
417418

418419

@@ -426,7 +427,6 @@ class HtmlWebpackInlineSVGPlugin {
426427

427428
const svgSrcObject = _.find(inlineImage.attrs, { name: 'src' })
428429

429-
430430
// image does not have a src attribute
431431

432432
if (!svgSrcObject) return ''
@@ -443,58 +443,85 @@ class HtmlWebpackInlineSVGPlugin {
443443

444444
}
445445

446-
447446
/**
448447
* append the inlineImages SVG data to the output HTML and remove the original img
449-
* @param {string} html
450-
* @param {Object} inlineImage - parse5 document
448+
* @param {Object{}} html
449+
* @param {Object{}} inlineImage - parse5 document
450+
* @param {Object{}} data - SVG data
451+
* @param {Object{}} resolve - Consumer's Promise resolve hook
451452
* @returns {Promise}
452453
*
453454
*/
454-
processOutputHtml (html, inlineImage) {
455+
optimizeSvg ({ html, inlineImage, data, resolve }) {
456+
const configObj = Object.assign(svgoDefaultConfig, this.userConfig)
455457

456-
return new Promise((resolve, reject) => {
458+
const config = {}
457459

458-
const svgSrc = this.getImagesSrc(inlineImage)
459460

461+
// pass all objects to the config.plugins array
460462

461-
// if the image isn't valid resolve
463+
config.plugins = _.map(configObj, (value, key) => ({ [key]: value }));
462464

463-
if (!svgSrc) return resolve(html)
464465

466+
// create a new instance of SVGO
467+
// passing it the merged config, to optimize the svg
465468

466-
// read in the svg
467-
468-
fs.readFile(path.resolve(this.outputPath, svgSrc), 'utf8', (err, data) => {
469+
const svgo = new SVGO(config)
469470

470-
if (err) reject(err)
471+
svgo.optimize(data)
472+
.then((result) => {
471473

472-
const configObj = Object.assign(svgoDefaultConfig, this.userConfig)
474+
const optimisedSVG = result.data
473475

474-
const config = {}
476+
html = this.replaceImageWithSVG(html, inlineImage, optimisedSVG)
475477

478+
resolve(html)
476479

477-
// pass all objects to the config.plugins array
480+
})
481+
.catch((err) => console.log(chalk.red(err)))
482+
}
478483

479-
config.plugins = _.map(configObj, (value, key) => ({ [key]: value }));
480484

485+
/**
486+
* append the inlineImages SVG data to the output HTML and remove the original img by
487+
* loading the SVG data from the filesystem or from an URL
488+
* @param {string} html
489+
* @param {Object} inlineImage - parse5 document
490+
* @returns {Promise}
491+
*
492+
*/
493+
processOutputHtml (html, inlineImage) {
481494

482-
// create a new instance of SVGO
483-
// passing it the merged config, to optimize the svg
495+
return new Promise((resolve, reject) => {
484496

485-
const svgo = new SVGO(config)
497+
const svgSrc = this.getImagesSrc(inlineImage)
486498

487-
svgo.optimize(data)
488-
.then((result) => {
489499

490-
const optimisedSVG = result.data
500+
// if the image isn't valid resolve
501+
if (!svgSrc) return resolve(html)
491502

492-
html = this.replaceImageWithSVG(html, inlineImage, optimisedSVG)
503+
// read in the svg
504+
fs.readFile(path.resolve(this.outputPath, svgSrc), 'utf8', (err, data) => {
505+
if (!err) {
506+
this.optimizeSvg({ html, inlineImage, data, resolve })
507+
return
508+
}
493509

494-
resolve(html)
510+
// loading from the filesystem failed
511+
if (!this.allowFromUrl) {
512+
reject(err)
513+
return
514+
}
495515

516+
axios.get(svgSrc)
517+
.then(({ data, status }) => {
518+
if (status !== 200) {
519+
throw new Error(`Error when retrieving image from URL: ${status} status`)
520+
}
521+
this.optimizeSvg({ html, inlineImage, svgSrc, data, resolve })
496522
})
497-
.catch((err) => console.log(chalk.red(err)))
523+
.catch((err) => reject(err))
524+
498525

499526
})
500527

@@ -504,7 +531,7 @@ class HtmlWebpackInlineSVGPlugin {
504531

505532

506533
/**
507-
* replace the img with the optimised SVG
534+
* replace the img with the optimized SVG
508535
* @param {string} html
509536
* @param {Object} inlineImage - parse5 document
510537
* @param {Object} svg

package-lock.json

Lines changed: 49 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: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "html-webpack-inline-svg-plugin",
3-
"version": "2.1.1",
3+
"version": "2.2.0",
44
"description": "Embed svg inline when using the html webpack plugin",
55
"main": "index.js",
66
"files": [
@@ -30,6 +30,7 @@
3030
},
3131
"homepage": "https://github.com/thegc/html-webpack-inline-svg-plugin",
3232
"devDependencies": {
33+
"axios-mock-adapter": "^1.18.1",
3334
"file-loader": "^6.0.0",
3435
"html-loader": "^1.1.0",
3536
"html-webpack-plugin": "^4.3.0",
@@ -38,7 +39,8 @@
3839
"webpack": "^4.43.0"
3940
},
4041
"dependencies": {
41-
"chalk": "^4.0.0",
42+
"axios": "^0.19.2",
43+
"chalk": "^4.1.0",
4244
"cheerio": "^1.0.0-rc.3",
4345
"lodash": "^4.17.15",
4446
"parse5": "^6.0.0",
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<!DOCTYPE html>
2+
<html>
3+
4+
<head>
5+
<meta charset="utf-8">
6+
<meta http-equiv="x-ua-compatible" content="ie=edge">
7+
<title>Allow From URL SVG Tests index</title>
8+
<style>
9+
.icon {
10+
display: inline-block;
11+
width: 1em;
12+
height: 1em;
13+
stroke-width: 0;
14+
stroke: currentColor;
15+
fill: currentColor;
16+
}
17+
18+
</style>
19+
20+
</head>
21+
22+
<body>
23+
24+
<div>
25+
<p>should not touch this: <img width="20px" height="auto" class="leave-me" src="~img/face.svg"></p>
26+
<p>
27+
<span>if below SVG is inlined correctly we can reference its content:</span>
28+
<svg class="icon mood-good">
29+
<use xlink:href="#icon-mood-good"></use>
30+
</svg>
31+
<img id="find-and-replace-me" src="images/face.svg">
32+
</p>
33+
</div>
34+
35+
<img id="replace-me" inline src="https://badge.fury.io/js/html-webpack-inline-svg-plugin.svg" />
36+
37+
<!-- These three images, if uncommented, will make fail the webpack build process, as expected -->
38+
39+
<!-- <img id="not-found" inline src="https://notFound/typoInExtension/html-webpack-inline-svg-plugin-typoInNaming.svg" />
40+
41+
<img id="error-loading" inline src="https://errorLoading/someIconWhichDoesNotExist.svg" />
42+
43+
<img id="timeout-loading" inline src="https://timeoutLoading/someIconWhichDoesNotExist-timeout.svg" /> -->
44+
45+
<img id="replace-me-too" inline src="https://badge.fury.io/js/html-webpack-inline-svg-plugin.svg" />
46+
47+
<img id="not-an-svg" inline src="images/not-an-svg.png" />
48+
49+
<div id="do-not-decode"><?= $foo->bar; ?></div>
50+
51+
</body>
52+
53+
</html>
54+
55+
</body>
56+
57+
</html>

0 commit comments

Comments
 (0)