Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: escape double quote of url value in CSS url() #7718

Merged
12 changes: 12 additions & 0 deletions packages/core/integration-tests/test/css.js
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,18 @@ describe('css', () => {
);
});

it('should handle quote in CSS URL correctly', async function () {
await bundle(path.join(__dirname, '/integration/css-url-quote/index.css'));

let css = await outputFS.readFile(path.join(distDir, 'index.css'), 'utf8');

assert(
css.includes(
'url("data:image/svg+xml;utf8,with quote \\" and escape \\\\");',
),
);
});

it('should ignore url() with IE behavior specifiers', async function () {
let b = await bundle(
path.join(__dirname, '/integration/css-url-behavior/index.css'),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.quotes {
background-image: url('data:image/svg+xml;utf8,with quote " and escape \\');
width: 100px;
height: 100px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
require('./index.css');

module.exports = function () {
return 2;
};
10 changes: 8 additions & 2 deletions packages/core/utils/src/replaceBundleReferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@ export function replaceURLReferences({
bundleGraph,
contents,
map,
getReplacement,
relative = true,
}: {|
bundle: NamedBundle,
bundleGraph: BundleGraph<NamedBundle>,
contents: string,
relative?: boolean,
map?: ?SourceMap,
getReplacement: string => string,
mischnic marked this conversation as resolved.
Show resolved Hide resolved
|}): {|+contents: string, +map: ?SourceMap|} {
let replacements = new Map();
let urlDependencies = [];
Expand All @@ -61,7 +63,7 @@ export function replaceURLReferences({
if (resolved == null) {
replacements.set(placeholder, {
from: placeholder,
to: dependency.specifier,
to: getReplacement(dependency.specifier),
});
continue;
}
Expand All @@ -79,6 +81,7 @@ export function replaceURLReferences({
fromBundle: bundle,
toBundle: resolved,
relative,
getReplacement,
}),
);
}
Expand Down Expand Up @@ -156,11 +159,13 @@ export function getURLReplacement({
fromBundle,
toBundle,
relative,
getReplacement,
}: {|
dependency: Dependency,
fromBundle: NamedBundle,
toBundle: NamedBundle,
relative: boolean,
getReplacement?: string => string,
|}): {|from: string, to: string|} {
let to;

Expand Down Expand Up @@ -191,9 +196,10 @@ export function getURLReplacement({

let placeholder = dependency.meta?.placeholder ?? dependency.id;
invariant(typeof placeholder === 'string');

return {
from: placeholder,
to,
to: getReplacement ? getReplacement(to) : to,
};
}

Expand Down
7 changes: 6 additions & 1 deletion packages/packagers/css/src/CSSPackager.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ export default (new Packager({
bundleGraph,
contents,
map,
getReplacement: escapeString,
}));

return replaceInlineReferences({
Expand All @@ -138,7 +139,7 @@ export default (new Packager({
getInlineBundleContents,
getInlineReplacement: (dep, inlineType, contents) => ({
from: getSpecifier(dep),
to: contents,
to: escapeString(contents),
}),
map,
});
Expand All @@ -153,6 +154,10 @@ export function getSpecifier(dep: Dependency): string {
return dep.id;
}

function escapeString(contents: string): string {
return contents.replace(/(["\\])/g, '\\$1');
}

async function processCSSModule(
options,
logger,
Expand Down
1 change: 1 addition & 0 deletions packages/packagers/html/src/HTMLPackager.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export default (new Packager({
bundleGraph,
contents: html,
relative: false,
getReplacement: contents => contents.replace(/"/g, '&quot;'),
});

return replaceInlineReferences({
Expand Down
1 change: 1 addition & 0 deletions packages/packagers/js/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export default (new Packager({
bundleGraph,
contents,
map,
getReplacement: s => JSON.stringify(s).slice(1, -1),
}));
}

Expand Down
1 change: 1 addition & 0 deletions packages/packagers/raw-url/src/RawUrlPackager.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export default (new Packager({
bundleGraph,
contents: await assets[0].getCode(),
relative: false,
getReplacement: s => s,
});
return {contents};
},
Expand Down
1 change: 1 addition & 0 deletions packages/packagers/svg/src/SVGPackager.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export default (new Packager({
bundleGraph,
contents: svg,
relative: false,
getReplacement: contents => contents.replace(/"/g, '&quot;'),
});

return replaceInlineReferences({
Expand Down
1 change: 1 addition & 0 deletions packages/packagers/xml/src/XMLPackager.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export default (new Packager({
bundleGraph,
contents: code,
relative: false,
getReplacement: contents => contents.replace(/"/g, '&quot;'),
});

return replaceInlineReferences({
Expand Down