Skip to content

Commit ae37fd9

Browse files
refactor: url
1 parent 3905e87 commit ae37fd9

File tree

5 files changed

+96
-43
lines changed

5 files changed

+96
-43
lines changed

src/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,8 @@ export default function loader(content, map, meta) {
146146
null,
147147
[
148148
runtime ? `// CSS runtime\n${runtime}` : '',
149-
imports.length > 0 ? `\n// CSS imports\n${imports.join('\n')}` : '',
150-
module ? `\n// CSS module\n${module}` : '',
149+
imports.length > 0 ? `// CSS imports\n${imports.join('\n')}` : '',
150+
module ? `// CSS module\n${module}` : '',
151151
exports.length > 0 ? `// CSS exports\n${exports.join('\n')}` : '',
152152
].join('\n')
153153
);

src/plugins/url.js

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
11
import postcss from 'postcss';
22
import valueParser from 'postcss-value-parser';
3-
import { isUrlRequest } from 'loader-utils';
3+
import { isUrlRequest, stringifyRequest, urlToRequest } from 'loader-utils';
44

55
const pluginName = 'postcss-css-loader-icss-url';
66

7+
function normalizeUrl(url) {
8+
return url.split(/(\?)?#/);
9+
}
10+
711
const walkUrls = (parsed, callback) => {
812
parsed.walk((node) => {
913
if (node.type !== 'function' || node.value.toLowerCase() !== 'url') {
1014
return;
1115
}
1216

13-
const content =
17+
const url =
1418
node.nodes.length !== 0 && node.nodes[0].type === 'string'
1519
? node.nodes[0].value
1620
: valueParser.stringify(node.nodes);
1721

18-
if (content.trim().replace(/\\[\r\n]/g, '').length !== 0) {
19-
callback(node, content);
22+
if (url.trim().replace(/\\[\r\n]/g, '').length !== 0) {
23+
callback(node, url);
2024
}
2125

2226
// Do not traverse inside url
@@ -57,7 +61,8 @@ const walkDeclsWithUrl = (css, filter) => {
5761
result.push({
5862
decl,
5963
parsed,
60-
values,
64+
// Remove `#hash` and `?#hash` to avoid duplicate require for assets with `#hash` and `?#hash`
65+
values: values.map((value) => normalizeUrl(value)[0]),
6166
});
6267
});
6368

@@ -79,26 +84,69 @@ const mapUrls = (parsed, map) => {
7984
export default postcss.plugin(
8085
pluginName,
8186
() =>
82-
function process(css) {
87+
function process(css, result) {
8388
const traversed = walkDeclsWithUrl(css, (value) => isUrlRequest(value));
8489
const paths = uniq(flatten(traversed.map((item) => item.values)));
85-
const imports = {};
86-
const aliases = {};
8790

88-
paths.forEach((path, index) => {
89-
const alias = `__url__${index}__`;
91+
if (paths.length === 0) {
92+
return;
93+
}
9094

91-
imports[`"${path}"`] = {
92-
[alias]: 'default',
93-
};
94-
aliases[path] = alias;
95+
const urls = {};
96+
97+
paths.forEach((path, index) => {
98+
urls[path] = `___CSS_LOADER_URL___${index}___`;
9599
});
96100

97101
traversed.forEach((item) => {
98-
mapUrls(item.parsed, (value) => aliases[value]);
102+
mapUrls(item.parsed, (url) => {
103+
const [normalizedUrl, singleQuery, hashValue] = normalizeUrl(url);
104+
105+
// Return `#hash` and `?#hash` in css
106+
return `${urls[normalizedUrl]}${singleQuery || ''}${
107+
hashValue ? `#${hashValue}` : ''
108+
}`;
109+
});
99110

100111
// eslint-disable-next-line no-param-reassign
101112
item.decl.value = item.parsed.toString();
102113
});
114+
115+
let hasURLEscapeRuntime = false;
116+
117+
Object.keys(urls).forEach((url) => {
118+
result.messages.push({
119+
pluginName,
120+
type: 'module',
121+
modify(moduleObj, loaderContext) {
122+
if (!hasURLEscapeRuntime) {
123+
moduleObj.imports.push(
124+
`var escape = require(${stringifyRequest(
125+
loaderContext,
126+
require.resolve('../runtime/escape')
127+
)});`
128+
);
129+
130+
hasURLEscapeRuntime = true;
131+
}
132+
133+
const placeholder = urls[url];
134+
const [normalizedUrl] = normalizeUrl(url);
135+
136+
moduleObj.imports.push(
137+
`var ${placeholder} = escape(require(${stringifyRequest(
138+
loaderContext,
139+
urlToRequest(normalizedUrl)
140+
)}));`
141+
);
142+
moduleObj.module = moduleObj.module.replace(
143+
new RegExp(placeholder, 'g'),
144+
`" + ${placeholder} + "`
145+
);
146+
147+
return moduleObj;
148+
},
149+
});
150+
});
103151
}
104152
);

0 commit comments

Comments
 (0)