@canofold/vite 0.3.0-rc.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 ADDED
@@ -0,0 +1,18 @@
1
+ # @canofold/vite
2
+
3
+ The official React + Vite Demo Engine for Canofold. It reuses the component project's Vite configuration, plugins, aliases, and CSS dependency graph to provide live previews, HMR, and production bundles for component examples in ordinary Markdown. The current release supports React 18 and React 19.
4
+
5
+ ```ts
6
+ import { defineConfig } from 'canofold'
7
+ import { vite } from '@canofold/vite'
8
+
9
+ export default defineConfig({
10
+ demos: {
11
+ engine: vite()
12
+ }
13
+ })
14
+ ```
15
+
16
+ Run `canofold dev`; Vite is mounted on the same development server and port.
17
+
18
+ Demos render inline by default. `sandbox="iframe"` places trusted local demo code in a restricted iframe for DOM and global-style isolation; it is not a security boundary for untrusted code.
@@ -0,0 +1,16 @@
1
+ # @canofold/vite
2
+
3
+ Canofold 官方 React + Vite Demo Engine。它复用组件项目已有的 Vite 配置、插件、别名和 CSS 依赖图,为普通 Markdown 中的组件示例提供开发预览、HMR 与生产构建。当前版本支持 React 18 和 React 19。
4
+
5
+ ```ts
6
+ import { defineConfig } from 'canofold'
7
+ import { vite } from '@canofold/vite'
8
+
9
+ export default defineConfig({
10
+ demos: {
11
+ engine: vite()
12
+ }
13
+ })
14
+ ```
15
+
16
+ Demo 默认渲染在文档页面中。`sandbox="iframe"` 会把可信的本地 Demo 放进受限 iframe,隔离 DOM 与全局样式;它不是运行不可信代码的安全边界。
@@ -0,0 +1,11 @@
1
+ import { CanofoldDemoEngine } from 'canofold/demo-engine';
2
+
3
+ interface CanofoldViteOptions {
4
+ /** Project root passed to Vite. Defaults to the Canofold project root. */
5
+ root?: string;
6
+ /** Vite config file. Use false to disable config discovery. */
7
+ configFile?: string | false;
8
+ }
9
+ declare function vite(options?: CanofoldViteOptions): CanofoldDemoEngine;
10
+
11
+ export { type CanofoldViteOptions, vite as default, vite };
package/dist/index.js ADDED
@@ -0,0 +1,471 @@
1
+ // src/index.ts
2
+ import { realpathSync } from "fs";
3
+ import { readFile, writeFile } from "fs/promises";
4
+ import { extname, isAbsolute, join, relative, resolve, sep } from "path";
5
+ import {
6
+ build as viteBuild,
7
+ createServer as createViteServer,
8
+ loadConfigFromFile,
9
+ mergeConfig,
10
+ normalizePath
11
+ } from "vite";
12
+
13
+ // src/runtime.ts
14
+ function demoRuntimeSource(registryEntries, setupImport, styleUrls = []) {
15
+ const imports = registryEntries.join("\n");
16
+ const setup = setupImport ?? "const CanofoldDemoSetup = null;";
17
+ return `${imports}
18
+ ${setup}
19
+ import React from 'react';
20
+ import { createRoot } from 'react-dom/client';
21
+
22
+ const registry = new Map(CANOFOLD_DEMO_REGISTRY);
23
+ const iframeStyleUrls = ${JSON.stringify(styleUrls)};
24
+ const roots = new Set();
25
+ const frameObservers = new Set();
26
+ let eventController;
27
+
28
+ class DemoBoundary extends React.Component {
29
+ constructor(props) { super(props); this.state = { error: null }; }
30
+ static getDerivedStateFromError(error) { return { error }; }
31
+ render() {
32
+ if (!this.state.error) return this.props.children;
33
+ return React.createElement('div', { className: 'cf-demo-error', role: 'alert' }, this.props.message);
34
+ }
35
+ }
36
+
37
+ function componentFor(id) {
38
+ const value = registry.get(id);
39
+ const component = value && (value.default || value.Demo);
40
+ if (!component) throw new Error('Demo module ' + id + ' must export a default React component.');
41
+ return component;
42
+ }
43
+
44
+ export function mountDemo(element, id, failedLabel) {
45
+ const Demo = componentFor(id);
46
+ const content = React.createElement(Demo);
47
+ const wrapped = CanofoldDemoSetup ? React.createElement(CanofoldDemoSetup, null, content) : content;
48
+ const root = createRoot(element);
49
+ roots.add(root);
50
+ root.render(React.createElement(DemoBoundary, { message: failedLabel }, wrapped));
51
+ return root;
52
+ }
53
+
54
+ function iframeDocument(id, failedLabel) {
55
+ const script = \`import(\${JSON.stringify(import.meta.url)}).then(({ mountDemo }) => mountDemo(document.getElementById('root'),\${JSON.stringify(id)},\${JSON.stringify(failedLabel)})).catch((error) => { console.error('[Canofold demo iframe]', error); const root = document.getElementById('root'); root.setAttribute('role', 'alert'); root.textContent = \${JSON.stringify(failedLabel)}; });\`;
56
+ const styles = iframeStyleUrls.map((href) => '<link rel="stylesheet" href="' + href.replace(/&/g, '&amp;').replace(/"/g, '&quot;') + '">').join('');
57
+ return '<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">' + styles + '<style>html,body,#root{min-height:100%;margin:0}body{display:grid;place-items:center;padding:24px;box-sizing:border-box;font-family:system-ui,sans-serif}</style></head><body><div id="root"></div><script type="module">' + script.replace(/<\\/script/gi, '<\\\\/script') + '<\\/script></body></html>';
58
+ }
59
+
60
+ function fitFrame(frame) {
61
+ const frameDocument = frame.contentDocument;
62
+ if (!frameDocument) return;
63
+ const update = () => {
64
+ frame.style.height = Math.max(192, Math.ceil(frameDocument.documentElement.scrollHeight)) + 'px';
65
+ };
66
+ update();
67
+ if (typeof ResizeObserver === 'undefined') return;
68
+ const observer = new ResizeObserver(update);
69
+ observer.observe(frameDocument.documentElement);
70
+ frameObservers.add(observer);
71
+ }
72
+
73
+ function bindSourceToggle(button, signal) {
74
+ const sourceId = button.getAttribute('aria-controls');
75
+ const source = sourceId && document.getElementById(sourceId);
76
+ if (!source) return;
77
+ const setExpanded = (expanded) => {
78
+ const label = button.getAttribute(expanded ? 'data-cf-demo-hide-label' : 'data-cf-demo-show-label') || '';
79
+ button.setAttribute('aria-expanded', String(expanded));
80
+ button.setAttribute('aria-label', label);
81
+ source.hidden = !expanded;
82
+ const tooltip = button.querySelector('[data-cf-demo-tooltip]');
83
+ if (tooltip) tooltip.textContent = label;
84
+ };
85
+ setExpanded(button.getAttribute('aria-expanded') === 'true');
86
+ button.addEventListener('click', () => setExpanded(button.getAttribute('aria-expanded') !== 'true'), { signal });
87
+ }
88
+
89
+ function standaloneDemo() {
90
+ const id = new URL(window.location.href).searchParams.get('canofold-demo');
91
+ if (!id || !registry.has(id)) return false;
92
+ const preview = Array.from(document.querySelectorAll('[data-cf-demo-preview]')).find(
93
+ (element) => element.getAttribute('data-cf-demo-id') === id
94
+ );
95
+ const failed = preview?.getAttribute('data-cf-demo-failed-label') || 'This example could not be loaded.';
96
+ const root = document.createElement('main');
97
+ root.className = 'cf-demo-standalone';
98
+ root.setAttribute('data-cf-demo-id', id);
99
+ document.documentElement.setAttribute('data-cf-demo-standalone', '');
100
+ document.body.replaceChildren(root);
101
+ mountDemo(root, id, failed);
102
+ return true;
103
+ }
104
+
105
+ export async function bootstrapDemos() {
106
+ window.__canofoldDemoDispose?.();
107
+ if (standaloneDemo()) {
108
+ window.__canofoldDemoDispose = () => {
109
+ roots.forEach((root) => root.unmount());
110
+ roots.clear();
111
+ document.documentElement.removeAttribute('data-cf-demo-standalone');
112
+ };
113
+ return;
114
+ }
115
+ document.documentElement.removeAttribute('data-cf-demo-standalone');
116
+ eventController = new AbortController();
117
+ document.querySelectorAll('[data-cf-demo-source-toggle]').forEach((button) => bindSourceToggle(button, eventController.signal));
118
+ document.querySelectorAll('[data-cf-demo-preview]').forEach((preview) => {
119
+ const id = preview.getAttribute('data-cf-demo-id');
120
+ if (!id) return;
121
+ const loading = preview.getAttribute('data-cf-demo-loading-label') || 'Loading example\u2026';
122
+ const failed = preview.getAttribute('data-cf-demo-failed-label') || 'This example could not be loaded.';
123
+ preview.textContent = loading;
124
+ try {
125
+ const card = preview.closest('[data-cf-component="demo"]');
126
+ if (card?.getAttribute('data-cf-demo-sandbox') === 'iframe') {
127
+ const frame = document.createElement('iframe');
128
+ frame.className = 'cf-demo-frame';
129
+ frame.title = card.querySelector('.cf-demo-title')?.textContent || 'Component example';
130
+ frame.loading = 'lazy';
131
+ frame.referrerPolicy = 'no-referrer';
132
+ frame.setAttribute('sandbox', 'allow-scripts allow-same-origin');
133
+ frame.addEventListener('load', () => fitFrame(frame), { once: true });
134
+ frame.srcdoc = iframeDocument(id, failed);
135
+ preview.replaceChildren(frame);
136
+ } else {
137
+ preview.textContent = '';
138
+ mountDemo(preview, id, failed);
139
+ }
140
+ } catch (error) {
141
+ console.error('[Canofold demo]', error);
142
+ preview.textContent = failed;
143
+ preview.setAttribute('data-cf-demo-error', '');
144
+ }
145
+ });
146
+ window.__canofoldDemoDispose = () => {
147
+ eventController?.abort();
148
+ eventController = undefined;
149
+ frameObservers.forEach((observer) => observer.disconnect());
150
+ frameObservers.clear();
151
+ roots.forEach((root) => root.unmount());
152
+ roots.clear();
153
+ };
154
+ }
155
+
156
+ window.__canofoldBootstrapDemos = bootstrapDemos;
157
+ void bootstrapDemos();
158
+
159
+ if (import.meta.hot) {
160
+ import.meta.hot.accept(() => void bootstrapDemos());
161
+ }
162
+ `;
163
+ }
164
+
165
+ // src/index.ts
166
+ var PUBLIC_CLIENT_ID = "virtual:canofold-demo-client";
167
+ var RESOLVED_CLIENT_ID = `\0${PUBLIC_CLIENT_ID}`;
168
+ function baseUrl(basePath, path) {
169
+ const prefix = basePath === "/" ? "" : basePath.replace(/\/$/, "");
170
+ return `${prefix}/${path.replace(/^\//, "")}`;
171
+ }
172
+ function languageFor(path) {
173
+ const extension = extname(path).toLowerCase();
174
+ if (extension === ".tsx") return "tsx";
175
+ if (extension === ".jsx") return "jsx";
176
+ if (extension === ".js" || extension === ".mjs" || extension === ".cjs") return "js";
177
+ return "ts";
178
+ }
179
+ function filePathFromResolvedId(id) {
180
+ const clean = id.replace(/[?#].*$/, "");
181
+ if (clean.startsWith("/@fs/")) return clean.slice("/@fs".length);
182
+ return clean;
183
+ }
184
+ function importerFor(reference) {
185
+ return normalizePath(reference.pageSourcePath);
186
+ }
187
+ function canonicalPath(path) {
188
+ try {
189
+ return realpathSync.native(resolve(path));
190
+ } catch {
191
+ return resolve(path);
192
+ }
193
+ }
194
+ function isProjectSource(cwd, path) {
195
+ const projectRelative = relative(canonicalPath(cwd), canonicalPath(path));
196
+ return projectRelative !== ".." && !projectRelative.startsWith(`..${sep}`) && !isAbsolute(projectRelative) && !projectRelative.split(sep).some((segment) => segment === "node_modules" || segment === ".canofold");
197
+ }
198
+ function moduleRequestUrl(server, modulePath) {
199
+ const rootRelative = relative(canonicalPath(server.config.root), canonicalPath(modulePath));
200
+ if (rootRelative !== ".." && !rootRelative.startsWith(`..${sep}`) && !isAbsolute(rootRelative)) {
201
+ return `/${normalizePath(rootRelative)}`;
202
+ }
203
+ return `/@fs/${normalizePath(modulePath)}`;
204
+ }
205
+ async function collectLocalDependencies(server, modulePath, cwd) {
206
+ await server.transformRequest(moduleRequestUrl(server, modulePath));
207
+ const first = server.moduleGraph.getModuleById(normalizePath(modulePath)) ?? server.moduleGraph.getModulesByFile(modulePath)?.values().next().value;
208
+ const visited = /* @__PURE__ */ new Set();
209
+ const dependencies = /* @__PURE__ */ new Set();
210
+ async function visit(module) {
211
+ if (!module) return;
212
+ const key = module.id ?? module.url;
213
+ if (visited.has(key)) return;
214
+ visited.add(key);
215
+ if (!module.file || !isProjectSource(cwd, module.file)) return;
216
+ dependencies.add(canonicalPath(module.file));
217
+ await server.transformRequest(module.url);
218
+ await Promise.all([...module.importedModules].map((dependency) => visit(dependency)));
219
+ }
220
+ await visit(first);
221
+ return [...dependencies].sort();
222
+ }
223
+ async function resolveDemo(server, reference, cwd) {
224
+ const resolved = await server.pluginContainer.resolveId(reference.specifier, importerFor(reference));
225
+ if (!resolved || resolved.external || resolved.id.startsWith("\0")) {
226
+ throw new Error(
227
+ `Vite could not resolve demo ${JSON.stringify(reference.specifier)} in ${reference.pageSourceRelativePath}`
228
+ );
229
+ }
230
+ const modulePath = filePathFromResolvedId(resolved.id);
231
+ if (!isAbsolute(modulePath)) {
232
+ throw new Error(
233
+ `Demo ${JSON.stringify(reference.specifier)} must resolve to a local source file, got ${JSON.stringify(resolved.id)}`
234
+ );
235
+ }
236
+ if (!isProjectSource(cwd, modulePath)) {
237
+ throw new Error(
238
+ `Demo ${JSON.stringify(reference.specifier)} must resolve inside the Canofold project root`
239
+ );
240
+ }
241
+ let source;
242
+ try {
243
+ source = await readFile(modulePath, "utf8");
244
+ } catch (error) {
245
+ const message = error instanceof Error ? error.message : String(error);
246
+ throw new Error(`Could not read demo source ${modulePath}: ${message}`);
247
+ }
248
+ return {
249
+ ...reference,
250
+ modulePath,
251
+ moduleUrl: normalizePath(resolved.id),
252
+ dependencyPaths: await collectLocalDependencies(server, modulePath, cwd),
253
+ source,
254
+ language: languageFor(modulePath)
255
+ };
256
+ }
257
+ async function resolvedSetup(server, setup, cwd) {
258
+ if (!setup) return void 0;
259
+ const importer = normalizePath(join(cwd, "canofold.config.ts"));
260
+ const resolved = await server.pluginContainer.resolveId(setup, importer);
261
+ if (!resolved || resolved.external || resolved.id.startsWith("\0")) {
262
+ throw new Error(`Vite could not resolve demos.setup ${JSON.stringify(setup)}`);
263
+ }
264
+ const modulePath = filePathFromResolvedId(resolved.id);
265
+ if (!isAbsolute(modulePath)) {
266
+ throw new Error(`demos.setup must resolve to a local source file, got ${JSON.stringify(resolved.id)}`);
267
+ }
268
+ if (!isProjectSource(cwd, modulePath)) {
269
+ throw new Error(`demos.setup ${JSON.stringify(setup)} must resolve inside the Canofold project root`);
270
+ }
271
+ return {
272
+ id: normalizePath(resolved.id),
273
+ dependencyPaths: await collectLocalDependencies(server, modulePath, cwd)
274
+ };
275
+ }
276
+ function virtualClientPlugin({
277
+ getDemos,
278
+ getSetup,
279
+ styleUrls = []
280
+ }) {
281
+ return {
282
+ name: "canofold-demo-client",
283
+ enforce: "post",
284
+ resolveId(id) {
285
+ return id === PUBLIC_CLIENT_ID ? RESOLVED_CLIENT_ID : void 0;
286
+ },
287
+ load(id) {
288
+ if (id !== RESOLVED_CLIENT_ID) return void 0;
289
+ const entries = [];
290
+ const registry = [];
291
+ getDemos().forEach((demo, index) => {
292
+ const binding = `CanofoldDemo${index}`;
293
+ entries.push(`import * as ${binding} from ${JSON.stringify(normalizePath(demo.modulePath))};`);
294
+ registry.push(`[${JSON.stringify(demo.id)}, ${binding}]`);
295
+ });
296
+ entries.push(`const CANOFOLD_DEMO_REGISTRY = [${registry.join(",")}];`);
297
+ const setup = getSetup();
298
+ const setupImport = setup ? `import CanofoldDemoSetup from ${JSON.stringify(setup)};` : void 0;
299
+ return demoRuntimeSource(entries, setupImport, styleUrls);
300
+ }
301
+ };
302
+ }
303
+ function inlineConfig(cwd, basePath, options, plugins) {
304
+ const configFile = options.configFile === false ? false : options.configFile ? resolve(cwd, options.configFile) : void 0;
305
+ return {
306
+ root: canonicalPath(options.root ? resolve(cwd, options.root) : cwd),
307
+ configFile,
308
+ base: basePath,
309
+ appType: "custom",
310
+ plugins: Array.isArray(plugins) ? plugins : [plugins],
311
+ resolve: { dedupe: ["react", "react-dom"] }
312
+ };
313
+ }
314
+ function demoBuildOptions(context) {
315
+ return {
316
+ // The project may itself be a Vite library. Demos are a browser app and
317
+ // must not inherit library externals or output conventions.
318
+ lib: false,
319
+ minify: "esbuild",
320
+ outDir: join(context.outputRoot, "assets/canofold-demos"),
321
+ emptyOutDir: true,
322
+ copyPublicDir: false,
323
+ cssCodeSplit: false,
324
+ rollupOptions: {
325
+ external: () => false,
326
+ input: PUBLIC_CLIENT_ID,
327
+ output: {
328
+ format: "es",
329
+ inlineDynamicImports: true,
330
+ entryFileNames: "index.js",
331
+ assetFileNames: (asset) => asset.names?.some((name) => name.endsWith(".css")) ? "styles.css" : "[name][extname]"
332
+ }
333
+ }
334
+ };
335
+ }
336
+ async function isolatedBuildConfig(context, options, plugin, build) {
337
+ const root = canonicalPath(options.root ? resolve(context.cwd, options.root) : context.cwd);
338
+ const configFile = options.configFile ? resolve(context.cwd, options.configFile) : void 0;
339
+ const loaded = options.configFile === false ? void 0 : await loadConfigFromFile(
340
+ { command: "build", mode: "production", isSsrBuild: false, isPreview: false },
341
+ configFile,
342
+ root
343
+ );
344
+ const sharedConfig = { ...loaded?.config ?? {} };
345
+ delete sharedConfig.build;
346
+ delete sharedConfig.server;
347
+ delete sharedConfig.preview;
348
+ const engineConfig = {
349
+ ...inlineConfig(context.cwd, context.basePath, { ...options, configFile: false }, plugin),
350
+ mode: "production",
351
+ define: {
352
+ "process.env.NODE_ENV": JSON.stringify("production")
353
+ },
354
+ esbuild: {
355
+ jsxDev: false
356
+ },
357
+ build
358
+ };
359
+ return mergeConfig(sharedConfig, engineConfig);
360
+ }
361
+ async function prepareDemos(context, options) {
362
+ let demos = [];
363
+ let setup;
364
+ const plugin = virtualClientPlugin({
365
+ getDemos: () => demos,
366
+ getSetup: () => setup,
367
+ styleUrls: context.mode === "build" ? [baseUrl(context.basePath, "/assets/canofold-demos/styles.css")] : []
368
+ });
369
+ const server = await createViteServer({
370
+ ...inlineConfig(context.cwd, context.basePath, options, plugin),
371
+ // This server only resolves source files and walks Vite's module graph.
372
+ // Dependency pre-bundling belongs to the long-lived dev server below; when
373
+ // started here it can keep server.close() waiting after the analysis is done.
374
+ optimizeDeps: { noDiscovery: true },
375
+ server: { middlewareMode: true, hmr: false, ws: false }
376
+ });
377
+ try {
378
+ demos = await Promise.all(context.demos.map((reference) => resolveDemo(server, reference, context.cwd)));
379
+ const resolved = await resolvedSetup(server, context.setup, context.cwd);
380
+ setup = resolved?.id;
381
+ return {
382
+ demos,
383
+ setup,
384
+ dependencyPaths: [
385
+ .../* @__PURE__ */ new Set([
386
+ ...server.config.configFileDependencies.map((path) => canonicalPath(path)),
387
+ ...resolved?.dependencyPaths ?? []
388
+ ])
389
+ ],
390
+ plugin
391
+ };
392
+ } finally {
393
+ await server.close();
394
+ }
395
+ }
396
+ function vite(options = {}) {
397
+ return {
398
+ id: "@canofold/vite",
399
+ version: "2",
400
+ cacheKey: {
401
+ root: options.root ?? null,
402
+ configFile: options.configFile ?? null
403
+ },
404
+ async prepare(context) {
405
+ const prepared = await prepareDemos(context, options);
406
+ if (context.mode === "build") {
407
+ const build = demoBuildOptions(context);
408
+ await viteBuild(await isolatedBuildConfig(context, options, prepared.plugin, build));
409
+ await writeFile(join(context.outputRoot, "assets/canofold-demos/styles.css"), "", {
410
+ flag: "a"
411
+ });
412
+ }
413
+ return {
414
+ clientUrl: context.mode === "build" ? baseUrl(context.basePath, "/assets/canofold-demos/index.js") : baseUrl(context.basePath, `/@id/__x00__${PUBLIC_CLIENT_ID}`),
415
+ ...context.mode === "build" ? { styleUrls: [baseUrl(context.basePath, "/assets/canofold-demos/styles.css")] } : {},
416
+ demos: Object.fromEntries(prepared.demos.map((demo) => [demo.id, demo])),
417
+ dependencyPaths: prepared.dependencyPaths,
418
+ ...context.mode === "build" ? {
419
+ outputPaths: ["assets/canofold-demos/index.js", "assets/canofold-demos/styles.css"]
420
+ } : {}
421
+ };
422
+ },
423
+ async startDev(context) {
424
+ const currentDemos = () => context.getDemos();
425
+ let setup;
426
+ const plugin = virtualClientPlugin({ getDemos: currentDemos, getSetup: () => setup });
427
+ const server = await createViteServer({
428
+ ...inlineConfig(context.cwd, context.basePath, options, plugin),
429
+ server: {
430
+ middlewareMode: true,
431
+ hmr: { server: context.server },
432
+ watch: { ignored: (path) => context.shouldIgnorePath(path) }
433
+ }
434
+ });
435
+ setup = (await resolvedSetup(server, context.setup, context.cwd))?.id;
436
+ let demoSignature = JSON.stringify(
437
+ currentDemos().map((demo) => [demo.id, normalizePath(demo.modulePath)])
438
+ );
439
+ return {
440
+ middleware(request, response, next) {
441
+ server.middlewares(request, response, next);
442
+ },
443
+ handlesFile(path) {
444
+ const absolutePath = canonicalPath(path);
445
+ const isEntry = currentDemos().some((demo) => canonicalPath(demo.modulePath) === absolutePath);
446
+ if (isEntry || setup && canonicalPath(filePathFromResolvedId(setup)) === absolutePath) {
447
+ return false;
448
+ }
449
+ return Boolean(server.moduleGraph.getModulesByFile(absolutePath)?.size);
450
+ },
451
+ update() {
452
+ const nextSignature = JSON.stringify(
453
+ currentDemos().map((demo) => [demo.id, normalizePath(demo.modulePath)])
454
+ );
455
+ if (nextSignature === demoSignature) return;
456
+ demoSignature = nextSignature;
457
+ const module = server.moduleGraph.getModuleById(RESOLVED_CLIENT_ID);
458
+ if (module) server.moduleGraph.invalidateModule(module);
459
+ server.ws.send({ type: "full-reload" });
460
+ },
461
+ close: () => server.close()
462
+ };
463
+ }
464
+ };
465
+ }
466
+ var src_default = vite;
467
+ export {
468
+ src_default as default,
469
+ vite
470
+ };
471
+ //# sourceMappingURL=index.js.map
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@canofold/vite",
3
+ "version": "0.3.0-rc.0",
4
+ "description": "Official Vite demo engine for interactive Canofold component documentation.",
5
+ "license": "MIT",
6
+ "author": "Canofold Contributors",
7
+ "homepage": "https://canofold.dev/guide/writing/component-demos/",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/canofold/canofold.git",
11
+ "directory": "packages/vite"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/canofold/canofold/issues"
15
+ },
16
+ "keywords": [
17
+ "canofold",
18
+ "vite",
19
+ "documentation",
20
+ "components",
21
+ "demos"
22
+ ],
23
+ "type": "module",
24
+ "types": "./dist/index.d.ts",
25
+ "exports": {
26
+ ".": {
27
+ "types": "./dist/index.d.ts",
28
+ "import": "./dist/index.js"
29
+ }
30
+ },
31
+ "files": [
32
+ "dist/**/*.js",
33
+ "dist/**/*.d.ts",
34
+ "README.md",
35
+ "README.zh-CN.md"
36
+ ],
37
+ "engines": {
38
+ "node": ">=22"
39
+ },
40
+ "publishConfig": {
41
+ "access": "public",
42
+ "provenance": true
43
+ },
44
+ "scripts": {
45
+ "build": "tsup",
46
+ "typecheck": "tsc --noEmit",
47
+ "test": "vitest run --root ../.. packages/vite"
48
+ },
49
+ "peerDependencies": {
50
+ "canofold": "^0.3.0",
51
+ "react": "^18.2.0 || ^19.0.0",
52
+ "react-dom": "^18.2.0 || ^19.0.0",
53
+ "vite": "^6.4.0 || ^7.0.0 || ^8.0.0"
54
+ },
55
+ "devDependencies": {
56
+ "@types/node": "^22.10.0",
57
+ "canofold": "workspace:*",
58
+ "tsup": "^8.3.5",
59
+ "typescript": "^6.0.3",
60
+ "vite": "^6.4.3",
61
+ "vitest": "^4.1.11"
62
+ }
63
+ }