next-style 2.0.4 → 2.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +260 -188
- package/package.json +6 -15
package/README.md
CHANGED
|
@@ -1,323 +1,395 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
1
3
|
# Next Style
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
**Zero-runtime CSS-in-JS for Next.js**
|
|
6
|
+
|
|
7
|
+
Write styles in TypeScript. Ship pure CSS. Zero overhead.
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/next-style)
|
|
10
|
+
[](https://opensource.org/licenses/MIT)
|
|
11
|
+
[](https://turbo.build/pack)
|
|
12
|
+
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
**next-style** extracts all styles at build time through a PostCSS plugin — no style injection, no hydration cost, no runtime. The compiled CSS lands in your `globals.css` exactly once.
|
|
4
18
|
|
|
5
|
-
|
|
19
|
+
```tsx
|
|
20
|
+
import { css } from "next-style"
|
|
21
|
+
|
|
22
|
+
const button = css({
|
|
23
|
+
padding: "8px 16px",
|
|
24
|
+
borderRadius: "6px",
|
|
25
|
+
backgroundColor: "#7F77DD",
|
|
26
|
+
":hover": { backgroundColor: "#534AB7" },
|
|
27
|
+
"@md": { padding: "10px 20px" },
|
|
28
|
+
})
|
|
6
29
|
|
|
7
|
-
|
|
30
|
+
export function Button() {
|
|
31
|
+
return <button className={button}>Click me</button>
|
|
32
|
+
}
|
|
33
|
+
```
|
|
8
34
|
|
|
9
|
-
##
|
|
35
|
+
## Features
|
|
10
36
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
37
|
+
| | |
|
|
38
|
+
|---|---|
|
|
39
|
+
| ⚡ **Zero runtime** | All styles extracted at build time — 0 bytes of style JS shipped |
|
|
40
|
+
| 🔷 **Turbopack ready** | Works out of the box with Next.js 15+ and Turbopack |
|
|
41
|
+
| 🔒 **Fully typed** | Every CSS property and value typed via [csstype](https://github.com/frenic/csstype) |
|
|
42
|
+
| 📱 **Responsive first** | Shorthand breakpoints (`@sm` → `@2xl`) sorted mobile-first automatically |
|
|
43
|
+
| ♻️ **Deduplication** | Identical style objects always hash to the same class name |
|
|
44
|
+
| 🌍 **Global styles** | `global()` for resets, base typography, and third-party overrides |
|
|
45
|
+
| 🎞️ **Keyframes** | Declare `@keyframes` inline next to the style that uses them |
|
|
46
|
+
| 📦 **Tiny** | ~2 KB minified + gzipped |
|
|
17
47
|
|
|
18
|
-
|
|
48
|
+
Full support for pseudo-classes, pseudo-elements, media queries, container queries, `@supports`, `@layer`, and CSS variables.
|
|
19
49
|
|
|
20
|
-
|
|
50
|
+
## Installation
|
|
21
51
|
|
|
22
52
|
```bash
|
|
53
|
+
# npm
|
|
54
|
+
npm install next-style
|
|
55
|
+
|
|
56
|
+
# pnpm
|
|
57
|
+
pnpm add next-style
|
|
58
|
+
|
|
59
|
+
# bun
|
|
23
60
|
bun add next-style
|
|
24
61
|
```
|
|
25
62
|
|
|
26
|
-
|
|
63
|
+
> **Peer dependency:** `postcss >= 8.0.0` is required. Most Next.js projects already include it.
|
|
27
64
|
|
|
28
|
-
|
|
65
|
+
## Setup
|
|
66
|
+
|
|
67
|
+
### 1. Configure PostCSS
|
|
29
68
|
|
|
30
69
|
Create `postcss.config.js` in your project root:
|
|
31
70
|
|
|
32
71
|
```js
|
|
72
|
+
// postcss.config.js
|
|
33
73
|
export default {
|
|
34
74
|
plugins: {
|
|
35
|
-
"next-style/plugin": {}
|
|
36
|
-
}
|
|
75
|
+
"next-style/plugin": {},
|
|
76
|
+
},
|
|
37
77
|
}
|
|
38
78
|
```
|
|
39
79
|
|
|
40
|
-
|
|
80
|
+
<details>
|
|
81
|
+
<summary>Using with Autoprefixer</summary>
|
|
82
|
+
|
|
83
|
+
Install autoprefixer and add it **after** next-style:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npm install -D autoprefixer
|
|
87
|
+
```
|
|
41
88
|
|
|
42
89
|
```js
|
|
90
|
+
// postcss.config.js
|
|
43
91
|
export default {
|
|
44
92
|
plugins: {
|
|
45
93
|
"next-style/plugin": {},
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
94
|
+
autoprefixer: {},
|
|
95
|
+
},
|
|
49
96
|
}
|
|
50
97
|
```
|
|
51
98
|
|
|
52
|
-
> **Order matters** — next-style must
|
|
99
|
+
> **Order matters** — `next-style/plugin` must be listed before other plugins.
|
|
100
|
+
|
|
101
|
+
</details>
|
|
53
102
|
|
|
54
|
-
|
|
103
|
+
### 2. Add the import to `globals.css`
|
|
55
104
|
|
|
56
105
|
```css
|
|
106
|
+
/* app/globals.css */
|
|
57
107
|
@import "next-style";
|
|
58
|
-
/* your other imports/rules */
|
|
59
108
|
```
|
|
60
109
|
|
|
61
|
-
The PostCSS plugin replaces this
|
|
110
|
+
The PostCSS plugin replaces this import with all compiled styles at build time. Add it before any other rules.
|
|
62
111
|
|
|
63
|
-
|
|
112
|
+
### 3. Use in your components
|
|
64
113
|
|
|
65
114
|
```tsx
|
|
115
|
+
// app/page.tsx
|
|
66
116
|
import { css } from "next-style"
|
|
67
117
|
|
|
68
118
|
const title = css({
|
|
69
119
|
fontSize: "32px",
|
|
70
|
-
fontWeight:
|
|
120
|
+
fontWeight: 600,
|
|
71
121
|
"@md": { fontSize: "40px" },
|
|
72
|
-
":hover": { color: "#7F77DD" }
|
|
122
|
+
":hover": { color: "#7F77DD" },
|
|
73
123
|
})
|
|
74
124
|
|
|
75
|
-
export default function
|
|
125
|
+
export default function Page() {
|
|
76
126
|
return <h1 className={title}>Hello World</h1>
|
|
77
127
|
}
|
|
78
128
|
```
|
|
79
129
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
| Feature | Status | Details |
|
|
83
|
-
|---------|--------|---------|
|
|
84
|
-
| Zero Runtime | ✅ | Styles extracted at build time |
|
|
85
|
-
| Turbopack | ✅ | Native support for Next.js 15+ |
|
|
86
|
-
| Type Safety | ✅ | Powered by csstype — full property + value autocomplete |
|
|
87
|
-
| Responsive Breakpoints | ✅ | `@sm` `@md` `@lg` `@xl` `@2xl` |
|
|
88
|
-
| Arbitrary Media Queries | ✅ | `'@media (min-width: 900px)'` |
|
|
89
|
-
| Pseudo-classes | ✅ | `:hover` `:focus` `:active` `:disabled` `:focus-visible` … |
|
|
90
|
-
| Pseudo-elements | ✅ | `::before` `::after` `::first-letter` … |
|
|
91
|
-
| Keyframe Animations | ✅ | `'@keyframes name'` inline with the style object |
|
|
92
|
-
| Container Queries | ✅ | `'@container sidebar (min-width: 300px)'` |
|
|
93
|
-
| `@supports` | ✅ | `'@supports (display: grid)'` |
|
|
94
|
-
| `@layer` | ✅ | `'@layer utilities'` |
|
|
95
|
-
| CSS Variables | ✅ | `var(--token)` as values |
|
|
96
|
-
| Deduplication | ✅ | Same object → same class, always |
|
|
97
|
-
| Global Styles | ✅ | `global()` for resets and base rules |
|
|
130
|
+
That's it. No providers, no wrappers, no configuration beyond PostCSS.
|
|
98
131
|
|
|
99
132
|
## API
|
|
100
133
|
|
|
101
|
-
### `css(styles
|
|
102
|
-
|
|
103
|
-
Converts a style object into a unique, stable class name. Identical objects always return the same class (deduplication). Styles are collected at build time — zero cost at runtime.
|
|
104
|
-
|
|
105
|
-
```tsx
|
|
106
|
-
const button = css({
|
|
107
|
-
padding: "8px 16px",
|
|
108
|
-
borderRadius: "6px",
|
|
109
|
-
backgroundColor: "#7F77DD",
|
|
110
|
-
color: "#fff",
|
|
111
|
-
cursor: "pointer",
|
|
112
|
-
":hover": { backgroundColor: "#534AB7" },
|
|
113
|
-
"@md": { padding: "10px 20px" }
|
|
114
|
-
})
|
|
134
|
+
### `css(styles)`
|
|
115
135
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
136
|
+
```ts
|
|
137
|
+
function css(styles: CSSObject): string
|
|
119
138
|
```
|
|
120
139
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
Registers global CSS rules applied directly to selectors — no scoped class. Useful for resets, base typography, and third-party element overrides.
|
|
140
|
+
Converts a style object into a stable, unique class name. Identical style objects always produce the same hash — duplicates are eliminated automatically. All processing happens at build time.
|
|
124
141
|
|
|
125
142
|
```tsx
|
|
126
|
-
|
|
143
|
+
const card = css({
|
|
144
|
+
// Base styles
|
|
145
|
+
display: "flex",
|
|
146
|
+
flexDirection: "column",
|
|
147
|
+
padding: "16px",
|
|
148
|
+
borderRadius: "8px",
|
|
149
|
+
backgroundColor: "var(--surface)",
|
|
127
150
|
|
|
128
|
-
|
|
129
|
-
"
|
|
130
|
-
"
|
|
131
|
-
"
|
|
132
|
-
})
|
|
133
|
-
```
|
|
151
|
+
// Pseudo-classes & pseudo-elements
|
|
152
|
+
":hover": { boxShadow: "0 4px 12px rgba(0,0,0,0.1)" },
|
|
153
|
+
":focus-visible": { outline: "2px solid #7F77DD", outlineOffset: "2px" },
|
|
154
|
+
"::before": { content: '""', display: "block" },
|
|
134
155
|
|
|
135
|
-
|
|
156
|
+
// Responsive breakpoints
|
|
157
|
+
"@md": { flexDirection: "row", padding: "24px" },
|
|
158
|
+
"@lg": { padding: "32px" },
|
|
136
159
|
|
|
137
|
-
|
|
160
|
+
// Arbitrary media query
|
|
161
|
+
"@media (prefers-reduced-motion: reduce)": { transition: "none" },
|
|
138
162
|
|
|
139
|
-
|
|
163
|
+
// Container query
|
|
164
|
+
"@container sidebar (min-width: 300px)": { fontSize: "16px" },
|
|
140
165
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
| `@sm` | `@media (min-width: 640px)` |
|
|
144
|
-
| `@md` | `@media (min-width: 768px)` |
|
|
145
|
-
| `@lg` | `@media (min-width: 1024px)` |
|
|
146
|
-
| `@xl` | `@media (min-width: 1280px)` |
|
|
147
|
-
| `@2xl` | `@media (min-width: 1536px)` |
|
|
166
|
+
// Feature query
|
|
167
|
+
"@supports (display: grid)": { display: "grid" },
|
|
148
168
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
169
|
+
// Cascade layer
|
|
170
|
+
"@layer utilities": { isolation: "isolate" },
|
|
171
|
+
|
|
172
|
+
// Inline keyframes
|
|
173
|
+
animationName: "fadeIn",
|
|
174
|
+
animationDuration: "0.3s",
|
|
175
|
+
"@keyframes fadeIn": {
|
|
176
|
+
from: { opacity: 0, transform: "translateY(4px)" },
|
|
177
|
+
to: { opacity: 1, transform: "translateY(0)" },
|
|
178
|
+
},
|
|
155
179
|
})
|
|
156
180
|
```
|
|
157
181
|
|
|
158
|
-
|
|
182
|
+
### `global(styles)`
|
|
159
183
|
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
display: "none",
|
|
163
|
-
"@media (min-width: 900px)": { display: "block" }
|
|
164
|
-
})
|
|
184
|
+
```ts
|
|
185
|
+
function global(styles: Record<string, CSSObject>): void
|
|
165
186
|
```
|
|
166
187
|
|
|
167
|
-
|
|
188
|
+
Registers styles directly against selectors — no scoping, no class name. Use for CSS resets, base typography, and overriding third-party elements.
|
|
168
189
|
|
|
169
190
|
```tsx
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
"
|
|
175
|
-
|
|
176
|
-
|
|
191
|
+
// app/globals.ts (imported once in your layout)
|
|
192
|
+
import { global } from "next-style"
|
|
193
|
+
|
|
194
|
+
global({
|
|
195
|
+
"*": {
|
|
196
|
+
boxSizing: "border-box",
|
|
197
|
+
margin: "0",
|
|
198
|
+
padding: "0",
|
|
199
|
+
},
|
|
200
|
+
"body": {
|
|
201
|
+
fontFamily: "system-ui, sans-serif",
|
|
202
|
+
lineHeight: "1.6",
|
|
203
|
+
color: "var(--text-primary)",
|
|
204
|
+
},
|
|
205
|
+
"h1, h2, h3, h4": {
|
|
206
|
+
fontWeight: 600,
|
|
207
|
+
lineHeight: "1.2",
|
|
208
|
+
},
|
|
177
209
|
})
|
|
178
210
|
```
|
|
179
211
|
|
|
180
|
-
|
|
212
|
+
## Responsive Design
|
|
181
213
|
|
|
182
|
-
|
|
214
|
+
Shorthand breakpoints expand to `min-width` media queries and are always emitted in mobile-first order, regardless of how you write them.
|
|
183
215
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
to: { transform: "rotate(360deg)" }
|
|
192
|
-
}
|
|
193
|
-
})
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### Container queries
|
|
216
|
+
| Shorthand | Expands to |
|
|
217
|
+
|-----------|------------|
|
|
218
|
+
| `@sm` | `@media (min-width: 640px)` |
|
|
219
|
+
| `@md` | `@media (min-width: 768px)` |
|
|
220
|
+
| `@lg` | `@media (min-width: 1024px)` |
|
|
221
|
+
| `@xl` | `@media (min-width: 1280px)` |
|
|
222
|
+
| `@2xl` | `@media (min-width: 1536px)` |
|
|
197
223
|
|
|
198
224
|
```tsx
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
225
|
+
const layout = css({
|
|
226
|
+
display: "grid",
|
|
227
|
+
gridTemplateColumns: "1fr", // mobile: single column
|
|
228
|
+
"@md": { gridTemplateColumns: "1fr 2fr" }, // tablet: sidebar + content
|
|
229
|
+
"@lg": { gridTemplateColumns: "240px 1fr 200px" }, // desktop: full layout
|
|
202
230
|
})
|
|
203
231
|
```
|
|
204
232
|
|
|
205
|
-
|
|
233
|
+
For custom breakpoints, use an arbitrary media query string:
|
|
206
234
|
|
|
207
235
|
```tsx
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
padding: "var(--spacing-4)",
|
|
212
|
-
borderRadius: "var(--radius-lg)"
|
|
236
|
+
const widget = css({
|
|
237
|
+
display: "none",
|
|
238
|
+
"@media (min-width: 900px)": { display: "block" },
|
|
213
239
|
})
|
|
214
240
|
```
|
|
215
241
|
|
|
216
242
|
## TypeScript
|
|
217
243
|
|
|
218
|
-
All CSS properties and values are
|
|
244
|
+
All CSS properties and values are typed via [csstype](https://github.com/frenic/csstype). Property typos fail at compile time. Values get IDE autocomplete.
|
|
219
245
|
|
|
220
246
|
```tsx
|
|
221
247
|
import { css, type CSSObject } from "next-style"
|
|
222
248
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
"
|
|
227
|
-
|
|
249
|
+
// Type a reusable style object before passing it to css()
|
|
250
|
+
const base: CSSObject = {
|
|
251
|
+
fontSize: "16px", // ✅
|
|
252
|
+
colour: "red", // ❌ TypeScript error: unknown property
|
|
253
|
+
display: "flx", // ❌ TypeScript error: invalid value
|
|
228
254
|
}
|
|
229
255
|
|
|
230
|
-
const
|
|
256
|
+
const el = css(base)
|
|
231
257
|
```
|
|
232
258
|
|
|
233
|
-
|
|
259
|
+
**Exported types:**
|
|
234
260
|
|
|
235
261
|
| Type | Description |
|
|
236
262
|
|------|-------------|
|
|
237
|
-
| `CSSObject` |
|
|
238
|
-
| `CSSProperties` | CSS properties only
|
|
263
|
+
| `CSSObject` | Full style object — properties, at-rules, and pseudos |
|
|
264
|
+
| `CSSProperties` | CSS properties only, no at-rules or pseudos |
|
|
239
265
|
|
|
240
|
-
## Advanced
|
|
266
|
+
## Advanced
|
|
241
267
|
|
|
242
|
-
|
|
268
|
+
### `createTransformer`
|
|
269
|
+
|
|
270
|
+
For build tooling, SWC/Babel plugins, and test harnesses that need an isolated style collector independent of the global runtime:
|
|
243
271
|
|
|
244
272
|
```ts
|
|
245
273
|
import { createTransformer } from "next-style"
|
|
246
274
|
|
|
247
275
|
const { collector, transformCssCall } = createTransformer()
|
|
248
|
-
|
|
249
|
-
const
|
|
276
|
+
|
|
277
|
+
const className = transformCssCall({ color: "red", fontSize: "16px" })
|
|
278
|
+
// → "ns-abc123"
|
|
279
|
+
|
|
280
|
+
const css = collector.getAllStyles()
|
|
281
|
+
// → ".ns-abc123 { color: red; font-size: 16px; }"
|
|
250
282
|
```
|
|
251
283
|
|
|
252
|
-
|
|
284
|
+
### `StyleCollector`
|
|
253
285
|
|
|
254
|
-
|
|
255
|
-
# Install dependencies
|
|
256
|
-
bun install
|
|
286
|
+
The class powering both the runtime and `createTransformer`. Exposed for custom integrations:
|
|
257
287
|
|
|
258
|
-
|
|
259
|
-
|
|
288
|
+
```ts
|
|
289
|
+
import { StyleCollector } from "next-style"
|
|
260
290
|
|
|
261
|
-
|
|
262
|
-
|
|
291
|
+
const collector = new StyleCollector()
|
|
292
|
+
collector.addStyle({ color: "red" }) // → "ns-abc123"
|
|
293
|
+
collector.addGlobalStyle("body", { margin: "0" })
|
|
294
|
+
collector.getAllStyles() // full CSS string
|
|
295
|
+
collector.flush("/custom/path/styles.css") // write to disk
|
|
296
|
+
```
|
|
263
297
|
|
|
264
|
-
|
|
265
|
-
bunx tsc --noEmit
|
|
298
|
+
### How the PostCSS bridge works
|
|
266
299
|
|
|
267
|
-
|
|
268
|
-
bun run lint
|
|
300
|
+
Because PostCSS runs in a separate process from the module graph, in-memory style collectors cannot be shared. next-style solves this with a file-based bridge:
|
|
269
301
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
```
|
|
302
|
+
1. Every `css()` / `global()` call writes compiled CSS to `node_modules/.cache/next-style.css`
|
|
303
|
+
2. The PostCSS plugin reads that file and replaces `@import "next-style"` with its contents
|
|
273
304
|
|
|
274
|
-
|
|
305
|
+
This is why `@import "next-style"` must appear in `globals.css` — it's the injection point.
|
|
275
306
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
307
|
+
### CSS Variables
|
|
308
|
+
|
|
309
|
+
next-style pairs naturally with CSS custom properties for design tokens:
|
|
310
|
+
|
|
311
|
+
```tsx
|
|
312
|
+
// Define tokens once in global()
|
|
313
|
+
global({
|
|
314
|
+
":root": {
|
|
315
|
+
"--color-brand": "#7F77DD",
|
|
316
|
+
"--color-surface": "#ffffff",
|
|
317
|
+
"--radius-base": "6px",
|
|
318
|
+
"--spacing-4": "16px",
|
|
319
|
+
},
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
// Consume anywhere in css()
|
|
323
|
+
const card = css({
|
|
324
|
+
backgroundColor: "var(--color-surface)",
|
|
325
|
+
borderRadius: "var(--radius-base)",
|
|
326
|
+
padding: "var(--spacing-4)",
|
|
327
|
+
":hover": { color: "var(--color-brand)" },
|
|
328
|
+
})
|
|
282
329
|
```
|
|
283
330
|
|
|
284
|
-
##
|
|
331
|
+
## CSS output order
|
|
332
|
+
|
|
333
|
+
Styles are emitted in this order to ensure correct cascade:
|
|
285
334
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
-
|
|
335
|
+
1. `@keyframes` blocks
|
|
336
|
+
2. Base class rules
|
|
337
|
+
3. Pseudo-class / pseudo-element rules
|
|
338
|
+
4. `@layer` blocks
|
|
339
|
+
5. `@supports` blocks
|
|
340
|
+
6. Media queries (ascending `min-width`, mobile-first)
|
|
341
|
+
|
|
342
|
+
## Performance
|
|
289
343
|
|
|
290
|
-
|
|
344
|
+
| Metric | Value |
|
|
345
|
+
|--------|-------|
|
|
346
|
+
| Runtime JS | **0 bytes** |
|
|
347
|
+
| Bundle size | ~2 KB minified + gzipped |
|
|
348
|
+
| Build overhead | Negligible — hashing + string emit only |
|
|
349
|
+
| CSS deduplication | Automatic — one class per unique style object |
|
|
291
350
|
|
|
292
|
-
|
|
351
|
+
Because styles are extracted at build time, there is no style recalculation, no `<style>` injection, and no FOUC. The output is a single static CSS file.
|
|
293
352
|
|
|
294
353
|
## Troubleshooting
|
|
295
354
|
|
|
296
|
-
|
|
355
|
+
**Styles not appearing**
|
|
297
356
|
|
|
298
|
-
1.
|
|
299
|
-
2.
|
|
300
|
-
3. Restart the dev server
|
|
301
|
-
4. Clear the Next.js cache: `rm -rf .next`
|
|
357
|
+
1. Check that `postcss.config.js` includes `"next-style/plugin": {}`
|
|
358
|
+
2. Check that `@import "next-style";` is at the top of `globals.css`
|
|
359
|
+
3. Restart the dev server after any PostCSS config change
|
|
360
|
+
4. Clear the Next.js cache: `rm -rf .next` and restart
|
|
302
361
|
|
|
303
|
-
|
|
362
|
+
**First cold boot shows no styles**
|
|
304
363
|
|
|
305
|
-
|
|
364
|
+
On the very first build, no `css()` calls have been evaluated yet so the cache file doesn't exist. Run the dev server once to populate the cache, then styles will appear on reload. This is expected behaviour on cold starts.
|
|
306
365
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
366
|
+
**Build errors after adding PostCSS plugins**
|
|
367
|
+
|
|
368
|
+
Ensure next-style is listed **first** in the plugins object — it must run before any other transformations.
|
|
369
|
+
|
|
370
|
+
## Contributing
|
|
371
|
+
|
|
372
|
+
```bash
|
|
373
|
+
bun install # install dependencies
|
|
374
|
+
bun run export # production build (note: script is "export", not "build")
|
|
375
|
+
bun run dev # watch mode
|
|
376
|
+
bun test # run tests
|
|
377
|
+
bun run lint # lint with Biome
|
|
378
|
+
bun run format # format with Biome
|
|
379
|
+
bunx tsc --noEmit # type-check only
|
|
315
380
|
```
|
|
316
381
|
|
|
317
|
-
|
|
382
|
+
**Project structure**
|
|
318
383
|
|
|
319
|
-
|
|
384
|
+
```
|
|
385
|
+
src/
|
|
386
|
+
├── index.ts # public exports
|
|
387
|
+
├── runtime/ # css() · global() · CSSObject type
|
|
388
|
+
├── postcss-plugin/ # @import "next-style" → compiled CSS
|
|
389
|
+
├── compiler/ # StyleCollector · createTransformer · CompiledStyle
|
|
390
|
+
└── utils/ # camelToKebab · generateClassHash · BREAKPOINTS · normalizeMediaQuery
|
|
391
|
+
```
|
|
320
392
|
|
|
321
|
-
|
|
393
|
+
## License
|
|
322
394
|
|
|
323
|
-
|
|
395
|
+
MIT © [TiwPhiraphan](https://github.com/TiwPhiraphan)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "next-style",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.6",
|
|
4
4
|
"description": "Zero-Runtime CSS-in-JS for Next.js + Turbopack",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -28,9 +28,7 @@
|
|
|
28
28
|
"publishConfig": {
|
|
29
29
|
"access": "public"
|
|
30
30
|
},
|
|
31
|
-
"files": [
|
|
32
|
-
"dist"
|
|
33
|
-
],
|
|
31
|
+
"files": ["dist"],
|
|
34
32
|
"scripts": {
|
|
35
33
|
"export": "tsup",
|
|
36
34
|
"build:watch": "tsup --watch",
|
|
@@ -43,23 +41,16 @@
|
|
|
43
41
|
"@biomejs/biome": "^2.4.15",
|
|
44
42
|
"@types/node": "^25.7.0",
|
|
45
43
|
"@types/bun": "^1.3.14",
|
|
46
|
-
"csstype": "^3.2.3",
|
|
47
44
|
"typescript": "^5",
|
|
48
45
|
"tsup": "^8.5.1"
|
|
49
46
|
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"csstype": "latest"
|
|
49
|
+
},
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"postcss": ">=8.0.0"
|
|
52
52
|
},
|
|
53
|
-
"keywords": [
|
|
54
|
-
"css-in-js",
|
|
55
|
-
"zero-runtime",
|
|
56
|
-
"next.js",
|
|
57
|
-
"turbopack",
|
|
58
|
-
"postcss",
|
|
59
|
-
"style",
|
|
60
|
-
"next-style",
|
|
61
|
-
"css"
|
|
62
|
-
],
|
|
53
|
+
"keywords": ["css-in-js", "zero-runtime", "next.js", "nextjs", "typescript", "turbopack", "postcss", "style", "next-style", "css"],
|
|
63
54
|
"author": "TiwPhiraphan",
|
|
64
55
|
"license": "MIT"
|
|
65
56
|
}
|