Skip to content

Commit 635f4d1

Browse files
author
Vladimir Panimaskin
committed
Name interpolation. EsLint updated.
1 parent 399f459 commit 635f4d1

File tree

10 files changed

+124
-38
lines changed

10 files changed

+124
-38
lines changed

.idea/jsLinters/eslint.xml

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

+12
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ and additional options object as second:
4141
new SVGSpriteExtractPlugin(outputFilename, options = {});
4242
```
4343

44+
`outputFilename` can contain \[hash] placeholder:
45+
46+
```js
47+
new SVGSpriteExtractPlugin('my.svg.bundle.[hash].js');
48+
```
49+
4450
### .extract(loaders = [])
4551

4652
This method returns a configured loader string for this plugin.
@@ -55,6 +61,12 @@ plugin.extract('svgo!other!etc');
5561
plugin.extract(['svgo', 'other', 'etc']);
5662
```
5763

64+
## Options
65+
66+
* idTemplate - default: \[name] - sprite id. You can use all built-in webpack placeholders here.
67+
Slashes and backslashes will be replaced with a dash. Other symbols unallowed in HTML identifiers will be removed.
68+
* context - default: '.' - root path from which \[path] placeholders in ids will be resolved
69+
5870
## Loader
5971

6072
The built-in loader processes SVG content. It expects each required file has `<svg>` root tag.

example/build.js

+49-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,51 @@
1+
'use strict';
2+
13
require('babel-register');
2-
var Webpack = require('webpack');
3-
var config = require('./webpack.config').default;
44

5-
new Webpack(config, function() {
6-
});
5+
const Webpack = require('webpack');
6+
const config = require('./webpack.config').default;
7+
8+
const WEBPACK_STATS = {
9+
assets: true,
10+
children: true,
11+
chunkModules: true,
12+
chunks: true,
13+
colors: true,
14+
errorDetails: true,
15+
errors: true,
16+
hash: true,
17+
modules: true,
18+
publicPath: true,
19+
reasons: true,
20+
source: false,
21+
timings: false,
22+
version: true,
23+
warnings: true
24+
};
25+
26+
const compiler = new Webpack(config, (error, stats) => {
27+
if (error) {
28+
printError(error);
29+
} else {
30+
const jsonStats = stats.toJson();
31+
if (jsonStats.errors.length > 0) {
32+
printError(jsonStats.errors);
33+
} else {
34+
console.log(stats.toString(WEBPACK_STATS));
35+
}
36+
}
37+
});
38+
39+
/**
40+
* @param {Array|Object} e
41+
*/
42+
function printError(e) {
43+
const errors = Array.isArray(e) ? e : [e];
44+
errors.forEach(error => {
45+
console.error();
46+
console.error(error.stack || error);
47+
console.error();
48+
});
49+
50+
process.exit(1);
51+
}

example/main.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import iconClearId from './icons/icon-clear.svg';
2-
import iconEditId from './icons/icon-edit.svg';
2+
import iconEditId from './icons/icon-edit.svg';
33
import iconBoughtSold from './icons/icon-bought-sold.svg';
44

55
console.assert(iconEditId === 'icon-edit', 'Invalid id for "icon-edit.svg"');

example/webpack.config.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import path from 'path';
22
import SVGSpriteExtractPlugin from '../index';
33

4-
const plugin = new SVGSpriteExtractPlugin('svg.bundle.js');
4+
const plugin = new SVGSpriteExtractPlugin('svg.bundle.[hash].js', {
5+
idTemplate: '[path][name].[hash].[ext]',
6+
context: path.resolve(__dirname)
7+
});
58

