@doubao-apps/create 0.0.33 → 0.0.34

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.
Files changed (48) hide show
  1. package/dist/421.js +4 -4
  2. package/dist/cli.js +74 -66
  3. package/dist/index.d.ts +1 -2
  4. package/dist/template-empty/README.md +1 -1
  5. package/dist/template-empty/package.json +2 -2
  6. package/dist/template-starter/README.md +48 -169
  7. package/dist/template-starter/package.json +2 -2
  8. package/dist/template-starter/src/app.config.ts +2 -3
  9. package/dist/template-starter/src/pages/home/index.scss +38 -172
  10. package/dist/template-starter/src/pages/home/index.tsx +20 -78
  11. package/dist/template-starter/src/widgets/hello-world/index.scss +23 -0
  12. package/dist/template-starter/src/widgets/hello-world/index.tsx +29 -0
  13. package/package.json +6 -2
  14. package/dist/template-empty/AGENTS.md +0 -299
  15. package/dist/template-empty/references/examples/common-patterns.md +0 -589
  16. package/dist/template-empty/references/examples/component-basics.md +0 -526
  17. package/dist/template-empty/references/guides/best-practices.md +0 -571
  18. package/dist/template-empty/references/guides/component-development.md +0 -891
  19. package/dist/template-empty/references/guides/performance-optimization.md +0 -402
  20. package/dist/template-empty/references/guides/troubleshooting.md +0 -287
  21. package/dist/template-empty/references/reference/components-quick-ref.md +0 -103
  22. package/dist/template-empty/references/reference/framework-api-quick-ref.md +0 -550
  23. package/dist/template-empty/references/reference/open-api/README.md +0 -8
  24. package/dist/template-empty/references/reference/open-api.md +0 -11
  25. package/dist/template-empty/references/rules/dos-and-donts.md +0 -467
  26. package/dist/template-starter/AGENTS.md +0 -299
  27. package/dist/template-starter/debug-scene/render-home-page-full.json +0 -6
  28. package/dist/template-starter/debug-scene/render-home-page.json +0 -5
  29. package/dist/template-starter/debug-scene/render-react-lynx-page-full.json +0 -6
  30. package/dist/template-starter/references/examples/common-patterns.md +0 -589
  31. package/dist/template-starter/references/examples/component-basics.md +0 -526
  32. package/dist/template-starter/references/guides/best-practices.md +0 -571
  33. package/dist/template-starter/references/guides/component-development.md +0 -891
  34. package/dist/template-starter/references/guides/performance-optimization.md +0 -402
  35. package/dist/template-starter/references/guides/troubleshooting.md +0 -287
  36. package/dist/template-starter/references/reference/components-quick-ref.md +0 -103
  37. package/dist/template-starter/references/reference/framework-api-quick-ref.md +0 -550
  38. package/dist/template-starter/references/reference/open-api/README.md +0 -8
  39. package/dist/template-starter/references/reference/open-api.md +0 -11
  40. package/dist/template-starter/references/rules/dos-and-donts.md +0 -467
  41. package/dist/template-starter/src/pages/applet/index.scss +0 -279
  42. package/dist/template-starter/src/pages/applet/index.tsx +0 -78
  43. package/dist/template-starter/src/pages/lynx/index.scss +0 -249
  44. package/dist/template-starter/src/pages/lynx/index.tsx +0 -78
  45. package/dist/template-starter/src/pages/react-lynx/index.scss +0 -335
  46. package/dist/template-starter/src/pages/react-lynx/index.tsx +0 -132
  47. package/dist/template-starter/src/widgets/weather-card/index.scss +0 -272
  48. package/dist/template-starter/src/widgets/weather-card/index.tsx +0 -193
