Skip to content

Commit 97b6373

Browse files
refactor: url replacer logic
1 parent 9e52d26 commit 97b6373

File tree

3 files changed

+20
-25
lines changed

3 files changed

+20
-25
lines changed

lib/loader.js

+11-23
Original file line numberDiff line numberDiff line change
@@ -213,39 +213,27 @@ module.exports = function loader(content, map) {
213213
placholderRegExps.urlItemG,
214214
(item) => {
215215
const match = placholderRegExps.urlItem.exec(item);
216-
let idx = Number(match[1]);
216+
const idx = Number(match[1]);
217217

218218
if (!urlItems[idx]) {
219219
return item;
220220
}
221221

222222
const urlItem = urlItems[idx];
223223
const { url } = urlItem;
224-
225-
idx = url.indexOf('?#');
226-
227-
if (idx < 0) {
228-
idx = url.indexOf('#');
229-
}
230-
231-
let urlRequest;
232-
233-
if (idx > 0) {
234-
// idx === 0 is catched by isUrlRequest
235-
// in cases like url('webfont.eot?#iefix')
236-
urlRequest = url.substr(0, idx);
237-
return `" + escape(require(${stringifyRequest(
238-
this,
239-
urlRequest
240-
)}) + "${url.substr(idx)}") + "`;
241-
}
242-
243-
urlRequest = url;
224+
// Remove `#hash` and `?#hash` from `require`
225+
const [normalizedUrl, singleQuery, hashValue] = url.split(/(\?)?#/);
226+
const hash =
227+
singleQuery || hashValue
228+
? `"${singleQuery ? '?' : ''}${
229+
hashValue ? `#${hashValue}` : ''
230+
}"`
231+
: '';
244232

245233
return `" + escape(require(${stringifyRequest(
246234
this,
247-
urlRequest
248-
)})) + "`;
235+
normalizedUrl
236+
)})${hash ? `+ ${hash}` : ''}) + "`;
249237
}
250238
);
251239
}

lib/plugins/postcss-url-parser.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,20 @@ function mapUrls(parsed, map) {
8282
});
8383
}
8484