69
export default {
710
context: path.resolve(__dirname),

index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export {default as default} from './src/plugin';
1+
export {default} from './src/plugin';

package.json

+4-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"description": "Webpack plugin for extracting SVG and creating sprites",
55
"main": "./index.js",
66
"scripts": {
7-
"eslint": "eslint --config ./node_modules/eslint-config-dx/.eslintrc --ext .js ./src",
7+
"eslint": "eslint --config ./node_modules/dx-lint/.eslintrc --ext .js ./src",
88
"test": "node ./example/build.js"
99
},
1010
"repository": {
@@ -30,8 +30,9 @@
3030
"babel-plugin-transform-decorators-legacy": "^1.3.4",
3131
"babel-preset-es2015": "^6.9.0",
3232
"babel-register": "^6.9.0",
33-
"eslint": "^1.10.1",
34-
"eslint-config-dx": "github:devex-web-frontend/eslint-config-dx",
33+
"dx-lint": "github:devex-web-frontend/dx-lint#0.2.0",
34+
"eslint-plugin-babel": "~3.3.0",
35+
"eslint": "~2.13.1",
3536
"webpack": "^1.13.1"
3637
}
3738
}

src/loader.js

+24-11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import path from 'path';
21
import cheerio from 'cheerio';
32
import loaderUtils from 'loader-utils';
43

