Skip to content

Commit 218ed12

Browse files
feat: issue 1256
1 parent 28fb950 commit 218ed12

File tree

7 files changed

+332
-22
lines changed

7 files changed

+332
-22
lines changed

README.md

+44
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,50 @@ module.exports = {
11321132

11331133
## Examples
11341134

1135+
### Disable url resolving using the `/* webpackIgnore: true */` comment
1136+
1137+
With the help of the `/* webpackIgnore: true */`comment, it is possible to disable sources handling for rules and for individual declarations.
1138+
1139+
```css
1140+
/* webpackIgnore: true*/
1141+
@import url(./basic.css);
1142+
@import /* webpackIgnore: true */ url(./imported.css);
1143+
1144+
/** webpackIgnore: true */
1145+
.class {
1146+
/* Disabled url handling for the all .class */
1147+
color: red;
1148+
background: url("./url/img.png");
1149+
}
1150+
1151+
.class {
1152+
/* Disabled url handling for the first url in 'background' declaration */
1153+
color: red;
1154+
background: /** webpackIgnore: true */ url("./url/img.png"),
1155+
url("./url/img.png");
1156+
}
1157+
.class {
1158+
/* Disabled url handling for the all urls in 'background' declaration */
1159+
color: red;
1160+
/** webpackIgnore: true */
1161+
background: url("./url/img.png"), url("./url/img.png");
1162+
}
1163+
1164+
/* prettier-ignore */
1165+
.class {
1166+
/* Disabled url handling for the 3 and 6 urls in 'background-image' declaration */
1167+
background-image: image-set(
1168+
url(./url/img.png) 2x,
1169+
url(./url/img.png) 3x,
1170+
/*webpackIgnore: true*/ url(./url/img.png) 4x,
1171+
url(./url/img.png) 5x,
1172+
url(./url/img.png) 6x,
1173+
/*webpackIgnore: true*/
1174+
url(./url/img.png) 7x
1175+
);
1176+
}
1177+
```
1178+
11351179
### Assets
11361180

11371181
The following `webpack.config.js` can load CSS files, embed small PNG/JPG/GIF/SVG images as well as fonts as [Data URLs](https://tools.ietf.org/html/rfc2397) and copy larger files to the output directory.

src/plugins/postcss-import-parser.js

+5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
resolveRequests,
66
isUrlRequestable,
77
requestify,
8+
isWebpackIgnoreComment,
89
} from "../utils";
910

1011
function visitor(result, parsedResults, node, key) {
@@ -13,6 +14,10 @@ function visitor(result, parsedResults, node, key) {
1314
return;
1415
}
1516

17+
if (isWebpackIgnoreComment(node)) {
18+
return;
19+
}
20+
1621
// Nodes do not exists - `@import url('http://') :root {}`
1722
if (node.nodes) {
1823
result.warn(

src/plugins/postcss-url-parser.js

+51-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import {
55
requestify,
66
resolveRequests,
77
isUrlRequestable,
8+
isWebpackIgnoreComment,
9+
webpackIgnoreCommentRegexp,
810
} from "../utils";
911

1012
const isUrlFunc = /url/i;
@@ -35,13 +37,39 @@ function visitor(result, parsedResults, node, key) {
3537
return;
3638
}
3739

38-
const parsed = valueParser(node[key]);
40+
if (isWebpackIgnoreComment(node)) {
41+
return;
42+
}
43+
44+
const parsed = valueParser(
45+
typeof node.raws.value === "undefined" ? node[key] : node.raws.value.raw
46+
);
47+
48+
let webpackIgnore =
49+
typeof node.raws.between !== "undefined" &&
50+
webpackIgnoreCommentRegexp.test(node.raws.between);
51+
52+
if (webpackIgnore && isImageSetFunc.test(parsed.nodes[0].value)) {
53+
return;
54+
}
3955

4056
parsed.walk((valueNode) => {
57+
if (valueNode.type === "comment") {
58+
if (webpackIgnoreCommentRegexp.test(valueNode.value)) {
59+
webpackIgnore = true;
60+
}
61+
return;
62+
}
63+
4164
if (valueNode.type !== "function") {
4265
return;
4366
}
4467

68+
if (webpackIgnore) {
69+
webpackIgnore = false;
70+
return;
71+
}
72+
4573
if (isUrlFunc.test(valueNode.value)) {
4674
const { nodes } = valueNode;
4775
const isStringValue = nodes.length !== 0 && nodes[0].type === "string";
@@ -62,10 +90,26 @@ function visitor(result, parsedResults, node, key) {
6290
// eslint-disable-next-line consistent-return
6391
return false;
6492
} else if (isImageSetFunc.test(valueNode.value)) {
93+
let imageSetWebpackIgnore = false;
94+
6595
for (const nNode of valueNode.nodes) {
6696
const { type, value } = nNode;
6797

98+
if (type === "comment") {
99+
if (webpackIgnoreCommentRegexp.test(value)) {
100+
imageSetWebpackIgnore = true;
101+
}
102+
// eslint-disable-next-line no-continue
103+
continue;
104+
}
105+
68106
if (type === "function" && isUrlFunc.test(value)) {
107+
if (imageSetWebpackIgnore) {
108+
imageSetWebpackIgnore = false;
109+
// eslint-disable-next-line no-continue
110+
continue;
111+
}
112+
69113
const { nodes } = nNode;
70114
const isStringValue =
71115
nodes.length !== 0 && nodes[0].type === "string";
@@ -88,6 +132,12 @@ function visitor(result, parsedResults, node, key) {
88132
});
89133
}
90134
} else if (type === "string") {
135+
if (imageSetWebpackIgnore) {
136+
imageSetWebpackIgnore = false;
137+
// eslint-disable-next-line no-continue
138+
continue;
139+
}
140+
91141
const rule = {
92142
node: nNode,
93143
url: value,
@@ -104,7 +154,6 @@ function visitor(result, parsedResults, node, key) {
104154
}
105155
}
106156
}
107-
108157
// Do not traverse inside `image-set`
109158
// eslint-disable-next-line consistent-return
110159
return false;

src/utils.js

+28
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const unescapeRegExp = new RegExp(
1919
"ig"
2020
);
2121
const matchNativeWin32Path = /^[A-Z]:[/\\]|^\\\\/i;
22+
const webpackIgnoreCommentRegexp = /webpackIgnore:(\s+)?true/i;
2223

2324
function unescape(str) {
2425
return str.replace(unescapeRegExp, (_, escaped, escapedWhitespace) => {
@@ -702,6 +703,31 @@ function sort(a, b) {
702703
return a.index - b.index;
703704
}
704705

706+
function isWebpackIgnoreComment(node) {
707+
if (webpackIgnoreCommentRegexp.test(`${node.raws.afterName}`)) {
708+
return true;
709+
}
710+
711+
const possibleCommentPlaces = [node.prev()];
712+
713+
if (node.type === "decl") {
714+
possibleCommentPlaces.push(node.parent.prev());
715+
}
716+
717+
for (const prevNode of possibleCommentPlaces.filter((i) => Boolean(i))) {
718+
if (prevNode.type !== "comment") {
719+
// eslint-disable-next-line no-continue
720+
continue;
721+
}
722+
723+
if (webpackIgnoreCommentRegexp.test(prevNode.text)) {
724+
return true;
725+
}
726+
}
727+
728+
return false;
729+
}
730+
705731
export {
706732
normalizeOptions,
707733
shouldUseModulesPlugins,
@@ -721,4 +747,6 @@ export {
721747
resolveRequests,
722748
isUrlRequestable,
723749
sort,
750+
isWebpackIgnoreComment,
751+
webpackIgnoreCommentRegexp,
724752
};

test/__snapshots__/loader.test.js.snap

+170
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,176 @@ exports[`loader should work with the "modules.auto" option and the "importLoader
723723

724724
exports[`loader should work with the "modules.auto" option and the "importLoaders" option: warnings 1`] = `Array []`;
725725

726+
exports[`loader should work with webpackIgnore comment: errors 1`] = `Array []`;
727+
728+
exports[`loader should work with webpackIgnore comment: module 1`] = `
729+
"// Imports
730+
import ___CSS_LOADER_API_IMPORT___ from \\"../../src/runtime/api.js\\";
731+
import ___CSS_LOADER_GET_URL_IMPORT___ from \\"../../src/runtime/getUrl.js\\";
732+
import ___CSS_LOADER_URL_IMPORT_0___ from \\"./url/img.png\\";
733+
import ___CSS_LOADER_URL_IMPORT_1___ from \\"./fonts/Roboto-Regular.woff2\\";
734+
import ___CSS_LOADER_URL_IMPORT_2___ from \\"./fonts/Roboto-Regular.woff\\";
735+
import ___CSS_LOADER_URL_IMPORT_3___ from \\"./fonts/Roboto-Regular.ttf\\";
736+
import ___CSS_LOADER_URL_IMPORT_4___ from \\"./fonts/Roboto-Regular.svg\\";
737+
import ___CSS_LOADER_URL_IMPORT_5___ from \\"./fonts/Roboto-Regular.eot\\";
738+
var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(function(i){return i[1]});
739+
var ___CSS_LOADER_URL_REPLACEMENT_0___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_0___);
740+
var ___CSS_LOADER_URL_REPLACEMENT_1___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_1___);
741+
var ___CSS_LOADER_URL_REPLACEMENT_2___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_2___);
742+
var ___CSS_LOADER_URL_REPLACEMENT_3___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_3___);
743+
var ___CSS_LOADER_URL_REPLACEMENT_4___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_4___, { hash: \\"#Roboto-Regular\\" });
744+
var ___CSS_LOADER_URL_REPLACEMENT_5___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_5___);
745+
var ___CSS_LOADER_URL_REPLACEMENT_6___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_5___, { hash: \\"#iefix\\" });
746+
// Module
747+
___CSS_LOADER_EXPORT___.push([module.id, \\"/*webpackIgnore: true*/\\\\n@import url(./basic.css);\\\\n\\\\n@import /* webpackIgnore: true */ url(./imported.css);\\\\n\\\\n/** webpackIgnore: true **/\\\\n@import url(./simple.css);\\\\n\\\\n/** webpackIgnore: true */\\\\n.class {\\\\n color: red;\\\\n background: url(\\\\\\"./url/img.png\\\\\\");\\\\n}\\\\n\\\\n.class {\\\\n color: red;\\\\n background: /** webpackIgnore: true */ url(\\\\\\"./url/img.png\\\\\\"), url(\\" + ___CSS_LOADER_URL_REPLACEMENT_0___ + \\");\\\\n}\\\\n\\\\n.class {\\\\n color: red;\\\\n /** webpackIgnore: true */\\\\n background: url(\\\\\\"./url/img.png\\\\\\"), url(\\\\\\"./url/img.png\\\\\\");\\\\n}\\\\n\\\\n.class {\\\\n background:\\\\n url(\\" + ___CSS_LOADER_URL_REPLACEMENT_0___ + \\"),\\\\n url(\\" + ___CSS_LOADER_URL_REPLACEMENT_0___ + \\"),\\\\n /** webpackIgnore: true **/ url(\\\\\\"./url/img.png\\\\\\"),\\\\n url(\\" + ___CSS_LOADER_URL_REPLACEMENT_0___ + \\"),\\\\n /** webpackIgnore: true **/ url(\\\\\\"./url/img.png\\\\\\"),\\\\n url(\\" + ___CSS_LOADER_URL_REPLACEMENT_0___ + \\"),\\\\n url(\\" + ___CSS_LOADER_URL_REPLACEMENT_0___ + \\"),\\\\n url(\\" + ___CSS_LOADER_URL_REPLACEMENT_0___ + \\"),\\\\n /** webpackIgnore: true **/\\\\n url(\\\\\\"./url/img.png\\\\\\");\\\\n}\\\\n\\\\n/** webpackIgnore: true **/\\\\n@font-face {\\\\n font-family: \\\\\\"Roboto\\\\\\";\\\\n src: url(\\\\\\"./fonts/Roboto-Regular.eot\\\\\\");\\\\n src:\\\\n url(\\\\\\"./fonts/Roboto-Regular.eot#iefix\\\\\\") format(\\\\\\"embedded-opentype\\\\\\"),\\\\n url(\\\\\\"./fonts/Roboto-Regular.woff2\\\\\\") format(\\\\\\"woff\\\\\\"),\\\\n url(\\\\\\"./fonts/Roboto-Regular.woff\\\\\\") format(\\\\\\"woff\\\\\\"),\\\\n url(\\\\\\"./fonts/Roboto-Regular.ttf\\\\\\") format(\\\\\\"truetype\\\\\\"),\\\\n url(\\\\\\"./fonts/Roboto-Regular.svg#Roboto-Regular\\\\\\") format(\\\\\\"svg\\\\\\");\\\\n font-weight: 400;\\\\n font-style: normal;\\\\n}\\\\n\\\\n@font-face {\\\\n font-family: \\\\\\"Roboto\\\\\\";\\\\n src: /** webpackIgnore: true **/ url(\\\\\\"./fonts/Roboto-Regular.eot\\\\\\");\\\\n src:\\\\n /** webpackIgnore: true **/\\\\n url(\\\\\\"./fonts/Roboto-Regular.eot#iefix\\\\\\") format(\\\\\\"embedded-opentype\\\\\\"),\\\\n url(\\" + ___CSS_LOADER_URL_REPLACEMENT_1___ + \\") format(\\\\\\"woff\\\\\\"),\\\\n url(\\" + ___CSS_LOADER_URL_REPLACEMENT_2___ + \\") format(\\\\\\"woff\\\\\\"),\\\\n url(\\" + ___CSS_LOADER_URL_REPLACEMENT_3___ + \\") format(\\\\\\"truetype\\\\\\"),\\\\n url(\\" + ___CSS_LOADER_URL_REPLACEMENT_4___ + \\") format(\\\\\\"svg\\\\\\");\\\\n font-weight: 400;\\\\n font-style: normal;\\\\n}\\\\n\\\\n@font-face {\\\\n font-family: \\\\\\"Roboto\\\\\\";\\\\n src: /** webpackIgnore: true **/ url(\\\\\\"./fonts/Roboto-Regular.eot\\\\\\");\\\\n /** webpackIgnore: true **/\\\\n src:\\\\n url(\\\\\\"./fonts/Roboto-Regular.eot#iefix\\\\\\") format(\\\\\\"embedded-opentype\\\\\\"),\\\\n url(\\\\\\"./fonts/Roboto-Regular.woff2\\\\\\") format(\\\\\\"woff\\\\\\"),\\\\n url(\\\\\\"./fonts/Roboto-Regular.woff\\\\\\") format(\\\\\\"woff\\\\\\"),\\\\n url(\\\\\\"./fonts/Roboto-Regular.ttf\\\\\\") format(\\\\\\"truetype\\\\\\"),\\\\n url(\\\\\\"./fonts/Roboto-Regular.svg#Roboto-Regular\\\\\\") format(\\\\\\"svg\\\\\\");\\\\n font-weight: 400;\\\\n font-style: normal;\\\\n}\\\\n\\\\n@font-face {\\\\n font-family: \\\\\\"Roboto\\\\\\";\\\\n src: url(\\" + ___CSS_LOADER_URL_REPLACEMENT_5___ + \\");\\\\n src:\\\\n url(\\" + ___CSS_LOADER_URL_REPLACEMENT_6___ + \\") format(\\\\\\"embedded-opentype\\\\\\"),\\\\n /** webpackIgnore: true **/\\\\n url(\\\\\\"./fonts/Roboto-Regular.woff2\\\\\\") format(\\\\\\"woff\\\\\\"),\\\\n url(\\" + ___CSS_LOADER_URL_REPLACEMENT_2___ + \\") format(\\\\\\"woff\\\\\\"),\\\\n /** webpackIgnore: true **/\\\\n url(\\\\\\"./fonts/Roboto-Regular.ttf\\\\\\") format(\\\\\\"truetype\\\\\\"),\\\\n url(\\" + ___CSS_LOADER_URL_REPLACEMENT_4___ + \\") format(\\\\\\"svg\\\\\\");\\\\n font-weight: 400;\\\\n font-style: normal;\\\\n}\\\\n\\\\n/*webpackIgnore: true*/\\\\n.class {\\\\n background-image: image-set(\\\\n url(./url/img.png) 2x,\\\\n url(./url/img.png) 3x,\\\\n url(./url/img.png) 4x\\\\n );\\\\n}\\\\n\\\\n.class {\\\\n /*webpackIgnore: true*/\\\\n background-image: image-set(\\\\n url(./url/img.png) 2x,\\\\n url(./url/img.png) 3x,\\\\n url(./url/img.png) 4x\\\\n );\\\\n}\\\\n\\\\n.class {\\\\n background-image: /*webpackIgnore: true*/ image-set(\\\\n url(./url/img.png) 2x,\\\\n url(./url/img.png) 3x,\\\\n url(./url/img.png) 4x\\\\n );\\\\n}\\\\n\\\\n.class {\\\\n background-image: image-set(\\\\n /*webpackIgnore: true*/\\\\n url(./url/img.png) 2x,\\\\n url(\\" + ___CSS_LOADER_URL_REPLACEMENT_0___ + \\") 3x,\\\\n /*webpackIgnore: true*/\\\\n url(./url/img.png) 5x\\\\n );\\\\n}\\\\n\\", \\"\\"]);
748+
// Exports
749+
export default ___CSS_LOADER_EXPORT___;
750+
"
751+
`;
752+
753+
exports[`loader should work with webpackIgnore comment: result 1`] = `
754+
Array [
755+
Array [
756+
"./webpackIgnore.css",
757+
"/*webpackIgnore: true*/
758+
@import url(./basic.css);
759+
760+
@import /* webpackIgnore: true */ url(./imported.css);
761+
762+
/** webpackIgnore: true **/
763+
@import url(./simple.css);
764+
765+
/** webpackIgnore: true */
766+
.class {
767+
color: red;
768+
background: url(\\"./url/img.png\\");
769+
}
770+
771+
.class {
772+
color: red;
773+
background: /** webpackIgnore: true */ url(\\"./url/img.png\\"), url(/webpack/public/path/img.png);
774+
}
775+
776+
.class {
777+
color: red;
778+
/** webpackIgnore: true */
779+
background: url(\\"./url/img.png\\"), url(\\"./url/img.png\\");
780+
}
781+
782+
.class {
783+
background:
784+
url(/webpack/public/path/img.png),
785+
url(/webpack/public/path/img.png),
786+
/** webpackIgnore: true **/ url(\\"./url/img.png\\"),
787+
url(/webpack/public/path/img.png),
788+
/** webpackIgnore: true **/ url(\\"./url/img.png\\"),
789+
url(/webpack/public/path/img.png),
790+
url(/webpack/public/path/img.png),
791+
url(/webpack/public/path/img.png),
792+
/** webpackIgnore: true **/
793+
url(\\"./url/img.png\\");
794+
}
795+
796+
/** webpackIgnore: true **/
797+
@font-face {
798+
font-family: \\"Roboto\\";
799+
src: url(\\"./fonts/Roboto-Regular.eot\\");
800+
src:
801+
url(\\"./fonts/Roboto-Regular.eot#iefix\\") format(\\"embedded-opentype\\"),
802+
url(\\"./fonts/Roboto-Regular.woff2\\") format(\\"woff\\"),
803+
url(\\"./fonts/Roboto-Regular.woff\\") format(\\"woff\\"),
804+
url(\\"./fonts/Roboto-Regular.ttf\\") format(\\"truetype\\"),
805+
url(\\"./fonts/Roboto-Regular.svg#Roboto-Regular\\") format(\\"svg\\");
806+
font-weight: 400;
807+
font-style: normal;
808+
}
809+
810+
@font-face {
811+
font-family: \\"Roboto\\";
812+
src: /** webpackIgnore: true **/ url(\\"./fonts/Roboto-Regular.eot\\");
813+
src:
814+
/** webpackIgnore: true **/
815+
url(\\"./fonts/Roboto-Regular.eot#iefix\\") format(\\"embedded-opentype\\"),
816+
url(/webpack/public/path/Roboto-Regular.woff2) format(\\"woff\\"),
817+
url(/webpack/public/path/Roboto-Regular.woff) format(\\"woff\\"),
818+
url(/webpack/public/path/Roboto-Regular.ttf) format(\\"truetype\\"),
819+
url(/webpack/public/path/Roboto-Regular.svg#Roboto-Regular) format(\\"svg\\");
820+
font-weight: 400;
821+
font-style: normal;
822+
}
823+
824+
@font-face {
825+
font-family: \\"Roboto\\";
826+
src: /** webpackIgnore: true **/ url(\\"./fonts/Roboto-Regular.eot\\");
827+
/** webpackIgnore: true **/
828+
src:
829+
url(\\"./fonts/Roboto-Regular.eot#iefix\\") format(\\"embedded-opentype\\"),
830+
url(\\"./fonts/Roboto-Regular.woff2\\") format(\\"woff\\"),
831+
url(\\"./fonts/Roboto-Regular.woff\\") format(\\"woff\\"),
832+
url(\\"./fonts/Roboto-Regular.ttf\\") format(\\"truetype\\"),
833+
url(\\"./fonts/Roboto-Regular.svg#Roboto-Regular\\") format(\\"svg\\");
834+
font-weight: 400;
835+
font-style: normal;
836+
}
837+
838+
@font-face {
839+
font-family: \\"Roboto\\";
840+
src: url(/webpack/public/path/Roboto-Regular.eot);
841+
src:
842+
url(/webpack/public/path/Roboto-Regular.eot#iefix) format(\\"embedded-opentype\\"),
843+
/** webpackIgnore: true **/
844+
url(\\"./fonts/Roboto-Regular.woff2\\") format(\\"woff\\"),
845+
url(/webpack/public/path/Roboto-Regular.woff) format(\\"woff\\"),
846+
/** webpackIgnore: true **/
847+
url(\\"./fonts/Roboto-Regular.ttf\\") format(\\"truetype\\"),
848+
url(/webpack/public/path/Roboto-Regular.svg#Roboto-Regular) format(\\"svg\\");
849+
font-weight: 400;
850+
font-style: normal;
851+
}
852+
853+
/*webpackIgnore: true*/
854+
.class {
855+
background-image: image-set(
856+
url(./url/img.png) 2x,
857+
url(./url/img.png) 3x,
858+
url(./url/img.png) 4x
859+
);
860+
}
861+
862+
.class {
863+
/*webpackIgnore: true*/
864+
background-image: image-set(
865+
url(./url/img.png) 2x,
866+
url(./url/img.png) 3x,
867+
url(./url/img.png) 4x
868+
);
869+
}
870+
871+
.class {
872+
background-image: /*webpackIgnore: true*/ image-set(
873+
url(./url/img.png) 2x,
874+
url(./url/img.png) 3x,
875+
url(./url/img.png) 4x
876+
);
877+
}
878+
879+
.class {
880+
background-image: image-set(
881+
/*webpackIgnore: true*/
882+
url(./url/img.png) 2x,
883+
url(/webpack/public/path/img.png) 3x,
884+
/*webpackIgnore: true*/
885+
url(./url/img.png) 5x
886+
);
887+
}
888+
",
889+
"",
890+
],
891+
]
892+
`;
893+
894+
exports[`loader should work with webpackIgnore comment: warnings 1`] = `Array []`;
895+
726896
exports[`loader should work: errors 1`] = `Array []`;
727897

728898
exports[`loader should work: module 1`] = `

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

+20-20
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)