@kanso-labs/unplugin-style-dictionary 0.8.0 → 0.10.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/{LICENSE → LICENSE.md} +1 -1
- package/README.md +298 -27
- package/dist/index.js +229 -50
- package/dist/index.js.map +1 -1
- package/dist/rspack.d.ts +6 -0
- package/dist/rspack.js +7 -0
- package/dist/rspack.js.map +1 -0
- package/dist/types.d.ts +58 -2
- package/package.json +15 -3
package/{LICENSE → LICENSE.md}
RENAMED
package/README.md
CHANGED
|
@@ -10,19 +10,23 @@ compile **Style Dictionary** design tokens ahead of your bundler, with automatic
|
|
|
10
10
|
watching, rebuilding, and hot reloading (HMR) under Vite's dev server.
|
|
11
11
|
|
|
12
12
|
Built on unplugin, the same core plugin targets **Vite**, **Rolldown**,
|
|
13
|
-
**Rollup**, and **Webpack** from a single implementation — useful
|
|
14
|
-
has more than one build surface (e.g. Storybook/Vitest on Vite,
|
|
15
|
-
build on Rolldown/tsdown) that both need tokens compiled ahead of
|
|
13
|
+
**Rollup**, **Rspack**, and **Webpack** from a single implementation — useful
|
|
14
|
+
when a project has more than one build surface (e.g. Storybook/Vitest on Vite,
|
|
15
|
+
and a package build on Rolldown/tsdown) that both need tokens compiled ahead of
|
|
16
|
+
them.
|
|
16
17
|
|
|
17
18
|
## Features
|
|
18
19
|
|
|
19
|
-
- **Multi-bundler**: One implementation,
|
|
20
|
-
Rollup, and Webpack.
|
|
21
|
-
- **Asynchronous builds**: Native support for Style Dictionary
|
|
22
|
-
compilation API.
|
|
20
|
+
- **Multi-bundler**: One implementation, five entry points — Vite, Rolldown,
|
|
21
|
+
Rollup, Rspack, and Webpack.
|
|
22
|
+
- **Asynchronous builds**: Native support for Style Dictionary v5's async
|
|
23
|
+
compilation API. The `style-dictionary` range in
|
|
24
|
+
[`package.json`](package.json)'s `peerDependencies` is the contract — this
|
|
25
|
+
bullet follows it rather than standing beside it.
|
|
23
26
|
- **Automatic watching**: Reads the `source` and `include` patterns from your
|
|
24
|
-
Style Dictionary configurations and watches the files they match
|
|
25
|
-
|
|
27
|
+
Style Dictionary configurations and watches the files they match, including a
|
|
28
|
+
token package resolved through `node_modules` in a workspace. What a change
|
|
29
|
+
then triggers depends on the target — see
|
|
26
30
|
[Watching, per target](#watching-per-target).
|
|
27
31
|
- **Config flexibility**: Supports file paths (JSON, JSON5, JSONC, JS, MJS, TS),
|
|
28
32
|
configuration objects, or functions — including registering custom formats at
|
|
@@ -47,9 +51,19 @@ build on Rolldown/tsdown) that both need tokens compiled ahead of them.
|
|
|
47
51
|
npm install @kanso-labs/unplugin-style-dictionary style-dictionary --save-dev
|
|
48
52
|
```
|
|
49
53
|
|
|
50
|
-
_Note: `style-dictionary` and your bundler (`vite`, `rolldown`, `rollup`,
|
|
51
|
-
`webpack`) are peer dependencies, so you can manage their
|
|
52
|
-
independently._
|
|
54
|
+
_Note: `style-dictionary` and your bundler (`vite`, `rolldown`, `rollup`,
|
|
55
|
+
`@rspack/core`, or `webpack`) are peer dependencies, so you can manage their
|
|
56
|
+
versions independently._
|
|
57
|
+
|
|
58
|
+
**`style-dictionary` is the one peer that is not optional**, and its range is
|
|
59
|
+
`^5.0.0`. An older major is refused at the install rather than failing later:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
npm error code ERESOLVE
|
|
63
|
+
npm error Found: style-dictionary@4.4.0
|
|
64
|
+
npm error Could not resolve dependency:
|
|
65
|
+
npm error peer style-dictionary@"^5.0.0" from @kanso-labs/unplugin-style-dictionary@0.9.0
|
|
66
|
+
```
|
|
53
67
|
|
|
54
68
|
**This package needs Node 22.12 or newer.** The floor is Style Dictionary v5's,
|
|
55
69
|
not this plugin's: every 5.x release declares `engines.node >= 22.0.0`, and it
|
|
@@ -98,11 +112,12 @@ generated token files exist before the rest of the build consumes them.
|
|
|
98
112
|
Under a real `rolldown.watch()`, do not rely on a token edit triggering a
|
|
99
113
|
rebuild — see [Watching, per target](#watching-per-target).
|
|
100
114
|
|
|
101
|
-
### Rollup / Webpack
|
|
115
|
+
### Rollup / Webpack / Rspack
|
|
102
116
|
|
|
103
117
|
```typescript
|
|
104
118
|
import StyleDictionary from '@kanso-labs/unplugin-style-dictionary/rollup'
|
|
105
119
|
// or: import StyleDictionary from '@kanso-labs/unplugin-style-dictionary/webpack'
|
|
120
|
+
// or: import StyleDictionary from '@kanso-labs/unplugin-style-dictionary/rspack'
|
|
106
121
|
```
|
|
107
122
|
|
|
108
123
|
A `webpack.config.js` is often CommonJS rather than ESM. This package ships ESM
|
|
@@ -119,6 +134,14 @@ module.exports = {
|
|
|
119
134
|
}
|
|
120
135
|
```
|
|
121
136
|
|
|
137
|
+
**Rspack is webpack's plugin API, and this package treats it as one.** Swap the
|
|
138
|
+
import for `…/rspack` and an `rspack.config.js` reads the same, `.default` hop
|
|
139
|
+
included. Everything below that mentions webpack — where a relative `config` is
|
|
140
|
+
resolved from, where a failed compile is reported, what a `config` function is
|
|
141
|
+
told about the build — holds there too, and `tests/webpack-api.test.ts` runs the
|
|
142
|
+
same cases against both. It installs as `@rspack/core`, which is the peer this
|
|
143
|
+
package declares.
|
|
144
|
+
|
|
122
145
|
_Note: that path needs Node 20.19+ or 22.12+, the versions that can `require` an
|
|
123
146
|
ES module. Every Node release still in support clears it. Importing from ESM has
|
|
124
147
|
no such floor._
|
|
@@ -127,6 +150,33 @@ _The subpaths also need a TypeScript `moduleResolution` of `bundler`, `node16`
|
|
|
127
150
|
or `nodenext`. The deprecated `node10` cannot resolve them, and TypeScript 6
|
|
128
151
|
already warns that it stops working in 7._
|
|
129
152
|
|
|
153
|
+
### Finding a Config File
|
|
154
|
+
|
|
155
|
+
With no `config`, the root is searched for `sd.config.json`, `config.json`,
|
|
156
|
+
`sd.config.js` and `sd.config.mjs`, in that order — and the first one that
|
|
157
|
+
**looks like a Style Dictionary configuration** wins. That means declaring at
|
|
158
|
+
least one of `platforms`, `source`, `include` or `tokens`. A candidate that
|
|
159
|
+
fails the check is reported and skipped rather than adopted, so an unrelated
|
|
160
|
+
`config.json` — an extremely common name for something else — no longer gets
|
|
161
|
+
compiled over and added to the watch set. The path that was picked is printed,
|
|
162
|
+
so which configuration a build used is answerable from the console.
|
|
163
|
+
|
|
164
|
+
`config.json` stays in the list because Style Dictionary's own CLI defaults to
|
|
165
|
+
it, so a project relying on that default keeps working.
|
|
166
|
+
|
|
167
|
+
**Two of the four names are modules, and reading a module runs it.** A root
|
|
168
|
+
`sd.config.js` is imported — freshly, on every watch event — and validation
|
|
169
|
+
cannot prevent that, because the check can only look at what the import
|
|
170
|
+
returned. If you name your configuration explicitly, or have none, say so:
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
StyleDictionary({ config: false })
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
That turns discovery off entirely: nothing is looked for, nothing is watched,
|
|
177
|
+
and nothing is compiled. A configuration you name yourself is never
|
|
178
|
+
second-guessed by the check above — it goes straight to Style Dictionary.
|
|
179
|
+
|
|
130
180
|
### Config File Formats
|
|
131
181
|
|
|
132
182
|
A `config` path may be `.json`, `.json5`, `.jsonc`, `.js`, `.mjs` or `.ts`. The
|
|
@@ -262,6 +312,23 @@ export default defineConfig({
|
|
|
262
312
|
})
|
|
263
313
|
```
|
|
264
314
|
|
|
315
|
+
## Platforms
|
|
316
|
+
|
|
317
|
+
Linux, macOS and Windows. All three run the suite in CI, and Windows is a
|
|
318
|
+
`Test on Windows` job rather than a claim — it was added after two defects
|
|
319
|
+
reached `main` because nothing ran there.
|
|
320
|
+
|
|
321
|
+
Both are fixed. The atomic write used to fail under the condition it exists for:
|
|
322
|
+
with a reader holding the destination open, Windows refuses the rename, so the
|
|
323
|
+
compile failed rather than the read being protected. The rename now backs off on
|
|
324
|
+
`EPERM` and `EBUSY` and retries, bounded, so a rename that genuinely cannot
|
|
325
|
+
succeed still fails rather than hanging a dev server.
|
|
326
|
+
|
|
327
|
+
And a token package resolved through `node_modules` used to build once and never
|
|
328
|
+
rebuild. Vite's watcher cannot be made to deliver those events on Windows — no
|
|
329
|
+
spelling of the ignore-list negation reaches them, and `watcher.add()` does not
|
|
330
|
+
either — so the plugin watches those directories itself, on every platform.
|
|
331
|
+
|
|
265
332
|
## Watching, per target
|
|
266
333
|
|
|
267
334
|
Every target compiles tokens before the build that consumes them. What a later
|
|
@@ -273,6 +340,7 @@ on what the host bundler does with the watch list the plugin registers.
|
|
|
273
340
|
| **Vite** | yes | yes, under the dev server | yes |
|
|
274
341
|
| **Rollup** | yes | yes, under `rollup --watch` | yes |
|
|
275
342
|
| **Webpack** | yes | yes, under `webpack --watch` | yes |
|
|
343
|
+
| **Rspack** | yes | yes, under `rspack --watch` | yes |
|
|
276
344
|
| **Rolldown** | yes | platform-dependent — see below | yes |
|
|
277
345
|
|
|
278
346
|
Patterns and literal paths behave the same way wherever rebuilds happen at all.
|
|
@@ -287,12 +355,78 @@ reaches no hook, while on a Linux runner the same edit reaches a rebuild. Treat
|
|
|
287
355
|
rolldown's watch mode as compiling once and not tracking tokens, and reach for a
|
|
288
356
|
one-shot build or another target if you need rebuild-on-change.
|
|
289
357
|
|
|
358
|
+
**A token package resolved through `node_modules` is watched too, and that took
|
|
359
|
+
a fix.** In a workspace — `app/node_modules/@acme/tokens` symlinked to
|
|
360
|
+
`packages/tokens` — Vite's dev-server watcher is built with `**/node_modules/**`
|
|
361
|
+
already in its ignore list, and the entries a consumer adds are appended after
|
|
362
|
+
it rather than subtracted from it. So the first build was correct and no edit
|
|
363
|
+
ever rebuilt, with nothing printed to say so. The plugin now un-ignores exactly
|
|
364
|
+
the files it registers, by name, on Vite 6, 7 and 8. The rest of `node_modules`
|
|
365
|
+
stays ignored, which matters: handing the whole dependency tree to the watcher
|
|
366
|
+
is thousands of files no token build reads.
|
|
367
|
+
|
|
368
|
+
Nothing is needed from you for that. If you had worked around it with a
|
|
369
|
+
`server.watch.ignored` negation of your own, it still works — the plugin appends
|
|
370
|
+
to your list rather than replacing it.
|
|
371
|
+
|
|
290
372
|
"Safe from rebuild loops" is worth stating because consuming code imports the
|
|
291
373
|
generated file, so every regenerate is itself a change the host reacts to. The
|
|
292
374
|
plugin subtracts its own output from the watch list, skips recompiling when a
|
|
293
375
|
watch rebuild re-enters `buildStart`, and skips the write entirely when a
|
|
294
376
|
rebuild renders bytes identical to what is already on disk.
|
|
295
377
|
|
|
378
|
+
## Building Only Some Platforms
|
|
379
|
+
|
|
380
|
+
Every rebuild used to compile every platform, so a dev server serving a web app
|
|
381
|
+
paid for Objective-C headers, Android XML and Dart classes on every token save.
|
|
382
|
+
`platforms` narrows it:
|
|
383
|
+
|
|
384
|
+
```typescript
|
|
385
|
+
StyleDictionary({
|
|
386
|
+
config: 'sd.config.json',
|
|
387
|
+
// Build everything once, then rebuild only css while serving.
|
|
388
|
+
platforms: { watch: ['css'] },
|
|
389
|
+
})
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
Measured on a six-platform configuration (css, scss, js, ios, android, flutter),
|
|
393
|
+
with the timer around the build call alone:
|
|
394
|
+
|
|
395
|
+
| Tokens | All platforms | css only | Saved |
|
|
396
|
+
| ------ | ------------- | -------- | ------ |
|
|
397
|
+
| 500 | 12 ms | 1 ms | 10 ms |
|
|
398
|
+
| 3,000 | 36 ms | 2 ms | 34 ms |
|
|
399
|
+
| 10,000 | 103 ms | 4 ms | 99 ms |
|
|
400
|
+
| 30,000 | 330 ms | 12 ms | 319 ms |
|
|
401
|
+
|
|
402
|
+
An array — `platforms: ['css']` — applies to every build. The object form splits
|
|
403
|
+
the first compile from the watch rebuilds, and an omitted key means every
|
|
404
|
+
platform. A name the configuration does not define is an error, matching Style
|
|
405
|
+
Dictionary's own CLI.
|
|
406
|
+
|
|
407
|
+
**Unselected platforms keep whatever they last wrote.** Nothing removes or
|
|
408
|
+
refreshes their files, so scoping the `build` half ships stale output for the
|
|
409
|
+
rest. Scope `watch` unless that is what you want.
|
|
410
|
+
|
|
411
|
+
## Generated Output Is Disposable
|
|
412
|
+
|
|
413
|
+
Nothing removes a generated file, ever. Drop a `files` entry from a
|
|
414
|
+
configuration, remove a whole platform, or move a `buildPath`, and the old
|
|
415
|
+
output stays where it was — still resolving, still importable, still carrying
|
|
416
|
+
its old token values, and in a package build still published, with nothing in
|
|
417
|
+
the log mentioning it.
|
|
418
|
+
|
|
419
|
+
So treat the build directory as disposable: delete it when a configuration
|
|
420
|
+
changes shape, and keep it out of version control and out of any directory
|
|
421
|
+
holding hand-written files.
|
|
422
|
+
|
|
423
|
+
There is deliberately no `clean` option. Style Dictionary's
|
|
424
|
+
`cleanAllPlatforms()` does not solve this — it removes the destinations the
|
|
425
|
+
_current_ configuration declares, which are exactly the files that are not
|
|
426
|
+
orphans, and it removes the `buildPath` directory along with them. Measured:
|
|
427
|
+
after dropping `legacy.scss` from a configuration, a clean run left
|
|
428
|
+
`legacy.scss` standing and deleted `vars.css`, the file still in use.
|
|
429
|
+
|
|
296
430
|
## Skipping a Build That Would Change Nothing
|
|
297
431
|
|
|
298
432
|
A configuration whose output is already newer than everything it reads is not
|
|
@@ -340,8 +474,8 @@ and does not cache anything for later.
|
|
|
340
474
|
Two bases, and which one applies depends on whose path it is.
|
|
341
475
|
|
|
342
476
|
**The `config` option is the plugin's**, so a relative path is looked up under
|
|
343
|
-
the host's root: Vite's `root`, webpack's `context`, and the working
|
|
344
|
-
for rollup and rolldown, which report none. `root` overrides that.
|
|
477
|
+
the host's root: Vite's `root`, webpack's or rspack's `context`, and the working
|
|
478
|
+
directory for rollup and rolldown, which report none. `root` overrides that.
|
|
345
479
|
|
|
346
480
|
**Everything inside a Style Dictionary configuration is Style Dictionary's**, so
|
|
347
481
|
`source`, `include` and `buildPath` are resolved against the working directory.
|
|
@@ -399,13 +533,20 @@ own way:
|
|
|
399
533
|
| ------------------ | ------------------------ | ---------------------------------- |
|
|
400
534
|
| Vite | `config.logger.info` | `config.logger.error` |
|
|
401
535
|
| Rollup, Rolldown | the plugin context's log | the context's warning channel |
|
|
402
|
-
| Webpack
|
|
536
|
+
| Webpack, Rspack | the console | `compilation.warnings`, so `stats` |
|
|
403
537
|
| No host (one-shot) | the console | the console |
|
|
404
538
|
|
|
405
539
|
That is what makes a `customLogger` and `clearScreen` work under Vite, and what
|
|
406
540
|
puts a failed compile into `stats.toJson()` under webpack — where it reaches CI
|
|
407
541
|
annotations and anything else reading the build's own output.
|
|
408
542
|
|
|
543
|
+
**Rspack reformats what it is given, and webpack does not.** The plugin hands
|
|
544
|
+
both the same plain text; rspack wraps every diagnostic in its own frame — a `⚠`
|
|
545
|
+
marker and a `│` gutter — and colours that frame whenever it thinks colour is
|
|
546
|
+
wanted, which setting `CI` is enough to do. So a warning read out of rspack's
|
|
547
|
+
`stats` can carry ANSI escapes that came from rspack rather than from here.
|
|
548
|
+
Strip them before feeding that text to anything that expects plain output.
|
|
549
|
+
|
|
409
550
|
**A failure is reported as a warning, never on the host's error channel.**
|
|
410
551
|
Rollup's `this.error` aborts the bundle, so reporting a failure through it would
|
|
411
552
|
stop every build that reported one — taking the decision `failOnError` exists to
|
|
@@ -443,6 +584,19 @@ StyleDictionary({
|
|
|
443
584
|
})
|
|
444
585
|
```
|
|
445
586
|
|
|
587
|
+
**A configuration that resolves no tokens is a failure, not an empty build.**
|
|
588
|
+
Style Dictionary writes the destination with nothing in it and reports success,
|
|
589
|
+
so a token file deleted mid-session used to take the generated output down with
|
|
590
|
+
it, and a `source` matching nothing shipped an empty stylesheet from a build
|
|
591
|
+
that exited 0. The check runs before the compile, so the previous good output is
|
|
592
|
+
still on disk when it fires and nothing is overwritten. The message names the
|
|
593
|
+
configuration and the patterns that matched no files.
|
|
594
|
+
|
|
595
|
+
This is about the resolved token set, not about the patterns: a configuration
|
|
596
|
+
that supplies `tokens` inline and declares no `source` at all is valid and
|
|
597
|
+
builds. And it goes through `failOnError` like any other compile failure, so
|
|
598
|
+
`failOnError: false` reports it and carries on.
|
|
599
|
+
|
|
446
600
|
A failure is always reported by the plugin, whatever `failOnError` and `silent`
|
|
447
601
|
are set to — see [Where the messages go](#where-the-messages-go) for which
|
|
448
602
|
channel it arrives on, and for the one thing that can still suppress it.
|
|
@@ -497,14 +651,14 @@ the host stops, the other is that a build went wrong.
|
|
|
497
651
|
|
|
498
652
|
## Public API
|
|
499
653
|
|
|
500
|
-
Small on purpose.
|
|
654
|
+
Small on purpose. Five bundler entry points, one root entry, and two types.
|
|
501
655
|
|
|
502
|
-
| Import
|
|
503
|
-
|
|
|
504
|
-
| `…/vite`, `…/rolldown`, `…/rollup`, `…/webpack` | Default export: the plugin for that bundler. Call it with the options below.
|
|
505
|
-
| `…` (the root)
|
|
506
|
-
| `UnpluginStyleDictionaryOptions`
|
|
507
|
-
| `StyleDictionaryConfigContext`
|
|
656
|
+
| Import | What it is |
|
|
657
|
+
| ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
|
658
|
+
| `…/vite`, `…/rolldown`, `…/rollup`, `…/rspack`, `…/webpack` | Default export: the plugin for that bundler. Call it with the options below. |
|
|
659
|
+
| `…` (the root) | Default export, also named `unplugin`: the unplugin instance, carrying `.vite`, `.rolldown`, `.rollup`, `.rspack` and `.webpack`. |
|
|
660
|
+
| `UnpluginStyleDictionaryOptions` | The options type, exported from every entry above. |
|
|
661
|
+
| `StyleDictionaryConfigContext` | What the function form of `config` is handed, exported from every entry above. |
|
|
508
662
|
|
|
509
663
|
Anything not in that table is internal, whatever a build output happens to
|
|
510
664
|
contain. In particular the watch filter and the raw unplugin factory are not
|
|
@@ -524,7 +678,7 @@ const plugin = styleDictionary.rollup({ config: 'sd.config.json' })
|
|
|
524
678
|
|
|
525
679
|
## Options Reference
|
|
526
680
|
|
|
527
|
-
|
|
681
|
+
````typescript
|
|
528
682
|
/**
|
|
529
683
|
* Options for the Style Dictionary unplugin factory, shared across all bundler
|
|
530
684
|
* targets (Vite, Rolldown, Rollup, Webpack).
|
|
@@ -651,7 +805,19 @@ export interface UnpluginStyleDictionaryOptions {
|
|
|
651
805
|
*
|
|
652
806
|
* If not provided, the root directory is searched for 'sd.config.json',
|
|
653
807
|
* 'config.json', 'sd.config.js' and 'sd.config.mjs', in that order. The
|
|
654
|
-
* first one that
|
|
808
|
+
* first one that *looks like a Style Dictionary configuration* wins — it has
|
|
809
|
+
* to declare at least one of `platforms`, `source`, `include` or `tokens` —
|
|
810
|
+
* and the path it picked is announced, so which file a build used is
|
|
811
|
+
* answerable from the console. A candidate that fails that check is reported
|
|
812
|
+
* and skipped rather than adopted, because `config.json` is an extremely
|
|
813
|
+
* common name for something else entirely.
|
|
814
|
+
*
|
|
815
|
+
* **`false` turns discovery off.** Two of the four names are modules rather
|
|
816
|
+
* than data, and reading a module means running it: a `sd.config.js` in the
|
|
817
|
+
* root is imported, freshly, on every watch event. Validation cannot prevent
|
|
818
|
+
* that, because the check can only look at what the import returned — so a
|
|
819
|
+
* project that names its configuration explicitly, or has none, should say
|
|
820
|
+
* `config: false` rather than rely on there being nothing to find.
|
|
655
821
|
*/
|
|
656
822
|
config?:
|
|
657
823
|
| ((
|
|
@@ -659,6 +825,7 @@ export interface UnpluginStyleDictionaryOptions {
|
|
|
659
825
|
) => Config | Config[] | Promise<Config | Config[]>)
|
|
660
826
|
| Config
|
|
661
827
|
| Config[]
|
|
828
|
+
| false
|
|
662
829
|
| string
|
|
663
830
|
| string[]
|
|
664
831
|
|
|
@@ -780,6 +947,48 @@ export interface UnpluginStyleDictionaryOptions {
|
|
|
780
947
|
*/
|
|
781
948
|
onBuildStart?: () => Promise<void> | void
|
|
782
949
|
|
|
950
|
+
/**
|
|
951
|
+
* Which platforms to build, by the names the configuration defines.
|
|
952
|
+
*
|
|
953
|
+
* Every rebuild used to compile every platform. Measured on a six-platform
|
|
954
|
+
* configuration (css, scss, js, ios, android, flutter), with the timer around
|
|
955
|
+
* the build call alone:
|
|
956
|
+
*
|
|
957
|
+
* ```
|
|
958
|
+
* tokens all platforms css only saved
|
|
959
|
+
* 500 12 ms 1 ms 10 ms
|
|
960
|
+
* 3000 36 ms 2 ms 34 ms
|
|
961
|
+
* 10000 103 ms 4 ms 99 ms
|
|
962
|
+
* 30000 330 ms 12 ms 319 ms
|
|
963
|
+
* ```
|
|
964
|
+
*
|
|
965
|
+
* So a dev server serving a web app paid for Objective-C headers, Android
|
|
966
|
+
* XML and Dart classes on every token save, and the cost grows with the
|
|
967
|
+
* token count.
|
|
968
|
+
*
|
|
969
|
+
* Two shapes. An array selects the same platforms for every build. An object
|
|
970
|
+
* splits the first compile from the watch rebuilds, which is the common
|
|
971
|
+
* want — build everything once, then rebuild only what the page uses:
|
|
972
|
+
*
|
|
973
|
+
* ```typescript
|
|
974
|
+
* platforms: ['css']
|
|
975
|
+
* platforms: { watch: ['css'] }
|
|
976
|
+
* ```
|
|
977
|
+
*
|
|
978
|
+
* An omitted key means every platform, so `{ watch: ['css'] }` builds all of
|
|
979
|
+
* them once and then only css. A name the configuration does not define is an
|
|
980
|
+
* error, matching Style Dictionary's own CLI — "Must be defined in the
|
|
981
|
+
* config".
|
|
982
|
+
*
|
|
983
|
+
* **Unselected platforms keep whatever they last wrote.** Their files are not
|
|
984
|
+
* removed and not refreshed, so a one-shot build that scopes platforms ships
|
|
985
|
+
* stale output for the rest. Scope the watch half rather than the build half
|
|
986
|
+
* unless that is what you want.
|
|
987
|
+
*
|
|
988
|
+
* @default undefined, which builds every platform
|
|
989
|
+
*/
|
|
990
|
+
platforms?: string[] | { build?: string[]; watch?: string[] }
|
|
991
|
+
|
|
783
992
|
/**
|
|
784
993
|
* Whether the table of generated files and their sizes is produced.
|
|
785
994
|
*
|
|
@@ -843,7 +1052,7 @@ export interface UnpluginStyleDictionaryOptions {
|
|
|
843
1052
|
*/
|
|
844
1053
|
watch?: string | string[]
|
|
845
1054
|
}
|
|
846
|
-
|
|
1055
|
+
````
|
|
847
1056
|
|
|
848
1057
|
## Migrating from `vite-plugin-style-dictionary`
|
|
849
1058
|
|
|
@@ -864,6 +1073,68 @@ plugin. As of this unplugin-based rewrite:
|
|
|
864
1073
|
- Behavior under Vite is unchanged: the same `buildStart`-time compilation and
|
|
865
1074
|
dev-server watch/rebuild logic as before.
|
|
866
1075
|
|
|
1076
|
+
## Development
|
|
1077
|
+
|
|
1078
|
+
Fork, then clone the repository:
|
|
1079
|
+
|
|
1080
|
+
```shell
|
|
1081
|
+
git clone https://github.com/your-username/unplugin-style-dictionary.git
|
|
1082
|
+
```
|
|
1083
|
+
|
|
1084
|
+
Install with the Node version in [`.tool-versions`](.tool-versions). CI resolves
|
|
1085
|
+
it from that file, and an older npm rewrites `package-lock.json` as it installs.
|
|
1086
|
+
If `node --version` disagrees:
|
|
1087
|
+
|
|
1088
|
+
```shell
|
|
1089
|
+
mise exec node@"$(awk '/^nodejs/{print $2}' .tool-versions)" -- npm install
|
|
1090
|
+
```
|
|
1091
|
+
|
|
1092
|
+
### The four commands
|
|
1093
|
+
|
|
1094
|
+
These are what CI runs, and between them they are the whole gate:
|
|
1095
|
+
|
|
1096
|
+
```shell
|
|
1097
|
+
npm run lint # oxlint, then ESLint, then oxfmt --check
|
|
1098
|
+
npm run build # tsc -b, then tsdown into dist/
|
|
1099
|
+
npm test # vitest, one run, no watch
|
|
1100
|
+
npm run package:check # publint, attw, then scripts/check-package.mjs
|
|
1101
|
+
```
|
|
1102
|
+
|
|
1103
|
+
`npm run package:check` reads `dist/`, so it needs a build first.
|
|
1104
|
+
`npm run peers:check` is the slower one that packs the tarball and builds it
|
|
1105
|
+
against both ends of every declared peer range; `Build` runs it, and it is worth
|
|
1106
|
+
running locally when you touch the exports map or the peer declarations.
|
|
1107
|
+
|
|
1108
|
+
**oxfmt formats this repository, not Prettier**, and it covers Markdown, JSON
|
|
1109
|
+
and YAML as well as TypeScript. `npm run lint -- --fix` will not reformat
|
|
1110
|
+
anything — reach for `npm run format`.
|
|
1111
|
+
|
|
1112
|
+
### Tests
|
|
1113
|
+
|
|
1114
|
+
`tests/` drives real bundlers against real files in temporary directories rather
|
|
1115
|
+
than mocking Style Dictionary: a real Vite dev server, a real `rollup.watch()`,
|
|
1116
|
+
a real `webpack()` compile, a real `rspack()` compile, and all five targets
|
|
1117
|
+
through their own entry points. A new hook needs a matching caller in
|
|
1118
|
+
`tests/index.test.ts` — calling one bare leaves `this` undefined and the failure
|
|
1119
|
+
reads as a plugin bug.
|
|
1120
|
+
|
|
1121
|
+
The suite prints nothing. If you add a test that provokes the plugin's failure
|
|
1122
|
+
report, spy on `console.error`, **assert the message is there**, and restore in
|
|
1123
|
+
a `finally`. You can check the whole suite is quiet with:
|
|
1124
|
+
|
|
1125
|
+
```shell
|
|
1126
|
+
npx vitest run --reporter=verbose 2>&1 | grep -E '^std(out|err) \|'
|
|
1127
|
+
```
|
|
1128
|
+
|
|
1129
|
+
That should print nothing.
|
|
1130
|
+
|
|
1131
|
+
[`AGENTS.md`](AGENTS.md) carries the conventions, the traps, and the reasoning
|
|
1132
|
+
behind both. It is written for coding agents and is equally the fullest thing a
|
|
1133
|
+
human contributor can read.
|
|
1134
|
+
|
|
1135
|
+
Contribution guidelines for the organization are in
|
|
1136
|
+
[`kanso-labs/.github`](https://github.com/kanso-labs/.github).
|
|
1137
|
+
|
|
867
1138
|
## License
|
|
868
1139
|
|
|
869
1140
|
MIT
|
|
@@ -875,7 +1146,7 @@ MIT
|
|
|
875
1146
|
[codecov]: https://codecov.io/gh/kanso-labs/unplugin-style-dictionary
|
|
876
1147
|
[coverage-shield]:
|
|
877
1148
|
https://img.shields.io/codecov/c/github/kanso-labs/unplugin-style-dictionary?label=Coverage
|
|
878
|
-
[license]: ./LICENSE
|
|
1149
|
+
[license]: ./LICENSE.md
|
|
879
1150
|
[license-shield]:
|
|
880
1151
|
https://img.shields.io/github/license/kanso-labs/unplugin-style-dictionary
|
|
881
1152
|
[npm]: https://www.npmjs.com/package/@kanso-labs/unplugin-style-dictionary
|