Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add stripdeclarations option #102

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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. `<?xml version="1.0" encoding="UTF-8"?>` 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/)
Expand Down
11 changes: 8 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions test/input/icon-with-declaration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
var icon = require('./images/icon-with-declaration.svg');
module.exports = icon;
7 changes: 7 additions & 0 deletions test/input/images/icon-with-declaration.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 60 additions & 1 deletion test/loader.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ var webpack = require('webpack');

describe('svg-url-loader', function() {
'use strict';

this.timeout(10000);

var outputDir = path.resolve(__dirname, './output'),
Expand Down Expand Up @@ -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, {
Expand Down