Skip to content

Conversation

@layershifter
Copy link
Member

@layershifter layershifter commented Oct 3, 2022

Fixes #238. See the bug for the issue description in detail.

The main change is that we use tokenize from stylis instead of regexps. This is more robust and allows to parse multiple url() expressions.

@griffel/babel-preset and @griffel/webpack-extraction-plugin were updated/adjusted to handle this scenario.

@github-actions
Copy link

github-actions bot commented Oct 3, 2022

📊 Bundle size report

🤖 This report was generated against 28641c5bc7616ffe3ec327b0de67625bbd9c727c

@@ -0,0 +1,3 @@
export function isAssetUrl(value: string): boolean {
Copy link
Member Author

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) => {
Copy link
Member Author

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.

Comment on lines 36 to 61
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));
Copy link
Member Author

@layershifter layershifter Oct 3, 2022

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...

Copy link
Contributor

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 ??

Copy link
Member Author

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 url token 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.

Comment on lines -38 to -42
{
title: 'assets import handling',
fixture: path.resolve(fixturesDir, 'assets', 'code.ts'),
outputFixture: path.resolve(fixturesDir, 'assets', 'output.ts'),
},
Copy link
Member Author

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.

Comment on lines +124 to +152
const expressionPaths = literalPath.get('expressions');

expressionPaths.map(expressionPath => {
Copy link
Member Author

@layershifter layershifter Oct 3, 2022

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.

@layershifter layershifter marked this pull request as ready for review October 3, 2022 15:50
@layershifter layershifter requested a review from a team as a code owner October 3, 2022 15:50
function buildTemplateLiteralFromValue(value: string): t.TemplateLiteral {
const tokens = tokenize(value);

const quasis: t.TemplateElement[] = [];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what are quasis ?

Copy link
Member Author

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}:

image

https://babeljs.io/docs/en/babel-types#templateliteral

acc += tokens[i];

if (tokens[i] === 'url') {
const url = tokens[i + 1].slice(1, -1);
Copy link
Contributor

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 ?

Copy link
Contributor

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', '}')

Copy link
Contributor

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)"]

@layershifter layershifter force-pushed the fix/handle-multiple-urls branch from 7fa5811 to a3f91c9 Compare October 13, 2022 07:10
Copy link
Contributor

@ling1726 ling1726 left a 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

@layershifter layershifter merged commit 32d9b0b into microsoft:main Oct 13, 2022
@layershifter layershifter deleted the fix/handle-multiple-urls branch October 13, 2022 07:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

babel-preset: does not handle multiple url()

3 participants