Skip to content

Commit 5461836

Browse files
authored
feat(emotion): add emotion plugin (#15)
* feat(internal/oxc-unshadowed-visitor): add `oxc-unshadowed-visitor` internal package * feat(emotion): add emotion plugin * test(emotion): add e2e example * chore(emotion): add benchmark * chore: add swc output generation script
1 parent f7e031b commit 5461836

192 files changed

Lines changed: 6547 additions & 36 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# keep LF as-is even on Windows for consistent hash values across platforms
2+
* text=auto eol=lf

.github/workflows/ci.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ jobs:
4848
- name: Install deps
4949
run: pnpm install
5050

51+
- name: Install playwright
52+
run: pnpm --filter examples exec playwright install chromium --with-deps
53+
5154
- name: Build
5255
run: pnpm run build
5356

@@ -77,6 +80,9 @@ jobs:
7780
- name: Install deps
7881
run: pnpm install --no-frozen-lockfile
7982

83+
- name: Install playwright
84+
run: pnpm --filter examples exec playwright install chromium --with-deps
85+
8086
- name: Install @babel/core v7 types
8187
run: pnpm add -Dw @types/babel__core@^7.20.5
8288

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,8 @@ dist
142142
vite.config.js.timestamp-*
143143
vite.config.ts.timestamp-*
144144
.vite/
145+
146+
.swc
147+
148+
/examples-temp-*
149+
output.swc.*

.oxfmtrc.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,10 @@
22
"$schema": "./node_modules/oxfmt/configuration_schema.json",
33
"semi": false,
44
"singleQuote": true,
5-
"ignorePatterns": ["**/dist/**", "packages/*/CHANGELOG.md"]
5+
"ignorePatterns": [
6+
"**/dist/**",
7+
"packages/*/CHANGELOG.md",
8+
"**/fixtures/**",
9+
"**/fixtures-labels/**"
10+
]
611
}

.oxlintrc.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,8 @@
44
"correctness": "error",
55
"suspicious": "error"
66
},
7-
"ignorePatterns": ["**/dist/**"]
7+
"rules": {
8+
"no-shadow": "off"
9+
},
10+
"ignorePatterns": ["**/dist/**", "**/fixtures/**", "**/fixtures-labels/**", "**/benchmark/**"]
811
}

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,13 @@ Official Rolldown plugins
2020
## Packages
2121

2222
- [`@rolldown/plugin-babel`](https://github.com/rolldown/plugins/tree/main/packages/babel) ([![NPM version][badge-npm-version-babel]][url-npm-babel]): transform code with Babel
23+
- [`@rolldown/plugin-emotion`](https://github.com/rolldown/plugins/tree/main/packages/emotion) ([![NPM version][badge-npm-version-emotion]][url-npm-emotion]): minification and optimization of Emotion styles
2324

2425
## License
2526

2627
[MIT](https://github.com/rolldown/plugins/blob/main/LICENSE)
2728

2829
[badge-npm-version-babel]: https://img.shields.io/npm/v/@rolldown/plugin-babel/latest?color=brightgreen
30+
[badge-npm-version-emotion]: https://img.shields.io/npm/v/@rolldown/plugin-emotion/latest?color=brightgreen
2931
[url-npm-babel]: https://npmx.dev/package/@rolldown/plugin-babel/v/latest
32+
[url-npm-emotion]: https://npmx.dev/package/@rolldown/plugin-emotion/v/latest

examples/emotion/emotion.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { expect, test } from 'vitest'
2+
import { editFile, getBg, getColor, isServe, page } from '~utils'
3+
4+
test('should render app', async () => {
5+
expect(await page.textContent('.emotion-title')).toBe('Emotion Works!')
6+
})
7+
8+
test('styled component should apply styles', async () => {
9+
const title = page.locator('.emotion-title')
10+
const color = await getColor(title)
11+
expect(color).toBe('rgb(255, 105, 180)') // hotpink
12+
})
13+
14+
test('css prop should work', async () => {
15+
const button = page.locator('.emotion-button')
16+
const bgColor = await getBg(button)
17+
expect(bgColor).toBe('rgb(100, 108, 255)') // #646cff
18+
})
19+
20+
test.runIf(isServe)('hmr works', async () => {
21+
editFile('src/App.tsx', (code) => code.replace('hotpink', 'blue'))
22+
await expect
23+
.poll(async () => {
24+
const title = page.locator('.emotion-title')
25+
return getColor(title)
26+
})
27+
.toBe('rgb(0, 0, 255)') // blue
28+
})

examples/emotion/index.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Emotion Example</title>
7+
</head>
8+
<body>
9+
<div id="root"></div>
10+
<script type="module" src="/src/main.tsx"></script>
11+
</body>
12+
</html>

examples/emotion/package.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "@rolldown/example-emotion",
3+
"private": true,
4+
"type": "module",
5+
"scripts": {
6+
"dev": "vite",
7+
"build": "vite build",
8+
"preview": "vite preview"
9+
},
10+
"dependencies": {
11+
"@emotion/react": "^11.14.0",
12+
"@emotion/styled": "^11.14.1",
13+
"react": "^19.2.4",
14+
"react-dom": "^19.2.4"
15+
},
16+
"devDependencies": {
17+
"@rolldown/plugin-emotion": "workspace:*",
18+
"@types/react": "^19.2.14",
19+
"@types/react-dom": "^19.2.3",
20+
"@vitejs/plugin-react": "^6.0.1",
21+
"vite": "8.0.0"
22+
}
23+
}

examples/emotion/src/App.tsx

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/** @jsxImportSource @emotion/react */
2+
import { css } from '@emotion/react'
3+
import styled from '@emotion/styled'
4+
5+
const Title = styled.h1`
6+
color: hotpink;
7+
font-size: 2rem;
8+
`
9+
10+
const buttonStyle = css`
11+
padding: 0.5rem 1rem;
12+
background-color: #646cff;
13+
color: white;
14+
border: none;
15+
border-radius: 4px;
16+
cursor: pointer;
17+
18+
&:hover {
19+
background-color: #535bf2;
20+
}
21+
`
22+
23+
const Card = styled.div`
24+
padding: 2rem;
25+
border: 1px solid #ccc;
26+
border-radius: 8px;
27+
margin: 1rem;
28+
`
29+
30+
export default function App() {
31+
return (
32+
<div className="emotion-app">
33+
<Title className="emotion-title">Emotion Works!</Title>
34+
<Card className="emotion-card">
35+
<p className="emotion-text">This is a styled card component.</p>
36+
<button css={buttonStyle} className="emotion-button">
37+
Styled Button
38+
</button>
39+
</Card>
40+
</div>
41+
)
42+
}

0 commit comments

Comments
 (0)