Skip to content

Commit ddb0e93

Browse files
authored
Add deprecation warning for :global usage (#448)
1 parent 846cc4c commit ddb0e93

File tree

17 files changed

+792
-8
lines changed

17 files changed

+792
-8
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"next-yak": minor
3+
"yak-swc": minor
4+
"eslint-plugin-yak": minor
5+
---
6+
7+
Add deprecation warning for `:global()` selectors

.claude/settings.local.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(pnpm build:*)",
5+
"Bash(cd:*)",
6+
"Bash(cat:*)",
7+
"Bash(pnpm --filter next-yak build:*)",
8+
"Bash(git -C /Users/luca/personal/next-yak status examples/vite/dist --porcelain)",
9+
"Bash(git -C /Users/luca/personal/next-yak ls-files:*)",
10+
"Bash(cargo test:*)",
11+
"Bash(pnpm build:swc)",
12+
"Bash(pnpm --filter yak-swc build:*)",
13+
"Bash(pnpm install:*)",
14+
"Bash(pnpm --filter @example/storybook build-storybook:*)",
15+
"Bash(pnpm:*)",
16+
"Bash(ls:*)",
17+
"WebSearch",
18+
"mcp__fetch__fetch"
19+
]
20+
}
21+
}

CLAUDE.md

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance for Claude Code when working with the next-yak repository.
4+
5+
## Project Overview
6+
7+
next-yak is a CSS-in-JS solution for Next.js that combines styled-components syntax with build-time CSS extraction. It uses an SWC plugin (written in Rust) to transform TypeScript/JavaScript and extract CSS at compile time.
8+
9+
## Repository Structure
10+
11+
```
12+
next-yak/
13+
├── packages/
14+
│ ├── next-yak/ # Main TypeScript/JavaScript package
15+
│ ├── yak-swc/ # SWC plugin (Rust → WASM)
16+
│ │ ├── yak_swc/ # Core SWC plugin implementation
17+
│ │ ├── css_in_js_parser/ # CSS-in-JS parser library
18+
│ │ └── relative_posix_path/ # Path utility
19+
│ ├── eslint-plugin-yak/ # ESLint plugin
20+
│ └── example/ # Next.js example (symlinked to examples/next-js)
21+
├── examples/
22+
│ ├── next-js/ # Next.js example app
23+
│ └── vite/ # Vite example app
24+
├── docs/ # Documentation site (yak.js.org)
25+
├── cross-file-tests/ # Cross-file transformation tests
26+
└── benchmarks/ # Performance benchmarks
27+
```
28+
29+
## Common Commands
30+
31+
All commands use **pnpm** (v10.15.0+). Run from the repository root unless specified.
32+
33+
### Building
34+
35+
```bash
36+
# Build the main next-yak TypeScript package
37+
pnpm build
38+
39+
# Build the Rust SWC plugin (compiles to WASM)
40+
pnpm build:swc
41+
42+
# Build everything (required before first run)
43+
pnpm build && pnpm build:swc
44+
```
45+
46+
### Testing
47+
48+
```bash
49+
# Run all tests (builds first)
50+
pnpm test
51+
52+
# Run tests in watch mode
53+
pnpm test:watch
54+
55+
# Update test snapshots (both JS and Rust)
56+
pnpm test:snapshots
57+
```
58+
59+
### Running Examples
60+
61+
```bash
62+
# Run Next.js example (requires build first)
63+
pnpm example
64+
65+
# Run Vite example
66+
pnpm example:vite
67+
68+
# Run documentation site
69+
pnpm docs
70+
```
71+
72+
### Package-Specific Commands
73+
74+
```bash
75+
# Build only yak-swc WASM
76+
cd packages/yak-swc && pnpm build:yak
77+
78+
# Run Rust tests only
79+
cd packages/yak-swc && pnpm test
80+
81+
# Update Rust test snapshots
82+
cd packages/yak-swc && pnpm test:snapshots
83+
84+
# Format Rust code
85+
cd packages/yak-swc && pnpm prettier
86+
```
87+
88+
## Key Files
89+
90+
### TypeScript/JavaScript (packages/next-yak/)
91+
- `loaders/vite-plugin.ts` - Vite plugin implementation
92+
- `loaders/webpack-loader.ts` - Webpack loader
93+
- `loaders/turbo-loader.ts` - Turbopack loader
94+
- `withYak/index.ts` - Next.js config wrapper
95+
- `cross-file-resolver/` - Cross-file constant resolution
96+
97+
### Rust (packages/yak-swc/yak_swc/src/)
98+
- `lib.rs` - Main SWC plugin entry point and visitor
99+
- `plugin.rs` - WASM plugin wrapper
100+
- `naming_convention.rs` - CSS class/variable naming
101+
- `yak_transforms.rs` - Transformation implementations
102+
- `yak_imports.rs` - Import tracking
103+
- `variable_visitor.rs` - Variable/constant tracking
104+
105+
### Configuration
106+
- `pnpm-workspace.yaml` - Workspace configuration with version catalogs
107+
- `packages/yak-swc/Cargo.toml` - Rust dependencies
108+
109+
## Development Workflow
110+
111+
1. **After pulling changes**: Run `pnpm install` then `pnpm build && pnpm build:swc`
112+
113+
2. **When modifying Rust code**:
114+
- Run `cargo test` in `packages/yak-swc/yak_swc` for quick iteration
115+
- Run `pnpm build:swc` to rebuild the WASM plugin for integration testing
116+
- The WASM target is `wasm32-wasip1`
117+
118+
3. **When modifying TypeScript**:
119+
- Run `pnpm build` to rebuild
120+
- Use `pnpm watch` for automatic rebuilds
121+
122+
4. **Testing changes**:
123+
- Use the examples (`pnpm example` or `pnpm example:vite`) to verify
124+
- Run `pnpm test` for the full test suite
125+
126+
## SWC Fixture Tests
127+
128+
The SWC plugin uses fixture-based snapshot testing located in `packages/yak-swc/yak_swc/tests/fixture/`.
129+
130+
### How It Works
131+
132+
Tests are auto-generated from fixture directories using `#[testing::fixture("tests/fixture/**/input.tsx")]` macro in `lib.rs`. Each fixture directory contains:
133+
134+
```
135+
fixture/
136+
├── my-test-case/
137+
│ ├── input.tsx # Input file (required)
138+
│ ├── output.dev.tsx # Dev mode output (generated)
139+
│ ├── output.prod.tsx # Prod mode output (generated)
140+
│ ├── output.turbo.dev.tsx # Turbopack dev output (generated)
141+
│ └── output.turbo.prod.tsx # Turbopack prod output (generated)
142+
```
143+
144+
### Adding a New Test
145+
146+
1. Create a new directory: `mkdir tests/fixture/my-new-test`
147+
2. Create `input.tsx` with your test case
148+
3. Run `pnpm test:snapshots` to generate output files
149+
4. Review the generated outputs
150+
151+
### Running Tests
152+
153+
```bash
154+
# Run all Rust tests (from packages/yak-swc)
155+
cargo test
156+
157+
# Run specific fixture test
158+
cargo test my_test_name
159+
160+
# Update snapshots when output changes
161+
pnpm test:snapshots
162+
163+
# Or using cargo directly with UPDATE flag
164+
UPDATE=1 cargo test
165+
```
166+
167+
### Test Configurations
168+
169+
Each fixture generates 4 tests:
170+
- `fixture_dev` - Development mode with CSS modules
171+
- `fixture_prod` - Production mode with CSS modules
172+
- `fixture_dev_turbo` - Development mode with Turbopack (DataUrl)
173+
- `fixture_prod_turbo` - Production mode with Turbopack (DataUrl)
174+
175+
## Architecture Notes
176+
177+
### SWC Plugin Flow
178+
1. SWC passes AST to `TransformVisitor` in `lib.rs`
179+
2. Visitor identifies styled-components/CSS template literals
180+
3. CSS is extracted and transformed based on `CssDependencyMode`:
181+
- `InlineMatchResource` - Webpack inline resource syntax
182+
- `DataUrl` - Base64 encoded CSS (Turbopack)
183+
- `Custom` - Configurable import specifier (Vite)
184+
4. JavaScript is transformed to reference generated CSS classes
185+
186+
### Vite Plugin
187+
- Uses virtual modules (`virtual:yak-css:*`) for CSS
188+
- The `{{__MODULE_PATH__}}` placeholder in import specifiers is replaced by the Rust plugin with the actual file path
189+
- CSS is resolved and bundled by Vite's CSS pipeline
190+
191+
## Debugging
192+
193+
Enable debug logging in Next.js config:
194+
```js
195+
export default withYak({
196+
experiments: {
197+
debug: true, // or regex like 'component.tsx.css$'
198+
},
199+
});
200+
```
201+
202+
For Vite, debug logs are controlled the same way via plugin options.
203+
204+
## Prerequisites
205+
206+
- Node.js >= 22
207+
- pnpm >= 10.15.0
208+
- Rust toolchain (install from rust-lang.org, not brew)
209+
- WASM target: `rustup target add wasm32-wasip1`

