@zslabs/atomic-css-modules 0.1.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/GUIDE.md +32 -0
  3. package/LICENSE +21 -0
  4. package/README.md +121 -0
  5. package/dist/atom-key.d.ts +19 -0
  6. package/dist/atom-key.js +72 -0
  7. package/dist/atom-key.js.map +1 -0
  8. package/dist/atoms.d.ts +8 -0
  9. package/dist/atoms.js +33 -0
  10. package/dist/atoms.js.map +1 -0
  11. package/dist/declaration-utils.d.ts +37 -0
  12. package/dist/declaration-utils.js +99 -0
  13. package/dist/declaration-utils.js.map +1 -0
  14. package/dist/file-scan-cache.d.ts +21 -0
  15. package/dist/file-scan-cache.js +122 -0
  16. package/dist/file-scan-cache.js.map +1 -0
  17. package/dist/hash.d.ts +15 -0
  18. package/dist/hash.js +38 -0
  19. package/dist/hash.js.map +1 -0
  20. package/dist/index.d.ts +9 -0
  21. package/dist/index.js +9 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/process.d.ts +2 -0
  24. package/dist/process.js +19 -0
  25. package/dist/process.js.map +1 -0
  26. package/dist/registry.d.ts +3 -0
  27. package/dist/registry.js +107 -0
  28. package/dist/registry.js.map +1 -0
  29. package/dist/report.d.ts +7 -0
  30. package/dist/report.js +67 -0
  31. package/dist/report.js.map +1 -0
  32. package/dist/rewrite.d.ts +2 -0
  33. package/dist/rewrite.js +482 -0
  34. package/dist/rewrite.js.map +1 -0
  35. package/dist/rule-context.d.ts +35 -0
  36. package/dist/rule-context.js +86 -0
  37. package/dist/rule-context.js.map +1 -0
  38. package/dist/scan.d.ts +2 -0
  39. package/dist/scan.js +177 -0
  40. package/dist/scan.js.map +1 -0
  41. package/dist/selector-utils.d.ts +34 -0
  42. package/dist/selector-utils.js +156 -0
  43. package/dist/selector-utils.js.map +1 -0
  44. package/dist/shorthand-groups.d.ts +7 -0
  45. package/dist/shorthand-groups.js +85 -0
  46. package/dist/shorthand-groups.js.map +1 -0
  47. package/dist/skip-comment.d.ts +6 -0
  48. package/dist/skip-comment.js +48 -0
  49. package/dist/skip-comment.js.map +1 -0
  50. package/dist/types.d.ts +152 -0
  51. package/dist/types.js +14 -0
  52. package/dist/types.js.map +1 -0
  53. package/dist/vite-plugin.d.ts +27 -0
  54. package/dist/vite-plugin.js +231 -0
  55. package/dist/vite-plugin.js.map +1 -0
  56. package/package.json +75 -0
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Shared types for the atomic CSS Modules pipeline.
3
+ */
4
+ import type { ContainerCondition, Declaration, MediaList, MediaQuery, Selector, SelectorComponent, SelectorList, SupportsCondition } from 'lightningcss';
5
+ /** One at-rule a declaration was nested in, outermost first. */
6
+ export type AtomWrapper = {
7
+ kind: 'media';
8
+ query: MediaList<MediaQuery>;
9
+ } | {
10
+ kind: 'container';
11
+ name: string | null;
12
+ condition: ContainerCondition<Declaration> | null;
13
+ } | {
14
+ kind: 'supports';
15
+ condition: SupportsCondition;
16
+ } | {
17
+ kind: 'layer';
18
+ name: string[] | null;
19
+ } | {
20
+ kind: 'scope';
21
+ scopeStart: SelectorList | null;
22
+ scopeEnd: SelectorList | null;
23
+ } | {
24
+ kind: 'starting-style';
25
+ };
26
+ /** At-rule wrappers around a declaration. Empty means the declaration is unconditioned. */
27
+ export type AtomCondition = AtomWrapper[];
28
+ export declare function isBareCondition(condition: AtomCondition): boolean;
29
+ /** A single simple pseudo-class/pseudo-element that an atom's selector carries, kept as the real parsed component so it can be reprinted verbatim. */
30
+ export type AtomPseudo = SelectorComponent & {
31
+ type: 'pseudo-class' | 'pseudo-element';
32
+ };
33
+ /** Uniquely identifies one shareable atomic declaration group. */
34
+ export interface AtomKey {
35
+ property: string;
36
+ /** JSON-stable fingerprint of the declaration's value, used for grouping/hashing. */
37
+ valueFingerprint: string;
38
+ important: boolean;
39
+ pseudo: AtomPseudo | null;
40
+ condition: AtomCondition;
41
+ }
42
+ /** A collected atom: one declaration, shared across every rule that produced it. */
43
+ export interface Atom {
44
+ hash: string;
45
+ className: string;
46
+ key: AtomKey;
47
+ /** Cached {@link atomKeyString} for this key — avoid re-stringifying on lookup. */
48
+ keyString: string;
49
+ declaration: Declaration;
50
+ }
51
+ /** Registry of every atom collected while scanning a set of CSS module files. */
52
+ export interface AtomRegistry {
53
+ /** Keyed by a stable string derived from AtomKey. */
54
+ atoms: Map<string, Atom>;
55
+ }
56
+ /** One CSS module source file to process. */
57
+ export interface SourceFile {
58
+ filePath: string;
59
+ code: string;
60
+ }
61
+ /** Result of rewriting a single source file. */
62
+ export interface RewrittenFile {
63
+ filePath: string;
64
+ code: string;
65
+ /** True if anything in the file was changed. */
66
+ changed: boolean;
67
+ /** JSON source map when {@link ProcessOptions.sourceMap} is enabled. */
68
+ map?: string;
69
+ }
70
+ export declare const SKIP_REASONS: readonly ['combinator', 'compound', 'element', 'mixed-group', 'functional-pseudo', 'chained-pseudo', 'shorthand-conflict', 'skip-comment'];
71
+ export type SkipReason = (typeof SKIP_REASONS)[number];
72
+ /** One rule or declaration that was not atomized. */
73
+ export interface AtomizationSkip {
74
+ filePath: string;
75
+ selector: string;
76
+ reason: SkipReason;
77
+ }
78
+ /** Counts from one scan + registry pass. */
79
+ export interface AtomizationReport {
80
+ files: number;
81
+ atoms: number;
82
+ skippedRules: number;
83
+ bytesIn: number;
84
+ registryBytes: number;
85
+ skips: AtomizationSkip[];
86
+ }
87
+ /** Result of the full scan + rewrite pipeline. */
88
+ export interface ProcessResult {
89
+ files: RewrittenFile[];
90
+ /** Generated CSS for the shared atomic registry. Empty string if no atoms were found. */
91
+ registryCss: string;
92
+ report: AtomizationReport;
93
+ }
94
+ export interface ProcessOptions {
95
+ /**
96
+ * The path (as it should appear in generated `composes: ... from "<path>"`
97
+ * references) to the atomic registry file. Relative import specifiers are
98
+ * used as-is. Ignored when {@link composeFrom} is `"global"`.
99
+ */
100
+ registryImportPath: string;
101
+ /**
102
+ * `"file"` emits `composes: ... from "<registryImportPath>"`.
103
+ * `"global"` emits `composes: ... from global` so the bundler does not
104
+ * clone the registry into every CSS module.
105
+ */
106
+ composeFrom?: 'file' | 'global';
107
+ /** When true, rewritten files include a JSON source map. */
108
+ sourceMap?: boolean;
109
+ /** When true, atom class names use a readable slug plus a short key hash (`color-red-a1b2c3`) instead of production hashes. */
110
+ debugNames?: boolean;
111
+ }
112
+ /** Per-declaration decision recorded during scan for plan-driven rewrite. */
113
+ export type DeclDecision = {
114
+ action: 'composes';
115
+ } | {
116
+ action: 'keep';
117
+ important: boolean;
118
+ } | {
119
+ action: 'hoist';
120
+ atomKey: string;
121
+ };
122
+ /** Per-rule bookkeeping produced while scanning one file. */
123
+ export interface ScanRuleInfo {
124
+ eligible: boolean;
125
+ condition: AtomCondition;
126
+ pseudo: AtomPseudo | null;
127
+ /** True when this rule is nested inside another style rule. */
128
+ nested: boolean;
129
+ /** The selector actually used to atomize (pseudo stripped, if any). Empty when ineligible. */
130
+ selector: Selector;
131
+ /** Atom key strings (see {@link atomKeyString}) for this rule's hoisted decls, document order. */
132
+ atomKeys: string[];
133
+ /**
134
+ * Class names for {@link atomKeys}, resolved from the atom map.
135
+ * Kept in sync when names are remapped for global uniqueness.
136
+ */
137
+ atomHashes: string[];
138
+ /**
139
+ * Ordered decisions matching {@link flattenDeclarations} for this rule.
140
+ * Empty when ineligible.
141
+ */
142
+ decisions: DeclDecision[];
143
+ }
144
+ export interface ScanFileResult {
145
+ filePath: string;
146
+ rules: ScanRuleInfo[];
147
+ }
148
+ export interface ScanResult {
149
+ atoms: Map<string, Atom>;
150
+ files: ScanFileResult[];
151
+ skips: AtomizationSkip[];
152
+ }
package/dist/types.js ADDED
@@ -0,0 +1,14 @@
1
+ export function isBareCondition(condition) {
2
+ return condition.length === 0;
3
+ }
4
+ export const SKIP_REASONS = [
5
+ 'combinator',
6
+ 'compound',
7
+ 'element',
8
+ 'mixed-group',
9
+ 'functional-pseudo',
10
+ 'chained-pseudo',
11
+ 'shorthand-conflict',
12
+ 'skip-comment',
13
+ ];
14
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAkCA,MAAM,UAAU,eAAe,CAAC,SAAwB;IACtD,OAAO,SAAS,CAAC,MAAM,KAAK,CAAC,CAAA;AAC/B,CAAC;AAiDD,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,YAAY;IACZ,UAAU;IACV,SAAS;IACT,aAAa;IACb,mBAAmB;IACnB,gBAAgB;IAChB,oBAAoB;IACpB,cAAc;CACN,CAAA"}
@@ -0,0 +1,27 @@
1
+ import type { Plugin } from 'vite';
2
+ export declare const ATOMIC_REGISTRY_ID = "virtual:atomic-registry.css";
3
+ export declare const RESOLVED_ATOMIC_REGISTRY_ID = "\0virtual:atomic-registry.css";
4
+ export interface AtomicCssModulesPluginOptions {
5
+ /** Glob(s), relative to the Vite project root, matching CSS Modules files to atomize. */
6
+ include?: string | string[];
7
+ /** Glob(s), relative to the Vite project root, to exclude. */
8
+ exclude?: string | string[];
9
+ /**
10
+ * Readable atom names (`color-red-a1b2c3`) instead of production hashes.
11
+ * The trailing key hash keeps different at-rule conditions from colliding.
12
+ * Defaults to true in `vite serve` and false in `vite build`.
13
+ */
14
+ debugNames?: boolean;
15
+ /**
16
+ * `"verbose"` also lists each skipped selector after the buildStart summary.
17
+ * Defaults to `"summary"`.
18
+ */
19
+ report?: 'summary' | 'verbose';
20
+ /**
21
+ * Rewrite CSS before scan/atomize (e.g. expand design-token at-rules).
22
+ * Runs for disk sync, HMR, and transform so the registry and rewrites see
23
+ * the same expanded source.
24
+ */
25
+ preprocess?: (code: string, filePath: string) => string;
26
+ }
27
+ export declare function atomicCssModules(options?: AtomicCssModulesPluginOptions): Plugin;
@@ -0,0 +1,231 @@
1
+ /**
2
+ * Vite plugin wrapper around the core atomic CSS Modules pipeline.
3
+ *
4
+ * Each matching file is scanned into a content-hash cache, then rewritten
5
+ * independently. The shared registry is rematerialized from that cache as
6
+ * `virtual:atomic-registry.css` so it is not written to disk or cloned
7
+ * into every CSS module.
8
+ */
9
+ import { promises as fs } from 'node:fs';
10
+ import path from 'node:path';
11
+ import { FileScanCache } from './file-scan-cache.js';
12
+ import { formatAtomizationReport } from './report.js';
13
+ import { rewriteFiles } from './rewrite.js';
14
+ export const ATOMIC_REGISTRY_ID = 'virtual:atomic-registry.css';
15
+ export const RESOLVED_ATOMIC_REGISTRY_ID = `\0${ATOMIC_REGISTRY_ID}`;
16
+ const DEFAULT_INCLUDE = ['**/*.module.css'];
17
+ const DEFAULT_EXCLUDE = ['**/node_modules/**'];
18
+ function isJsModule(filePath) {
19
+ return /\.[cm]?[jt]sx?$/.test(filePath);
20
+ }
21
+ function matchesAny(filePath, patterns) {
22
+ return patterns.some((pattern) => path.matchesGlob(filePath, pattern));
23
+ }
24
+ function isVirtualRegistry(filename) {
25
+ return filename.replace(/\\/g, '/').includes(ATOMIC_REGISTRY_ID);
26
+ }
27
+ function cssContentHash(css) {
28
+ let hash = 5381;
29
+ for (let i = css.length - 1; i >= 0; i--) {
30
+ hash = Math.imul(hash, 33) ^ css.charCodeAt(i);
31
+ }
32
+ return hash >>> 0;
33
+ }
34
+ /** Same shape as Vite's default `_[local]_[hash]_[line]` generator. */
35
+ function defaultScopedName(name, _filename, css) {
36
+ const index = css.indexOf(`.${name}`);
37
+ const lineNumber = css
38
+ .slice(0, index === -1 ? 0 : index)
39
+ .split(/\r?\n/).length;
40
+ return `_${name}_${cssContentHash(css).toString(36).slice(0, 5)}_${lineNumber}`;
41
+ }
42
+ /**
43
+ * Applies a postcss-modules / Vite string pattern such as `[name]__[local]`.
44
+ * Unknown placeholders are left intact.
45
+ */
46
+ function interpolateScopedName(pattern, local, filename, css) {
47
+ const parsed = path.parse(filename);
48
+ const hash = cssContentHash(css);
49
+ return pattern.replace(/\[([^\]]+)\]/g, (original, token) => {
50
+ if (token === 'local')
51
+ return local;
52
+ if (token === 'name')
53
+ return parsed.name;
54
+ if (token === 'folder')
55
+ return path.basename(parsed.dir);
56
+ if (token === 'path')
57
+ return parsed.dir;
58
+ if (token === 'file')
59
+ return parsed.base;
60
+ if (token === 'ext')
61
+ return parsed.ext.replace(/^\./, '');
62
+ const hashMatch = /^hash(?::([a-z0-9]+))?(?::(\d+))?$/.exec(token);
63
+ if (!hashMatch)
64
+ return original;
65
+ const encoding = hashMatch[1] ?? 'base64';
66
+ const encoded = encoding === 'hex' ? hash.toString(16) : hash.toString(36);
67
+ return hashMatch[2] ? encoded.slice(0, Number(hashMatch[2])) : encoded;
68
+ });
69
+ }
70
+ const VIRTUAL_REGISTRY_IDS = [
71
+ RESOLVED_ATOMIC_REGISTRY_ID,
72
+ `${RESOLVED_ATOMIC_REGISTRY_ID}?raw`,
73
+ ];
74
+ export function atomicCssModules(options = {}) {
75
+ const includePatterns = options.include
76
+ ? [options.include].flat()
77
+ : DEFAULT_INCLUDE;
78
+ const excludePatterns = options.exclude
79
+ ? [options.exclude].flat()
80
+ : DEFAULT_EXCLUDE;
81
+ let root = process.cwd();
82
+ let debugNames = false;
83
+ let registryCss = '';
84
+ const cache = new FileScanCache();
85
+ const preprocess = options.preprocess;
86
+ function prepareSource(filePath, code) {
87
+ return {
88
+ filePath,
89
+ code: preprocess === undefined ? code : preprocess(code, filePath),
90
+ };
91
+ }
92
+ function publishSnapshot() {
93
+ const snap = cache.snapshot();
94
+ registryCss = snap.registryCss;
95
+ return snap;
96
+ }
97
+ async function syncFromDisk() {
98
+ const matches = fs.glob(includePatterns, {
99
+ cwd: root,
100
+ exclude: excludePatterns,
101
+ });
102
+ const filePaths = [];
103
+ for await (const match of matches)
104
+ filePaths.push(path.resolve(root, match));
105
+ cache.retain(filePaths);
106
+ await Promise.all(filePaths.map(async (filePath) => {
107
+ const code = await fs.readFile(filePath, 'utf8');
108
+ cache.update(prepareSource(filePath, code));
109
+ }));
110
+ return publishSnapshot();
111
+ }
112
+ async function applyFileChange(filePath) {
113
+ try {
114
+ const code = await fs.readFile(filePath, 'utf8');
115
+ cache.update(prepareSource(filePath, code));
116
+ }
117
+ catch {
118
+ cache.remove(filePath);
119
+ }
120
+ publishSnapshot();
121
+ }
122
+ function isMatchingCssModule(file) {
123
+ const relativeId = path.relative(root, file);
124
+ return (matchesAny(relativeId, includePatterns) &&
125
+ !matchesAny(relativeId, excludePatterns));
126
+ }
127
+ return {
128
+ name: 'atomic-css-modules',
129
+ enforce: 'pre',
130
+ config(userConfig) {
131
+ const modules = userConfig.css?.modules;
132
+ if (modules === false)
133
+ return;
134
+ const existingPaths = modules?.globalModulePaths ?? [];
135
+ const existingScoped = modules?.generateScopedName;
136
+ return {
137
+ css: {
138
+ modules: {
139
+ globalModulePaths: [
140
+ ...existingPaths,
141
+ new RegExp(`${ATOMIC_REGISTRY_ID.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`),
142
+ ],
143
+ generateScopedName(name, filename, css) {
144
+ if (isVirtualRegistry(filename))
145
+ return name;
146
+ if (typeof existingScoped === 'function') {
147
+ return existingScoped(name, filename, css);
148
+ }
149
+ if (typeof existingScoped === 'string') {
150
+ return interpolateScopedName(existingScoped, name, filename, css);
151
+ }
152
+ return defaultScopedName(name, filename, css);
153
+ },
154
+ },
155
+ },
156
+ };
157
+ },
158
+ configResolved(config) {
159
+ root = config.root;
160
+ debugNames = options.debugNames ?? config.command === 'serve';
161
+ cache.setDebugNames(debugNames);
162
+ },
163
+ resolveId(id) {
164
+ const clean = id.split('?')[0];
165
+ if (clean !== ATOMIC_REGISTRY_ID)
166
+ return undefined;
167
+ return id.includes('?') ? `\0${id}` : RESOLVED_ATOMIC_REGISTRY_ID;
168
+ },
169
+ load(id) {
170
+ if (!id.startsWith(RESOLVED_ATOMIC_REGISTRY_ID))
171
+ return undefined;
172
+ if (id.includes('?raw'))
173
+ return `export default ${JSON.stringify(registryCss)}`;
174
+ return registryCss;
175
+ },
176
+ async buildStart() {
177
+ const { report } = await syncFromDisk();
178
+ this.info(formatAtomizationReport(report, {
179
+ verbose: options.report === 'verbose',
180
+ root,
181
+ }));
182
+ },
183
+ configureServer(server) {
184
+ for (const pattern of includePatterns) {
185
+ server.watcher.add(path.resolve(root, pattern));
186
+ }
187
+ },
188
+ async hotUpdate(options) {
189
+ if (!isMatchingCssModule(options.file))
190
+ return;
191
+ await applyFileChange(options.file);
192
+ const extra = [];
193
+ for (const virtualId of VIRTUAL_REGISTRY_IDS) {
194
+ const mod = this.environment.moduleGraph.getModuleById(virtualId);
195
+ if (!mod)
196
+ continue;
197
+ this.environment.moduleGraph.invalidateModule(mod);
198
+ extra.push(mod);
199
+ }
200
+ return [...options.modules, ...extra];
201
+ },
202
+ transform(code, id) {
203
+ const cleanId = id.split('?')[0] ?? id;
204
+ if (isJsModule(cleanId) && code.includes('.module.css')) {
205
+ if (code.includes(ATOMIC_REGISTRY_ID))
206
+ return null;
207
+ return { code: `import ${JSON.stringify(ATOMIC_REGISTRY_ID)}\n${code}` };
208
+ }
209
+ const relativeId = path.relative(root, cleanId);
210
+ if (!matchesAny(relativeId, includePatterns) ||
211
+ matchesAny(relativeId, excludePatterns))
212
+ return null;
213
+ const source = prepareSource(cleanId, code);
214
+ if (cache.update(source))
215
+ publishSnapshot();
216
+ const scan = cache.getScan(cleanId);
217
+ if (!scan)
218
+ return null;
219
+ const [file] = rewriteFiles([source], [scan], {
220
+ registryImportPath: ATOMIC_REGISTRY_ID,
221
+ composeFrom: 'global',
222
+ sourceMap: true,
223
+ debugNames,
224
+ }, cache.getAtoms());
225
+ if (!file || !file.changed)
226
+ return null;
227
+ return { code: file.code, map: file.map };
228
+ },
229
+ };
230
+ }
231
+ //# sourceMappingURL=vite-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite-plugin.js","sourceRoot":"","sources":["../src/vite-plugin.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,75 @@
1
+ {
2
+ "name": "@zslabs/atomic-css-modules",
3
+ "version": "0.1.0",
4
+ "description": "Extract repeated CSS Modules declarations into shared atomic classes",
5
+ "keywords": [
6
+ "atomic-css",
7
+ "css-modules",
8
+ "vite",
9
+ "vite-plugin"
10
+ ],
11
+ "homepage": "https://github.com/zslabs/atomic-css-modules/tree/main/packages/atomic-css-modules#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/zslabs/atomic-css-modules/issues"
14
+ },
15
+ "license": "MIT",
16
+ "author": "Zach Schnackel <info@zslabs.com>",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/zslabs/atomic-css-modules.git",
20
+ "directory": "packages/atomic-css-modules"
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "GUIDE.md",
25
+ "CHANGELOG.md",
26
+ "LICENSE",
27
+ "README.md"
28
+ ],
29
+ "type": "module",
30
+ "main": "dist/index.js",
31
+ "types": "dist/index.d.ts",
32
+ "exports": {
33
+ ".": {
34
+ "types": "./dist/index.d.ts",
35
+ "import": "./dist/index.js"
36
+ },
37
+ "./vite": {
38
+ "types": "./dist/vite-plugin.d.ts",
39
+ "import": "./dist/vite-plugin.js"
40
+ }
41
+ },
42
+ "publishConfig": {
43
+ "access": "public"
44
+ },
45
+ "scripts": {
46
+ "prepack": "npm run build",
47
+ "build": "tsc -p tsconfig.json",
48
+ "type:check": "tsc --project tsconfig.json --pretty --noEmit",
49
+ "test": "vitest run",
50
+ "test:watch": "vitest",
51
+ "bench": "vitest run --config vitest.bench.config.ts --reporter=verbose",
52
+ "dump-registry": "node --experimental-strip-types ./scripts/dump-registry.ts"
53
+ },
54
+ "dependencies": {
55
+ "lightningcss": "1.33.0",
56
+ "mdn-data": "2.37.0"
57
+ },
58
+ "devDependencies": {
59
+ "@types/node": "26.6.2",
60
+ "typescript": "7.0.2",
61
+ "vite": "8.3.1",
62
+ "vitest": "5.0.1"
63
+ },
64
+ "peerDependencies": {
65
+ "vite": "^8.0.0"
66
+ },
67
+ "peerDependenciesMeta": {
68
+ "vite": {
69
+ "optional": true
70
+ }
71
+ },
72
+ "engines": {
73
+ "node": "^20.17.0 || >=22.5.0"
74
+ }
75
+ }