doc-render-sdk 0.0.12 → 0.0.14

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.
@@ -46,11 +46,18 @@ program
46
46
  program
47
47
  .command('dev')
48
48
  .description('启动开发服务器')
49
- .option('-p, --port <port>', '端口号', '3000')
49
+ .option('-p, --port <port>', '端口号', '8080')
50
50
  .option('-h, --host <host>', '主机地址', 'localhost')
51
51
  .action(async (options) => {
52
52
  console.log('🚀 启动开发服务器...');
53
- await startDevServer(options);
53
+
54
+ const configPath = findConfig();
55
+ if (!configPath) {
56
+ console.error('❌ 未找到配置文件');
57
+ process.exit(1);
58
+ }
59
+
60
+ await startDevServer(configPath, options);
54
61
  });
55
62
 
56
63
  // 构建项目
@@ -60,7 +67,14 @@ program
60
67
  .option('-o, --output <dir>', '输出目录', 'dist')
61
68
  .action(async (options) => {
62
69
  console.log('📦 构建文档站点...');
63
- await buildProject(options);
70
+
71
+ const configPath = findConfig();
72
+ if (!configPath) {
73
+ console.error('❌ 未找到配置文件');
74
+ process.exit(1);
75
+ }
76
+
77
+ await buildProject(configPath, options);
64
78
  });
65
79
 
66
80
 
@@ -78,618 +92,241 @@ program
78
92
  program.parse();
79
93
 
80
94
  /**
81
- * 创建组件目录结构
82
- */
83
- function createComponentStructure(projectDir) {
84
- const components = ['button', 'input', 'card'];
85
-
86
- components.forEach(comp => {
87
- const compDir = path.join(projectDir, 'components', comp, 'demo');
88
- fs.mkdirSync(compDir, { recursive: true });
89
-
90
- // 创建 demo 文件
91
- createDemoFiles(projectDir, comp);
92
- });
93
- }
94
-
95
- /**
96
- * 创建 demo 文件
95
+ * 创建新项目
97
96
  */
