diff --git a/README.md b/README.md index dcbe57c5..a494c8b7 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,11 @@ A webpack loader which loads SVG file as utf-8 encoded DataUrl string. -Existing [`url-loader`](https://github.com/webpack-contrib/url-loader) always does Base64 encoding for data-uri. As SVG content is a human-readable xml string, using base64 encoding is not mandatory. Instead, one may only escape [unsafe characters](http://www.ietf.org/rfc/rfc1738.txt) and replace `"` with `'` as described [in this article](http://codepen.io/Tigt/post/optimizing-svgs-in-data-uris). +Existing [`url-loader`](https://github.com/webpack-contrib/url-loader) always does Base64 encoding for data-uri. As SVG content is a human-readable xml string, using base64 encoding is not mandatory. Instead, one may only escape [unsafe characters](http://www.ietf.org/rfc/rfc1738.txt) and replace `"` with `'` as described [in this article](http://codepen.io/Tigt/post/optimizing-svgs-in-data-uris). -There are some benefits for choosing utf-8 encoding over base64. -1. Resulting string is shorter (can be ~2 times shorter for 2K-sized icons); -2. Resulting string will be compressed better when using gzip compression; +There are some benefits for choosing utf-8 encoding over base64. +1. Resulting string is shorter (can be ~2 times shorter for 2K-sized icons); +2. Resulting string will be compressed better when using gzip compression; 3. Browser parses utf-8 encoded string faster than its base64 equivalent. ## Supported parameters @@ -23,8 +23,8 @@ Passing this parameter (or setting to `true`) tells to loader *not to include* r ### `limit` -If given will tell the loader not to encode the source file if its content is greater than this limit. -Defaults to no limit. +If given will tell the loader not to encode the source file if its content is greater than this limit. +Defaults to no limit. If the file is greater than the limit the [`file-loader`](https://github.com/webpack-contrib/file-loader) is used and all query parameters are passed to it. ``` javascript @@ -36,6 +36,15 @@ require('svg-url-loader?prefix=img/!./file.svg'); // They are passed to the file-loader if used. ``` +### `stripdeclarations` + +If given will tell the loader to strip out any XML declaration, e.g. `` at the beginning of imported SVGs. +Internet Explorer (tested in Edge 14) cannot handle XML declarations in CSS data URLs (`content: url("data:image/svg...")`). + +``` javascript +require('svg-url-loader?stripdeclarations!./file.svg'); +``` + ## Usage [Documentation: Loaders](https://webpack.js.org/concepts/loaders/) diff --git a/index.js b/index.js index 3615488b..cd0b440c 100644 --- a/index.js +++ b/index.js @@ -8,11 +8,16 @@ module.exports = function(content) { this.cacheable && this.cacheable(); var query = loaderUtils.getOptions(this); - + var limit = query.limit ? parseInt(query.limit, 10) : 0; - - if(limit <= 0 || content.length < limit) { + + if (limit <= 0 || content.length < limit) { content = content.toString('utf8'); + + if (query.stripdeclarations) { + content = content.replace(/^\s*<\?xml [^>]*>\s*/i, ""); + } + content = content.replace(/"/g, "'"); content = content.replace(/\s+/g, " "); content = content.replace(/[{}\|\\\^~\[\]`"<>#%]/g, function(match) { diff --git a/test/input/icon-with-declaration.js b/test/input/icon-with-declaration.js new file mode 100644 index 00000000..73a0b674 --- /dev/null +++ b/test/input/icon-with-declaration.js @@ -0,0 +1,2 @@ +var icon = require('./images/icon-with-declaration.svg'); +module.exports = icon; diff --git a/test/input/images/icon-with-declaration.svg b/test/input/images/icon-with-declaration.svg new file mode 100644 index 00000000..fe6ad0fa --- /dev/null +++ b/test/input/images/icon-with-declaration.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/loader.spec.js b/test/loader.spec.js index 1862ff72..545e2697 100644 --- a/test/loader.spec.js +++ b/test/loader.spec.js @@ -6,7 +6,7 @@ var webpack = require('webpack'); describe('svg-url-loader', function() { 'use strict'; - + this.timeout(10000); var outputDir = path.resolve(__dirname, './output'), @@ -85,6 +85,65 @@ describe('svg-url-loader', function() { }); + describe('"stripdeclarations" option', function () { + it('if turned off - should do nothing to an SVG that has an XML declaration', function(done) { + var config = assign({}, globalConfig, { + entry: './test/input/icon-with-declaration.js' + }); + config.module.rules[0].use[0].options.stripdeclarations = false; + + webpack(config, function(err) { + expect(err).to.be(null); + fs.readFile(getBundleFile(), function(err, data) { + expect(err).to.be(null); + var encoded = (0,eval)(data.toString()); + expect(encoded.indexOf("%3C?xml version='1.0' encoding='UTF-8'?%3E")).to.be.greaterThan(-1); + return done(); + }); + }); + }); + + it('if turned on - should do nothing to an SVG that doesn\'t have an XML declaration', function(done) { + var config = assign({}, globalConfig, { + entry: './test/input/icon.js' + }); + config.module.rules[0].use[0].options.stripdeclarations = true; + + webpack(config, function(err) { + expect(err).to.be(null); + fs.readFile(getBundleFile(), function(err, data) { + expect(err).to.be(null); + var encoded = (0,eval)(data.toString()); + expect(encoded.indexOf('"')).to.be(0); + expect(encoded.lastIndexOf('"')).to.be(encoded.length - 1); + expect(encoded.indexOf('data:image/svg+xml,%3Csvg')).to.be(1); + return done(); + }); + }); + }); + + + it('if turned on - should remove XML declaration from a file that has one', function(done) { + var config = assign({}, globalConfig, { + entry: './test/input/icon-with-declaration.js' + }); + config.module.rules[0].use[0].options.stripdeclarations = true; + + webpack(config, function(err) { + expect(err).to.be(null); + fs.readFile(getBundleFile(), function(err, data) { + expect(err).to.be(null); + var encoded = (0,eval)(data.toString()); + expect(encoded.indexOf('%3C?xml version="1.0" encoding="UTF-8"?%3E')).to.be(-1); + expect(encoded.indexOf('data:image/svg+xml,%3Csvg')).to.be(1); + return done(); + }); + }); + }); + }); + + + describe('"limit" option and "url.dataUrlLimit" configuration', function () { it('should fall back to file-loader if the content of SVG file is longer than "limit" query parameter', function(done) { var config = assign({}, globalConfig, {