@cloudwerk/vite-plugin 0.6.1 → 0.6.3
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/dist/index.d.ts +32 -3
- package/dist/index.js +161 -16
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Plugin } from 'vite';
|
|
2
|
-
import { CloudwerkConfig,
|
|
2
|
+
import { CloudwerkConfig, QueueManifest, ServiceManifest, RouteManifest, ScanResult } from '@cloudwerk/core/build';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @cloudwerk/vite-plugin - Types
|
|
@@ -96,6 +96,17 @@ interface ClientComponentInfo {
|
|
|
96
96
|
/** Absolute file path */
|
|
97
97
|
absolutePath: string;
|
|
98
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Information about a CSS import detected in a layout or page.
|
|
101
|
+
*/
|
|
102
|
+
interface CssImportInfo {
|
|
103
|
+
/** Absolute path to the CSS file */
|
|
104
|
+
absolutePath: string;
|
|
105
|
+
/** File that imports the CSS */
|
|
106
|
+
importedBy: string;
|
|
107
|
+
/** Whether the importing file is a layout */
|
|
108
|
+
isLayout: boolean;
|
|
109
|
+
}
|
|
99
110
|
/**
|
|
100
111
|
* Virtual module IDs used by the plugin.
|
|
101
112
|
*/
|
|
@@ -150,6 +161,20 @@ declare function cloudwerkPlugin(options?: CloudwerkVitePluginOptions): Plugin;
|
|
|
150
161
|
* a Hono app with all routes registered from the file-based routing manifest.
|
|
151
162
|
*/
|
|
152
163
|
|
|
164
|
+
/**
|
|
165
|
+
* Asset manifest entry from Vite build.
|
|
166
|
+
*/
|
|
167
|
+
interface AssetManifestEntry {
|
|
168
|
+
file: string;
|
|
169
|
+
css?: string[];
|
|
170
|
+
assets?: string[];
|
|
171
|
+
isEntry?: boolean;
|
|
172
|
+
isDynamicEntry?: boolean;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Asset manifest from Vite build (maps source to output files).
|
|
176
|
+
*/
|
|
177
|
+
type AssetManifest = Record<string, AssetManifestEntry>;
|
|
153
178
|
/**
|
|
154
179
|
* Options for generating server entry.
|
|
155
180
|
*/
|
|
@@ -158,6 +183,8 @@ interface GenerateServerEntryOptions {
|
|
|
158
183
|
queueManifest?: QueueManifest | null;
|
|
159
184
|
/** Service manifest if services are configured */
|
|
160
185
|
serviceManifest?: ServiceManifest | null;
|
|
186
|
+
/** Asset manifest from Vite build for CSS injection */
|
|
187
|
+
assetManifest?: AssetManifest | null;
|
|
161
188
|
}
|
|
162
189
|
/**
|
|
163
190
|
* Generate the server entry module code.
|
|
@@ -187,14 +214,16 @@ declare function generateServerEntry(manifest: RouteManifest, scanResult: ScanRe
|
|
|
187
214
|
* Generate the client entry module code.
|
|
188
215
|
*
|
|
189
216
|
* This creates a hydration bootstrap that:
|
|
217
|
+
* - Imports CSS files from layouts and pages
|
|
190
218
|
* - Finds all elements with data-hydrate-id attributes
|
|
191
219
|
* - Dynamically imports the corresponding component bundles
|
|
192
220
|
* - Hydrates each component with its serialized props
|
|
193
221
|
*
|
|
194
222
|
* @param clientComponents - Map of detected client components
|
|
223
|
+
* @param cssImports - Map of CSS imports from layouts and pages
|
|
195
224
|
* @param options - Resolved plugin options
|
|
196
225
|
* @returns Generated JavaScript code
|
|
197
226
|
*/
|
|
198
|
-
declare function generateClientEntry(clientComponents: Map<string, ClientComponentInfo>, options: ResolvedCloudwerkOptions): string;
|
|
227
|
+
declare function generateClientEntry(clientComponents: Map<string, ClientComponentInfo>, cssImports: Map<string, CssImportInfo[]>, options: ResolvedCloudwerkOptions): string;
|
|
199
228
|
|
|
200
|
-
export { type ClientComponentInfo, type CloudwerkVitePluginOptions, RESOLVED_VIRTUAL_IDS, type ResolvedCloudwerkOptions, VIRTUAL_MODULE_IDS, cloudwerkPlugin, cloudwerkPlugin as default, generateClientEntry, generateServerEntry };
|
|
229
|
+
export { type AssetManifest, type AssetManifestEntry, type ClientComponentInfo, type CloudwerkVitePluginOptions, type CssImportInfo, type GenerateServerEntryOptions, RESOLVED_VIRTUAL_IDS, type ResolvedCloudwerkOptions, VIRTUAL_MODULE_IDS, cloudwerkPlugin, cloudwerkPlugin as default, generateClientEntry, generateServerEntry };
|
package/dist/index.js
CHANGED
|
@@ -39,6 +39,7 @@ import * as path from "path";
|
|
|
39
39
|
function generateServerEntry(manifest, scanResult, options, entryOptions) {
|
|
40
40
|
const queueManifest = entryOptions?.queueManifest;
|
|
41
41
|
const serviceManifest = entryOptions?.serviceManifest;
|
|
42
|
+
const assetManifest = entryOptions?.assetManifest;
|
|
42
43
|
const imports = [];
|
|
43
44
|
const pageRegistrations = [];
|
|
44
45
|
const routeRegistrations = [];
|
|
@@ -139,6 +140,18 @@ function generateServerEntry(manifest, scanResult, options, entryOptions) {
|
|
|
139
140
|
}
|
|
140
141
|
const rendererName = options.renderer;
|
|
141
142
|
const clientEntryPath = options.isProduction ? `${options.hydrationEndpoint}/client.js` : "/@id/__x00__virtual:cloudwerk/client-entry";
|
|
143
|
+
let cssLinksCode = "";
|
|
144
|
+
if (options.isProduction && assetManifest) {
|
|
145
|
+
const clientEntry = assetManifest["virtual:cloudwerk/client-entry"];
|
|
146
|
+
if (clientEntry?.css && clientEntry.css.length > 0) {
|
|
147
|
+
const cssLinks = clientEntry.css.map((css) => `<link rel="stylesheet" href="/${css}" />`).join("");
|
|
148
|
+
cssLinksCode = `const CSS_LINKS = '${cssLinks}'`;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (!cssLinksCode) {
|
|
152
|
+
cssLinksCode = `const CSS_LINKS = ''`;
|
|
153
|
+
}
|
|
154
|
+
const viteClientScript = options.isProduction ? "" : '<script type="module" src="/@vite/client"></script>';
|
|
142
155
|
return `/**
|
|
143
156
|
* Generated Cloudwerk Server Entry
|
|
144
157
|
* This file is auto-generated by @cloudwerk/vite-plugin - do not edit
|
|
@@ -176,6 +189,16 @@ const notFoundBoundaryMap = new Map([
|
|
|
176
189
|
${notFoundBoundaryMapEntries.join(",\n")}
|
|
177
190
|
])
|
|
178
191
|
|
|
192
|
+
// ============================================================================
|
|
193
|
+
// Asset Injection Configuration
|
|
194
|
+
// ============================================================================
|
|
195
|
+
|
|
196
|
+
// CSS links from asset manifest (production) or empty (dev - CSS served by Vite)
|
|
197
|
+
${cssLinksCode}
|
|
198
|
+
|
|
199
|
+
// Vite client script for HMR (dev only)
|
|
200
|
+
const VITE_CLIENT = '${viteClientScript}'
|
|
201
|
+
|
|
179
202
|
// ============================================================================
|
|
180
203
|
// Helper Functions
|
|
181
204
|
// ============================================================================
|
|
@@ -395,20 +418,34 @@ function registerPage(app, pattern, pageModule, layoutModules, middlewareModules
|
|
|
395
418
|
}
|
|
396
419
|
|
|
397
420
|
/**
|
|
398
|
-
* Render element to a Response, injecting
|
|
421
|
+
* Render element to a Response, injecting CSS and scripts.
|
|
422
|
+
* - CSS links are injected before </head>
|
|
423
|
+
* - Vite client (dev) and hydration script are injected before </body>
|
|
399
424
|
*/
|
|
400
425
|
function renderWithHydration(element, status = 200) {
|
|
401
426
|
// Hono JSX elements have toString() for synchronous rendering
|
|
402
|
-
|
|
427
|
+
let html = '<!DOCTYPE html>' + String(element)
|
|
403
428
|
|
|
404
|
-
// Inject
|
|
405
|
-
|
|
429
|
+
// Inject CSS links before </head> if present
|
|
430
|
+
if (CSS_LINKS) {
|
|
431
|
+
const headCloseRegex = /<\\/head>/i
|
|
432
|
+
if (headCloseRegex.test(html)) {
|
|
433
|
+
html = html.replace(headCloseRegex, CSS_LINKS + '</head>')
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// Inject scripts before </body>
|
|
438
|
+
// - Vite client for HMR (dev only)
|
|
439
|
+
// - Hydration script for client components
|
|
440
|
+
const scripts = VITE_CLIENT + '<script type="module" src="${clientEntryPath}"></script>'
|
|
406
441
|
const bodyCloseRegex = /<\\/body>/i
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
442
|
+
if (bodyCloseRegex.test(html)) {
|
|
443
|
+
html = html.replace(bodyCloseRegex, scripts + '</body>')
|
|
444
|
+
} else {
|
|
445
|
+
html = html + scripts
|
|
446
|
+
}
|
|
410
447
|
|
|
411
|
-
return new Response(
|
|
448
|
+
return new Response(html, {
|
|
412
449
|
status,
|
|
413
450
|
headers: {
|
|
414
451
|
'Content-Type': 'text/html; charset=utf-8',
|
|
@@ -469,6 +506,15 @@ app.use('*', async (c, next) => {
|
|
|
469
506
|
return
|
|
470
507
|
}
|
|
471
508
|
|
|
509
|
+
// Only serve static assets for GET/HEAD requests
|
|
510
|
+
// Other methods (POST, PUT, etc.) should go directly to route handlers
|
|
511
|
+
// to avoid consuming the request body
|
|
512
|
+
const method = c.req.method
|
|
513
|
+
if (method !== 'GET' && method !== 'HEAD') {
|
|
514
|
+
await next()
|
|
515
|
+
return
|
|
516
|
+
}
|
|
517
|
+
|
|
472
518
|
// Try to serve the request as a static asset
|
|
473
519
|
const response = await c.env.ASSETS.fetch(c.req.raw)
|
|
474
520
|
|
|
@@ -722,12 +768,28 @@ function generateServiceRegistration(serviceManifest) {
|
|
|
722
768
|
}
|
|
723
769
|
|
|
724
770
|
// src/virtual-modules/client-entry.ts
|
|
725
|
-
function
|
|
771
|
+
function collectCssImports(cssImports) {
|
|
772
|
+
const allCss = /* @__PURE__ */ new Set();
|
|
773
|
+
for (const imports of cssImports.values()) {
|
|
774
|
+
for (const info of imports) {
|
|
775
|
+
allCss.add(info.absolutePath);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
return Array.from(allCss);
|
|
779
|
+
}
|
|
780
|
+
function generateCssImportStatements(cssPaths) {
|
|
781
|
+
if (cssPaths.length === 0) {
|
|
782
|
+
return "";
|
|
783
|
+
}
|
|
784
|
+
return cssPaths.map((cssPath) => `import '${cssPath}'`).join("\n") + "\n\n";
|
|
785
|
+
}
|
|
786
|
+
function generateClientEntry(clientComponents, cssImports, options) {
|
|
726
787
|
const { renderer, hydrationEndpoint, isProduction } = options;
|
|
788
|
+
const cssPaths = collectCssImports(cssImports);
|
|
727
789
|
if (renderer === "react") {
|
|
728
|
-
return generateReactClientEntry(clientComponents, hydrationEndpoint, isProduction);
|
|
790
|
+
return generateReactClientEntry(clientComponents, cssPaths, hydrationEndpoint, isProduction);
|
|
729
791
|
}
|
|
730
|
-
return generateHonoClientEntry(clientComponents, hydrationEndpoint, isProduction);
|
|
792
|
+
return generateHonoClientEntry(clientComponents, cssPaths, hydrationEndpoint, isProduction);
|
|
731
793
|
}
|
|
732
794
|
function generateStaticImportsAndMap(clientComponents) {
|
|
733
795
|
const components = Array.from(clientComponents.values());
|
|
@@ -746,7 +808,7 @@ function generateProductionClientEntry(clientComponents, config) {
|
|
|
746
808
|
* This file is auto-generated by @cloudwerk/vite-plugin - do not edit
|
|
747
809
|
*/
|
|
748
810
|
|
|
749
|
-
${config.rendererImports}
|
|
811
|
+
${config.cssImports}${config.rendererImports}
|
|
750
812
|
|
|
751
813
|
// Static component imports
|
|
752
814
|
${imports}
|
|
@@ -810,10 +872,12 @@ if (document.readyState === 'loading') {
|
|
|
810
872
|
export { hydrate }
|
|
811
873
|
`;
|
|
812
874
|
}
|
|
813
|
-
function generateHonoClientEntry(clientComponents, _hydrationEndpoint, isProduction = false) {
|
|
875
|
+
function generateHonoClientEntry(clientComponents, cssPaths, _hydrationEndpoint, isProduction = false) {
|
|
876
|
+
const cssImportStatements = generateCssImportStatements(cssPaths);
|
|
814
877
|
if (isProduction) {
|
|
815
878
|
return generateProductionClientEntry(clientComponents, {
|
|
816
879
|
header: "Generated Cloudwerk Client Entry (Hono JSX - Production)",
|
|
880
|
+
cssImports: cssImportStatements,
|
|
817
881
|
rendererImports: `import { render } from 'hono/jsx/dom'
|
|
818
882
|
import { jsx } from 'hono/jsx/jsx-runtime'`,
|
|
819
883
|
additionalDeclarations: "",
|
|
@@ -830,7 +894,7 @@ import { jsx } from 'hono/jsx/jsx-runtime'`,
|
|
|
830
894
|
* This file is auto-generated by @cloudwerk/vite-plugin - do not edit
|
|
831
895
|
*/
|
|
832
896
|
|
|
833
|
-
import { render } from 'hono/jsx/dom'
|
|
897
|
+
${cssImportStatements}import { render } from 'hono/jsx/dom'
|
|
834
898
|
import { jsx } from 'hono/jsx/jsx-runtime'
|
|
835
899
|
|
|
836
900
|
// Bundle map for component lookups
|
|
@@ -914,10 +978,12 @@ if (document.readyState === 'loading') {
|
|
|
914
978
|
export { hydrate }
|
|
915
979
|
`;
|
|
916
980
|
}
|
|
917
|
-
function generateReactClientEntry(clientComponents, _hydrationEndpoint, isProduction = false) {
|
|
981
|
+
function generateReactClientEntry(clientComponents, cssPaths, _hydrationEndpoint, isProduction = false) {
|
|
982
|
+
const cssImportStatements = generateCssImportStatements(cssPaths);
|
|
918
983
|
if (isProduction) {
|
|
919
984
|
return generateProductionClientEntry(clientComponents, {
|
|
920
985
|
header: "Generated Cloudwerk Client Entry (React - Production)",
|
|
986
|
+
cssImports: cssImportStatements,
|
|
921
987
|
rendererImports: `import { hydrateRoot } from 'react-dom/client'
|
|
922
988
|
import { createElement } from 'react'`,
|
|
923
989
|
additionalDeclarations: `
|
|
@@ -937,7 +1003,7 @@ const rootCache = new Map()
|
|
|
937
1003
|
* This file is auto-generated by @cloudwerk/vite-plugin - do not edit
|
|
938
1004
|
*/
|
|
939
1005
|
|
|
940
|
-
import { hydrateRoot, createRoot } from 'react-dom/client'
|
|
1006
|
+
${cssImportStatements}import { hydrateRoot, createRoot } from 'react-dom/client'
|
|
941
1007
|
import { createElement } from 'react'
|
|
942
1008
|
|
|
943
1009
|
// Bundle map for component lookups
|
|
@@ -1594,6 +1660,66 @@ async function scanClientComponents(root, state) {
|
|
|
1594
1660
|
}
|
|
1595
1661
|
await scanDir(appDir);
|
|
1596
1662
|
}
|
|
1663
|
+
var CSS_IMPORT_REGEX = /import\s+(?:['"]([^'"]+\.css)['"]|(?:\w+\s+from\s+)?['"]([^'"]+\.css)['"])/g;
|
|
1664
|
+
function extractCssImports(code) {
|
|
1665
|
+
const imports = [];
|
|
1666
|
+
let match;
|
|
1667
|
+
CSS_IMPORT_REGEX.lastIndex = 0;
|
|
1668
|
+
while ((match = CSS_IMPORT_REGEX.exec(code)) !== null) {
|
|
1669
|
+
const cssPath = match[1] || match[2];
|
|
1670
|
+
if (cssPath) {
|
|
1671
|
+
imports.push(cssPath);
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
return imports;
|
|
1675
|
+
}
|
|
1676
|
+
function isLayoutOrPage(filePath) {
|
|
1677
|
+
const basename2 = path3.basename(filePath);
|
|
1678
|
+
const nameWithoutExt = basename2.replace(/\.(ts|tsx|js|jsx)$/, "");
|
|
1679
|
+
return {
|
|
1680
|
+
isLayout: nameWithoutExt === "layout",
|
|
1681
|
+
isPage: nameWithoutExt === "page"
|
|
1682
|
+
};
|
|
1683
|
+
}
|
|
1684
|
+
async function scanCssImports(root, state) {
|
|
1685
|
+
const appDir = path3.resolve(root, state.options.appDir);
|
|
1686
|
+
try {
|
|
1687
|
+
await fs2.promises.access(appDir);
|
|
1688
|
+
} catch {
|
|
1689
|
+
return;
|
|
1690
|
+
}
|
|
1691
|
+
async function scanDir(dir) {
|
|
1692
|
+
const entries = await fs2.promises.readdir(dir, { withFileTypes: true });
|
|
1693
|
+
await Promise.all(
|
|
1694
|
+
entries.map(async (entry) => {
|
|
1695
|
+
const fullPath = path3.join(dir, entry.name);
|
|
1696
|
+
if (entry.isDirectory()) {
|
|
1697
|
+
if (entry.name !== "node_modules" && !entry.name.startsWith(".")) {
|
|
1698
|
+
await scanDir(fullPath);
|
|
1699
|
+
}
|
|
1700
|
+
} else if (entry.isFile() && (entry.name.endsWith(".tsx") || entry.name.endsWith(".ts"))) {
|
|
1701
|
+
const { isLayout, isPage } = isLayoutOrPage(fullPath);
|
|
1702
|
+
if (isLayout || isPage) {
|
|
1703
|
+
const content = await fs2.promises.readFile(fullPath, "utf-8");
|
|
1704
|
+
const cssImportPaths = extractCssImports(content);
|
|
1705
|
+
if (cssImportPaths.length > 0) {
|
|
1706
|
+
const cssInfos = cssImportPaths.map((cssPath) => ({
|
|
1707
|
+
absolutePath: path3.resolve(path3.dirname(fullPath), cssPath),
|
|
1708
|
+
importedBy: fullPath,
|
|
1709
|
+
isLayout
|
|
1710
|
+
}));
|
|
1711
|
+
state.cssImports.set(fullPath, cssInfos);
|
|
1712
|
+
if (state.options.verbose) {
|
|
1713
|
+
console.log(`[cloudwerk] Found ${cssInfos.length} CSS import(s) in ${path3.relative(root, fullPath)}`);
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
})
|
|
1719
|
+
);
|
|
1720
|
+
}
|
|
1721
|
+
await scanDir(appDir);
|
|
1722
|
+
}
|
|
1597
1723
|
function cloudwerkPlugin(options = {}) {
|
|
1598
1724
|
let state = null;
|
|
1599
1725
|
let server = null;
|
|
@@ -1794,6 +1920,7 @@ function cloudwerkPlugin(options = {}) {
|
|
|
1794
1920
|
serviceManifest: null,
|
|
1795
1921
|
serviceScanResult: null,
|
|
1796
1922
|
clientComponents: /* @__PURE__ */ new Map(),
|
|
1923
|
+
cssImports: /* @__PURE__ */ new Map(),
|
|
1797
1924
|
serverEntryCache: null,
|
|
1798
1925
|
clientEntryCache: null
|
|
1799
1926
|
};
|
|
@@ -1801,6 +1928,7 @@ function cloudwerkPlugin(options = {}) {
|
|
|
1801
1928
|
await buildQueueManifestIfExists(root);
|
|
1802
1929
|
await buildServiceManifestIfExists(root);
|
|
1803
1930
|
await scanClientComponents(root, state);
|
|
1931
|
+
await scanCssImports(root, state);
|
|
1804
1932
|
},
|
|
1805
1933
|
/**
|
|
1806
1934
|
* Configure the dev server with file watching.
|
|
@@ -1945,6 +2073,7 @@ function cloudwerkPlugin(options = {}) {
|
|
|
1945
2073
|
if (!state.clientEntryCache) {
|
|
1946
2074
|
state.clientEntryCache = generateClientEntry(
|
|
1947
2075
|
state.clientComponents,
|
|
2076
|
+
state.cssImports,
|
|
1948
2077
|
state.options
|
|
1949
2078
|
);
|
|
1950
2079
|
}
|
|
@@ -2031,6 +2160,22 @@ function cloudwerkPlugin(options = {}) {
|
|
|
2031
2160
|
return parts.join("\n");
|
|
2032
2161
|
});
|
|
2033
2162
|
}
|
|
2163
|
+
const { isLayout, isPage } = isLayoutOrPage(id);
|
|
2164
|
+
if (isLayout || isPage) {
|
|
2165
|
+
const cssImportPaths = extractCssImports(transformedCode);
|
|
2166
|
+
if (cssImportPaths.length > 0) {
|
|
2167
|
+
const cssInfos = cssImportPaths.map((cssPath) => ({
|
|
2168
|
+
absolutePath: path3.resolve(path3.dirname(id), cssPath),
|
|
2169
|
+
importedBy: id,
|
|
2170
|
+
isLayout
|
|
2171
|
+
}));
|
|
2172
|
+
state.cssImports.set(id, cssInfos);
|
|
2173
|
+
state.clientEntryCache = null;
|
|
2174
|
+
if (state.options.verbose) {
|
|
2175
|
+
console.log(`[cloudwerk] Detected ${cssInfos.length} CSS import(s) in ${path3.relative(state.options.root, id)}`);
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2034
2179
|
if (hasUseClientDirective(transformedCode)) {
|
|
2035
2180
|
const componentId = generateComponentId(id, state.options.root);
|
|
2036
2181
|
const bundlePath = `${state.options.hydrationEndpoint}/${componentId}.js`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudwerk/vite-plugin",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3",
|
|
4
4
|
"description": "Vite plugin for Cloudwerk file-based routing with virtual entry generation",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@swc/core": "^1.3.100",
|
|
22
|
-
"@cloudwerk/core": "^0.
|
|
23
|
-
"@cloudwerk/ui": "^0.
|
|
22
|
+
"@cloudwerk/core": "^0.15.1",
|
|
23
|
+
"@cloudwerk/ui": "^0.15.1"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
26
|
"vite": "^5.0.0 || ^6.0.0",
|