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

Compress atomic class names #1408

Merged
merged 39 commits into from
Feb 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
e2abdb1
Update 'ax' to accept short class name
AtlassianRubberDuck Jan 24, 2023
ccbef95
Update 'ax' flow type and up the size limit
AtlassianRubberDuck Jan 25, 2023
b7b8602
Add benchmark test to test ax(compressed class names)
AtlassianRubberDuck Jan 31, 2023
1e2b969
Change the format of compress class names
AtlassianRubberDuck Feb 1, 2023
f9c1e77
Restore Flow type
AtlassianRubberDuck Feb 1, 2023
46fbdee
Compress class names
AtlassianRubberDuck Feb 6, 2023
a0760fb
Update snapshot
AtlassianRubberDuck Feb 6, 2023
709f42e
Merge branch 'master' into compress-atomic-class-names
AtlassianRubberDuck Feb 6, 2023
9e367ec
chore(deps): update dependency @types/node to ^18.11.19 (#1407)
renovate[bot] Feb 6, 2023
fa61820
Turn off compressing class names if stylesheet extraction is off
AtlassianRubberDuck Feb 8, 2023
52b4398
parcel integration
AtlassianRubberDuck Feb 8, 2023
f8201eb
Merge branch 'master' into compress-atomic-class-names
AtlassianRubberDuck Feb 8, 2023
4322536
Add changeset
AtlassianRubberDuck Feb 8, 2023
c629e8e
Replace rather than insert class name in the sheet and make ClassName…
AtlassianRubberDuck Feb 9, 2023
0f4c9a8
add 'generateCompressionMap'
AtlassianRubberDuck Feb 14, 2023
cb7db29
Update changelog
AtlassianRubberDuck Feb 14, 2023
447ff4a
Fix spelling mistake
AtlassianRubberDuck Feb 15, 2023
43e5b5d
Allow uppercase in class-name-generator
AtlassianRubberDuck Feb 15, 2023
c3a4ac2
chore(deps): update dependency css-what to >=5.1.0 (#1409)
renovate[bot] Feb 8, 2023
d405481
chore(deps): update webpack packages (#1411)
renovate[bot] Feb 8, 2023
9b94342
Fix transparent and currentcolor not being treated as a color (#1412)
JakeLane Feb 9, 2023
bf5bed3
chore(deps): update dependency css-what to >=6.1.0 (#1414)
renovate[bot] Feb 10, 2023
76e74f2
Version Packages (#1413)
atlas-dst-bot Feb 13, 2023
703ea6c
chore(deps): update dependency nth-check to >=2.1.1 (#1415)
renovate[bot] Feb 13, 2023
259be2d
chore(deps): update dependency prettier to ^2.8.4 (#1416)
renovate[bot] Feb 13, 2023
5c2bf12
chore(deps): update dependency @types/node to ^18.13.0 (#1417)
renovate[bot] Feb 13, 2023
097cff1
Bump node version to v18 (#1392)
JakeLane Feb 13, 2023
d905599
chore(deps): update parcel packages (#1390)
renovate[bot] Feb 13, 2023
bf5b751
chore(deps): update eslint packages (#1420)
renovate[bot] Feb 13, 2023
fd93618
chore(deps): update dependency jest to v29 (#1384)
renovate[bot] Feb 15, 2023
aad8d3a
Add Grant Wong as codeowner (#1421)
JakeLane Feb 15, 2023
5a26e15
Replace rather than insert class name in the sheet and make ClassName…
AtlassianRubberDuck Feb 9, 2023
956e2fc
Merge branch 'master' into compress-atomic-class-names
AtlassianRubberDuck Feb 15, 2023
9ef388d
Add prefix option and avoid 'ad'
AtlassianRubberDuck Feb 16, 2023
476102c
Add comment to ax benchmark
AtlassianRubberDuck Feb 16, 2023
f1a69e0
Make classNameCompressionMap a separate file in parcel example app
AtlassianRubberDuck Feb 16, 2023
c18666f
Remove default reservedClassNames
AtlassianRubberDuck Feb 16, 2023
f4b5e88
Export generateCompressionMap
AtlassianRubberDuck Feb 16, 2023
62aab19
Update comment
AtlassianRubberDuck Feb 16, 2023
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
10 changes: 10 additions & 0 deletions .changeset/grumpy-cows-look.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@compiled/parcel-transformer': minor
'@compiled/webpack-loader': minor
'@compiled/babel-plugin': minor
'@compiled/react': minor
'@compiled/css': minor
---

Add an option to compress class names based on "classNameCompressionMap", which is provided by library consumers.
Add a script to generate compressed class names.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module.exports = {
root: true,
ignorePatterns: [
'dist',
'build',
'flow-typed',
'*.d.ts',
'babel-cjs.js',
Expand Down
24 changes: 0 additions & 24 deletions examples/parcel/.compiledcssrc

This file was deleted.

18 changes: 18 additions & 0 deletions examples/parcel/class-name-compression-map.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"1wyb12am": "a",
"syaz5scu": "b",
"syazruxl": "c",
"k48pbfng": "d",
"30l35scu": "e",
"f8pj13q2": "f",
"1e0c1o8l": "g",
"ca0qftgi": "h",
"u5f3ftgi": "i",
"n3tdftgi": "j",
"19bvftgi": "k",
"19itak0l": "l",
"2rko1l7b": "m",
"syaz1aj3": "n",
"1p1dangw": "o",
"bfhkbf54": "p"
}
18 changes: 18 additions & 0 deletions examples/parcel/compiledcss.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const classNameCompressionMap = require('./class-name-compression-map.json');

module.exports = {
importReact: false,
extensions: ['.js', '.jsx', '.ts', '.tsx', '.customjsx'],
parserBabelPlugins: ['typescript', 'jsx'],
transformerBabelPlugins: [
[
'@babel/plugin-proposal-decorators',
{
legacy: true,
},
],
],
extract: true,
optimizeCss: false,
classNameCompressionMap: classNameCompressionMap,
};
27 changes: 27 additions & 0 deletions examples/webpack/class-name-compression-map.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"1wyb12am": "a",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Where/how does this map get generated?

Copy link
Collaborator Author

@liamqma liamqma Feb 8, 2023

Choose a reason for hiding this comment

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

Good question! For now it's assumed that library consumers manually curate the map and pass it to the babel-plugin. We will later create an automatic method to generate the map by statically analysing the codebase, and the map should be periodically updated by a build.

"syaz32ev": "b",
"k48pbfng": "c",
"30l35scu": "d",
"f8pj13q2": "e",
"19itptrx": "f",
"1kt92a4o": "g",
"171dak0l": "h",
"1swkri7e": "i",
"1tjq14ap": "j",
"yzbc5scu": "k",
"19pk1ul9": "l",
"syaz13q2": "m",
"1wyb1ul9": "n",
"19itlf8h": "o",
"ca0q1vi7": "p",
"u5f31vi7": "q",
"n3td1vi7": "r",
"19bv1vi7": "s",
"k48p1fw0": "t",
"syaz1cnh": "u",
"19it1srw": "v",
"bfhk1j28": "w",
"syazruxl": "x",
"bfhkbf54": "y"
}
3 changes: 3 additions & 0 deletions examples/webpack/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const webpack = require('webpack');

const classNameCompressionMap = require('./class-name-compression-map.json');

const extractCSS = process.env.EXTRACT_TO_CSS === 'true';

module.exports = {
Expand Down Expand Up @@ -40,6 +42,7 @@ module.exports = {
parserBabelPlugins: ['typescript', 'jsx'],
transformerBabelPlugins: [['@babel/plugin-proposal-decorators', { legacy: true }]],
optimizeCss: false,
classNameCompressionMap,
},
},
],
Expand Down
156 changes: 156 additions & 0 deletions packages/babel-plugin/src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,160 @@ describe('babel plugin', () => {

expect(actual).toInclude('c_MyDiv');
});

Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we still have cases where compression is not safe, hence we should bail out?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Compression should be safe everywhere now.

it('should compress class name for styled component', () => {
const actual = transform(
`
import { styled } from '@compiled/react';

const MyDiv = styled.div\`
font-size: 12px;
\`;
`,
{
classNameCompressionMap: {
'1wyb1fwx': 'a',
},
}
);

expect(actual).toIncludeMultiple(['.a{font-size:12px}', 'ax(["_1wyb_a", __cmplp.className])']);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does the extracted CSS also contain
._1wyb_a, .1wyb1fwx {font-size:12px}?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No, the extracted CSS looks like

.a {font-size:12px}

});

it('should compress class name for css props', () => {
const actual = transform(
`
import '@compiled/react';

<div css={{ fontSize: 12 }} />
`,
{
classNameCompressionMap: {
'1wyb1fwx': 'a',
},
}
);

expect(actual).toIncludeMultiple(['.a{font-size:12px}', 'ax(["_1wyb_a"])']);
});

it('should compress class name for ClassNames', () => {
const actual = transform(
`
import { ClassNames } from '@compiled/react';

<ClassNames>
{({ css }) => (
<div className={css({ fontSize: 12 })} />
)}
</ClassNames>
`,
{
classNameCompressionMap: {
'1wyb1fwx': 'a',
},
}
);

expect(actual).toIncludeMultiple(['.a{font-size:12px}', 'className={ax(["_1wyb_a"])']);
});

it('should compress class names with atrules', () => {
const actual = transform(
`
import '@compiled/react';
<div css={{ "@media (max-width: 1250px) ": { fontSize: 12 } }} />
`,
{
classNameCompressionMap: {
pz521fwx: 'a',
},
}
);

expect(actual).toIncludeMultiple([
'@media (max-width:1250px){.a{font-size:12px}}',
'ax(["_pz52_a"])',
]);
});

it('should compress pseudo classes', () => {
const actual = transform(
`
import '@compiled/react';
<div css={{ "&:hover": { fontSize: 12 }, "&:active": { color: 'red' } }} />
`,
{
classNameCompressionMap: {
'9h8h5scu': 'a',
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: inconsistent quotes?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

e9151fwx: 'b',
},
}
);

expect(actual).toIncludeMultiple([
'.a:active{color:red}',
'.b:hover{font-size:12px}',
'ax(["_e915_b _9h8h_a"])',
]);
});

it('should compress nested selector', () => {
const actual = transform(
`
import '@compiled/react';
<div css={{ '>div': { 'div div:hover': { fontSize: 12 } } }} />
`,
{
classNameCompressionMap: {
'1jkf1fwx': 'a',
},
}
);

expect(actual).toIncludeMultiple(['.a >div div div:hover{font-size:12px}', 'ax(["_1jkf_a"]']);
});

it('should compress conditional class names', () => {
const actual = transform(
`
import '@compiled/react';
<div css={[{ fontSize: ({ bar }) => bar ? 14 : 16 }, () => foo ? { fontSize: 12 } : {}, baz && { fontSize: 20 }]} />
`,
{
classNameCompressionMap: {
'1wyb19ub': 'a',
'1wyb1fwx': 'b',
},
}
);

expect(actual).toIncludeMultiple([
'.a{font-size:16}',
'.b{font-size:12px}',
'bar ? "_1wyb1o8a" : "_1wyb_a"',
'foo && "_1wyb_b"',
]);
});

it('should compress class names according to the map', () => {
const actual = transform(
`
import '@compiled/react';
<div css={{ fontSize: 12, color: 'red', marginTop: 10 }} />
`,
{
classNameCompressionMap: {
syaz5scu: 'a',
},
}
);

expect(actual).toIncludeMultiple([
'._19pk19bv{margin-top:10px}',
'.a{color:red}',
'._1wyb1fwx{font-size:12px}',
'ax(["_1wyb1fwx _syaz_a _19pk19bv"]',
]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ describe('jsx automatic', () => {
children: [_],
}),
_jsx("div", {
className: "_syaz13q2",
className: ax(["_syaz13q2"]),
}),
],
});
Expand Down
Loading