doc-render-sdk 0.0.8 → 0.0.12

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,18 +46,11 @@ program
46
46
  program
47
47
  .command('dev')
48
48
  .description('启动开发服务器')
49
- .option('-p, --port <port>', '端口号', '8080')
49
+ .option('-p, --port <port>', '端口号', '3000')
50
50
  .option('-h, --host <host>', '主机地址', 'localhost')
51
51
  .action(async (options) => {
52
52
  console.log('🚀 启动开发服务器...');
53
-
54
- const configPath = findConfig();
55
- if (!configPath) {
56
- console.error('❌ 未找到配置文件');
57
- process.exit(1);
58
- }
59
-
60
- await startDevServer(configPath, options);
53
+ await startDevServer(options);
61
54
  });
62
55
 
63
56
  // 构建项目
@@ -67,14 +60,7 @@ program
67
60
  .option('-o, --output <dir>', '输出目录', 'dist')
68
61
  .action(async (options) => {
69
62
  console.log('📦 构建文档站点...');
70
-
71
- const configPath = findConfig();
72
- if (!configPath) {
73
- console.error('❌ 未找到配置文件');
74
- process.exit(1);
75
- }
76
-
77
- await buildProject(configPath, options);
63
+ await buildProject(options);
78
64
  });
79
65
 
80
66
 
@@ -92,241 +78,618 @@ program
92
78
  program.parse();
93
79
 
94
80
  /**
95
- * 创建新项目
81
+ * 创建组件目录结构
96
82
  */
97
- async function createProject(projectDir, template) {
98
- // 创建项目目录
99
- fs.mkdirSync(projectDir, { recursive: true });
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
+ }
100
94
 
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
- };
95
+ /**
96
+ * 创建 demo 文件
97
+ */
98
+ function createDemoFiles(projectDir, componentName) {
99
+ const demos = {
100
+ button: {
101
+ basic: `import React from 'react';
102
+ import { Button } from 'antd';
123
103
 
124
- fs.writeFileSync(
125
- path.join(projectDir, 'package.json'),
126
- JSON.stringify(packageJson, null, 2)
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>
127
113
  );
114
+ }`,
115
+ sizes: `import React from 'react';
116
+ import { Button } from 'antd';
128
117
 
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
- }
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';
131
+
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>
139
+ );
140
+ }`
141
+ },
142
+ card: {
143
+ basic: `import React from 'react';
144
+ import { Card } from 'antd';
145
+
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
+ }`
152
155
  }
153
156
  };
154
157
 
155
- fs.writeFileSync(
156
- path.join(projectDir, 'doc.config.js'),
157
- `export default ${JSON.stringify(config, null, 2)};`
158
- );
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
+ }
159
165
 
160
- // 生成入口文件
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
+ }
199
+
200
+ /**
201
+ * 创建入口文件
202
+ */
203
+ function createIndexFile(projectDir) {
161
204
  const indexJs = `import DocSDK from 'doc-render-sdk';
162
- import config from './doc.config.js';
163
205
 
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
- };
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';
173
215
 
174
216
  // 注册全局组件
175
217
  window.__DOC_SDK_DEMOS__ = {
176
- 'example': {
177
- 'basic': ExampleComponent
178
- }
218
+ 'button': {
219
+ 'basic': buttonBasic,
220
+ 'sizes': buttonSizes,
221
+ },
222
+ 'input': {
223
+ 'basic': inputBasic,
224
+ },
225
+ 'card': {
226
+ 'basic': cardBasic,
227
+ },
179
228
  };
180
229
 
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
- };
230
+ // Demo 源码将由 vite-plugin-demo-code 自动注入
193
231
 
232
+ // 注册 API 文档
194
233
  window.__DOC_SDK_APIS__ = {
195
- 'example': {
196
- 'Example': [
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
+ },
197
324
  {
198
325
  param: 'children',
199
326
  type: 'ReactNode',
200
- desc: 'The content of the component',
201
- option: '',
202
- default: '',
327
+ desc: '卡片内容',
328
+ option: '-',
329
+ default: '-',
203
330
  required: false
204
- }
331
+ },
205
332
  ]
206
- }
333
+ },
207
334
  };
208
335
 
209
- const docSdk = new DocSDK(config);
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
+ // 渲染文档
210
467
  docSdk.render('#app');
211
468
  `;
212
469
 
213
- fs.writeFileSync(path.join(projectDir, 'index.jsx'), indexJs);
470
+ fs.writeFileSync(path.join(projectDir, 'index.js'), indexJs);
471
+ }
214
472
 
215
- // 生成HTML文件
473
+ /**
474
+ * 创建 HTML 文件
475
+ */
476
+ function createIndexHtml(projectDir) {
216
477
  const indexHtml = `<!DOCTYPE html>
217
478
  <html lang="zh-CN">
218
479
  <head>
219
480
  <meta charset="UTF-8">
220
481
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
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>
482
+ <title>My Component Library</title>
224
483
  </head>
225
484
  <body>
226
485
  <div id="app"></div>
227
- <script src="index.jsx"></script>
486
+ <script src="index.js" type="module"></script>
228
487
  </body>
229
488
  </html>`;
230
489
 
231
490
  fs.writeFileSync(path.join(projectDir, 'index.html'), indexHtml);
491
+ }
232
492
 