85+
function uniq(array) {
86+
return array.reduce(
87+
(acc, d) => (acc.indexOf(d) === -1 ? [...acc, d] : acc),
88+
[]
89+
);
90+
}
91+
8592
module.exports = postcss.plugin(
8693
pluginName,
8794
(options) =>
8895
function process(css) {
8996
const urlItems = [];
9097
const traversed = walkDeclsWithUrl(css, (value) => isUrlRequest(value));
91-
const paths = flatten(traversed.map((item) => item.values));
98+
const paths = uniq(flatten(traversed.map((item) => item.values)));
9299

93100
if (paths.length === 0) {
94101
return;

test/__snapshots__/url-option.test.js.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ exports = module.exports = require(\\"../../../lib/runtime/api.js\\")(false);
415415
exports.i(require(\\"-!../../../index.js??ref--4-0!./imported.css\\"), \\"\\");
416416
417417
// module
418-
exports.push([module.id, \\".class {\\\\n background: url(\\" + escape(require(\\"./img.png\\")) + \\");\\\\n}\\\\n\\\\n.class {\\\\n background: url(\\" + escape(require(\\"./img.png\\")) + \\");\\\\n}\\\\n\\\\n.class {\\\\n background: url(\\" + escape(require(\\"./img.png\\")) + \\");\\\\n}\\\\n\\\\n.class {\\\\n background: url(\\" + escape(require(\\"./img.png\\") + \\"#hash\\") + \\");\\\\n}\\\\n\\\\n.class {\\\\n background: url(\\" + escape(require(\\"./img.png\\")) + \\");\\\\n}\\\\n\\\\n.class {\\\\n background: green url(\\" + escape(require(\\"./img.png\\")) + \\") xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url(\\" + escape(require(\\"./img.png\\")) + \\") xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url(\\" + escape(require(\\"./img.png\\")) + \\") xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url(\\" + escape(require(\\"package/img.png\\")) + \\") url(\\" + escape(require(\\"./other-img.png\\")) + \\") xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url(\\" + escape(require(\\"./img img.png\\")) + \\") xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url(\\" + escape(require(\\"./img img.png\\")) + \\") xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url(/img.png) xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url(data:image/png;base64,AAA) url(http://example.com/image.jpg) url(//example.com/image.png) xyz;\\\\n}\\\\n\\\\n.class {\\\\n background-image: url(\\\\\\"data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 42 26' fill='%23007aff'><rect width='4' height='4'/><rect x='8' y='1' width='34' height='2'/><rect y='11' width='4' height='4'/><rect x='8' y='12' width='34' height='2'/><rect y='22' width='4' height='4'/><rect x='8' y='23' width='34' height='2'/></svg>\\\\\\");\\\\n}\\\\n\\\\n.class {\\\\n background-image: url(\\\\\\"data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2042%2026%27%20fill%3D%27%2523007aff%27%3E%3Crect%20width%3D%274%27%20height%3D%274%27%2F%3E%3Crect%20x%3D%278%27%20y%3D%271%27%20width%3D%2734%27%20height%3D%272%27%2F%3E%3Crect%20y%3D%2711%27%20width%3D%274%27%20height%3D%274%27%2F%3E%3Crect%20x%3D%278%27%20y%3D%2712%27%20width%3D%2734%27%20height%3D%272%27%2F%3E%3Crect%20y%3D%2722%27%20width%3D%274%27%20height%3D%274%27%2F%3E%3Crect%20x%3D%278%27%20y%3D%2723%27%20width%3D%2734%27%20height%3D%272%27%2F%3E%3C%2Fsvg%3E\\\\\\");\\\\n}\\\\n\\\\n.class {\\\\n filter: url('data:image/svg+xml;charset=utf-8,<svg xmlns=\\\\\\"http://www.w3.org/2000/svg\\\\\\"><filter id=\\\\\\"filter\\\\\\"><feGaussianBlur in=\\\\\\"SourceAlpha\\\\\\" stdDeviation=\\\\\\"0\\\\\\" /><feOffset dx=\\\\\\"1\\\\\\" dy=\\\\\\"2\\\\\\" result=\\\\\\"offsetblur\\\\\\" /><feFlood flood-color=\\\\\\"rgba(255,255,255,1)\\\\\\" /><feComposite in2=\\\\\\"offsetblur\\\\\\" operator=\\\\\\"in\\\\\\" /><feMerge><feMergeNode /><feMergeNode in=\\\\\\"SourceGraphic\\\\\\" /></feMerge></filter></svg>#filter');\\\\n}\\\\n\\\\n.class {\\\\n filter: url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%5C%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%5C%22%3E%3Cfilter%20id%3D%5C%22filter%5C%22%3E%3CfeGaussianBlur%20in%3D%5C%22SourceAlpha%5C%22%20stdDeviation%3D%5C%220%5C%22%20%2F%3E%3CfeOffset%20dx%3D%5C%221%5C%22%20dy%3D%5C%222%5C%22%20result%3D%5C%22offsetblur%5C%22%20%2F%3E%3CfeFlood%20flood-color%3D%5C%22rgba(255%2C255%2C255%2C1)%5C%22%20%2F%3E%3CfeComposite%20in2%3D%5C%22offsetblur%5C%22%20operator%3D%5C%22in%5C%22%20%2F%3E%3CfeMerge%3E%3CfeMergeNode%20%2F%3E%3CfeMergeNode%20in%3D%5C%22SourceGraphic%5C%22%20%2F%3E%3C%2FfeMerge%3E%3C%2Ffilter%3E%3C%2Fsvg%3E%23filter');\\\\n}\\\\n\\\\n.highlight {\\\\n filter: url(#highlight);\\\\n}\\\\n\\\\n.highlight {\\\\n filter: url('#line-marker');\\\\n}\\\\n\\\\n@font-face {\\\\n src: url(\\" + escape(require(\\"./font.woff\\")) + \\") format('woff'),\\\\n url(\\" + escape(require(\\"./font.woff2\\")) + \\") format('woff2'),\\\\n url(\\" + escape(require(\\"./font.eot\\")) + \\") format('eot'),\\\\n url(\\" + escape(require(\\"package/font.ttf\\")) + \\") format('truetype'),\\\\n url(\\" + escape(require(\\"./font with spaces.eot\\")) + \\") format(\\\\\\"embedded-opentype\\\\\\"),\\\\n url(\\" + escape(require(\\"./font.svg\\") + \\"#svgFontName\\") + \\") format('svg'),\\\\n url(\\" + escape(require(\\"./font.woff2?foo=bar\\")) + \\") format('woff2'),\\\\n url(\\" + escape(require(\\"./font.eot\\") + \\"?#iefix\\") + \\") format('embedded-opentype'),\\\\n url(\\" + escape(require(\\"./font with spaces.eot\\") + \\"?#iefix\\") + \\") format('embedded-opentype');\\\\n}\\\\n\\\\n@media (min-width: 500px) {\\\\n body {\\\\n background: url(\\" + escape(require(\\"./img.png\\")) + \\");\\\\n }\\\\n}\\\\n\\\\na {\\\\n content: \\\\\\"do not use url(path)\\\\\\";\\\\n}\\\\n\\\\nb {\\\\n content: 'do not \\\\\\"use\\\\\\" url(path)';\\\\n}\\\\n\\\\n@keyframes anim {\\\\n background: green url(\\" + escape(require(\\"./img.png\\")) + \\") xyz;\\\\n}\\\\n\\\\n.a {\\\\n background-image: -webkit-image-set(url(\\" + escape(require(\\"./img1x.png\\")) + \\") 1x, url(\\" + escape(require(\\"./img2x.png\\")) + \\") 2x)\\\\n}\\\\n\\\\n.a {\\\\n background-image: image-set(url(\\" + escape(require(\\"./img1x.png\\")) + \\") 1x, url(\\" + escape(require(\\"./img2x.png\\")) + \\") 2x)\\\\n}\\\\n\\\\n.class {\\\\n background: green url() xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url('') xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url(\\\\\\"\\\\\\") xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url('') xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url(\\\\n \\\\n ) xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url(https://raw.githubusercontent.com/webpack/media/master/logo/icon.png) xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url(//raw.githubusercontent.com/webpack/media/master/logo/icon.png) xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: url(\\" + escape(require(\\"./img.png?foo\\")) + \\");\\\\n}\\\\n\\\\n.class {\\\\n background: url(\\" + escape(require(\\"./img.png?foo=bar\\")) + \\");\\\\n}\\\\n\\\\n.class {\\\\n background: url(\\" + escape(require(\\"./img.png?foo=bar\\") + \\"#hash\\") + \\");\\\\n}\\\\n\\\\n.class {\\\\n background: url(\\" + escape(require(\\"./img.png?foo=bar\\") + \\"#hash\\") + \\");\\\\n}\\\\n\\\\n.class {\\\\n background: url(\\" + escape(require(\\"./img.png?\\")) + \\");\\\\n}\\\\n\\\\n.class {\\\\n background-image: url(\\" + escape(require(\\"./img.png\\")) + \\") url(\\\\\\"data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 42 26' fill='%23007aff'><rect width='4' height='4'/><rect x='8' y='1' width='34' height='2'/><rect y='11' width='4' height='4'/><rect x='8' y='12' width='34' height='2'/><rect y='22' width='4' height='4'/><rect x='8' y='23' width='34' height='2'/></svg>\\\\\\") url(\\" + escape(require(\\"./img.png\\")) + \\");\\\\n}\\\\n\\\\n.class {\\\\n background: ___CSS_LOADER_URL___;\\\\n background: ___CSS_LOADER_URL___INDEX___;\\\\n background: ___CSS_LOADER_URL___99999___;\\\\n background: ___CSS_LOADER_IMPORT___;\\\\n background: ___CSS_LOADER_IMPORT___INDEX___;\\\\n background: ___CSS_LOADER_IMPORT___99999___;\\\\n}\\\\n\\", \\"\\"]);
418+
exports.push([module.id, \\".class {\\\\n background: url(\\" + escape(require(\\"./img.png\\")) + \\");\\\\n}\\\\n\\\\n.class {\\\\n background: url(\\" + escape(require(\\"./img.png\\")) + \\");\\\\n}\\\\n\\\\n.class {\\\\n background: url(\\" + escape(require(\\"./img.png\\")) + \\");\\\\n}\\\\n\\\\n.class {\\\\n background: url(\\" + escape(require(\\"./img.png\\")+ \\"#hash\\") + \\");\\\\n}\\\\n\\\\n.class {\\\\n background: url(\\" + escape(require(\\"./img.png\\")) + \\");\\\\n}\\\\n\\\\n.class {\\\\n background: green url(\\" + escape(require(\\"./img.png\\")) + \\") xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url(\\" + escape(require(\\"./img.png\\")) + \\") xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url(\\" + escape(require(\\"./img.png\\")) + \\") xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url(\\" + escape(require(\\"package/img.png\\")) + \\") url(\\" + escape(require(\\"./other-img.png\\")) + \\") xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url(\\" + escape(require(\\"./img img.png\\")) + \\") xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url(\\" + escape(require(\\"./img img.png\\")) + \\") xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url(/img.png) xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url(data:image/png;base64,AAA) url(http://example.com/image.jpg) url(//example.com/image.png) xyz;\\\\n}\\\\n\\\\n.class {\\\\n background-image: url(\\\\\\"data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 42 26' fill='%23007aff'><rect width='4' height='4'/><rect x='8' y='1' width='34' height='2'/><rect y='11' width='4' height='4'/><rect x='8' y='12' width='34' height='2'/><rect y='22' width='4' height='4'/><rect x='8' y='23' width='34' height='2'/></svg>\\\\\\");\\\\n}\\\\n\\\\n.class {\\\\n background-image: url(\\\\\\"data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2042%2026%27%20fill%3D%27%2523007aff%27%3E%3Crect%20width%3D%274%27%20height%3D%274%27%2F%3E%3Crect%20x%3D%278%27%20y%3D%271%27%20width%3D%2734%27%20height%3D%272%27%2F%3E%3Crect%20y%3D%2711%27%20width%3D%274%27%20height%3D%274%27%2F%3E%3Crect%20x%3D%278%27%20y%3D%2712%27%20width%3D%2734%27%20height%3D%272%27%2F%3E%3Crect%20y%3D%2722%27%20width%3D%274%27%20height%3D%274%27%2F%3E%3Crect%20x%3D%278%27%20y%3D%2723%27%20width%3D%2734%27%20height%3D%272%27%2F%3E%3C%2Fsvg%3E\\\\\\");\\\\n}\\\\n\\\\n.class {\\\\n filter: url('data:image/svg+xml;charset=utf-8,<svg xmlns=\\\\\\"http://www.w3.org/2000/svg\\\\\\"><filter id=\\\\\\"filter\\\\\\"><feGaussianBlur in=\\\\\\"SourceAlpha\\\\\\" stdDeviation=\\\\\\"0\\\\\\" /><feOffset dx=\\\\\\"1\\\\\\" dy=\\\\\\"2\\\\\\" result=\\\\\\"offsetblur\\\\\\" /><feFlood flood-color=\\\\\\"rgba(255,255,255,1)\\\\\\" /><feComposite in2=\\\\\\"offsetblur\\\\\\" operator=\\\\\\"in\\\\\\" /><feMerge><feMergeNode /><feMergeNode in=\\\\\\"SourceGraphic\\\\\\" /></feMerge></filter></svg>#filter');\\\\n}\\\\n\\\\n.class {\\\\n filter: url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%5C%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%5C%22%3E%3Cfilter%20id%3D%5C%22filter%5C%22%3E%3CfeGaussianBlur%20in%3D%5C%22SourceAlpha%5C%22%20stdDeviation%3D%5C%220%5C%22%20%2F%3E%3CfeOffset%20dx%3D%5C%221%5C%22%20dy%3D%5C%222%5C%22%20result%3D%5C%22offsetblur%5C%22%20%2F%3E%3CfeFlood%20flood-color%3D%5C%22rgba(255%2C255%2C255%2C1)%5C%22%20%2F%3E%3CfeComposite%20in2%3D%5C%22offsetblur%5C%22%20operator%3D%5C%22in%5C%22%20%2F%3E%3CfeMerge%3E%3CfeMergeNode%20%2F%3E%3CfeMergeNode%20in%3D%5C%22SourceGraphic%5C%22%20%2F%3E%3C%2FfeMerge%3E%3C%2Ffilter%3E%3C%2Fsvg%3E%23filter');\\\\n}\\\\n\\\\n.highlight {\\\\n filter: url(#highlight);\\\\n}\\\\n\\\\n.highlight {\\\\n filter: url('#line-marker');\\\\n}\\\\n\\\\n@font-face {\\\\n src: url(\\" + escape(require(\\"./font.woff\\")) + \\") format('woff'),\\\\n url(\\" + escape(require(\\"./font.woff2\\")) + \\") format('woff2'),\\\\n url(\\" + escape(require(\\"./font.eot\\")) + \\") format('eot'),\\\\n url(\\" + escape(require(\\"package/font.ttf\\")) + \\") format('truetype'),\\\\n url(\\" + escape(require(\\"./font with spaces.eot\\")) + \\") format(\\\\\\"embedded-opentype\\\\\\"),\\\\n url(\\" + escape(require(\\"./font.svg\\")+ \\"#svgFontName\\") + \\") format('svg'),\\\\n url(\\" + escape(require(\\"./font.woff2?foo=bar\\")) + \\") format('woff2'),\\\\n url(\\" + escape(require(\\"./font.eot\\")+ \\"?#iefix\\") + \\") format('embedded-opentype'),\\\\n url(\\" + escape(require(\\"./font with spaces.eot\\")+ \\"?#iefix\\") + \\") format('embedded-opentype');\\\\n}\\\\n\\\\n@media (min-width: 500px) {\\\\n body {\\\\n background: url(\\" + escape(require(\\"./img.png\\")) + \\");\\\\n }\\\\n}\\\\n\\\\na {\\\\n content: \\\\\\"do not use url(path)\\\\\\";\\\\n}\\\\n\\\\nb {\\\\n content: 'do not \\\\\\"use\\\\\\" url(path)';\\\\n}\\\\n\\\\n@keyframes anim {\\\\n background: green url(\\" + escape(require(\\"./img.png\\")) + \\") xyz;\\\\n}\\\\n\\\\n.a {\\\\n background-image: -webkit-image-set(url(\\" + escape(require(\\"./img1x.png\\")) + \\") 1x, url(\\" + escape(require(\\"./img2x.png\\")) + \\") 2x)\\\\n}\\\\n\\\\n.a {\\\\n background-image: image-set(url(\\" + escape(require(\\"./img1x.png\\")) + \\") 1x, url(\\" + escape(require(\\"./img2x.png\\")) + \\") 2x)\\\\n}\\\\n\\\\n.class {\\\\n background: green url() xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url('') xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url(\\\\\\"\\\\\\") xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url('') xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url(\\\\n \\\\n ) xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url(https://raw.githubusercontent.com/webpack/media/master/logo/icon.png) xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: green url(//raw.githubusercontent.com/webpack/media/master/logo/icon.png) xyz;\\\\n}\\\\n\\\\n.class {\\\\n background: url(\\" + escape(require(\\"./img.png?foo\\")) + \\");\\\\n}\\\\n\\\\n.class {\\\\n background: url(\\" + escape(require(\\"./img.png?foo=bar\\")) + \\");\\\\n}\\\\n\\\\n.class {\\\\n background: url(\\" + escape(require(\\"./img.png?foo=bar\\")+ \\"#hash\\") + \\");\\\\n}\\\\n\\\\n.class {\\\\n background: url(\\" + escape(require(\\"./img.png?foo=bar\\")+ \\"#hash\\") + \\");\\\\n}\\\\n\\\\n.class {\\\\n background: url(\\" + escape(require(\\"./img.png?\\")) + \\");\\\\n}\\\\n\\\\n.class {\\\\n background-image: url(\\" + escape(require(\\"./img.png\\")) + \\") url(\\\\\\"data:image/svg+xml;charset=utf-8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 42 26' fill='%23007aff'><rect width='4' height='4'/><rect x='8' y='1' width='34' height='2'/><rect y='11' width='4' height='4'/><rect x='8' y='12' width='34' height='2'/><rect y='22' width='4' height='4'/><rect x='8' y='23' width='34' height='2'/></svg>\\\\\\") url(\\" + escape(require(\\"./img.png\\")) + \\");\\\\n}\\\\n\\\\n.class {\\\\n background: ___CSS_LOADER_URL___;\\\\n background: ___CSS_LOADER_URL___INDEX___;\\\\n background: ___CSS_LOADER_URL___99999___;\\\\n background: ___CSS_LOADER_IMPORT___;\\\\n background: ___CSS_LOADER_IMPORT___INDEX___;\\\\n background: ___CSS_LOADER_IMPORT___99999___;\\\\n}\\\\n\\", \\"\\"]);
419419
420420
// exports
421421
"

0 commit comments

Comments
 (0)