@@ -1,571 +0,0 @@
1
- # 最佳实践
2
-
3
- Doubao Apps SDK 框架的最佳开发实践和代码规范。
4
-
5
- ---
6
-
7
- ## 🎯 核心原则
8
-
9
- ### SOLID 原则
10
-
11
- 1. **单一职责原则**(Single Responsibility)
12
- - 每个组件只负责一个功能
13
- - 函数保持简洁,只做一件事
14
-
15
- 2. **开闭原则**(Open/Closed)
16
- - 对扩展开放,对修改关闭
17
- - 使用组合而非修改现有代码
18
-
19
- 3. **依赖倒置原则**(Dependency Inversion)
20
- - 依赖抽象而非具体实现
21
- - 通过 props 传递依赖
22
-
23
- ### DRY 原则
24
-
25
- **Don't Repeat Yourself** - 避免重复代码
26
-
27
- ```tsx
28
- // ✅ 好的做法 - 抽取公共逻辑
29
- const useUserData = () => {
30
- const [user, setUser] = useState(null);
31
- const [loading, setLoading] = useState(false);
32
-
33
- const fetchUser = async () => {
34
- setLoading(true);
35
- try {
36
- const data = await api.getUser();
37
- setUser(data);
38
- } finally {
39
- setLoading(false);
40
- }
41
- };
42
-
43
- return { user, loading, fetchUser };
44
- };
45
-
46
- // 在多个组件中复用
47
- function ProfilePage() {
48
- const { user, loading } = useUserData();
49
- // ...
50
- }
51
- ```
52
-
53
- ```tsx
54
- // ❌ 不好的做法 - 重复代码
55
- function ProfilePage() {
56
- const [user, setUser] = useState(null);
57
- const [loading, setLoading] = useState(false);
58
-
59
- const fetchUser = async () => {
60
- setLoading(true);
61
- try {
62
- const data = await api.getUser();
63
- setUser(data);
64
- } finally {
65
- setLoading(false);
66
- }
67
- };
68
- // ...
69
- }
70
-
71
- function SettingsPage() {
72
- // 完全相同的代码又写一遍
73
- const [user, setUser] = useState(null);
74
- // ...
75
- }
76
- ```
77
-
78
- ---
79
-
80
- ## 📂 项目组织
81
-
82
- ### 目录结构
83
-
84
- ```
85
- src/
86
- ├── pages/ # 页面组件
87
- │ └── home/
88
- │ ├── index.tsx
89
- │ ├── index.scss
90
- │ └── components/ # 页面私有组件
91
- │ └── Header.tsx
92
- ├── widgets/ # Widget 组件
93
- │ └── weather-card/
94
- │ ├── index.tsx
95
- │ └── index.scss
96
- ├── components/ # 公共组件
97
- │ ├── Button/
98
- │ │ ├── index.tsx
99
- │ │ └── index.scss
100
- │ └── Loading/
101
- │ ├── index.tsx
102
- │ └── index.scss
103
- ├── hooks/ # 自定义 Hooks
104
- │ ├── useAuth.ts
105
- │ └── useData.ts
106
- ├── utils/ # 工具函数
107
- │ ├── format.ts
108
- │ └── validate.ts
109
- ├── constants/ # 常量定义
110
- │ └── index.ts
111
- ├── types/ # 类型定义
112
- │ └── index.ts
113
- └── app.ts # 应用入口
114
- ```
115
-
116
- ### 文件命名规范
117
-
118
- ```
119
- ✅ 好的命名:
120
- - UserProfile.tsx (组件:PascalCase)
121
- - useAuth.ts (Hook:camelCase with use prefix)
122
- - formatDate.ts (工具函数:camelCase)
123
- - API_BASE_URL.ts (常量:UPPER_SNAKE_CASE)
124
-
125
- ❌ 不好的命名:
126
- - userprofile.tsx
127
- - UseAuth.ts
128
- - Format-Date.ts
129
- - apibaseurl.ts
130
- ```
131
-
132
- ---
133
-
134
- ## 最佳实践
135
-
136
- ### 组件设计
137
-
138
- #### 保持组件简洁
139
-
140
- ```tsx
141
- // ✅ 好的做法 - 单一职责
142
- function UserAvatar({ url, size = 'medium' }: Props) {
143
- return (
144
- <image
145
- className={`user-avatar user-avatar--${size}`}
146
- src={url}
147
- />
148
- );
149
- }
150
-
151
- function UserCard({ user }: Props) {
152
- return (
153
- <view className="user-card">
154
- <UserAvatar url={user.avatar} size="large" />
155
- <text>{user.name}</text>
156
- </view>
157
- );
158
- }
159
- ```
160
-
161
- ```tsx
162
- // ❌ 不好的做法 - 组件过于复杂
163
- function UserCard({ user }: Props) {
164
- return (
165
- <view className="user-card">
166
- {/* 太多内联逻辑 */}
167
- <image
168
- src={user.avatar}
169
- style={{
170
- width: user.isVip ? '120rpx' : '80rpx',
171
- height: user.isVip ? '120rpx' : '80rpx',
172
- borderRadius: user.isVip ? '60rpx' : '40rpx',
173
- border: user.isVip ? '2px solid gold' : 'none'
174
- }}
175
- />
176
- <text>{user.name}</text>
177
- {user.isVip && <text>VIP</text>}
178
- {/* 更多复杂逻辑... */}
179
- </view>
180
- );
181
- }
182
- ```
183
-
184
- #### 使用 TypeScript 类型
185
-
186
- ```tsx
187
- // ✅ 好的做法 - 完整的类型定义
188
- interface User {
189
- id: string;
190
- name: string;
191
- email: string;
192
- avatar?: string;
193
- }
194
-
195
- interface UserCardProps {
196
- user: User;
197
- onPress?: (userId: string) => void;
198
- }
199
-
200
- function UserCard({ user, onPress }: UserCardProps) {
201
- return (
202
- <view onClick={() => onPress?.(user.id)}>
203
- <text>{user.name}</text>
204
- </view>
205
- );
206
- }
207
- ```
208
-
209
- ### Hooks 使用
210
-
211
- #### 自定义 Hooks
212
-
213
- ```tsx
214
- // ✅ 好的做法 - 封装复杂逻辑
215
- function useDebounce<T>(value: T, delay: number): T {
216
- const [debouncedValue, setDebouncedValue] = useState(value);
217
-
218
- useEffect(() => {
219
- const handler = setTimeout(() => {
220
- setDebouncedValue(value);
221
- }, delay);
222
-
223
- return () => clearTimeout(handler);
224
- }, [value, delay]);
225
-
226
- return debouncedValue;
227
- }
228
-
229
- // 使用
230
- function SearchPage() {
231
- const [query, setQuery] = useState('');
232
- const debouncedQuery = useDebounce(query, 500);
233
-
234
- useEffect(() => {
235
- if (debouncedQuery) {
236
- performSearch(debouncedQuery);
237
- }
238
- }, [debouncedQuery]);
239
-
240
- return <input value={query} onInput={e => setQuery(e.detail.value)} />;
241
- }
242
- ```
243
-
244
- #### useMemo 和 useCallback
245
-
246
- ```tsx
247
- // ✅ 好的做法 - 优化性能
248
- function DataList({ items, filter }: Props) {
249
- // 缓存计算结果
250
- const filteredItems = useMemo(() => {
251
- return items.filter(item => item.type === filter);
252
- }, [items, filter]);
253
-
254
- // 稳定函数引用
255
- const handleItemClick = useCallback((id: string) => {
256
- console.log('Clicked:', id);
257
- }, []);
258
-
259
- return (
260
- <view>
261
- {filteredItems.map(item => (
262
- <ItemCard key={item.id} item={item} onClick={handleItemClick} />
263
- ))}
264
- </view>
265
- );
266
- }
267
- ```
268
-
269
- ---
270
-
271
- ## 🎨 样式最佳实践
272
-
273
- ### SCSS 组织
274
-
275
- ```scss
276
- // ✅ 好的做法 - 使用变量和嵌套
277
- $primary-color: #1890ff;
278
- $spacing-unit: 8rpx;
279
- $border-radius: 8rpx;
280
-
281
- .user-card {
282
- padding: $spacing-unit * 2;
283
- border-radius: $border-radius;
284
- background: #ffffff;
285
-
286
- &__header {
287
- display: flex;
288
- align-items: center;
289
- margin-bottom: $spacing-unit * 3;
290
- }
291
-
292
- &__title {
293
- font-size: 32rpx;
294
- color: $primary-color;
295
- font-weight: bold;
296
- }
297
-
298
- &--highlighted {
299
- border: 2rpx solid $primary-color;
300
- }
301
- }
302
- ```
303
-
304
- ### BEM 命名规范
305
-
306
- ```scss
307
- // Block__Element--Modifier
308
-
309
- .card { } // Block
310
- .card__header { } // Element
311
- .card__body { } // Element
312
- .card--featured { } // Modifier
313
- .card__header--large { } // Element Modifier
314
- ```
315
-
316
- ### 响应式设计
317
-
318
- ```scss
319
- // ✅ 使用 rpx 单位
320
- .container {
321
- padding: 32rpx; // 响应式单位
322
- font-size: 28rpx;
323
- }
324
-
325
- // ❌ 避免使用固定 px
326
- .container {
327
- padding: 16px; // 不会响应屏幕尺寸
328
- font-size: 14px;
329
- }
330
- ```
331
-
332
- ---
333
-
334
- ## 🚀 性能优化
335
-
336
- ### 避免不必要的渲染
337
-
338
- ```tsx
339
- // ✅ 好的做法 - 使用 useMemo
340
- function ParentComponent({ items }: Props) {
341
- const processedData = useMemo(() => {
342
- return items.map(item => ({
343
- ...item,
344
- computed: expensiveCalculation(item)
345
- }));
346
- }, [items]);
347
-
348
- return <ExpensiveComponent data={processedData} />;
349
- }
350
- ```
351
-
352
- ### 列表渲染优化
353
-
354
- ```tsx
355
- // ✅ 好的做法 - 使用唯一稳定的 key
356
- function ItemList({ items }: Props) {
357
- return (
358
- <list>
359
- {items.map(item => (
360
- <list-item key={item.id}> {/* 使用唯一 ID */}
361
- <ItemCard item={item} />
362
- </list-item>
363
- ))}
364
- </list>
365
- );
366
- }
367
-
368
- // ❌ 不好的做法 - 使用 index 作为 key
369
- function ItemList({ items }: Props) {
370
- return (
371
- <list>
372
- {items.map((item, index) => (
373
- <list-item key={index}> {/* 列表顺序改变会有问题 */}
374
- <ItemCard item={item} />
375
- </list-item>
376
- ))}
377
- </list>
378
- );
379
- }
380
- ```
381
-
382
- ---
383
-
384
- ## 🔒 错误处理
385
-
386
- ### Try-Catch 使用
387
-
388
- ```tsx
389
- // ✅ 好的做法 - 完整的错误处理
390
- async function fetchData() {
391
- try {
392
- setLoading(true);
393
- setError(null);
394
-
395
- const response = await api.getData();
396
- setData(response);
397
- } catch (error) {
398
- // 记录错误
399
- console.error('Failed to fetch data:', error);
400
-
401
- // 设置用户友好的错误信息
402
- if (error.code === 'NETWORK_ERROR') {
403
- setError('网络连接失败,请检查您的网络');
404
- } else if (error.code === 'AUTH_ERROR') {
405
- setError('您的登录已过期,请重新登录');
406
- } else {
407
- setError('数据加载失败,请稍后重试');
408
- }
409
-
410
- // 可选:上报错误到监控系统
411
- reportError(error);
412
- } finally {
413
- setLoading(false);
414
- }
415
- }
416
- ```
417
-
418
- ### 边界情况处理
419
-
420
- ```tsx
421
- // ✅ 好的做法 - 处理各种边界情况
422
- function DataDisplay({ data }: { data?: Data[] }) {
423
- // 处理 undefined
424
- if (!data) {
425
- return <LoadingView />;
426
- }
427
-
428
- // 处理空数组
429
- if (data.length === 0) {
430
- return <EmptyView message="暂无数据" />;
431
- }
432
-
433
- // 正常展示
434
- return (
435
- <view>
436
- {data.map(item => (
437
- <ItemCard key={item.id} item={item} />
438
- ))}
439
- </view>
440
- );
441
- }
442
- ```
443
-
444
- ---
445
-
446
- ## 📱 用户体验
447
-
448
- ### 加载状态
449
-
450
- ```tsx
451
- // ✅ 好的做法 - 提供清晰的加载反馈
452
- function DataPage() {
453
- const [data, setData] = useState(null);
454
- const [loading, setLoading] = useState(true);
455
-
456
- if (loading) {
457
- return (
458
- <view className="loading-container">
459
- <loading-spinner />
460
- <text>加载中...</text>
461
- </view>
462
- );
463
- }
464
-
465
- return <DataView data={data} />;
466
- }
467
- ```
468
-
469
- ### 错误反馈
470
-
471
- ```tsx
472
- // ✅ 好的做法 - 提供可操作的错误提示
473
- function ErrorView({ error, onRetry }: Props) {
474
- return (
475
- <view className="error-container">
476
- <image src="/assets/error-icon.png" className="error-icon" />
477
- <text className="error-message">{error}</text>
478
- <button className="retry-button" onClick={onRetry}>
479
- 重试
480
- </button>
481
- </view>
482
- );
483
- }
484
- ```
485
-
486
- ### 交互反馈
487
-
488
- ```tsx
489
- // ✅ 好的做法 - 提供即时反馈
490
- function SubmitButton({ onSubmit }: Props) {
491
- const [submitting, setSubmitting] = useState(false);
492
-
493
- const handleSubmit = async () => {
494
- setSubmitting(true);
495
- try {
496
- await onSubmit();
497
- showToast({ message: '提交成功' });
498
- } catch (error) {
499
- showToast({ message: '提交失败,请重试' });
500
- } finally {
501
- setSubmitting(false);
502
- }
503
- };
504
-
505
- return (
506
- <button
507
- className="submit-button"
508
- onClick={handleSubmit}
509
- disabled={submitting}
510
- >
511
- {submitting ? '提交中...' : '提交'}
512
- </button>
513
- );
514
- }
515
- ```
516
-
517
- ---
518
-
519
- ## 📝 代码注释
520
-
521
- ### 何时添加注释
522
-
523
- ```tsx
524
- // ✅ 好的做法 - 解释"为什么",而不是"是什么"
525
- function calculateDiscount(price: number, userLevel: string): number {
526
- // VIP 用户享受额外 10% 折扣(业务需求)
527
- if (userLevel === 'VIP') {
528
- return price * 0.9;
529
- }
530
-
531
- return price;
532
- }
533
-
534
- // ❌ 不好的做法 - 注释重复代码
535
- function calculateDiscount(price: number, userLevel: string): number {
536
- // 如果用户等级是 VIP
537
- if (userLevel === 'VIP') {
538
- // 返回价格乘以 0.9
539
- return price * 0.9;
540
- }
541
-
542
- // 返回原价
543
- return price;
544
- }
545
- ```
546
-
547
- ### JSDoc 注释
548
-
549
- ```tsx
550
- /**
551
- * 格式化日期为 YYYY-MM-DD 格式
552
- * @param date - 要格式化的日期对象
553
- * @param separator - 分隔符,默认为 '-'
554
- * @returns 格式化后的日期字符串
555
- * @example
556
- * formatDate(new Date('2024-01-15')) // '2024-01-15'
557
- * formatDate(new Date('2024-01-15'), '/') // '2024/01/15'
558
- */
559
- function formatDate(date: Date, separator: string = '-'): string {
560
- // 实现...
561
- }
562
- ```
563
-
564
- ---
565
-
566
- ## 🔗 相关文档
567
-
568
- - [开发规则](../rules/dos-and-donts.md)
569
- - [组件开发完整指南](./component-development.md)
570
- - [性能优化](./performance-optimization.md)
571
- - [故障排查](./troubleshooting.md)