Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "fix: handle multiple url()",
"packageName": "@griffel/babel-preset",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "fix: handle multiple url()",
"packageName": "@griffel/webpack-extraction-plugin",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { makeStyles } from '@griffel/react';

import blank from './blank.jpg';
import empty from './empty.jpg';

export const useStyles = makeStyles({
root: { backgroundImage: `url(${blank}), url(${empty})` },
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import _asset2 from './empty.jpg';
import _asset from './blank.jpg';
import { __styles } from '@griffel/react';
import blank from './blank.jpg';
import empty from './empty.jpg';
export const useStyles = __styles(
{
root: {
Bcmaq0h: 'fp00rh9',
},
},
{
d: [`.fp00rh9{background-image:url(${_asset}),url(${_asset2});}`],
},
);
5 changes: 5 additions & 0 deletions packages/babel-preset/__fixtures__/assets-urls/code.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { makeStyles } from '@griffel/react';

export const useStyles = makeStyles({
data: { backgroundImage: 'url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2Q==)' },
});
11 changes: 11 additions & 0 deletions packages/babel-preset/__fixtures__/assets-urls/output.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { __styles } from '@griffel/react';
export const useStyles = __styles(
{
data: {
Bcmaq0h: 'fclgv40',
},
},
{
d: [`.fclgv40{background-image:url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2Q==);}`],
},
);
1 change: 1 addition & 0 deletions packages/babel-preset/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@linaria/babel-preset": "^3.0.0-beta.23",
"@linaria/shaker": "^3.0.0-beta.22",
"ajv": "^8.4.0",
"stylis": "^4.0.13",
"tslib": "^2.1.0"
},
"peerDependencies": {
Expand Down
3 changes: 3 additions & 0 deletions packages/babel-preset/src/assets/isAssetUrl.ts
Original file line number Diff line number Diff line change
@@ -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.

return !value.startsWith('data:');
}
29 changes: 29 additions & 0 deletions packages/babel-preset/src/assets/normalizeStyleRules.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,33 @@ describe('normalizeStyleRules', () => {
},
});
});

it('handles multiple URLs', () => {
expect(
normalizeStyleRules(
path.posix,
'/home/projects/foo',
'/home/projects/foo/src/styles/Component.styles.ts',

{
root: {
// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Backgrounds_and_Borders/Using_multiple_backgrounds
backgroundImage: [
'url(../../assets/firefox.png),',
'url(../../assets/bubbles.png),',
'linear-gradient(to right, rgba(30, 75, 115, 1), rgba(255, 255, 255, 0))',
].join(' '),
},
},
),
).toEqual({
root: {
backgroundImage: [
'url(assets/firefox.png),',
'url(assets/bubbles.png),',
'linear-gradient(to right, rgba(30, 75, 115, 1), rgba(255, 255, 255, 0))',
].join(' '),
},
});
});
});
23 changes: 14 additions & 9 deletions packages/babel-preset/src/assets/normalizeStyleRules.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { GriffelStyle } from '@griffel/core';
import { parseStringWithUrl } from './parseStringWithUrl';
import { tokenize } from 'stylis';

import { isAssetUrl } from './isAssetUrl';

