-
Notifications
You must be signed in to change notification settings - Fork 65
fix: handle multiple url() #237
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: handle multiple url() #237
Conversation
📊 Bundle size report🤖 This report was generated against 28641c5bc7616ffe3ec327b0de67625bbd9c727c |
2d0b301 to
7fa5811
Compare
| @@ -0,0 +1,3 @@ | |||
| export function isAssetUrl(value: string): boolean { | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I intentionally didn't cover this by tests directly as it will be changed/removed in #234.
| // Quotes in URL are optional, so we can also normalize them | ||
| // https://www.w3.org/TR/CSS2/syndata.html#value-def-uri | ||
| const url = result.url.replace(/['|"](.+)['|"]/, '$1'); | ||
| return tokenize(ruleValue).reduce((result, token, index, array) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of a regex I am using tokenize() from stylis so we can parse all url() entries properly.
| const quasis: t.TemplateElement[] = []; | ||
| const expressions: t.Identifier[] = []; | ||
|
|
||
| let acc = ''; | ||
|
|
||
| for (let i = 0, l = tokens.length; i < l; i++) { | ||
| for (; i < l; i++) { | ||
| acc += tokens[i]; | ||
|
|
||
| if (tokens[i] === 'url') { | ||
| const url = tokens[i + 1].slice(1, -1); | ||
|
|
||
| if (isAssetUrl(url)) { | ||
| quasis.push(t.templateElement({ raw: acc + '(' }, false)); | ||
| expressions.push(getAssetIdentifier(url)); | ||
|
|
||
| acc = ')'; | ||
| i++; | ||
|
|
||
| break; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| quasis.push(t.templateElement({ raw: acc }, true)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not the loop that makes me proud, but it works ¯_(ツ)_/¯ (opened for suggestions).
Based on tokens ('.foo', '{', 'url', '(image.png)', '}') we need to create:
- N
TemplateElements (t.templateElement({ raw: '.foo{url(' }, false),t.templateElement({ raw: ')}' }, true)) - N-1 expressions (
t.identifier('image.png'))
N & N-1 are a requirement as it's how Babel manages template literals...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't think of much better....
but I don't quite understand why you need the second nested loop, once you find the url token you break out of the inner loop and the outer one continues where the inner one left off anyway ??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but I don't quite understand why you need the second nested loop, once you find the
urltoken you break out of the inner loop and the outer one continues where the inner one left off anyway ??
Good catch, it's a leftover from the previous attempt. Removed.
| { | ||
| title: 'assets import handling', | ||
| fixture: path.resolve(fixturesDir, 'assets', 'code.ts'), | ||
| outputFixture: path.resolve(fixturesDir, 'assets', 'output.ts'), | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved into a separate group.
| const expressionPaths = literalPath.get('expressions'); | ||
|
|
||
| expressionPaths.map(expressionPath => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The inner part is 100% percent the same: now we parse all expressions instead of only first.
| function buildTemplateLiteralFromValue(value: string): t.TemplateLiteral { | ||
| const tokens = tokenize(value); | ||
|
|
||
| const quasis: t.TemplateElement[] = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what are quasis ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's how Babel names string in template literals i.e. foo from foo${bar}:
| acc += tokens[i]; | ||
|
|
||
| if (tokens[i] === 'url') { | ||
| const url = tokens[i + 1].slice(1, -1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why ignore the first and last characters of a url ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going by your example of tokens: ('.foo', '{', 'url', 'image.png', '}')
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first and last characters are parens. url(image.png) tokenizes to ["url", "(image.png)"]
7fa5811 to
a3f91c9
Compare
ling1726
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have doubts about the ugly nested loop in the preset, but otherwise LGTM

Fixes #238. See the bug for the issue description in detail.
The main change is that we use
tokenizefromstylisinstead of regexps. This is more robust and allows to parse multipleurl()expressions.@griffel/babel-presetand@griffel/webpack-extraction-pluginwere updated/adjusted to handle this scenario.