Skip to content

Commit 911f02d

Browse files
perf: improve (webpack-contrib#1290)
1 parent 4f10583 commit 911f02d

File tree

3 files changed

+101
-34
lines changed

3 files changed

+101
-34
lines changed

src/plugins/postcss-import-parser.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
resolveRequests,
66
isUrlRequestable,
77
requestify,
8-
webpackIgnoreCommentRegexp,
8+
WEBPACK_IGNORE_COMMENT_REGEXP,
99
} from "../utils";
1010

1111
function parseNode(atRule, key) {
@@ -22,7 +22,7 @@ function parseNode(atRule, key) {
2222
const lastCommentIndex = atRule.raws.afterName.lastIndexOf("/*");
2323
const matched = atRule.raws.afterName
2424
.slice(lastCommentIndex)
25-
.match(webpackIgnoreCommentRegexp);
25+
.match(WEBPACK_IGNORE_COMMENT_REGEXP);
2626

2727
if (matched && matched[2] === "true") {
2828
return;
@@ -32,7 +32,7 @@ function parseNode(atRule, key) {
3232
const prevNode = atRule.prev();
3333

3434
if (prevNode && prevNode.type === "comment") {
35-
const matched = prevNode.text.match(webpackIgnoreCommentRegexp);
35+
const matched = prevNode.text.match(WEBPACK_IGNORE_COMMENT_REGEXP);
3636

3737
if (matched && matched[2] === "true") {
3838
return;

src/plugins/postcss-url-parser.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
requestify,
66
resolveRequests,
77
isUrlRequestable,
8-
webpackIgnoreCommentRegexp,
8+
WEBPACK_IGNORE_COMMENT_REGEXP,
99
} from "../utils";
1010

1111
const isUrlFunc = /url/i;
@@ -42,7 +42,7 @@ function getWebpackIgnoreCommentValue(index, nodes, inBetween) {
4242
return;
4343
}
4444

45-
const matched = prevValueNode.value.match(webpackIgnoreCommentRegexp);
45+
const matched = prevValueNode.value.match(WEBPACK_IGNORE_COMMENT_REGEXP);
4646

4747
return matched && matched[2] === "true";
4848
}
@@ -81,7 +81,7 @@ function parseDeclaration(declaration, key, result) {
8181

8282
const matched = declaration.raws.between
8383
.slice(lastCommentIndex)
84-
.match(webpackIgnoreCommentRegexp);
84+
.match(WEBPACK_IGNORE_COMMENT_REGEXP);
8585

8686
if (matched) {
8787
inBetween = matched[2] === "true";
@@ -93,7 +93,7 @@ function parseDeclaration(declaration, key, result) {
9393
const prevNode = declaration.prev();
9494

9595
if (prevNode && prevNode.type === "comment") {
96-
const matched = prevNode.text.match(webpackIgnoreCommentRegexp);
96+
const matched = prevNode.text.match(WEBPACK_IGNORE_COMMENT_REGEXP);
9797

9898
if (matched) {
9999
isIgnoreOnDeclaration = matched[2] === "true";

src/utils.js

+94-27
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,7 @@ import extractImports from "postcss-modules-extract-imports";
1212
import modulesScope from "postcss-modules-scope";
1313
import camelCase from "camelcase";
1414

15-
const whitespace = "[\\x20\\t\\r\\n\\f]";
16-
const unescapeRegExp = new RegExp(
17-
`\\\\([\\da-f]{1,6}${whitespace}?|(${whitespace})|.)`,
18-
"ig"
19-
);
20-
const matchNativeWin32Path = /^[A-Z]:[/\\]|^\\\\/i;
21-
const webpackIgnoreCommentRegexp = /webpackIgnore:(\s+)?(true|false)/;
15+
const WEBPACK_IGNORE_COMMENT_REGEXP = /webpackIgnore:(\s+)?(true|false)/;
2216

2317
// eslint-disable-next-line no-useless-escape
2418
const regexSingleEscape = /[ -,.\/:-@[\]\^`{-~]/;
@@ -72,24 +66,95 @@ function escape(string) {
7266
return output;
7367
}
7468

69+
function gobbleHex(str) {
70+
const lower = str.toLowerCase();
71+
let hex = "";
72+
let spaceTerminated = false;
73+
74+
// eslint-disable-next-line no-undefined
75+
for (let i = 0; i < 6 && lower[i] !== undefined; i++) {
76+
const code = lower.charCodeAt(i);
77+
// check to see if we are dealing with a valid hex char [a-f|0-9]
78+
const valid = (code >= 97 && code <= 102) || (code >= 48 && code <= 57);
79+
// https://drafts.csswg.org/css-syntax/#consume-escaped-code-point
80+
spaceTerminated = code === 32;
81+
82+
if (!valid) {
83+
break;
84+
}
85+
86+
hex += lower[i];
87+
}
88+
89+
if (hex.length === 0) {
90+
// eslint-disable-next-line no-undefined
91+
return undefined;
92+
}
93+
94+
const codePoint = parseInt(hex, 16);
95+
96+
const isSurrogate = codePoint >= 0xd800 && codePoint <= 0xdfff;
97+
// Add special case for
98+
// "If this number is zero, or is for a surrogate, or is greater than the maximum allowed code point"
99+
// https://drafts.csswg.org/css-syntax/#maximum-allowed-code-point
100+
if (isSurrogate || codePoint === 0x0000 || codePoint > 0x10ffff) {
101+
return ["\uFFFD", hex.length + (spaceTerminated ? 1 : 0)];
102+
}
103+
104+
return [
105+
String.fromCodePoint(codePoint),
106+
hex.length + (spaceTerminated ? 1 : 0),
107+
];
108+
}
109+
110+
const CONTAINS_ESCAPE = /\\/;
111+
75112
function unescape(str) {
76-
return str.replace(unescapeRegExp, (_, escaped, escapedWhitespace) => {
77-
const high = `0x${escaped}` - 0x10000;
78-
79-
/* eslint-disable line-comment-position */
80-
// NaN means non-codepoint
81-
// Workaround erroneous numeric interpretation of +"0x"
82-
// eslint-disable-next-line no-self-compare
83-
return high !== high || escapedWhitespace
84-
? escaped
85-
: high < 0
86-
? // BMP codepoint
87-
String.fromCharCode(high + 0x10000)
88-
: // Supplemental Plane codepoint (surrogate pair)
89-
// eslint-disable-next-line no-bitwise
90-
String.fromCharCode((high >> 10) | 0xd800, (high & 0x3ff) | 0xdc00);
91-
/* eslint-enable line-comment-position */
92-
});
113+
const needToProcess = CONTAINS_ESCAPE.test(str);
114+
115+
if (!needToProcess) {
116+
return str;
117+
}
118+
119+
let ret = "";
120+
121+
for (let i = 0; i < str.length; i++) {
122+
if (str[i] === "\\") {
123+
const gobbled = gobbleHex(str.slice(i + 1, i + 7));
124+
125+
// eslint-disable-next-line no-undefined
126+
if (gobbled !== undefined) {
127+
ret += gobbled[0];
128+
i += gobbled[1];
129+
130+
// eslint-disable-next-line no-continue
131+
continue;
132+
}
133+
134+
// Retain a pair of \\ if double escaped `\\\\`
135+
// https://github.com/postcss/postcss-selector-parser/commit/268c9a7656fb53f543dc620aa5b73a30ec3ff20e
136+
if (str[i + 1] === "\\") {
137+
ret += "\\";
138+
i += 1;
139+
140+
// eslint-disable-next-line no-continue
141+
continue;
142+
}
143+
144+
// if \\ is at the end of the string retain it
145+
// https://github.com/postcss/postcss-selector-parser/commit/01a6b346e3612ce1ab20219acc26abdc259ccefb
146+
if (str.length === i + 1) {
147+
ret += str[i];
148+
}
149+
150+
// eslint-disable-next-line no-continue
151+
continue;
152+
}
153+
154+
ret += str[i];
155+
}
156+
157+
return ret;
93158
}
94159

95160
function normalizePath(file) {
@@ -139,6 +204,8 @@ function defaultGetLocalIdent(
139204
return interpolateName(loaderContext, localIdentName, options);
140205
}
141206

207+
const NATIVE_WIN32_PATH = /^[A-Z]:[/\\]|^\\\\/i;
208+
142209
function normalizeUrl(url, isStringValue) {
143210
let normalizedUrl = url
144211
.replace(/^( |\t\n|\r\n|\r|\f)*/g, "")
@@ -148,7 +215,7 @@ function normalizeUrl(url, isStringValue) {
148215
normalizedUrl = normalizedUrl.replace(/\\(\n|\r\n|\r|\f)/g, "");
149216
}
150217

151-
if (matchNativeWin32Path.test(url)) {
218+
if (NATIVE_WIN32_PATH.test(url)) {
152219
try {
153220
normalizedUrl = decodeURI(normalizedUrl);
154221
} catch (error) {
@@ -768,7 +835,7 @@ function isUrlRequestable(url) {
768835
}
769836

770837
// Absolute URLs
771-
if (/^[a-z][a-z0-9+.-]*:/i.test(url) && !matchNativeWin32Path.test(url)) {
838+
if (/^[a-z][a-z0-9+.-]*:/i.test(url) && !NATIVE_WIN32_PATH.test(url)) {
772839
return false;
773840
}
774841

@@ -811,6 +878,6 @@ export {
811878
resolveRequests,
812879
isUrlRequestable,
813880
sort,
814-
webpackIgnoreCommentRegexp,
881+
WEBPACK_IGNORE_COMMENT_REGEXP,
815882
combineRequests,
816883
};

0 commit comments

Comments
 (0)