/**
* Linaria v3 emits relative paths for assets, we normalize these paths to be relative from the project root to be the
Expand All @@ -22,16 +24,19 @@ export function normalizeStyleRule(
return ruleValue;
}

const result = parseStringWithUrl(ruleValue);
// 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.

if (token === 'url') {
// Quotes in URL are optional, so we can also normalize them
// https://www.w3.org/TR/CSS2/syndata.html#value-def-uri
const url = array[index + 1].replace(/['|"](.+)['|"]/, '$1').slice(1, -1);

if (url.startsWith('data:')) {
return `${result.prefix}${url}${result.suffix}`;
}
if (isAssetUrl(url)) {
array[index + 1] = `(${normalizeAssetPath(path, projectRoot, filename, url)})`;
}
}

return `${result.prefix}${normalizeAssetPath(path, projectRoot, filename, url)}${result.suffix}`;
return result + token;
}, '');
}

export function normalizeStyleRules(
Expand Down
15 changes: 0 additions & 15 deletions packages/babel-preset/src/assets/parseStringWithUrl.ts

This file was deleted.

42 changes: 32 additions & 10 deletions packages/babel-preset/src/assets/replaceAssetsWithImports.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { NodePath, traverse, types as t } from '@babel/core';
import * as path from 'path';
import { tokenize } from 'stylis';

import { absolutePathToRelative } from './absolutePathToRelative';
import { parseStringWithUrl } from './parseStringWithUrl';
import { isAssetUrl } from './isAssetUrl';

/**
* Replaces assets used in styles with imports and template literals.
Expand All @@ -29,6 +30,35 @@ export function replaceAssetsWithImports(
return assetIdentifiers.get(assetPath) as t.Identifier;
}

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

const expressions: t.Identifier[] = [];

let acc = '';

for (let i = 0, l = tokens.length; 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++;
}
}
}

quasis.push(t.templateElement({ raw: acc }, true));

return t.templateLiteral(quasis, expressions);
}

traverse(
pathToUpdate.node,
{
Expand All @@ -39,15 +69,7 @@ export function replaceAssetsWithImports(
return;
}

const result = parseStringWithUrl(value);
const assetIdentifier = getAssetIdentifier(result.url);

const templateLiteral = t.templateLiteral(
[t.templateElement({ raw: result.prefix }, false), t.templateElement({ raw: result.suffix }, true)],
[assetIdentifier],
);

literalPath.replaceWith(templateLiteral);
literalPath.replaceWith(buildTemplateLiteralFromValue(value));
},
},
programPath.scope,
Expand Down
24 changes: 19 additions & 5 deletions packages/babel-preset/src/transformPlugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,6 @@ pluginTester({
// Fixtures
//
//
{
title: 'assets import handling',
fixture: path.resolve(fixturesDir, 'assets', 'code.ts'),
outputFixture: path.resolve(fixturesDir, 'assets', 'output.ts'),
},
Comment on lines -38 to -42
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.

{
title: 'duplicated imports',
fixture: path.resolve(fixturesDir, 'duplicated-imports', 'code.ts'),
Expand All @@ -59,6 +54,25 @@ pluginTester({
outputFixture: path.resolve(fixturesDir, 'non-existing-module-call', 'output.ts'),
},

// Assets
//
//
{
title: 'assets: import handling',
fixture: path.resolve(fixturesDir, 'assets', 'code.ts'),
outputFixture: path.resolve(fixturesDir, 'assets', 'output.ts'),
},
{
title: 'assets: multiple url()',
fixture: path.resolve(fixturesDir, 'assets-multiple-declarations', 'code.ts'),
outputFixture: path.resolve(fixturesDir, 'assets-multiple-declarations', 'output.ts'),
},
{
title: 'assets: url() without imports',
fixture: path.resolve(fixturesDir, 'assets-urls', 'code.ts'),
outputFixture: path.resolve(fixturesDir, 'assets-urls', 'output.ts'),
},

// Evaluation
//
//
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { __styles } from '@griffel/react';
import _asset from './blank.jpg';
import _asset2 from './empty.jpg';

export const useStyles = __styles(
{
root: {
Bcmaq0h: 'fp00rh9',
},
},
{
d: [`.fp00rh9{background-image:url(${_asset}),url(${_asset2});}`],
},
);
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
["blank.jpg", "bundle.js", "empty.jpg", "griffel.css"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.fp00rh9 {
background-image: url(blank.jpg), url(empty.jpg);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { __styles, __css } from '@griffel/react';
export const useStyles = __css({
root: {
Bcmaq0h: 'fp00rh9',
},
});

import 'griffel.css!=!../../../virtual-loader/index.js!../../../virtual-loader/griffel.css?style=.fp00rh9%7Bbackground-image%3Aurl(..%2F__fixtures__%2Fwebpack%2Fassets-multiple%2Fblank.jpg)%2Curl(..%2F__fixtures__%2Fwebpack%2Fassets-multiple%2Fempty.jpg)%3B%7D';
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ describe('webpackLoader', () => {

// Assets
testFixture('assets');
testFixture('assets-multiple');
testFixture('reset-assets');

// Custom filenames in mini-css-extract-plugin
Expand Down
Loading