@dinesh-gamage/react-scoped-css 2.0.0
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 +373 -0
- package/dist/adapters/next.d.mts +45 -0
- package/dist/adapters/next.d.ts +45 -0
- package/dist/adapters/next.js +14465 -0
- package/dist/adapters/next.js.map +1 -0
- package/dist/adapters/next.mjs +14461 -0
- package/dist/adapters/next.mjs.map +1 -0
- package/dist/adapters/vite.d.mts +15 -0
- package/dist/adapters/vite.d.ts +15 -0
- package/dist/adapters/vite.js +14465 -0
- package/dist/adapters/vite.js.map +1 -0
- package/dist/adapters/vite.mjs +14461 -0
- package/dist/adapters/vite.mjs.map +1 -0
- package/dist/adapters/webpack.d.mts +25 -0
- package/dist/adapters/webpack.d.ts +25 -0
- package/dist/adapters/webpack.js +14440 -0
- package/dist/adapters/webpack.js.map +1 -0
- package/dist/adapters/webpack.mjs +14436 -0
- package/dist/adapters/webpack.mjs.map +1 -0
- package/dist/babel/index.d.mts +14 -0
- package/dist/babel/index.d.ts +14 -0
- package/dist/babel/index.js +14392 -0
- package/dist/babel/index.js.map +1 -0
- package/dist/babel/index.mjs +14386 -0
- package/dist/babel/index.mjs.map +1 -0
- package/dist/cli/init.d.mts +1 -0
- package/dist/cli/init.d.ts +1 -0
- package/dist/cli/init.js +122 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/init.mjs +99 -0
- package/dist/cli/init.mjs.map +1 -0
- package/dist/index.d.mts +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +17 -0
- package/dist/index.mjs.map +1 -0
- package/dist/options-DBNexJk6.d.mts +25 -0
- package/dist/options-DBNexJk6.d.ts +25 -0
- package/dist/postcss/index.d.mts +17 -0
- package/dist/postcss/index.d.ts +17 -0
- package/dist/postcss/index.js +113 -0
- package/dist/postcss/index.js.map +1 -0
- package/dist/postcss/index.mjs +83 -0
- package/dist/postcss/index.mjs.map +1 -0
- package/package.json +102 -0
package/README.md
ADDED
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
# react-scoped-css
|
|
2
|
+
|
|
3
|
+
CSS scoping for React with zero code changes. Write your JSX and CSS exactly as you always have — class names get a per-file hash appended at build time so they never collide.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
// You write this
|
|
7
|
+
<div className="container">
|
|
8
|
+
<button className="btn">Save</button>
|
|
9
|
+
</div>
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```scss
|
|
13
|
+
// You write this
|
|
14
|
+
.container { padding: 16px; }
|
|
15
|
+
.btn { background: blue; }
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
// Build output (invisible to you)
|
|
20
|
+
<div className="container-a3f9b2c1">
|
|
21
|
+
<button className="btn-a3f9b2c1">Save</button>
|
|
22
|
+
</div>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```css
|
|
26
|
+
/* Build output (invisible to you) */
|
|
27
|
+
.container-a3f9b2c1 { padding: 16px; }
|
|
28
|
+
.btn-a3f9b2c1 { background: blue; }
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The hash is derived from the file path — same hash in JSX and CSS, unique per file, identical on every developer machine and in CI.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Overview
|
|
36
|
+
|
|
37
|
+
react-scoped-css is a build-time CSS scoping tool for React. It has two parts that work together:
|
|
38
|
+
|
|
39
|
+
**Babel plugin** — transforms every `className` JSX attribute at compile time, appending a per-file hash to each class name token. Static strings are rewritten inline (zero runtime cost). Dynamic expressions are wrapped with a small `scopeClass()` runtime helper, imported automatically only in files that need it.
|
|
40
|
+
|
|
41
|
+
**PostCSS plugin** — transforms every CSS/SCSS class selector at build time, appending the same per-file hash. SCSS syntax is handled automatically (no extra config). Files matching `*.module.*` are skipped.
|
|
42
|
+
|
|
43
|
+
Both plugins derive the hash the same way: `MD5(relativeFilePath + salt).slice(0, 8)`, where the file extension is stripped so `Card.tsx` and `Card.scss` always produce the same hash. The path is relative to the project root (nearest `package.json`), so the hash is identical on every machine and in CI. The salt defaults to the `name` field in `package.json`, making hashes globally unique across apps in the same monorepo or deployment without any extra configuration.
|
|
44
|
+
|
|
45
|
+
The result: `.container` in `Card.tsx` and `.container` in `UserProfile.tsx` each get different hashes, ending up as `.container-a3f9b2c1` and `.container-b4c8d1e2` — the same code, zero collisions, zero code changes from the developer.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Why not CSS Modules or CSS-in-JS?
|
|
50
|
+
|
|
51
|
+
Every existing solution requires you to change how you write code:
|
|
52
|
+
|
|
53
|
+
| Tool | What you have to change |
|
|
54
|
+
|---|---|
|
|
55
|
+
| CSS Modules | Rename every import; use `styles.className` everywhere |
|
|
56
|
+
| styled-components / Emotion | Entirely different syntax |
|
|
57
|
+
| babel-plugin-react-css-modules | Rename `className` to `styleName` |
|
|
58
|
+
|
|
59
|
+
This tool requires no changes. Add it to your build config once, and existing code is scoped automatically.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Install
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm install @dinesh-gamage/react-scoped-css
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Then run the init command to get the config snippet for your bundler:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npx @dinesh-gamage/react-scoped-css init
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Setup
|
|
78
|
+
|
|
79
|
+
### Vite
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
// vite.config.ts
|
|
83
|
+
import { defineConfig } from 'vite';
|
|
84
|
+
import react from '@vitejs/plugin-react';
|
|
85
|
+
import { scopedCss } from '@dinesh-gamage/react-scoped-css/vite';
|
|
86
|
+
|
|
87
|
+
export default defineConfig({
|
|
88
|
+
plugins: [
|
|
89
|
+
react(),
|
|
90
|
+
scopedCss({ exclude: ['global-'] }),
|
|
91
|
+
],
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Next.js
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
// next.config.js
|
|
99
|
+
const { withScopedCss } = require('@dinesh-gamage/react-scoped-css/next');
|
|
100
|
+
|
|
101
|
+
module.exports = withScopedCss({
|
|
102
|
+
exclude: ['global-'],
|
|
103
|
+
})({
|
|
104
|
+
// ...your existing Next.js config
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### webpack
|
|
109
|
+
|
|
110
|
+
```js
|
|
111
|
+
// webpack.config.js
|
|
112
|
+
const { scopedCssWebpack } = require('@dinesh-gamage/react-scoped-css/webpack');
|
|
113
|
+
const { babelPlugin, postcssPlugin } = scopedCssWebpack({
|
|
114
|
+
exclude: ['global-'],
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
module.exports = {
|
|
118
|
+
module: {
|
|
119
|
+
rules: [
|
|
120
|
+
{
|
|
121
|
+
test: /\.[jt]sx?$/,
|
|
122
|
+
use: {
|
|
123
|
+
loader: 'babel-loader',
|
|
124
|
+
options: {
|
|
125
|
+
plugins: [babelPlugin],
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
test: /\.css$/,
|
|
131
|
+
use: [
|
|
132
|
+
'style-loader',
|
|
133
|
+
'css-loader',
|
|
134
|
+
{
|
|
135
|
+
loader: 'postcss-loader',
|
|
136
|
+
options: {
|
|
137
|
+
postcssOptions: {
|
|
138
|
+
plugins: [postcssPlugin],
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Manual (Babel + PostCSS directly)
|
|
150
|
+
|
|
151
|
+
If you configure Babel and PostCSS yourself:
|
|
152
|
+
|
|
153
|
+
```js
|
|
154
|
+
// babel.config.js
|
|
155
|
+
const { default: scopedCssBabel } = require('@dinesh-gamage/react-scoped-css/babel');
|
|
156
|
+
|
|
157
|
+
module.exports = {
|
|
158
|
+
plugins: [
|
|
159
|
+
[scopedCssBabel, { exclude: ['global-'] }],
|
|
160
|
+
],
|
|
161
|
+
};
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
```js
|
|
165
|
+
// postcss.config.js
|
|
166
|
+
const { scopedCssPostcss } = require('@dinesh-gamage/react-scoped-css/postcss');
|
|
167
|
+
|
|
168
|
+
module.exports = {
|
|
169
|
+
plugins: [
|
|
170
|
+
scopedCssPostcss({ exclude: ['global-'] }),
|
|
171
|
+
],
|
|
172
|
+
};
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Excluding class names
|
|
178
|
+
|
|
179
|
+
Use `exclude` to list class name prefixes that should never be scoped. This is the main mechanism for component library overrides — you want to write `.uxp-button { color: red }` to override a library style, not `.uxp-button-a3f9b2c1`.
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
scopedCss({
|
|
183
|
+
exclude: ['uxp-', 'mantine-', 'global-', 'app-'],
|
|
184
|
+
})
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Any class name whose string value starts with an excluded prefix is left exactly as written, in both JSX output and CSS output.
|
|
188
|
+
|
|
189
|
+
```tsx
|
|
190
|
+
// exclude: ['uxp-']
|
|
191
|
+
|
|
192
|
+
<div className="container uxp-button">
|
|
193
|
+
// ^^^^^^^^^^^^^^^^^^^
|
|
194
|
+
// "container" → "container-a3f9b2c1"
|
|
195
|
+
// "uxp-button" → "uxp-button" (untouched)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
```scss
|
|
199
|
+
.container { padding: 16px; } // → .container-a3f9b2c1
|
|
200
|
+
.uxp-button { font-weight: bold; } // → .uxp-button (untouched)
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Configuration
|
|
206
|
+
|
|
207
|
+
```ts
|
|
208
|
+
interface ScopedCssOptions {
|
|
209
|
+
/**
|
|
210
|
+
* Class name prefixes to leave unscoped.
|
|
211
|
+
* Default: []
|
|
212
|
+
*/
|
|
213
|
+
exclude?: string[];
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Override the salt used in hash generation.
|
|
217
|
+
* Defaults to the `name` field from the nearest package.json.
|
|
218
|
+
* Override in monorepos or multi-app deployments to guarantee
|
|
219
|
+
* globally unique class names across apps.
|
|
220
|
+
*/
|
|
221
|
+
salt?: string;
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Number of hex characters in the hash suffix.
|
|
225
|
+
* Default: 8
|
|
226
|
+
*/
|
|
227
|
+
hashLength?: number;
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## How it works
|
|
234
|
+
|
|
235
|
+
**Babel plugin** (`@dinesh-gamage/react-scoped-css/babel`) — visits every `className` JSX attribute and appends `-{hash}` to each class name token at compile time. Handles all real-world patterns:
|
|
236
|
+
|
|
237
|
+
| Pattern | Input | Output |
|
|
238
|
+
|---|---|---|
|
|
239
|
+
| String literal | `className="foo bar"` | `className="foo-a3f9b2c1 bar-a3f9b2c1"` |
|
|
240
|
+
| String expression | `className={"foo"}` | `className={"foo-a3f9b2c1"}` |
|
|
241
|
+
| Template literal (static) | `` className={`foo`} `` | `` className={`foo-a3f9b2c1`} `` |
|
|
242
|
+
| Template literal (dynamic) | `` className={`foo ${x}`} `` | `` className={`foo-a3f9b2c1 ${scopeClass(x, "a3f9b2c1")}`} `` |
|
|
243
|
+
| Variable | `className={myClass}` | `className={scopeClass(myClass, "a3f9b2c1")}` |
|
|
244
|
+
| classNames() call | `className={classNames("foo", {bar: x})}` | `className={classNames("foo-a3f9b2c1", {"bar-a3f9b2c1": x})}` |
|
|
245
|
+
| Ternary | `className={x ? "a" : "b"}` | `className={x ? "a-a3f9b2c1" : "b-a3f9b2c1"}` |
|
|
246
|
+
| Logical | `className={x && "foo"}` | `className={x && "foo-a3f9b2c1"}` |
|
|
247
|
+
| Excluded prefix | `className="uxp-button"` | `className="uxp-button"` |
|
|
248
|
+
|
|
249
|
+
Static string literals are transformed entirely at compile time — no runtime cost, no import added. Dynamic expressions use `scopeClass()`, a small runtime helper that is imported automatically only in files that need it.
|
|
250
|
+
|
|
251
|
+
**PostCSS plugin** (`@dinesh-gamage/react-scoped-css/postcss`) — walks every CSS rule selector and appends `-{hash}` to each class token, matching what the Babel plugin produces. SCSS and Less are supported via `postcss-scss` (bundled). Files matching `*.module.*` are skipped — they are already scoped by CSS Modules.
|
|
252
|
+
|
|
253
|
+
**Hash** — `MD5(relativeFilePath + salt).slice(0, 8)`. The path is relative to the nearest `package.json`, so the hash is identical on every developer machine and in CI regardless of where the repo is cloned. The salt defaults to the `name` field from `package.json`, which makes hashes globally unique across different apps without any configuration.
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Known limitations
|
|
258
|
+
|
|
259
|
+
**Dynamic class names set outside JSX** — `element.className = 'foo'` and `document.createElement` calls are not transformed. The Babel plugin only processes JSX `className` attributes. Workaround: use `scopeClass` from `react-scoped-css` directly:
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
import { scopeClass } from '@dinesh-gamage/react-scoped-css';
|
|
263
|
+
// you need to supply the hash manually — get it from the build output
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
For most React codebases this is not an issue.
|
|
267
|
+
|
|
268
|
+
**Template literals with nested `classNames()` calls** — `` className={`wrapper ${classNames({active: x})}`} `` — the outer template literal is processed but the inner `classNames()` call is not recursively transformed. Workaround: move the `classNames()` call outside the template literal.
|
|
269
|
+
|
|
270
|
+
**Third-party components that accept `className`** — A library component that uses your scoped class name internally (not just forwards it to a DOM element) may not match your CSS. The `exclude` list handles top-level library class names. Internal library classes are unaffected.
|
|
271
|
+
|
|
272
|
+
**React compiler (experimental)** — Untested with the React 19 compiler. The Babel plugin runs before the React compiler in the standard pipeline, but verify in your specific setup.
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Contributing
|
|
277
|
+
|
|
278
|
+
Contributions are welcome. Here is what the project needs most:
|
|
279
|
+
|
|
280
|
+
- **e2e tests** — full build integration tests for Vite and webpack (`tests/e2e/`) — currently empty
|
|
281
|
+
- **Less support** — `postcss-less` is not yet bundled; `.less` files are not auto-detected in the PostCSS plugin
|
|
282
|
+
- **React 19 / React compiler verification** — the Babel plugin is untested with the React compiler; someone with a React 19 + compiler project should validate it
|
|
283
|
+
- **Rollup adapter** — `src/adapters/rollup.ts` following the same pattern as the Vite adapter
|
|
284
|
+
- **Nested `classNames()` inside template literals** — known limitation, see [Known limitations](#known-limitations)
|
|
285
|
+
- **Bug reports with minimal reproductions** — open an issue with the smallest possible code that shows the problem
|
|
286
|
+
|
|
287
|
+
### Setup
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
git clone https://github.com/dinesh-gamage/react-scoped-css
|
|
291
|
+
cd react-scoped-css
|
|
292
|
+
npm install
|
|
293
|
+
npm test # 38 tests, should all pass
|
|
294
|
+
npm run build # builds dist/
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Project structure
|
|
298
|
+
|
|
299
|
+
```
|
|
300
|
+
src/
|
|
301
|
+
babel/index.ts JSX className transform — all 9 patterns, AST-based
|
|
302
|
+
postcss/index.ts CSS class selector transform, SCSS auto-detected
|
|
303
|
+
cli/init.ts npx @dinesh-gamage/react-scoped-css init — detect bundler, print snippet
|
|
304
|
+
adapters/
|
|
305
|
+
vite.ts Vite plugin (wires up both automatically)
|
|
306
|
+
next.ts Next.js withScopedCss() wrapper
|
|
307
|
+
webpack.ts webpack {babelPlugin, postcssPlugin} helper
|
|
308
|
+
shared/
|
|
309
|
+
hash.ts MD5(relPathWithoutExt + salt).slice(0,8)
|
|
310
|
+
exclude.ts prefix-based exclusion check
|
|
311
|
+
options.ts ScopedCssOptions interface
|
|
312
|
+
classNames.ts scopeClass() runtime helper
|
|
313
|
+
index.ts package root export
|
|
314
|
+
|
|
315
|
+
tests/
|
|
316
|
+
shared/ hash and exclude unit tests
|
|
317
|
+
babel/ Babel plugin tests — one per className pattern
|
|
318
|
+
postcss/ PostCSS plugin tests
|
|
319
|
+
e2e/ (empty — needs full Vite/webpack integration tests)
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Key design decisions
|
|
323
|
+
|
|
324
|
+
**Hash = `MD5(relPathWithoutExt + salt)`** — extension is stripped so `Card.tsx` and `Card.scss` produce the same hash. Without this, the Babel plugin (processing `.tsx`) and the PostCSS plugin (processing `.scss`) would generate different hashes for the same component.
|
|
325
|
+
|
|
326
|
+
**Babel over regex** — className transformation uses Babel AST, not regex. This is correct for all edge cases (template literals, ternaries, variables, classNames() calls) where regex silently produces wrong output.
|
|
327
|
+
|
|
328
|
+
**PostCSS over string replacement** — CSS transformation uses PostCSS rule walking, not string replacement. Handles nested SCSS, multi-selector rules, and pseudo-classes correctly.
|
|
329
|
+
|
|
330
|
+
**`scopeClass()` import injected per-file** — the runtime helper is only imported in files that contain dynamic className expressions. Static-only files get no import, no runtime cost.
|
|
331
|
+
|
|
332
|
+
**`exclude` is prefix-based** — any class starting with an excluded prefix is left completely unchanged in both JSX and CSS. Intended for component library overrides (e.g. `uxp-`, `mantine-`).
|
|
333
|
+
|
|
334
|
+
### Adding a new adapter
|
|
335
|
+
|
|
336
|
+
Follow the pattern in `src/adapters/vite.ts`:
|
|
337
|
+
|
|
338
|
+
1. Import `scopedCssPostcss` from `../postcss/index` and `reactScopedCssBabelPlugin` from `../babel/index`
|
|
339
|
+
2. Wire up both plugins for the target bundler
|
|
340
|
+
3. Export a named function with the bundler's conventional API shape
|
|
341
|
+
4. Add the entry to `tsup.config.ts` and `package.json` exports
|
|
342
|
+
|
|
343
|
+
### Submitting a PR
|
|
344
|
+
|
|
345
|
+
- Keep PRs focused — one concern per PR
|
|
346
|
+
- Add or update tests for any behaviour change
|
|
347
|
+
- `npm test` must pass with no failures
|
|
348
|
+
- `npm run build` must succeed with no type errors (`tsc --noEmit`)
|
|
349
|
+
- For bug fixes: include a test that fails before your fix and passes after
|
|
350
|
+
|
|
351
|
+
Open an issue first for anything large (new adapters, new configuration options, behaviour changes) so we can agree on the approach before you write the code.
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## Migrating from react-scoped-css-loader (v1)
|
|
356
|
+
|
|
357
|
+
v1 (`react-scoped-css-loader`) and v2 (`@dinesh-gamage/react-scoped-css`) are separate packages. v1 remains on npm unchanged.
|
|
358
|
+
|
|
359
|
+
To migrate:
|
|
360
|
+
|
|
361
|
+
```bash
|
|
362
|
+
npm uninstall react-scoped-css-loader
|
|
363
|
+
npm install @dinesh-gamage/react-scoped-css
|
|
364
|
+
npx @dinesh-gamage/react-scoped-css init
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
Then replace the v1 webpack loader config with the v2 config snippet printed by `init`.
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
## License
|
|
372
|
+
|
|
373
|
+
MIT
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { S as ScopedCssOptions } from '../options-DBNexJk6.mjs';
|
|
2
|
+
|
|
3
|
+
type NextConfig = Record<string, unknown> & {
|
|
4
|
+
webpack?: (config: WebpackConfig, options: NextWebpackOptions) => WebpackConfig;
|
|
5
|
+
experimental?: {
|
|
6
|
+
turbo?: unknown;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
type WebpackConfig = {
|
|
10
|
+
module?: {
|
|
11
|
+
rules?: WebpackRule[];
|
|
12
|
+
};
|
|
13
|
+
[key: string]: unknown;
|
|
14
|
+
};
|
|
15
|
+
type WebpackRule = {
|
|
16
|
+
test?: RegExp;
|
|
17
|
+
use?: WebpackUse | WebpackUse[];
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
};
|
|
20
|
+
type WebpackUse = {
|
|
21
|
+
loader?: string;
|
|
22
|
+
options?: {
|
|
23
|
+
plugins?: unknown[];
|
|
24
|
+
presets?: unknown[];
|
|
25
|
+
postcssOptions?: {
|
|
26
|
+
plugins?: unknown[];
|
|
27
|
+
};
|
|
28
|
+
[key: string]: unknown;
|
|
29
|
+
};
|
|
30
|
+
[key: string]: unknown;
|
|
31
|
+
};
|
|
32
|
+
type NextWebpackOptions = {
|
|
33
|
+
isServer: boolean;
|
|
34
|
+
[key: string]: unknown;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Next.js config wrapper — injects Babel + PostCSS plugins automatically.
|
|
38
|
+
*
|
|
39
|
+
* Usage (next.config.js):
|
|
40
|
+
* const { withScopedCss } = require('react-scoped-css/next');
|
|
41
|
+
* module.exports = withScopedCss({ exclude: ['uxp-'] })({ ... next config ... });
|
|
42
|
+
*/
|
|
43
|
+
declare function withScopedCss(opts?: ScopedCssOptions): (nextConfig?: NextConfig) => NextConfig;
|
|
44
|
+
|
|
45
|
+
export { withScopedCss };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { S as ScopedCssOptions } from '../options-DBNexJk6.js';
|
|
2
|
+
|
|
3
|
+
type NextConfig = Record<string, unknown> & {
|
|
4
|
+
webpack?: (config: WebpackConfig, options: NextWebpackOptions) => WebpackConfig;
|
|
5
|
+
experimental?: {
|
|
6
|
+
turbo?: unknown;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
type WebpackConfig = {
|
|
10
|
+
module?: {
|
|
11
|
+
rules?: WebpackRule[];
|
|
12
|
+
};
|
|
13
|
+
[key: string]: unknown;
|
|
14
|
+
};
|
|
15
|
+
type WebpackRule = {
|
|
16
|
+
test?: RegExp;
|
|
17
|
+
use?: WebpackUse | WebpackUse[];
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
};
|
|
20
|
+
type WebpackUse = {
|
|
21
|
+
loader?: string;
|
|
22
|
+
options?: {
|
|
23
|
+
plugins?: unknown[];
|
|
24
|
+
presets?: unknown[];
|
|
25
|
+
postcssOptions?: {
|
|
26
|
+
plugins?: unknown[];
|
|
27
|
+
};
|
|
28
|
+
[key: string]: unknown;
|
|
29
|
+
};
|
|
30
|
+
[key: string]: unknown;
|
|
31
|
+
};
|
|
32
|
+
type NextWebpackOptions = {
|
|
33
|
+
isServer: boolean;
|
|
34
|
+
[key: string]: unknown;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Next.js config wrapper — injects Babel + PostCSS plugins automatically.
|
|
38
|
+
*
|
|
39
|
+
* Usage (next.config.js):
|
|
40
|
+
* const { withScopedCss } = require('react-scoped-css/next');
|
|
41
|
+
* module.exports = withScopedCss({ exclude: ['uxp-'] })({ ... next config ... });
|
|
42
|
+
*/
|
|
43
|
+
declare function withScopedCss(opts?: ScopedCssOptions): (nextConfig?: NextConfig) => NextConfig;
|
|
44
|
+
|
|
45
|
+
export { withScopedCss };
|