Description
🐞 Bug report
Command (mark with an x
)
- new
- build
- serve
- test
- e2e
- generate
- add
- update
- lint
- extract-i18n
- run
- config
- help
- version
- doc
Is this a regression?
Yes, the previous version in which this bug was not present was: @angular-devkit/build-angular 14.1.1Description
When loading a CSS file containing a url
that contains a closing parenthesis )
the regular expression fails to capture the full value in the url
. In addition if the value contains another url
expression (inside the svg markup) then the parser will try to resolve that url as well.
🔬 Minimal Reproduction
- Clone https://github.com/snocorp/angular-url-issue (Base angular app with mapbox-gl installed for CSS)
- Run
npm install
- Run
ng build
(orng build --verbose
to see a trace of the error)
🔥 Exception or Error
./node_modules/mapbox-gl/dist/mapbox-gl.css - Error: Module Error (from ./node_modules/postcss-loader/dist/cjs.js):
/Users/dave/dev/snocorp/angular-url-issue/url-issue/node_modules/mapbox-gl/dist/mapbox-gl.css:1:28378: Can't resolve '%23clip' in '/Users/dave/dev/snocorp/angular-url-issue/url-issue/node_modules/mapbox-gl/dist'
🌍 Your Environment
_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/
Angular CLI: 14.1.3
Node: 16.15.1
Package Manager: npm 6.14.15
OS: darwin arm64
Angular: 14.1.3
... animations, cli, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router
Package Version
---------------------------------------------------------
@angular-devkit/architect 0.1401.3
@angular-devkit/build-angular 14.1.3
@angular-devkit/core 14.1.3
@angular-devkit/schematics 14.1.3
@schematics/angular 14.1.3
rxjs 7.5.6
typescript 4.7.4
Anything else relevant?
This is a regression caused by #23691
The current regular expression is /url(?:\(\s*['"]?)(.*?)(?:['"]?\s*\))/g
which is problematic because it can find a closing parenthesis without finding a closing quote, since the closing quote is optional.
A regular expression that solves the problem and still fixes #23680 is something like /url(?:\(\s*(['"]?))(.*?)(?:\1\s*\))/
. This uses a back reference to ensure that the quotes are the same. This does mean there is an extra capturing group and so const originalUrl = match[1];
would need to be const originalUrl = match[2];
instead.
A small-ish test case:
background-image:url("data:image/svg+xml;charset=utf-8,<svg><mask id='clip'><rect x='0' y='0' width='100%' height='100%' fill='white'/></mask> <g> <circle mask='url(%23clip)' cx='11.5' cy='11.5' r='9.25'/> <use xlink:href='#text' mask='url(#clip)'/> </g></svg>")