Skip to content

Commit

Permalink
feat: issue 1256
Browse files Browse the repository at this point in the history
  • Loading branch information
cap-Bernardito authored and alexander-akait committed Feb 19, 2021
1 parent e18c5a9 commit e3f251b
Show file tree
Hide file tree
Showing 7 changed files with 332 additions and 22 deletions.
44 changes: 44 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1132,6 +1132,50 @@ module.exports = {

## Examples

### Disable url resolving using the `/* webpackIgnore: true */` comment

With the help of the `/* webpackIgnore: true */`comment, it is possible to disable sources handling for rules and for individual declarations.

```css
/* webpackIgnore: true*/
@import url(./basic.css);
@import /* webpackIgnore: true */ url(./imported.css);

/** webpackIgnore: true */
.class {
/* Disabled url handling for the all .class */
color: red;
background: url("./url/img.png");
}

.class {
/* Disabled url handling for the first url in 'background' declaration */
color: red;
background: /** webpackIgnore: true */ url("./url/img.png"),
url("./url/img.png");
}
.class {
/* Disabled url handling for the all urls in 'background' declaration */
color: red;
/** webpackIgnore: true */
background: url("./url/img.png"), url("./url/img.png");
}

/* prettier-ignore */
.class {
/* Disabled url handling for the 3 and 6 urls in 'background-image' declaration */
background-image: image-set(
url(./url/img.png) 2x,
url(./url/img.png) 3x,
/*webpackIgnore: true*/ url(./url/img.png) 4x,
url(./url/img.png) 5x,
url(./url/img.png) 6x,
/*webpackIgnore: true*/
url(./url/img.png) 7x
);
}
```

### Assets

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.
Expand Down
5 changes: 5 additions & 0 deletions src/plugins/postcss-import-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
resolveRequests,
isUrlRequestable,
requestify,
isWebpackIgnoreComment,
} from "../utils";