@@ -37,12 +36,15 @@ function getNormalizedContent($svg) {
3736
* @returns {*} Cheerio object for <symbol>.
3837
*/
3938
function createSymbol(content, id) {
40-
let $ = cheerio.load(content, {xmlMode: true});
41-
let $svg = $('svg');
42-
let viewBox = $svg.attr('viewBox');
43-
let $symbol = $('<symbol></symbol>');
39+
const $ = cheerio.load(content, {
40+
xmlMode: true
41+
});
4442

45-
let $content = getNormalizedContent($svg);
43+
const $svg = $('svg');
44+
const viewBox = $svg.attr('viewBox');
45+
const $symbol = $('<symbol></symbol>');
46+
47+
const $content = getNormalizedContent($svg);
4648

4749
$symbol.attr('id', id);
4850
$symbol.attr('viewBox', viewBox);
@@ -61,6 +63,14 @@ function processSvg(content, id) {
6163
return cheerio.html(createSymbol(content, id));
6264
}
6365

66+
/**
67+
* @param {String} id
68+
* @returns {String} escaped id
69+
*/
70+
function escapeId(id) {
71+
return id.replace(/[\/\\]/g, '-').replace(/[^\w:\.\-]/g, '');
72+
}
73+
6474
/**
6575
* Loader for webpack.
6676
* It takes SVG file content and returns a module, exporting the id of this sprite.
@@ -72,14 +82,17 @@ module.exports = function(content) {
7282
//noinspection JSUnresolvedVariable,JSUnresolvedFunction
7383
this.cacheable && this.cacheable();
7484

75-
let result;
7685
//noinspection JSUnresolvedVariable
77-
let spriteId = path.basename(this.resourcePath, '.svg');
78-
let query = loaderUtils.parseQuery(this.query);
86+
const query = loaderUtils.parseQuery(this.query);
87+
const {context = '.'} = query;
88+
const cacheSVG = this[query.svgCacheNamespace][query.svgCacheFuncName];
7989

80-
result = processSvg(content, spriteId);
90+
const spriteId = escapeId(loaderUtils.interpolateName(this, query.idTemplate, {
91+
content,
92+
context
93+
}));
8194

82-
let cacheSVG = this[query.svgCacheNamespace][query.svgCacheFuncName];
95+
const result = processSvg(content, spriteId);
8396
cacheSVG(result);
8497

8598
return `module.exports = ${JSON.stringify(spriteId)};`;

src/plugin.js

+24-12
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,27 @@
1+
import loaderUtils from 'loader-utils';
12
import SvgSprite from './svg-sprite';
23

34
/**
45
* @typedef {Object} SVGSpriteExtractPluginOptions
56
* @property {string} [svgCacheNamespace]
6-
* @property {string} [svgCacheFuncPrefix]
77
* @property {string} [svgCacheFuncName]
8+
* @property {string} [idTemplate]
9+
* @property {string} [context]
810
*/
911

1012
/**
1113
* @type {SVGSpriteExtractPluginOptions}
1214
*/
1315
const DEFAULT_OPTIONS = {
1416
svgCacheNamespace: 'cacheSvg',
15-
svgCacheFuncPrefix: 'cacheSvg_'
17+
idTemplate: '[name]'
1618
};
1719

20+
/**
21+
* @type {string}
22+
*/
23+
const SVG_CACHE_FUNC_PREFIX = 'cacheSvg_';
24+
1825
/**
1926
* @type {number}
2027
*/
@@ -53,7 +60,7 @@ class SVGSpriteExtractPlugin {
5360
this._filename = filename;
5461

5562
this._options = Object.assign({}, DEFAULT_OPTIONS, options);
56-
this._options.svgCacheFuncName = this._options.svgCacheFuncPrefix + this._id;
63+
this._options.svgCacheFuncName = SVG_CACHE_FUNC_PREFIX + this._id;
5764
}
5865

5966
/**
@@ -62,26 +69,26 @@ class SVGSpriteExtractPlugin {
6269
* @returns {string} loader string
6370
*/
6471
extract(loader = []) {
65-
let {svgCacheNamespace, svgCacheFuncName} = this._options;
72+
let beforeLoaders = loader;
6673

67-
if (typeof loader === 'string') {
68-
loader = loader.split('!');
74+
if (typeof beforeLoaders === 'string') {
75+
beforeLoaders = beforeLoaders.split('!');
6976
}
7077

7178
return [
72-
require.resolve('./loader') + '?' + JSON.stringify({svgCacheNamespace, svgCacheFuncName})
73-
].concat(loader).join('!');
79+
`${require.resolve('./loader')}?${JSON.stringify(this._options)}`
80+
].concat(beforeLoaders).join('!');
7481
}
7582

7683
/**
7784
* Entry point to this plugin for webpack.
7885
* @param {Object} compiler
7986
*/
8087
apply(compiler) {
81-
let {svgCacheNamespace, svgCacheFuncName} = this._options;
88+
const {svgCacheNamespace, svgCacheFuncName} = this._options;
8289

83-
let sprite = new SvgSprite();
84-
let cacheFunc = svgContent => sprite.append(svgContent);
90+
const sprite = new SvgSprite();
91+
const cacheFunc = svgContent => sprite.append(svgContent);
8592

8693
compiler.plugin('compilation', compilation => {
8794
compilation.plugin('normal-module-loader', (loaderContext, module) => {
@@ -91,7 +98,12 @@ class SVGSpriteExtractPlugin {
9198
});
9299

93100
compiler.plugin('emit', (compilation, callback) => {
94-
compilation.assets[this._filename] = sprite.render();
101+
const compiledSprite = sprite.render();
102+
const filename = loaderUtils.interpolateName({}, this._filename, {
103+
content: compiledSprite.source()
104+
});
105+
106+
compilation.assets[filename] = compiledSprite;
95107
callback();
96108
});
97109
}

src/svg-sprite.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import util from 'util';
44
/**
55
* @type {string}
66
*/
7-
const SCRIPT_HEADER = `(function() {`;
7+
const SCRIPT_HEADER = '(function() {';
88

99
/**
1010
* @type {string}
@@ -61,8 +61,8 @@ class SvgSprite {
6161
* @returns {ConcatSource} an object suitable for compilation.assets collection.
6262
*/
6363
render() {
64-
let source = new ConcatSource();
65-
let elements = this._elements.slice();
64+
const source = new ConcatSource();
65+
const elements = this._elements.slice();
6666

6767
source.add(SCRIPT_HEADER);
6868
source.add(util.format(SPRITE_CONTENT_TEMPLATE, JSON.stringify(elements.join(''))));

0 commit comments

Comments
 (0)