233
- // 生成README
493
+ /**
494
+ * 创建 README
495
+ */
496
+ function createReadme(projectDir) {
234
497
  const readme = `# ${path.basename(projectDir)}
235
498
 
236
- Documentation site built with Doc SDK.
499
+ 基于 Doc SDK 构建的组件文档站点。
237
500
 
238
- ## Getting Started
501
+ ## 快速开始
239
502
 
240
503
  \`\`\`bash
504
+ # 安装依赖
241
505
  npm install
506
+
507
+ # 启动开发服务器
242
508
  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
243
532
  \`\`\`
244
533
 
245
- ## Commands
534
+ ## 添加新组件
246
535
 
247
- - \`npm run dev\` - Start development server
248
- - \`npm run build\` - Build for production
249
- - \`npm run preview\` - Preview build
536
+ 1. \`components/\` 目录下创建组件文件夹
537
+ 2. \`components/your-component/demo/\` 下创建示例文件
538
+ 3. \`index.js\` 中注册组件和 API 文档
250
539
 
251
- ## Documentation
540
+ ## 文档
252
541
 
253
- - [Doc SDK Documentation](https://github.com/Sunny-117/doc-render-sdk)
542
+ - [Doc SDK 文档](https://github.com/Sunny-117/doc-render-sdk)
543
+ - [Vite 文档](https://vitejs.dev/)
544
+ - [React 文档](https://react.dev/)
254
545
  `;
255
546
 
256
547
  fs.writeFileSync(path.join(projectDir, 'README.md'), readme);
257
548
  }
258
549
 
259
550
  /**
260
- * 查找配置文件
551
+ * 创建新项目
261
552
  */
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);
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'
273
578
  }
274
- }
579
+ };
275
580
 
276
- return null;
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);
597
+
598
+ // 生成README
599
+ createReadme(projectDir);
277
600
  }
278
601
 
279
602
  /**
280
603
  * 启动开发服务器
281
604
  */
282
- function startDevServer(configPath, options) {
283
- // Use Vite Node API to create a dev server via createViteServer
284
- (async () => {
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;
285
612
  try {
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()
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,
293
619
  });
294
-
295
- await server.listen();
296
- server.printUrls();
297
620
  } catch (err) {
298
- console.error(' 启动 Vite 开发服务器失败:', err);
299
- process.exit(1);
621
+ console.warn('⚠️ 未找到 doc-render-sdk 插件,将跳过 demo 代码注入功能');
622
+ }
623
+
624
+ const plugins = [react()];
625
+ if (demoPlugin) {
626
+ plugins.push(demoPlugin);
300
627
  }
301
- })();
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
+ }
302
647
  }
303
648
 
304
649
  /**
305
650
  * 构建项目
306
651
  */
307
- function buildProject(configPath, options) {
308
- // Use Vite build API with plugin-react
309
- (async () => {
310
- try {
311
- const { build } = require('vite');
312
- const outDir = options.output || 'dist';
313
-
314
- console.log('📦 running vite build...');
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';
315
657
 
316
- await build({
317
- root: process.cwd(),
318
- build: {
319
- outDir
320
- },
321
- plugins: createVitePlugins()
658
+ // 尝试加载 doc-render-sdk 插件
659
+ let demoPlugin = null;
660
+ 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,
322
667
  });
323
-
324
- console.log('✅ 构建完成!');
325
668
  } catch (err) {
326
- console.error(' Vite 构建失败:', err);
327
- process.exit(1);
669
+ console.warn('⚠️ 未找到 doc-render-sdk 插件,将跳过 demo 代码注入功能');
670
+ }
671
+
672
+ const plugins = [react()];
673
+ if (demoPlugin) {
674
+ plugins.push(demoPlugin);
328
675
  }
329
- })();
676
+
677
+ console.log('📦 开始构建...');
678
+
679
+ await build({
680
+ root: process.cwd(),
681
+ build: {
682
+ outDir
683
+ },
684
+ plugins
685
+ });
686
+
687
+ console.log('✅ 构建完成!');
688
+ console.log(`📁 输出目录: ${outDir}`);
689
+ } catch (err) {
690
+ console.error('❌ 构建失败:', err);
691
+ process.exit(1);
692
+ }
330
693
  }
331
694
 
332
695
  /**
@@ -351,47 +714,25 @@ function createVitePlugins() {
351
714
  /**
352
715
  * 预览构建结果
353
716
  */
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;
358
-
717
+ async function previewBuild(options) {
359
718
  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
- }
719
+ const { preview } = require('vite');
720
+ const port = Number(options.port) || 3000;
374
721
 
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
- }
722
+ console.log('👀 启动预览服务器...');
723
+
724
+ const server = await preview({
725
+ root: process.cwd(),
726
+ preview: {
727
+ port,
728
+ open: true
729
+ }
730
+ });
731
+
732
+ server.printUrls();
733
+ console.log('\n✨ 预览服务器已启动!');
389
734
  } catch (err) {
390
- // vite not installed locally, will fallback to npx
735
+ console.error('❌ 启动预览服务器失败:', err);
736
+ process.exit(1);
391
737
  }
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));
397
738
  }