function visitor(result, parsedResults, node, key) {
Expand All @@ -13,6 +14,10 @@ function visitor(result, parsedResults, node, key) {
return;
}

if (isWebpackIgnoreComment(node)) {
return;
}

// Nodes do not exists - `@import url('http://') :root {}`
if (node.nodes) {
result.warn(
Expand Down
53 changes: 51 additions & 2 deletions src/plugins/postcss-url-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {
requestify,
resolveRequests,
isUrlRequestable,
isWebpackIgnoreComment,
webpackIgnoreCommentRegexp,
} from "../utils";

const isUrlFunc = /url/i;
Expand Down Expand Up @@ -35,13 +37,39 @@ function visitor(result, parsedResults, node, key) {
return;
}

const parsed = valueParser(node[key]);
if (isWebpackIgnoreComment(node)) {
return;
}

const parsed = valueParser(
typeof node.raws.value === "undefined" ? node[key] : node.raws.value.raw
);

let webpackIgnore =
typeof node.raws.between !== "undefined" &&
webpackIgnoreCommentRegexp.test(node.raws.between);

if (webpackIgnore && isImageSetFunc.test(parsed.nodes[0].value)) {
return;
}

parsed.walk((valueNode) => {
if (valueNode.type === "comment") {
if (webpackIgnoreCommentRegexp.test(valueNode.value)) {
webpackIgnore = true;
}
return;
}

if (valueNode.type !== "function") {
return;
}

if (webpackIgnore) {
webpackIgnore = false;
return;
}

if (isUrlFunc.test(valueNode.value)) {
const { nodes } = valueNode;
const isStringValue = nodes.length !== 0 && nodes[0].type === "string";
Expand All @@ -62,10 +90,26 @@ function visitor(result, parsedResults, node, key) {
// eslint-disable-next-line consistent-return
return false;
} else if (isImageSetFunc.test(valueNode.value)) {
let imageSetWebpackIgnore = false;

for (const nNode of valueNode.nodes) {
const { type, value } = nNode;

if (type === "comment") {
if (webpackIgnoreCommentRegexp.test(value)) {
imageSetWebpackIgnore = true;
}
// eslint-disable-next-line no-continue
continue;
}

if (type === "function" && isUrlFunc.test(value)) {
if (imageSetWebpackIgnore) {
imageSetWebpackIgnore = false;
// eslint-disable-next-line no-continue
continue;
}

const { nodes } = nNode;
const isStringValue =
nodes.length !== 0 && nodes[0].type === "string";
Expand All @@ -88,6 +132,12 @@ function visitor(result, parsedResults, node, key) {
});
}
} else if (type === "string") {
if (imageSetWebpackIgnore) {
imageSetWebpackIgnore = false;
// eslint-disable-next-line no-continue
continue;
}

const rule = {
node: nNode,
url: value,
Expand All @@ -104,7 +154,6 @@ function visitor(result, parsedResults, node, key) {
}
}
}

// Do not traverse inside `image-set`
// eslint-disable-next-line consistent-return
return false;
Expand Down
28 changes: 28 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const unescapeRegExp = new RegExp(
"ig"
);
const matchNativeWin32Path = /^[A-Z]:[/\\]|^\\\\/i;
const webpackIgnoreCommentRegexp = /webpackIgnore:(\s+)?true/i;

function unescape(str) {
return str.replace(unescapeRegExp, (_, escaped, escapedWhitespace) => {
Expand Down Expand Up @@ -702,6 +703,31 @@ function sort(a, b) {
return a.index - b.index;
}

function isWebpackIgnoreComment(node) {
if (webpackIgnoreCommentRegexp.test(`${node.raws.afterName}`)) {
return true;
}

const possibleCommentPlaces = [node.prev()];

if (node.type === "decl") {
possibleCommentPlaces.push(node.parent.prev());
}

for (const prevNode of possibleCommentPlaces.filter((i) => Boolean(i))) {
if (prevNode.type !== "comment") {
// eslint-disable-next-line no-continue
continue;
}

if (webpackIgnoreCommentRegexp.test(prevNode.text)) {
return true;
}
}

return false;
}

export {
normalizeOptions,
shouldUseModulesPlugins,
Expand All @@ -721,4 +747,6 @@ export {
resolveRequests,
isUrlRequestable,
sort,
isWebpackIgnoreComment,
webpackIgnoreCommentRegexp,
};
170 changes: 170 additions & 0 deletions test/__snapshots__/loader.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,176 @@ exports[`loader should work with the "modules.auto" option and the "importLoader
exports[`loader should work with the "modules.auto" option and the "importLoaders" option: warnings 1`] = `Array []`;
exports[`loader should work with webpackIgnore comment: errors 1`] = `Array []`;
exports[`loader should work with webpackIgnore comment: module 1`] = `
"// Imports
import ___CSS_LOADER_API_IMPORT___ from \\"../../src/runtime/api.js\\";
import ___CSS_LOADER_GET_URL_IMPORT___ from \\"../../src/runtime/getUrl.js\\";
import ___CSS_LOADER_URL_IMPORT_0___ from \\"./url/img.png\\";
import ___CSS_LOADER_URL_IMPORT_1___ from \\"./fonts/Roboto-Regular.woff2\\";
import ___CSS_LOADER_URL_IMPORT_2___ from \\"./fonts/Roboto-Regular.woff\\";
import ___CSS_LOADER_URL_IMPORT_3___ from \\"./fonts/Roboto-Regular.ttf\\";
import ___CSS_LOADER_URL_IMPORT_4___ from \\"./fonts/Roboto-Regular.svg\\";
import ___CSS_LOADER_URL_IMPORT_5___ from \\"./fonts/Roboto-Regular.eot\\";
var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(function(i){return i[1]});
var ___CSS_LOADER_URL_REPLACEMENT_0___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_0___);
var ___CSS_LOADER_URL_REPLACEMENT_1___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_1___);
var ___CSS_LOADER_URL_REPLACEMENT_2___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_2___);
var ___CSS_LOADER_URL_REPLACEMENT_3___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_3___);
var ___CSS_LOADER_URL_REPLACEMENT_4___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_4___, { hash: \\"#Roboto-Regular\\" });
var ___CSS_LOADER_URL_REPLACEMENT_5___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_5___);
var ___CSS_LOADER_URL_REPLACEMENT_6___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_5___, { hash: \\"#iefix\\" });
// Module
___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\\", \\"\\"]);
// Exports
export default ___CSS_LOADER_EXPORT___;
"
`;
exports[`loader should work with webpackIgnore comment: result 1`] = `
Array [
Array [
"./webpackIgnore.css",
"/*webpackIgnore: true*/
@import url(./basic.css);
@import /* webpackIgnore: true */ url(./imported.css);
/** webpackIgnore: true **/
@import url(./simple.css);
/** webpackIgnore: true */
.class {
color: red;
background: url(\\"./url/img.png\\");
}
.class {
color: red;
background: /** webpackIgnore: true */ url(\\"./url/img.png\\"), url(/webpack/public/path/img.png);
}
.class {
color: red;
/** webpackIgnore: true */
background: url(\\"./url/img.png\\"), url(\\"./url/img.png\\");
}
.class {
background:
url(/webpack/public/path/img.png),
url(/webpack/public/path/img.png),
/** webpackIgnore: true **/ url(\\"./url/img.png\\"),
url(/webpack/public/path/img.png),
/** webpackIgnore: true **/ url(\\"./url/img.png\\"),
url(/webpack/public/path/img.png),
url(/webpack/public/path/img.png),
url(/webpack/public/path/img.png),
/** webpackIgnore: true **/
url(\\"./url/img.png\\");
}
/** webpackIgnore: true **/
@font-face {
font-family: \\"Roboto\\";
src: url(\\"./fonts/Roboto-Regular.eot\\");
src:
url(\\"./fonts/Roboto-Regular.eot#iefix\\") format(\\"embedded-opentype\\"),
url(\\"./fonts/Roboto-Regular.woff2\\") format(\\"woff\\"),
url(\\"./fonts/Roboto-Regular.woff\\") format(\\"woff\\"),
url(\\"./fonts/Roboto-Regular.ttf\\") format(\\"truetype\\"),
url(\\"./fonts/Roboto-Regular.svg#Roboto-Regular\\") format(\\"svg\\");
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: \\"Roboto\\";
src: /** webpackIgnore: true **/ url(\\"./fonts/Roboto-Regular.eot\\");
src:
/** webpackIgnore: true **/
url(\\"./fonts/Roboto-Regular.eot#iefix\\") format(\\"embedded-opentype\\"),
url(/webpack/public/path/Roboto-Regular.woff2) format(\\"woff\\"),
url(/webpack/public/path/Roboto-Regular.woff) format(\\"woff\\"),
url(/webpack/public/path/Roboto-Regular.ttf) format(\\"truetype\\"),
url(/webpack/public/path/Roboto-Regular.svg#Roboto-Regular) format(\\"svg\\");
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: \\"Roboto\\";
src: /** webpackIgnore: true **/ url(\\"./fonts/Roboto-Regular.eot\\");
/** webpackIgnore: true **/
src:
url(\\"./fonts/Roboto-Regular.eot#iefix\\") format(\\"embedded-opentype\\"),
url(\\"./fonts/Roboto-Regular.woff2\\") format(\\"woff\\"),
url(\\"./fonts/Roboto-Regular.woff\\") format(\\"woff\\"),
url(\\"./fonts/Roboto-Regular.ttf\\") format(\\"truetype\\"),
url(\\"./fonts/Roboto-Regular.svg#Roboto-Regular\\") format(\\"svg\\");
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: \\"Roboto\\";
src: url(/webpack/public/path/Roboto-Regular.eot);
src:
url(/webpack/public/path/Roboto-Regular.eot#iefix) format(\\"embedded-opentype\\"),
/** webpackIgnore: true **/
url(\\"./fonts/Roboto-Regular.woff2\\") format(\\"woff\\"),
url(/webpack/public/path/Roboto-Regular.woff) format(\\"woff\\"),
/** webpackIgnore: true **/
url(\\"./fonts/Roboto-Regular.ttf\\") format(\\"truetype\\"),
url(/webpack/public/path/Roboto-Regular.svg#Roboto-Regular) format(\\"svg\\");
font-weight: 400;
font-style: normal;
}
/*webpackIgnore: true*/
.class {
background-image: image-set(
url(./url/img.png) 2x,
url(./url/img.png) 3x,
url(./url/img.png) 4x
);
}
.class {
/*webpackIgnore: true*/
background-image: image-set(
url(./url/img.png) 2x,
url(./url/img.png) 3x,
url(./url/img.png) 4x
);
}
.class {
background-image: /*webpackIgnore: true*/ image-set(
url(./url/img.png) 2x,
url(./url/img.png) 3x,
url(./url/img.png) 4x
);
}
.class {
background-image: image-set(
/*webpackIgnore: true*/
url(./url/img.png) 2x,
url(/webpack/public/path/img.png) 3x,
/*webpackIgnore: true*/
url(./url/img.png) 5x
);
}
",
"",
],
]
`;
exports[`loader should work with webpackIgnore comment: warnings 1`] = `Array []`;
exports[`loader should work: errors 1`] = `Array []`;
exports[`loader should work: module 1`] = `
Expand Down
40 changes: 20 additions & 20 deletions test/__snapshots__/url-option.test.js.snap

Large diffs are not rendered by default.

Loading

0 comments on commit e3f251b

Please sign in to comment.