vite-plugin-kiru 0.29.9 → 0.29.11
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 +96 -23
- package/dist/index.d.ts +85 -0
- package/dist/index.js +106 -10
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
# vite-plugin-kiru
|
|
2
2
|
|
|
3
|
-
Vite plugin for <a href="https://kirujs.dev">Kiru</a> apps that enables HMR, devtools, file-based routing
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm i -D vite-plugin-kiru
|
|
9
|
-
# or
|
|
10
|
-
pnpm add -D vite-plugin-kiru
|
|
11
|
-
```
|
|
3
|
+
Vite plugin for <a href="https://kirujs.dev">Kiru</a> apps that enables HMR, devtools, and SSG with file-based routing & sitemap generation.
|
|
12
4
|
|
|
13
5
|
## Basic Usage
|
|
14
6
|
|
|
@@ -60,25 +52,106 @@ kiru({
|
|
|
60
52
|
onFileExcluded: (id) => {
|
|
61
53
|
console.log(`Excluded: ${id}`)
|
|
62
54
|
},
|
|
55
|
+
|
|
56
|
+
// Static Site Generation (SSG) configuration
|
|
57
|
+
ssg: {
|
|
58
|
+
// Base URL for the app
|
|
59
|
+
baseUrl: "/",
|
|
60
|
+
// Directory containing pages
|
|
61
|
+
dir: "./src/pages",
|
|
62
|
+
// Document component filename pattern
|
|
63
|
+
document: "document.{tsx,jsx}",
|
|
64
|
+
// Page component filename pattern
|
|
65
|
+
page: "index.{tsx,jsx}",
|
|
66
|
+
// Layout component filename pattern
|
|
67
|
+
layout: "layout.{tsx,jsx}",
|
|
68
|
+
// Enable view transitions for route changes and page loaders
|
|
69
|
+
transition: true,
|
|
70
|
+
// Build options
|
|
71
|
+
build: {
|
|
72
|
+
// Maximum number of pages to render concurrently
|
|
73
|
+
maxConcurrentRenders: 100,
|
|
74
|
+
},
|
|
75
|
+
// Sitemap generation options
|
|
76
|
+
sitemap: {
|
|
77
|
+
// Domain for sitemap URLs (required)
|
|
78
|
+
domain: "https://example.com",
|
|
79
|
+
// Default last modified date for all URLs
|
|
80
|
+
lastmod: new Date(),
|
|
81
|
+
// Default change frequency (hourly | daily | weekly | monthly | yearly | never)
|
|
82
|
+
changefreq: "weekly", // default: "weekly"
|
|
83
|
+
// Default priority (0.0 to 1.0)
|
|
84
|
+
priority: 0.5, // default: 0.5
|
|
85
|
+
// Per-route overrides
|
|
86
|
+
overrides: {
|
|
87
|
+
"/": {
|
|
88
|
+
changefreq: "daily",
|
|
89
|
+
priority: 0.8,
|
|
90
|
+
lastmod: new Date("2024-01-01"),
|
|
91
|
+
// Images to include for this route
|
|
92
|
+
images: ["/images/hero.png"],
|
|
93
|
+
// Videos to include for this route
|
|
94
|
+
videos: [
|
|
95
|
+
{
|
|
96
|
+
title: "Product Demo",
|
|
97
|
+
thumbnail_loc: "/images/video-thumbnail.png",
|
|
98
|
+
description: "A demonstration of our product features.",
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
"/blog": {
|
|
103
|
+
changefreq: "weekly",
|
|
104
|
+
priority: 0.7,
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
// Or, if you want to enable SSG with default configuration:
|
|
111
|
+
ssg: true,
|
|
112
|
+
// (this will not include sitemap generation as it requires manual configuration)
|
|
63
113
|
})
|
|
64
114
|
```
|
|
65
115
|
|
|
116
|
+
## Static Site Generation (SSG)
|
|
117
|
+
|
|
118
|
+
The plugin supports static site generation with configurable sitemap creation. When SSG is enabled, all routes are pre-rendered at build time and a `sitemap.xml` file is generated if configured.
|
|
119
|
+
|
|
120
|
+
### Sitemap Generation
|
|
121
|
+
|
|
122
|
+
The sitemap feature generates a `sitemap.xml` file in your build output with all discovered routes (excluding 404 pages).
|
|
123
|
+
|
|
124
|
+
**Features:**
|
|
125
|
+
|
|
126
|
+
- Automatic route discovery from your file structure
|
|
127
|
+
- Configurable default `changefreq`, `priority`, and `lastmod` for all routes
|
|
128
|
+
- Per-route overrides for fine-grained control
|
|
129
|
+
- Support for images and videos (Google sitemap extensions)
|
|
130
|
+
|
|
131
|
+
**Example:**
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
ssg: {
|
|
135
|
+
sitemap: {
|
|
136
|
+
domain: "https://kirujs.dev",
|
|
137
|
+
changefreq: "weekly",
|
|
138
|
+
priority: 0.5,
|
|
139
|
+
overrides: {
|
|
140
|
+
"/": {
|
|
141
|
+
changefreq: "daily",
|
|
142
|
+
priority: 0.8,
|
|
143
|
+
images: ["/images/kiru.png"],
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
This will generate a `sitemap.xml` file in `dist/client/sitemap.xml` with all your routes properly formatted.
|
|
151
|
+
|
|
66
152
|
## Features
|
|
67
153
|
|
|
68
|
-
- **
|
|
69
|
-
- **SSR/SSG**: Server-side rendering and static site generation
|
|
154
|
+
- **SSG + file-based routing**: Automatic route discovery, static site and sitemap generation
|
|
70
155
|
- **HMR**: Hot module replacement for fast development
|
|
71
156
|
- **Devtools**: Built-in development tools for debugging
|
|
72
157
|
- **TypeScript**: Full TypeScript support with proper type definitions
|
|
73
|
-
|
|
74
|
-
## Architecture
|
|
75
|
-
|
|
76
|
-
The plugin is organized into focused modules:
|
|
77
|
-
|
|
78
|
-
- `virtual-modules.ts` - Virtual module generation for routing
|
|
79
|
-
- `dev-server.ts` - Development server SSR handling
|
|
80
|
-
- `preview-server.ts` - Preview server middleware
|
|
81
|
-
- `devtools.ts` - Development tools integration
|
|
82
|
-
- `ssg.ts` - Static site generation
|
|
83
|
-
- `config.ts` - Configuration management
|
|
84
|
-
- `utils.ts` - Shared utilities
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,86 @@ export interface SSGBuildOptions {
|
|
|
10
10
|
maxConcurrentRenders?: number
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
export type SSGSitemapChangefreq =
|
|
14
|
+
// | "always"
|
|
15
|
+
"hourly" | "daily" | "weekly" | "monthly" | "yearly" | "never"
|
|
16
|
+
|
|
17
|
+
export interface SSGSitemapVideo {
|
|
18
|
+
title: string
|
|
19
|
+
thumbnail_loc: string
|
|
20
|
+
description?: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface SSGSitemapOverride {
|
|
24
|
+
/**
|
|
25
|
+
* Change frequency override for this route
|
|
26
|
+
* @default "weekly"
|
|
27
|
+
*/
|
|
28
|
+
changefreq?: SSGSitemapChangefreq
|
|
29
|
+
/**
|
|
30
|
+
* Priority override for this route (0.0 to 1.0)
|
|
31
|
+
* @default 0.5
|
|
32
|
+
*/
|
|
33
|
+
priority?: number
|
|
34
|
+
/**
|
|
35
|
+
* Last modified date override for this route
|
|
36
|
+
*/
|
|
37
|
+
lastmod?: Date
|
|
38
|
+
/**
|
|
39
|
+
* Images to include for this route
|
|
40
|
+
* @example ["/images/kiru.png"]
|
|
41
|
+
*/
|
|
42
|
+
images?: string[]
|
|
43
|
+
/**
|
|
44
|
+
* Videos to include for this route
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* videos: [
|
|
48
|
+
* {
|
|
49
|
+
* title: "Kiru",
|
|
50
|
+
* thumbnail_loc: "/images/kiru.png",
|
|
51
|
+
* description: "Kiru is a framework for building web applications."
|
|
52
|
+
* }
|
|
53
|
+
* ]
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
videos?: Array<SSGSitemapVideo>
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface SSGSitemapOptions {
|
|
60
|
+
/**
|
|
61
|
+
* The domain to use for sitemap URLs
|
|
62
|
+
* @example "https://example.com"
|
|
63
|
+
*/
|
|
64
|
+
domain: string
|
|
65
|
+
/**
|
|
66
|
+
* Default last modified date for all URLs
|
|
67
|
+
*/
|
|
68
|
+
lastmod?: Date
|
|
69
|
+
/**
|
|
70
|
+
* Default change frequency for all URLs
|
|
71
|
+
* @default "weekly"
|
|
72
|
+
*/
|
|
73
|
+
changefreq?: SSGSitemapChangefreq
|
|
74
|
+
/**
|
|
75
|
+
* Default priority for all URLs (0.0 to 1.0)
|
|
76
|
+
* @default 0.5
|
|
77
|
+
*/
|
|
78
|
+
priority?: number
|
|
79
|
+
/**
|
|
80
|
+
* Per-route overrides for sitemap entries
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* overrides: {
|
|
84
|
+
* "/": {
|
|
85
|
+
* changefreq: "never",
|
|
86
|
+
* priority: 0.8,
|
|
87
|
+
* },
|
|
88
|
+
* }
|
|
89
|
+
*/
|
|
90
|
+
overrides?: Record<string, SSGSitemapOverride>
|
|
91
|
+
}
|
|
92
|
+
|
|
13
93
|
export interface SSGOptions {
|
|
14
94
|
/**
|
|
15
95
|
* The base URL of the app
|
|
@@ -42,6 +122,11 @@ export interface SSGOptions {
|
|
|
42
122
|
*/
|
|
43
123
|
transition?: boolean
|
|
44
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Options for sitemap generation
|
|
127
|
+
*/
|
|
128
|
+
sitemap?: SSGSitemapOptions
|
|
129
|
+
|
|
45
130
|
/**
|
|
46
131
|
* Options for build
|
|
47
132
|
*/
|
package/dist/index.js
CHANGED
|
@@ -8810,11 +8810,10 @@ function createLogger(state) {
|
|
|
8810
8810
|
}
|
|
8811
8811
|
function resolveUserDocument(projectRoot, ssgOptions) {
|
|
8812
8812
|
const { dir, document } = ssgOptions;
|
|
8813
|
-
const
|
|
8814
|
-
|
|
8815
|
-
});
|
|
8813
|
+
const fp = path2.resolve(projectRoot, dir, document).replace(/\\/g, "/");
|
|
8814
|
+
const matches = globSync(fp);
|
|
8816
8815
|
if (!matches.length) {
|
|
8817
|
-
throw new Error(`Document not found`);
|
|
8816
|
+
throw new Error(`Document not found at ${fp}`);
|
|
8818
8817
|
}
|
|
8819
8818
|
return path2.resolve(projectRoot, matches[0]).replace(/\\/g, "/");
|
|
8820
8819
|
}
|
|
@@ -8969,6 +8968,7 @@ function createPluginState(opts = {}) {
|
|
|
8969
8968
|
page: ssg.page ?? page,
|
|
8970
8969
|
layout: ssg.layout ?? layout,
|
|
8971
8970
|
transition: ssg.transition ?? transition,
|
|
8971
|
+
sitemap: ssg.sitemap,
|
|
8972
8972
|
build: {
|
|
8973
8973
|
maxConcurrentRenders: ssg.build?.maxConcurrentRenders ?? maxConcurrentRenders
|
|
8974
8974
|
}
|
|
@@ -11213,7 +11213,7 @@ import path6 from "node:path";
|
|
|
11213
11213
|
import fs3 from "node:fs";
|
|
11214
11214
|
import { pathToFileURL } from "node:url";
|
|
11215
11215
|
async function generateStaticSite(state, outputOptions, bundle, log) {
|
|
11216
|
-
const { projectRoot, baseOutDir, manifestPath } = state;
|
|
11216
|
+
const { projectRoot, baseOutDir, manifestPath, ssgOptions } = state;
|
|
11217
11217
|
const outDirAbs = path6.resolve(projectRoot, outputOptions?.dir ?? "dist");
|
|
11218
11218
|
const ssrEntry = Object.values(bundle).find(
|
|
11219
11219
|
(c) => c.type === "chunk" && c.isEntry
|
|
@@ -11235,7 +11235,7 @@ async function generateStaticSite(state, outputOptions, bundle, log) {
|
|
|
11235
11235
|
const routes = Object.keys(paths);
|
|
11236
11236
|
log(ANSI.cyan("[SSG]"), `discovered ${routes.length} routes:`, routes);
|
|
11237
11237
|
const renderingChunks = [];
|
|
11238
|
-
const maxConcurrentRenders =
|
|
11238
|
+
const maxConcurrentRenders = ssgOptions.build.maxConcurrentRenders;
|
|
11239
11239
|
for (let i = 0; i < routes.length; i += maxConcurrentRenders) {
|
|
11240
11240
|
const chunkKeys = routes.slice(i, i + maxConcurrentRenders);
|
|
11241
11241
|
renderingChunks.push(
|
|
@@ -11254,8 +11254,7 @@ async function generateStaticSite(state, outputOptions, bundle, log) {
|
|
|
11254
11254
|
route,
|
|
11255
11255
|
srcFilePath,
|
|
11256
11256
|
clientEntry,
|
|
11257
|
-
manifest
|
|
11258
|
-
log
|
|
11257
|
+
manifest
|
|
11259
11258
|
);
|
|
11260
11259
|
const filePath = getOutputPath(clientOutDirAbs, route);
|
|
11261
11260
|
log(ANSI.cyan("[SSG]"), "write:", ANSI.black(filePath));
|
|
@@ -11265,6 +11264,9 @@ async function generateStaticSite(state, outputOptions, bundle, log) {
|
|
|
11265
11264
|
);
|
|
11266
11265
|
}
|
|
11267
11266
|
await appendStaticPropsToClientModules(state, clientOutDirAbs, log);
|
|
11267
|
+
if (ssgOptions.sitemap?.domain) {
|
|
11268
|
+
await generateSitemap(state, routes, clientOutDirAbs, log);
|
|
11269
|
+
}
|
|
11268
11270
|
}
|
|
11269
11271
|
async function getClientAssets(clientOutDirAbs, manifestPath) {
|
|
11270
11272
|
let clientEntry = null;
|
|
@@ -11350,7 +11352,7 @@ function findClientEntry(dir) {
|
|
|
11350
11352
|
}
|
|
11351
11353
|
return null;
|
|
11352
11354
|
}
|
|
11353
|
-
async function renderRoute(state, mod, route, srcFilePath, clientEntry, manifest
|
|
11355
|
+
async function renderRoute(state, mod, route, srcFilePath, clientEntry, manifest) {
|
|
11354
11356
|
const moduleIds = [];
|
|
11355
11357
|
const { projectRoot, ssgOptions } = state;
|
|
11356
11358
|
const documentPath = path6.resolve(
|
|
@@ -11371,7 +11373,6 @@ async function renderRoute(state, mod, route, srcFilePath, clientEntry, manifest
|
|
|
11371
11373
|
};
|
|
11372
11374
|
const result = await mod.render(route, ctx);
|
|
11373
11375
|
let html = result.body;
|
|
11374
|
-
log(ANSI.cyan("[SSG]"), ` Total modules tracked: ${moduleIds.length}`);
|
|
11375
11376
|
let cssLinks = "";
|
|
11376
11377
|
if (manifest) {
|
|
11377
11378
|
cssLinks = collectCssForModules(manifest, moduleIds, projectRoot);
|
|
@@ -11398,6 +11399,101 @@ function getOutputPath(clientOutDirAbs, route) {
|
|
|
11398
11399
|
}
|
|
11399
11400
|
return path6.resolve(dirPath, `${last}.html`);
|
|
11400
11401
|
}
|
|
11402
|
+
async function generateSitemap(state, routes, clientOutDirAbs, log) {
|
|
11403
|
+
const sitemapConfig = state.ssgOptions.sitemap;
|
|
11404
|
+
const {
|
|
11405
|
+
domain,
|
|
11406
|
+
lastmod: lastModified,
|
|
11407
|
+
changefreq = "weekly",
|
|
11408
|
+
priority = 0.5,
|
|
11409
|
+
overrides = {}
|
|
11410
|
+
} = sitemapConfig;
|
|
11411
|
+
const baseUrl = state.ssgOptions.baseUrl;
|
|
11412
|
+
const normalizedDomain = domain.replace(/\/$/, "");
|
|
11413
|
+
const normalizedBaseUrl = baseUrl === "/" ? "" : baseUrl.replace(/\/$/, "");
|
|
11414
|
+
let hasImages = false;
|
|
11415
|
+
let hasVideos = false;
|
|
11416
|
+
for (const route of routes) {
|
|
11417
|
+
const override = overrides[route];
|
|
11418
|
+
if (override?.images?.length) {
|
|
11419
|
+
hasImages = true;
|
|
11420
|
+
}
|
|
11421
|
+
if (override?.videos?.length) {
|
|
11422
|
+
hasVideos = true;
|
|
11423
|
+
}
|
|
11424
|
+
}
|
|
11425
|
+
const sortedRoutes = [...routes].filter((route) => !route.endsWith("/404")).sort((a, b) => {
|
|
11426
|
+
if (a === "/") return -1;
|
|
11427
|
+
if (b === "/") return 1;
|
|
11428
|
+
const aDepth = a.split("/").filter(Boolean).length;
|
|
11429
|
+
const bDepth = b.split("/").filter(Boolean).length;
|
|
11430
|
+
if (aDepth !== bDepth) {
|
|
11431
|
+
return aDepth - bDepth;
|
|
11432
|
+
}
|
|
11433
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
11434
|
+
});
|
|
11435
|
+
const urls = sortedRoutes.map((route) => {
|
|
11436
|
+
const normalizedRoute = route.startsWith("/") ? route : `/${route}`;
|
|
11437
|
+
const url = `${normalizedDomain}${normalizedBaseUrl}${normalizedRoute}`;
|
|
11438
|
+
const override = overrides[route] || {};
|
|
11439
|
+
const routeChangefreq = override.changefreq ?? changefreq;
|
|
11440
|
+
const routePriority = override.priority ?? priority;
|
|
11441
|
+
const routeLastModified = override.lastmod ?? lastModified;
|
|
11442
|
+
let urlEntry = ` <url>
|
|
11443
|
+
<loc>${escapeXml(url)}</loc>
|
|
11444
|
+
<changefreq>${routeChangefreq}</changefreq>
|
|
11445
|
+
<priority>${routePriority}</priority>`;
|
|
11446
|
+
if (routeLastModified) {
|
|
11447
|
+
const lastMod = routeLastModified.toISOString().split("T")[0];
|
|
11448
|
+
urlEntry += `
|
|
11449
|
+
<lastmod>${lastMod}</lastmod>`;
|
|
11450
|
+
}
|
|
11451
|
+
if (override.images?.length) {
|
|
11452
|
+
for (const image of override.images) {
|
|
11453
|
+
const imageUrl = image.startsWith("http") ? image : `${normalizedDomain}${normalizedBaseUrl}${image.startsWith("/") ? image : `/${image}`}`;
|
|
11454
|
+
urlEntry += `
|
|
11455
|
+
<image:image>
|
|
11456
|
+
<image:loc>${escapeXml(imageUrl)}</image:loc>
|
|
11457
|
+
</image:image>`;
|
|
11458
|
+
}
|
|
11459
|
+
}
|
|
11460
|
+
if (override.videos?.length) {
|
|
11461
|
+
for (const video of override.videos) {
|
|
11462
|
+
const thumbnailUrl = video.thumbnail_loc.startsWith("http") ? video.thumbnail_loc : `${normalizedDomain}${normalizedBaseUrl}${video.thumbnail_loc.startsWith("/") ? video.thumbnail_loc : `/${video.thumbnail_loc}`}`;
|
|
11463
|
+
urlEntry += `
|
|
11464
|
+
<video:video>
|
|
11465
|
+
<video:title>${escapeXml(video.title)}</video:title>
|
|
11466
|
+
<video:thumbnail_loc>${escapeXml(thumbnailUrl)}</video:thumbnail_loc>`;
|
|
11467
|
+
if (video.description) {
|
|
11468
|
+
urlEntry += `
|
|
11469
|
+
<video:description>${escapeXml(
|
|
11470
|
+
video.description
|
|
11471
|
+
)}</video:description>`;
|
|
11472
|
+
}
|
|
11473
|
+
urlEntry += `
|
|
11474
|
+
</video:video>`;
|
|
11475
|
+
}
|
|
11476
|
+
}
|
|
11477
|
+
urlEntry += `
|
|
11478
|
+
</url>`;
|
|
11479
|
+
return urlEntry;
|
|
11480
|
+
}).join("\n");
|
|
11481
|
+
const namespaces = [
|
|
11482
|
+
'xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"',
|
|
11483
|
+
hasImages && 'xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"',
|
|
11484
|
+
hasVideos && 'xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"'
|
|
11485
|
+
].filter(Boolean).join(" ");
|
|
11486
|
+
const sitemapXml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
11487
|
+
<urlset ${namespaces}>
|
|
11488
|
+
${urls}
|
|
11489
|
+
</urlset>`;
|
|
11490
|
+
const sitemapPath = path6.resolve(clientOutDirAbs, "sitemap.xml");
|
|
11491
|
+
fs3.writeFileSync(sitemapPath, sitemapXml, "utf-8");
|
|
11492
|
+
log(ANSI.cyan("[SSG]"), "Generated sitemap:", ANSI.black(sitemapPath));
|
|
11493
|
+
}
|
|
11494
|
+
function escapeXml(unsafe) {
|
|
11495
|
+
return unsafe.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
11496
|
+
}
|
|
11401
11497
|
async function appendStaticPropsToClientModules(state, clientOutDirAbs, log) {
|
|
11402
11498
|
const { projectRoot, manifestPath, ssgOptions } = state;
|
|
11403
11499
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-kiru",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.11",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -17,14 +17,14 @@
|
|
|
17
17
|
"rollup": "^4.46.2",
|
|
18
18
|
"tsx": "^4.20.3",
|
|
19
19
|
"typescript": "^5.9.2",
|
|
20
|
-
"kiru-devtools-
|
|
21
|
-
"kiru-devtools-
|
|
20
|
+
"kiru-devtools-client": "^0.0.0",
|
|
21
|
+
"kiru-devtools-host": "^1.0.0"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"glob": "^11.0.3",
|
|
25
25
|
"magic-string": "^0.30.17",
|
|
26
26
|
"mime": "^4.1.0",
|
|
27
|
-
"vite": "^7.
|
|
27
|
+
"vite": "^7.2.2"
|
|
28
28
|
},
|
|
29
29
|
"scripts": {
|
|
30
30
|
"test": "echo \"Error: no test specified\"",
|