docs/.source/index.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
// @ts-nocheck -- skip type checking
2-
import * as docs_10 from "../content/docs/why-next-yak.mdx?collection=docs"
3-
import * as docs_9 from "../content/docs/vite.mdx?collection=docs"
4-
import * as docs_8 from "../content/docs/roadmap.mdx?collection=docs"
2+
import * as docs_11 from "../content/docs/why-next-yak.mdx?collection=docs"
3+
import * as docs_10 from "../content/docs/vite.mdx?collection=docs"
4+
import * as docs_9 from "../content/docs/roadmap.mdx?collection=docs"
5+
import * as docs_8 from "../content/docs/migration-to-native-css.mdx?collection=docs"
56
import * as docs_7 from "../content/docs/migration-from-styled-components.mdx?collection=docs"
67
import * as docs_6 from "../content/docs/how-does-it-work.mdx?collection=docs"
78
import * as docs_5 from "../content/docs/getting-started.mdx?collection=docs"
@@ -12,4 +13,4 @@ import * as docs_1 from "../content/docs/eslint-plugin.mdx?collection=docs"
1213
import * as docs_0 from "../content/docs/comparison.mdx?collection=docs"
1314
import { _runtime } from "fumadocs-mdx/runtime/next"
1415
import * as _source from "../source.config"
15-
export const docs = _runtime.docs<typeof _source.docs>([{ info: {"path":"comparison.mdx","fullPath":"content/docs/comparison.mdx"}, data: docs_0 }, { info: {"path":"eslint-plugin.mdx","fullPath":"content/docs/eslint-plugin.mdx"}, data: docs_1 }, { info: {"path":"examples.mdx","fullPath":"content/docs/examples.mdx"}, data: docs_2 }, { info: {"path":"faq.mdx","fullPath":"content/docs/faq.mdx"}, data: docs_3 }, { info: {"path":"features.mdx","fullPath":"content/docs/features.mdx"}, data: docs_4 }, { info: {"path":"getting-started.mdx","fullPath":"content/docs/getting-started.mdx"}, data: docs_5 }, { info: {"path":"how-does-it-work.mdx","fullPath":"content/docs/how-does-it-work.mdx"}, data: docs_6 }, { info: {"path":"migration-from-styled-components.mdx","fullPath":"content/docs/migration-from-styled-components.mdx"}, data: docs_7 }, { info: {"path":"roadmap.mdx","fullPath":"content/docs/roadmap.mdx"}, data: docs_8 }, { info: {"path":"vite.mdx","fullPath":"content/docs/vite.mdx"}, data: docs_9 }, { info: {"path":"why-next-yak.mdx","fullPath":"content/docs/why-next-yak.mdx"}, data: docs_10 }], [{"info":{"path":"meta.json","fullPath":"content/docs/meta.json"},"data":{"title":"ui","pages":["---Guide---","index","getting-started","vite","migration-from-styled-components","eslint-plugin","faq","---Details---","why-next-yak","features","how-does-it-work","comparison","examples","roadmap","---Links---","[Next-Yak](https://github.com/DigitecGalaxus/next-yak)"],"root":true}}])
16+
export const docs = _runtime.docs<typeof _source.docs>([{ info: {"path":"comparison.mdx","fullPath":"content/docs/comparison.mdx"}, data: docs_0 }, { info: {"path":"eslint-plugin.mdx","fullPath":"content/docs/eslint-plugin.mdx"}, data: docs_1 }, { info: {"path":"examples.mdx","fullPath":"content/docs/examples.mdx"}, data: docs_2 }, { info: {"path":"faq.mdx","fullPath":"content/docs/faq.mdx"}, data: docs_3 }, { info: {"path":"features.mdx","fullPath":"content/docs/features.mdx"}, data: docs_4 }, { info: {"path":"getting-started.mdx","fullPath":"content/docs/getting-started.mdx"}, data: docs_5 }, { info: {"path":"how-does-it-work.mdx","fullPath":"content/docs/how-does-it-work.mdx"}, data: docs_6 }, { info: {"path":"migration-from-styled-components.mdx","fullPath":"content/docs/migration-from-styled-components.mdx"}, data: docs_7 }, { info: {"path":"migration-to-native-css.mdx","fullPath":"content/docs/migration-to-native-css.mdx"}, data: docs_8 }, { info: {"path":"roadmap.mdx","fullPath":"content/docs/roadmap.mdx"}, data: docs_9 }, { info: {"path":"vite.mdx","fullPath":"content/docs/vite.mdx"}, data: docs_10 }, { info: {"path":"why-next-yak.mdx","fullPath":"content/docs/why-next-yak.mdx"}, data: docs_11 }], [{"info":{"path":"meta.json","fullPath":"content/docs/meta.json"},"data":{"title":"ui","pages":["---Guide---","index","getting-started","vite","migration-from-styled-components","migration-to-native-css","eslint-plugin","faq","---Details---","why-next-yak","features","how-does-it-work","comparison","examples","roadmap","---Links---","[Next-Yak](https://github.com/DigitecGalaxus/next-yak)"],"root":true}}])

docs/content/docs/meta.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"getting-started",
88
"vite",
99
"migration-from-styled-components",
10+
"migration-to-native-css",
1011
"eslint-plugin",
1112
"faq",
1213
"---Details---",

docs/content/docs/migration-from-styled-components.mdx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ export const mixin = css<{ $primary: boolean }>` // [!code --]
348348
349349
### Reference external styles
350350
351+
351352
If you reference external styles (styles that aren't component styles) in your styled components, you need to change the identifier in addition to the import.
352353
353354
```tsx title="component.tsx"
@@ -366,6 +367,11 @@ const Button = styled.button`
366367
`;
367368
```
368369
370+
371+
<Callout type="warn">
372+
**Deprecation Notice**: The `:global()` selector syntax is deprecated. Please migrate to native CSS transpilation mode to ensure compatibility with future versions. For more informations read <a href="/docs/migration-to-native-css">Migration to native CSS</a>
373+
</Callout>
374+
369375
The reason for this is that next-yak transforms your styles to module-css styles. And if you want to reference global selectors, you need to use the `:global` selector.
370376
More can be found in the [docs of css-modules](https://github.com/css-modules/css-modules/blob/master/docs/composition.md#exceptions)
371377

0 commit comments

Comments
 (0)