Skip to content

Commit ca8bbc8

Browse files
committed
chore(scripts): 新增添加组件脚本,不需要手动创建各文件
1 parent 2370a52 commit ca8bbc8

File tree

3 files changed

+216
-5
lines changed

3 files changed

+216
-5
lines changed

package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
"doctor": "father doctor",
1919
"lint": "npm run lint:es && npm run lint:css",
2020
"lint:css": "stylelint \"**/*.{css,scss}\"",
21-
"prepublishOnly": "father doctor && npm run build"
21+
"prepublishOnly": "father doctor && npm run build",
22+
"new:component": "tsx scripts/new-component.ts"
2223
},
2324
"lint-staged": {
2425
"*.{md,json}": [
@@ -61,6 +62,7 @@
6162
"@vitejs/plugin-react": "^4.0.0",
6263
"chalk": "^5.2.0",
6364
"dumi": "^2.2.0",
65+
"enquirer": "^2.3.6",
6466
"eslint": "^8.41.0",
6567
"eslint-config-prettier": "^8.8.0",
6668
"eslint-plugin-prettier": "^4.2.1",

pnpm-lock.yaml

+19-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/new-component.ts

+194
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
import { prompt } from 'enquirer';
2+
import { capitalize } from '@tool-pack/basic';
3+
import * as Path from 'path';
4+
import Fse from 'fs-extra';
5+
import chalk from 'chalk';
6+
7+
type InitRes = [filename: string, content: string];
8+
9+
const config = {
10+
name: '',
11+
componentName: '',
12+
componentsPath: Path.resolve(__dirname, '../packages/components/src'),
13+
};
14+
async function run() {
15+
const separator = '-'.repeat(10);
16+
console.log(chalk.cyan(separator, '添加组件开始', separator));
17+
try {
18+
await getConfig();
19+
writeFile(...initComponent());
20+
writeFile(...initTypes());
21+
writeFile(...initScss());
22+
writeFile(...initDemo());
23+
writeFile(...initIndex());
24+
writeFile(...initDoc());
25+
appendIndex();
26+
console.log(chalk.cyan('添加组件成功'));
27+
} catch (e) {
28+
console.log(chalk.grey('添加组件失败,因为:', (e as Error).message));
29+
}
30+
}
31+
32+
run();
33+
34+
async function getConfig() {
35+
({ name: config.name } = await prompt<{ name: string }>({
36+
type: 'input',
37+
name: 'name',
38+
message: '输入新组件名(小写英文和连字符"-")',
39+
validate(value: string) {
40+
if (!value) return '组件名不能为空';
41+
const illegalWord = value.replace(/[a-z-]/g, '');
42+
if (illegalWord) {
43+
return `包含不支持的字符: [${illegalWord.split('').join(',')}]`;
44+
}
45+
return true;
46+
},
47+
}));
48+
49+
config.componentName = capitalize(config.name);
50+
51+
const { confirm } = await prompt<{ confirm: boolean }>({
52+
type: 'confirm',
53+
name: 'confirm',
54+
message: `确认添加组件(${config.name})?`,
55+
});
56+
57+
if (!confirm) throw new Error('放弃添加组件');
58+
}
59+
60+
function initComponent(): InitRes {
61+
const componentName = config.componentName;
62+
const filename = getFilename('component');
63+
const props = `${componentName}Props`;
64+
const content = `
65+
import React from 'react';
66+
import type { ${props} } from './${getFilename('types').replace(/\.ts$/, '')}';
67+
68+
export const ${componentName}: React.FC<${props}> = (props) => {
69+
70+
};
71+
`;
72+
73+
return [filename, content];
74+
}
75+
function initTypes(): InitRes {
76+
const filename = getFilename('types');
77+
const content = `
78+
export interface ${config.componentName}Props {}
79+
`;
80+
return [filename, content];
81+
}
82+
83+
function initScss(): InitRes {
84+
const filename = getFilename('scss');
85+
const content = `
86+
@import '../scss.variable';
87+
88+
$r: '#{$prefix}${config.name}';
89+
90+
.#{$r} {}
91+
`;
92+
return [filename, content];
93+
}
94+
95+
function initDemo(): InitRes {
96+
const filename = getFilename('demo');
97+
const content = `
98+
/**
99+
* title: 基础用法
100+
* description: ${config.componentName} 基础用法。
101+
*/
102+
103+
import React from 'react';
104+
import { ${config.componentName} } from '@tool-pack/react-ui';
105+
106+
const App: React.FC = () => {
107+
return <${config.componentName}></${config.componentName}>;
108+
};
109+
110+
export default App;
111+
`;
112+
return [filename, content];
113+
}
114+
115+
function initIndex(): InitRes {
116+
const filename = getFilename('index');
117+
const content = `
118+
export type { ${config.componentName}Props } from './${config.name}.types';
119+
export * from './${config.componentName}';
120+
`;
121+
return [filename, content];
122+
}
123+
124+
function initDoc(): InitRes {
125+
const filename = getFilename('doc');
126+
const content = `
127+
---
128+
category: Components
129+
title: ${config.componentName}
130+
subtitle: ${config.componentName}
131+
demo:
132+
cols: 2
133+
group:
134+
title: 通用
135+
---
136+
137+
${config.componentName} 说明。
138+
139+
## 代码演示
140+
141+
<!-- prettier-ignore -->
142+
<code src="./demo/basic.tsx"></code>
143+
144+
## API
145+
146+
${config.componentName} 的属性说明如下:
147+
148+
| 属性 | 说明 | 类型 | 默认值 | 版本 |
149+
| ---- | ---- | ---- | ------ | ---- |
150+
| -- | -- | -- | -- | -- |
151+
152+
其他说明。
153+
154+
`;
155+
return [filename, content];
156+
}
157+
function appendIndex() {
158+
const tsContent = `export * from './${config.name}';\n`;
159+
Fse.appendFileSync(
160+
Path.resolve(config.componentsPath, 'index.ts'),
161+
tsContent,
162+
);
163+
const scssContent = `@import './${config.name}';`;
164+
Fse.appendFileSync(
165+
Path.resolve(config.componentsPath, 'index.scss'),
166+
scssContent,
167+
);
168+
}
169+
170+
function getFilename(
171+
type: 'doc' | 'scss' | 'index' | 'component' | 'types' | 'demo',
172+
) {
173+
const name = config.name;
174+
return (
175+
{
176+
doc: 'index.zh-CN.md',
177+
scss: 'index.scss',
178+
component: `${capitalize(name)}.tsx`,
179+
index: 'index.ts',
180+
types: `${name}.types.ts`,
181+
demo: 'demo/basic.tsx',
182+
} as Record<typeof type, string>
183+
)[type];
184+
}
185+
186+
function getFilepath(filename: string) {
187+
return Path.resolve(config.componentsPath, `${config.name}/${filename}`);
188+
}
189+
190+
function writeFile(filename: string, content: string) {
191+
const filepath = getFilepath(filename);
192+
Fse.createFileSync(filepath);
193+
Fse.writeFileSync(filepath, content.trim() + '\n', 'utf-8');
194+
}

0 commit comments

Comments
 (0)