98
- function createDemoFiles(projectDir, componentName) {
99
- const demos = {
100
- button: {
101
- basic: `import React from 'react';
102
- import { Button } from 'antd';
103
-
104
- export default function BasicButton() {
105
- return (
106
- <div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap' }}>
107
- <Button>Default</Button>
108
- <Button type="primary">Primary</Button>
109
- <Button type="dashed">Dashed</Button>
110
- <Button type="text">Text</Button>
111
- <Button type="link">Link</Button>
112
- </div>
113
- );
114
- }`,
115
- sizes: `import React from 'react';
116
- import { Button } from 'antd';
97
+ async function createProject(projectDir, template) {
98
+ // 创建项目目录
99
+ fs.mkdirSync(projectDir, { recursive: true });
117
100
 
118
- export default function ButtonSizes() {
119
- return (
120
- <div style={{ display: 'flex', gap: '8px', alignItems: 'center', flexWrap: 'wrap' }}>
121
- <Button size="large">Large</Button>
122
- <Button>Default</Button>
123
- <Button size="small">Small</Button>
124
- </div>
125
- );
126
- }`
127
- },
128
- input: {
129
- basic: `import React from 'react';
130
- import { Input } from 'antd';
101
+ // 生成package.json
102
+ const packageJson = {
103
+ name: path.basename(projectDir),
104
+ version: '1.0.0',
105
+ description: 'Documentation site built with Doc SDK',
106
+ main: 'index.jsx',
107
+ scripts: {
108
+ dev: 'doc-render-sdk dev',
109
+ build: 'doc-render-sdk build',
110
+ // TODO
111
+ // preview: 'doc-render-sdk preview'
112
+ },
113
+ dependencies: {
114
+ 'doc-render-sdk': sdkVersion,
115
+ "react": "^18.2.0",
116
+ "react-dom": "^18.2.0"
117
+ },
118
+ devDependencies: {
119
+ vite: '^5.0.0',
120
+ '@vitejs/plugin-react': '^3.1.0'
121
+ }
122
+ };
131
123
 
132
- export default function BasicInput() {
133
- return (
134
- <div style={{ display: 'flex', flexDirection: 'column', gap: '16px', maxWidth: '400px' }}>
135
- <Input placeholder="Basic usage" />
136
- <Input placeholder="Disabled" disabled />
137
- <Input.Password placeholder="Password" />
138
- </div>
124
+ fs.writeFileSync(
125
+ path.join(projectDir, 'package.json'),
126
+ JSON.stringify(packageJson, null, 2)
139
127
  );
140
- }`
141
- },
142
- card: {
143
- basic: `import React from 'react';
144
- import { Card } from 'antd';
145
128
 
146
- export default function BasicCard() {
147
- return (
148
- <Card title="Card Title" style={{ width: 300 }}>
149
- <p>Card content</p>
150
- <p>Card content</p>
151
- <p>Card content</p>
152
- </Card>
153
- );
154
- }`
129
+ // 生成配置文件
130
+ const config = {
131
+ title: 'My Documentation',
132
+ description: 'Component documentation built with Doc SDK',
133
+ version: '1.0.0',
134
+ components: {
135
+ 'example': {
136
+ label: 'Example Component',
137
+ description: 'An example component to get you started',
138
+ demos: [
139
+ {
140
+ title: 'Basic Usage',
141
+ desc: 'Basic usage of the component',
142
+ source: 'basic'
143
+ }
144
+ ],
145
+ apis: [
146
+ {
147
+ title: 'Example',
148
+ apiKey: 'Example'
149
+ }
150
+ ]
151
+ }
155
152
  }
156
153
  };
157
154
 
158
- const componentDemos = demos[componentName] || {};
159
-
160
- Object.entries(componentDemos).forEach(([demoName, content]) => {
161
- const demoPath = path.join(projectDir, 'components', componentName, 'demo', `${demoName}.jsx`);
162
- fs.writeFileSync(demoPath, content);
163
- });
164
- }
165
-
166
- /**
167
- * 创建 Vite 配置
168
- */
169
- function createViteConfig(projectDir) {
170
- const viteConfig = `import { defineConfig } from 'vite';
171
- import react from '@vitejs/plugin-react';
172
- import { resolve } from 'path';
173
- import { createDemoCodePlugin } from 'doc-render-sdk/plugin';
174
-
175
- export default defineConfig({
176
- plugins: [
177
- react(),
178
- createDemoCodePlugin({
179
- include: 'index.js',
180
- demoPattern: '/demo/',
181
- globalVar: 'window.__DOC_SDK_DEMO_CODES__',
182
- debug: process.env.NODE_ENV === 'development',
183
- })
184
- ],
185
- resolve: {
186
- alias: {
187
- '@': resolve(__dirname, 'src')
188
- }
189
- },
190
- server: {
191
- port: 3000,
192
- open: true
193
- }
194
- });
195
- `;
196
-
197
- fs.writeFileSync(path.join(projectDir, 'vite.config.js'), viteConfig);
198
- }
155
+ fs.writeFileSync(
156
+ path.join(projectDir, 'doc.config.js'),
157
+ `export default ${JSON.stringify(config, null, 2)};`
158
+ );
199
159
 
200
- /**
201
- * 创建入口文件
202
- */
203
- function createIndexFile(projectDir) {
160
+ // 生成入口文件
204
161
  const indexJs = `import DocSDK from 'doc-render-sdk';
162
+ import config from './doc.config.js';
205
163
 
206
- // Button 组件 demos
207
- import buttonBasic from './components/button/demo/basic.jsx';
208
- import buttonSizes from './components/button/demo/sizes.jsx';
209
-
210
- // Input 组件 demos
211
- import inputBasic from './components/input/demo/basic.jsx';
212
-
213
- // Card 组件 demos
214
- import cardBasic from './components/card/demo/basic.jsx';
164
+ // 注册示例组件
165
+ const ExampleComponent = () => {
166
+ return (
167
+ <div style={{ padding: '20px' }}>
168
+ <h3>Example Component</h3>
169
+ <p>This is an example component.</p>
170
+ </div>
171
+ );
172
+ };
215
173
 
216
174
  // 注册全局组件
217
175
  window.__DOC_SDK_DEMOS__ = {
218
- 'button': {
219
- 'basic': buttonBasic,
220
- 'sizes': buttonSizes,
221
- },
222
- 'input': {
223
- 'basic': inputBasic,
224
- },
225
- 'card': {
226
- 'basic': cardBasic,
227
- },
176
+ 'example': {
177
+ 'basic': ExampleComponent
178
+ }
228
179
  };
229
180
 
230
- // Demo 源码将由 vite-plugin-demo-code 自动注入
181
+ window.__DOC_SDK_DEMO_CODES__ = {
182
+ 'example': {
183
+ 'basic': \`const ExampleComponent = () => {
184
+ return (
185
+ <div style={{ padding: '20px' }}>
186
+ <h3>Example Component</h3>
187
+ <p>This is an example component.</p>
188
+ </div>
189
+ );
190
+ };\`
191
+ }
192
+ };
231
193
 
232
- // 注册 API 文档
233
194
  window.__DOC_SDK_APIS__ = {
234
- 'button': {
235
- 'Button': [
236
- {
237
- param: 'type',
238
- type: 'string',
239
- desc: '按钮类型',
240
- option: 'default | primary | dashed | text | link',
241
- default: 'default',
242
- required: false
243
- },
244
- {
245
- param: 'size',
246
- type: 'string',
247
- desc: '按钮尺寸',
248
- option: 'small | middle | large',
249
- default: 'middle',
250
- required: false
251
- },
252
- {
253
- param: 'disabled',
254
- type: 'boolean',
255
- desc: '是否禁用',
256
- option: 'true | false',
257
- default: 'false',
258
- required: false
259
- },
260
- {
261
- param: 'onClick',
262
- type: 'function',
263
- desc: '点击事件回调',
264
- option: '(event) => void',
265
- default: '-',
266
- required: false
267
- },
268
- ]
269
- },
270
- 'input': {
271
- 'Input': [
272
- {
273
- param: 'value',
274
- type: 'string',
275
- desc: '输入框的值',
276
- option: '-',
277
- default: '-',
278
- required: false
279
- },
280
- {
281
- param: 'placeholder',
282
- type: 'string',
283
- desc: '占位文本',
284
- option: '-',
285
- default: '-',
286
- required: false
287
- },
288
- {
289
- param: 'disabled',
290
- type: 'boolean',
291
- desc: '是否禁用',
292
- option: 'true | false',
293
- default: 'false',
294
- required: false
295
- },
296
- {
297
- param: 'onChange',
298
- type: 'function',
299
- desc: '值变化时的回调',
300
- option: '(e) => void',
301
- default: '-',
302
- required: false
303
- },
304
- ]
305
- },
306
- 'card': {
307
- 'Card': [
308
- {
309
- param: 'title',
310
- type: 'string | ReactNode',
311
- desc: '卡片标题',
312
- option: '-',
313
- default: '-',
314
- required: false
315
- },
316
- {
317
- param: 'bordered',
318
- type: 'boolean',
319
- desc: '是否有边框',
320
- option: 'true | false',
321
- default: 'true',
322
- required: false
323
- },
195
+ 'example': {
196
+ 'Example': [
324
197
  {
325
198
  param: 'children',
326
199
  type: 'ReactNode',
327
- desc: '卡片内容',
328
- option: '-',
329
- default: '-',
200
+ desc: 'The content of the component',
201
+ option: '',
202
+ default: '',
330
203
  required: false
331
- },
204
+ }
332
205
  ]
333
- },
206
+ }
334
207
  };
335
208
 
336
- // 创建文档SDK实例
337
- const docSdk = new DocSDK({
338
- title: 'My Component Library',
339
- description: '基于 Doc SDK 构建的组件文档',
340
- version: '1.0.0',
341
-
342
- theme: {
343
- name: 'default',
344
- colors: {
345
- primary: '#1890ff'
346
- }
347
- },
348
-
349
- layout: {
350
- type: 'sidebar',
351
- sidebar: {
352
- width: 280,
353
- collapsible: true
354
- }
355
- },
356
-
357
- components: {
358
- 'button': {
359
- label: 'Button 按钮',
360
- description: '按钮用于触发一个操作',
361
- group: '基础组件',
362
- demos: [
363
- {
364
- title: '按钮类型',
365
- desc: '按钮有五种类型:默认按钮、主要按钮、虚线按钮、文本按钮和链接按钮',
366
- source: 'basic'
367
- },
368
- {
369
- title: '按钮尺寸',
370
- desc: '按钮有三种尺寸:大、中、小',
371
- source: 'sizes'
372
- }
373
- ],
374
- apis: [
375
- {
376
- title: 'Button Props',
377
- apiKey: 'Button'
378
- }
379
- ]
380
- },
381
- 'input': {
382
- label: 'Input 输入框',
383
- description: '通过鼠标或键盘输入内容',
384
- group: '表单组件',
385
- demos: [
386
- {
387
- title: '基础用法',
388
- desc: '基础的输入框用法',
389
- source: 'basic'
390
- }
391
- ],
392
- apis: [
393
- {
394
- title: 'Input Props',
395
- apiKey: 'Input'
396
- }
397
- ]
398
- },
399
- 'card': {
400
- label: 'Card 卡片',
401
- description: '通用卡片容器',
402
- group: '数据展示',
403
- demos: [
404
- {
405
- title: '基础卡片',
406
- desc: '包含标题、内容的基础卡片',
407
- source: 'basic'
408
- }
409
- ],
410
- apis: [
411
- {
412
- title: 'Card Props',
413
- apiKey: 'Card'
414
- }
415
- ]
416
- },
417
- },
418
-
419
- installation: \`# 使用 npm
420
- npm install my-component-library
421
-
422
- # 使用 yarn
423
- yarn add my-component-library
424
-
425
- # 使用 pnpm
426
- pnpm add my-component-library\`,
427
-
428
- usage: \`import { Button } from 'my-component-library';
429
-
430
- function App() {
431
- return <Button type="primary">Click me</Button>;
432
- }\`,
433
-
434
- features: [
435
- {
436
- icon: '🎨',
437
- title: '主题定制',
438
- description: '支持自定义主题颜色、字体、间距等'
439
- },
440
- {
441
- icon: '📱',
442
- title: '响应式设计',
443
- description: '完美适配桌面端和移动端'
444
- },
445
- {
446
- icon: '⚡',
447
- title: '高性能',
448
- description: '采用 React 18 和虚拟滚动技术'
449
- },
450
- {
451
- icon: '🔍',
452
- title: '智能搜索',
453
- description: '内置全文搜索功能'
454
- }
455
- ],
456
-
457
- footerLinks: [
458
- {
459
- text: 'GitHub',
460
- url: 'https://github.com/yourusername/your-repo',
461
- external: true
462
- }
463
- ]
464
- });
465
-
466
- // 渲染文档
209
+ const docSdk = new DocSDK(config);
467
210
  docSdk.render('#app');
468
211
  `;
469
212
 
470
- fs.writeFileSync(path.join(projectDir, 'index.js'), indexJs);
471
- }
213
+ fs.writeFileSync(path.join(projectDir, 'index.jsx'), indexJs);
472
214
 
473
- /**
474
- * 创建 HTML 文件
475
- */
476
- function createIndexHtml(projectDir) {
215
+ // 生成HTML文件
477
216
  const indexHtml = `<!DOCTYPE html>
478
217
  <html lang="zh-CN">
479
218
  <head>
480
219
  <meta charset="UTF-8">
481
220
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
482
- <title>My Component Library</title>
221
+ <title>My Documentation</title>
222
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github.min.css">
223
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"></script>
483
224
  </head>
484
225
  <body>
485
226
  <div id="app"></div>
486
- <script src="index.js" type="module"></script>
227
+ <script src="index.jsx" type="module"></script>
487
228
  </body>
488
229
  </html>`;
489
230
 
490
231
  fs.writeFileSync(path.join(projectDir, 'index.html'), indexHtml);
491
- }
492
232
 
493
- /**
494
- * 创建 README
495
- */
496
- function createReadme(projectDir) {
233
+ // 生成README
497
234
  const readme = `# ${path.basename(projectDir)}
498
235
 
499
- 基于 Doc SDK 构建的组件文档站点。
236
+ Documentation site built with Doc SDK.
500
237
 
501
- ## 快速开始
238
+ ## Getting Started
502
239
 
503
240
  \`\`\`bash
504
- # 安装依赖
505
241
  npm install
506
-
507
- # 启动开发服务器
508
242
  npm run dev
509
-
510
- # 构建生产版本
511
- npm run build
512
-
513
- # 预览构建结果
514
- npm run preview
515
- \`\`\`
516
-
517
- ## 项目结构
518
-
519
- \`\`\`
520
- ${path.basename(projectDir)}/
521
- ├── components/ # 组件目录
522
- │ ├── button/
523
- │ │ └── demo/ # Button 组件示例
524
- │ ├── input/
525
- │ │ └── demo/ # Input 组件示例
526
- │ └── card/
527
- │ └── demo/ # Card 组件示例
528
- ├── index.html # HTML 入口
529
- ├── index.js # JS 入口
530
- ├── vite.config.js # Vite 配置
531
- └── package.json
532
243
  \`\`\`
533
244
 
534
- ## 添加新组件
245
+ ## Commands
535
246
 
536
- 1. \`components/\` 目录下创建组件文件夹
537
- 2. \`components/your-component/demo/\` 下创建示例文件
538
- 3. \`index.js\` 中注册组件和 API 文档
247
+ - \`npm run dev\` - Start development server
248
+ - \`npm run build\` - Build for production
249
+ - \`npm run preview\` - Preview build
539
250
 
540
- ## 文档
251
+ ## Documentation
541
252
 
542
- - [Doc SDK 文档](https://github.com/Sunny-117/doc-render-sdk)
543
- - [Vite 文档](https://vitejs.dev/)
544
- - [React 文档](https://react.dev/)
253
+ - [Doc SDK Documentation](https://github.com/Sunny-117/doc-render-sdk)
545
254
  `;
546
255
 
547
256
  fs.writeFileSync(path.join(projectDir, 'README.md'), readme);
548
257
  }
549
258
 
550
259
  /**
551
- * 创建新项目
260
+ * 查找配置文件
552
261
  */
553
- async function createProject(projectDir, template) {
554
- // 创建项目目录
555
- fs.mkdirSync(projectDir, { recursive: true });
556
-
557
- // 生成package.json
558
- const packageJson = {
559
- name: path.basename(projectDir),
560
- version: '1.0.0',
561
- description: 'Documentation site built with Doc SDK',
562
- type: 'module',
563
- main: 'index.js',
564
- scripts: {
565
- dev: 'doc-render-sdk dev',
566
- build: 'doc-render-sdk build',
567
- preview: 'doc-render-sdk preview'
568
- },
569
- dependencies: {
570
- 'doc-render-sdk': `^${sdkVersion}`,
571
- 'react': '^18.2.0',
572
- 'react-dom': '^18.2.0',
573
- 'antd': '6.0.0-alpha.3'
574
- },
575
- devDependencies: {
576
- 'vite': '7.1.8',
577
- '@vitejs/plugin-react': '5.0.4'
262
+ function findConfig() {
263
+ const configFiles = [
264
+ 'doc.config.js',
265
+ 'doc.config.json',
266
+ 'docs.config.js',
267
+ 'docs.config.json'
268
+ ];
269
+
270
+ for (const file of configFiles) {
271
+ if (fs.existsSync(file)) {
272
+ return path.resolve(file);
578
273
  }
579
- };
580
-
581
- fs.writeFileSync(
582
- path.join(projectDir, 'package.json'),
583
- JSON.stringify(packageJson, null, 2)
584
- );
585
-
586
- // 创建组件目录结构
587
- createComponentStructure(projectDir);
588
-
589
- // 生成 vite.config.js
590
- createViteConfig(projectDir);
591
-
592
- // 生成入口文件
593
- createIndexFile(projectDir);
594
-
595
- // 生成HTML文件
596
- createIndexHtml(projectDir);
274
+ }
597
275
 
598
- // 生成README
599
- createReadme(projectDir);
276
+ return null;
600
277
  }
601
278
 
602
279
  /**
603
280
  * 启动开发服务器
604
281
  */
605
- async function startDevServer(options) {
606
- try {
607
- const { createServer } = require('vite');
608
- const react = require('@vitejs/plugin-react');
609
-
610
- // 尝试加载 doc-render-sdk 插件
611
- let demoPlugin = null;
282
+ function startDevServer(configPath, options) {
283
+ // Use Vite Node API to create a dev server via createViteServer
284
+ (async () => {
612
285
  try {
613
- const { createDemoCodePlugin } = require('doc-render-sdk/plugin');
614
- demoPlugin = createDemoCodePlugin({
615
- include: 'index.js',
616
- demoPattern: '/demo/',
617
- globalVar: 'window.__DOC_SDK_DEMO_CODES__',
618
- debug: true,
286
+ const server = await createViteServer({
287
+ root: process.cwd(),
288
+ server: {
289
+ port: Number(options.port) || 8080,
290
+ host: options.host || 'localhost'
291
+ },
292
+ plugins: createVitePlugins()
619
293
  });
620
- } catch (err) {
621
- console.warn('⚠️ 未找到 doc-render-sdk 插件,将跳过 demo 代码注入功能');
622
- }
623
294
 
624
- const plugins = [react()];
625
- if (demoPlugin) {
626
- plugins.push(demoPlugin);
295
+ await server.listen();
296
+ server.printUrls();
297
+ } catch (err) {
298
+ console.error('❌ 启动 Vite 开发服务器失败:', err);
299
+ process.exit(1);
627
300
  }
628
-
629
- const server = await createServer({
630
- root: process.cwd(),
631
- server: {
632
- port: Number(options.port) || 3000,
633
- host: options.host || 'localhost',
634
- open: true
635
- },
636
- plugins
637
- });
638
-
639
- await server.listen();
640
- server.printUrls();
641
-
642
- console.log('\n✨ 开发服务器已启动!');
643
- } catch (err) {
644
- console.error('❌ 启动开发服务器失败:', err);
645
- process.exit(1);
646
- }
301
+ })();
647
302
  }
648
303
 
649
304
  /**
650
305
  * 构建项目
651
306
  */
652
- async function buildProject(options) {
653
- try {
654
- const { build } = require('vite');
655
- const react = require('@vitejs/plugin-react');
656
- const outDir = options.output || 'dist';
657
-
658
- // 尝试加载 doc-render-sdk 插件
659
- let demoPlugin = null;
307
+ function buildProject(configPath, options) {
308
+ // Use Vite build API with plugin-react
309
+ (async () => {
660
310
  try {
661
- const { createDemoCodePlugin } = require('doc-render-sdk/plugin');
662
- demoPlugin = createDemoCodePlugin({
663
- include: 'index.js',
664
- demoPattern: '/demo/',
665
- globalVar: 'window.__DOC_SDK_DEMO_CODES__',
666
- debug: false,
667
- });
668
- } catch (err) {
669
- console.warn('⚠️ 未找到 doc-render-sdk 插件,将跳过 demo 代码注入功能');
670
- }
671
-
672
- const plugins = [react()];
673
- if (demoPlugin) {
674
- plugins.push(demoPlugin);
675
- }
311
+ const { build } = require('vite');
312
+ const outDir = options.output || 'dist';
676
313
 
677
- console.log('📦 开始构建...');
314
+ console.log('📦 running vite build...');
678
315
 
679
- await build({
680
- root: process.cwd(),
681
- build: {
682
- outDir
683
- },
684
- plugins
685
- });
316
+ await build({
317
+ root: process.cwd(),
318
+ build: {
319
+ outDir
320
+ },
321
+ plugins: createVitePlugins()
322
+ });
686
323
 
687
- console.log('✅ 构建完成!');
688
- console.log(`📁 输出目录: ${outDir}`);
689
- } catch (err) {
690
- console.error('❌ 构建失败:', err);
691
- process.exit(1);
692
- }
324
+ console.log('✅ 构建完成!');
325
+ } catch (err) {
326
+ console.error('❌ Vite 构建失败:', err);
327
+ process.exit(1);
328
+ }
329
+ })();
693
330
  }
694
331
 
695
332
  /**
@@ -714,25 +351,47 @@ function createVitePlugins() {
714
351
  /**
715
352
  * 预览构建结果
716
353
  */
717
- async function previewBuild(options) {
718
- try {
719
- const { preview } = require('vite');
720
- const port = Number(options.port) || 3000;
721
-
722
- console.log('👀 启动预览服务器...');
354
+ function previewBuild(options) {
355
+ // Use Vite programmatic preview API if available, else fallback to npx vite preview
356
+ const distDir = options.dir || 'dist';
357
+ const port = Number(options.port) || 3000;
723
358
 
724
- const server = await preview({
725
- root: process.cwd(),
726
- preview: {
727
- port,
728
- open: true
729
- }
730
- });
359
+ try {
360
+ const vite = require('vite');
361
+ if (typeof vite.preview === 'function') {
362
+ // Vite exposes preview function in some versions
363
+ (async () => {
364
+ try {
365
+ const server = await vite.preview({ root: process.cwd(), preview: { port } });
366
+ console.log(`📖 预览地址: http://localhost:${port}`);
367
+ } catch (err) {
368
+ console.error('❌ 启动 Vite preview 失败:', err);
369
+ process.exit(1);
370
+ }
371
+ })();
372
+ return;
373
+ }
731
374
 
732
- server.printUrls();
733
- console.log('\n✨ 预览服务器已启动!');
375
+ // Fallback: try to create a server configured for preview
376
+ if (typeof vite.createServer === 'function') {
377
+ (async () => {
378
+ try {
379
+ const server = await vite.createServer({ root: process.cwd(), preview: { port } });
380
+ await server.listen();
381
+ console.log(`📖 预览地址: http://localhost:${port}`);
382
+ } catch (err) {
383
+ // continue to fallback
384
+ console.error('❌ 使用 createServer 作为 preview 启动失败,回退到 CLI:', err.message || err);
385
+ }
386
+ })();
387
+ return;
388
+ }
734
389
  } catch (err) {
735
- console.error('❌ 启动预览服务器失败:', err);
736
- process.exit(1);
390
+ // vite not installed locally, will fallback to npx
737
391
  }
392
+
393
+ // Final fallback: spawn npx vite preview
394
+ const args = ['vite', 'preview', '--port', String(port)];
395
+ const child = spawn('npx', args, { stdio: 'inherit', shell: true, cwd: process.cwd() });
396
+ child.on('close', (code) => process.exit(code));
738
397
  }