create-miniprogram-scaffold 1.0.0 → 1.0.1

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 (2) hide show
  1. package/bin/cli.js +59 -305
  2. package/package.json +1 -1
package/bin/cli.js CHANGED
@@ -1,315 +1,69 @@
1
1
  #!/usr/bin/env node
2
-
3
2
  const { Command } = require('commander');
4
3
  const inquirer = require('inquirer');
5
4
  const fs = require('fs-extra');
6
5
  const path = require('path');
7
6
  const chalk = require('chalk');
8
-
9
7
  const program = new Command();
10
-
11
- program
12
- .name('create-mini-scaffold')
13
- .description('Create Taro + Go mini program projects')
14
- .version('1.0.0')
15
- .argument('[project-name]', 'Project name')
16
- .option('-f, --framework <framework>', 'Framework to use (React/Vue)', 'React')
17
- .option('-c, --css <preprocessor>', 'CSS preprocessor (Sass/Less/Stylus/None)', 'Sass')
18
- .option('-p, --port <port>', 'Server port', '8080')
19
- .option('-y, --yes', 'Skip prompts and use defaults')
20
- .option('--overwrite', 'Overwrite existing directory')
21
- .action(async (projectName, options) => {
8
+ program.name('create-mini-scaffold').description('Create Taro + Go mini program projects').version('1.0.0')
9
+ .argument('[project-name]').option('-f, --framework <f>', 'Framework', 'React').option('-c, --css <css>', 'CSS preprocessor', 'Sass')
10
+ .option('-l, --layout <l>', 'Layout: header-tabbar | tabbar | fullscreen | all', 'header-tabbar')
11
+ .option('-p, --port <port>', 'Server port', '8080').option('-y, --yes', 'Skip prompts').option('--overwrite')
12
+ .action(async (name, opts) => {
22
13
  try {
23
- // If project name not provided, ask for it
24
- if (!projectName) {
25
- if (options.yes) {
26
- projectName = 'my-mini-app';
27
- } else {
28
- const answers = await inquirer.prompt([
29
- {
30
- type: 'input',
31
- name: 'projectName',
32
- message: 'What is your project name?',
33
- default: 'my-mini-app'
34
- }
35
- ]);
36
- projectName = answers.projectName;
37
- }
14
+ if (!name) { if (opts.yes) name = 'my-mini-app'; else { const a = await inquirer.prompt([{ type: 'input', name: 'n', message: 'Project name?', default: 'my-mini-app' }]); name = a.n; } }
15
+ if (!/^[a-zA-Z0-9-_]+$/.test(name)) { console.error(chalk.red('Invalid name')); process.exit(1); }
16
+ const dir = path.join(process.cwd(), name);
17
+ if (await fs.pathExists(dir)) { if (!opts.overwrite) { if (opts.yes) { console.error(chalk.red('Exists. Use --overwrite.')); process.exit(1); } const { o } = await inquirer.prompt([{ type: 'confirm', name: 'o', message: 'Overwrite?', default: false }]); if (!o) { process.exit(0); } } await fs.remove(dir); }
18
+ const cfg = { framework: opts.framework, css: opts.css, layout: opts.layout, port: opts.port };
19
+ if (!opts.yes) { const a = await inquirer.prompt([
20
+ { type: 'list', name: 'framework', message: 'Framework?', choices: ['React', 'Vue'] },
21
+ { type: 'list', name: 'css', message: 'CSS?', choices: ['Sass', 'Less', 'Stylus', 'None'] },
22
+ { type: 'list', name: 'layout', message: 'Layout?', choices: [
23
+ { name: 'header-tabbar - 自定义 Header + 原生 TabBar', value: 'header-tabbar' },
24
+ { name: 'tabbar - 原生导航栏 + 原生 TabBar', value: 'tabbar' },
25
+ { name: 'fullscreen - 全屏沉浸式', value: 'fullscreen' },
26
+ { name: 'all - 全部布局(推荐)', value: 'all' }
27
+ ]}, { type: 'input', name: 'port', message: 'Port?', default: cfg.port } ]); Object.assign(cfg, a); }
28
+ if (!['header-tabbar','tabbar','fullscreen','all'].includes(cfg.layout)) { console.error(chalk.red('Invalid layout')); process.exit(1); }
29
+ console.log(chalk.blue('\nCreating...'));
30
+ const tDir = path.join(__dirname, '..', '..', 'templates');
31
+ const mDir = path.join(dir, 'miniprogram');
32
+ await fs.ensureDir(mDir); await fs.ensureDir(path.join(dir, 'server'));
33
+ // Copy miniprogram (skip pages)
34
+ await fs.copy(path.join(tDir, 'miniprogram'), mDir, { filter: s => !path.relative(path.join(tDir, 'miniprogram'), s).startsWith('src/pages') });
35
+ await fs.copy(path.join(tDir, 'miniprogram/src/layouts'), path.join(mDir, 'src/layouts'));
36
+ // Copy pages based on layout
37
+ const sP = path.join(tDir, 'miniprogram/src/pages'), dP = path.join(mDir, 'src/pages');
38
+ let pages = [], tabbar = [];
39
+ if (cfg.layout === 'all') {
40
+ pages = ['pages/home/index','pages/discover/index','pages/mine/index','pages/splash/index'];
41
+ tabbar = [{ pagePath:'pages/home/index',text:'首页',iconPath:'assets/tabbar/home.png',selectedIconPath:'assets/tabbar/home-active.png' },{ pagePath:'pages/discover/index',text:'发现',iconPath:'assets/tabbar/discover.png',selectedIconPath:'assets/tabbar/discover-active.png' },{ pagePath:'pages/mine/index',text:'我的',iconPath:'assets/tabbar/mine.png',selectedIconPath:'assets/tabbar/mine-active.png' }];
42
+ for (const p of ['home','discover','mine','splash']) await fs.copy(path.join(sP, p), path.join(dP, p));
43
+ } else if (cfg.layout === 'header-tabbar') {
44
+ pages = ['pages/home/index']; tabbar = [{ pagePath:'pages/home/index',text:'首页',iconPath:'assets/tabbar/home.png',selectedIconPath:'assets/tabbar/home-active.png' }];
45
+ await fs.copy(path.join(sP, 'home'), path.join(dP, 'home'));
46
+ } else if (cfg.layout === 'tabbar') {
47
+ pages = ['pages/discover/index']; tabbar = [{ pagePath:'pages/discover/index',text:'发现',iconPath:'assets/tabbar/discover.png',selectedIconPath:'assets/tabbar/discover-active.png' }];
48
+ await fs.copy(path.join(sP, 'discover'), path.join(dP, 'discover'));
49
+ } else {
50
+ pages = ['pages/splash/index']; await fs.copy(path.join(sP, 'splash'), path.join(dP, 'splash'));
38
51
  }
39
-
40
- // Validate project name
41
- if (!/^[a-zA-Z0-9-_]+$/.test(projectName)) {
42
- console.error(chalk.red('Error: Project name can only contain letters, numbers, hyphens, and underscores'));
43
- process.exit(1);
44
- }
45
-
46
- const targetDir = path.join(process.cwd(), projectName);
47
-
48
- // Check if directory already exists
49
- if (await fs.pathExists(targetDir)) {
50
- if (!options.overwrite) {
51
- if (options.yes) {
52
- console.error(chalk.red(`Directory ${projectName} already exists. Use --overwrite to overwrite.`));
53
- process.exit(1);
54
- }
55
-
56
- const { overwrite } = await inquirer.prompt([
57
- {
58
- type: 'confirm',
59
- name: 'overwrite',
60
- message: `Directory ${projectName} already exists. Overwrite?`,
61
- default: false
62
- }
63
- ]);
64
-
65
- if (!overwrite) {
66
- console.log(chalk.yellow('Operation cancelled'));
67
- process.exit(0);
68
- }
69
- }
70
-
71
- await fs.remove(targetDir);
72
- }
73
-
74
- // Configuration
75
- const config = {
76
- framework: options.framework,
77
- cssPreprocessor: options.css,
78
- serverPort: options.port
79
- };
80
-
81
- // Ask for configuration options if not using --yes
82
- if (!options.yes) {
83
- const answers = await inquirer.prompt([
84
- {
85
- type: 'list',
86
- name: 'framework',
87
- message: 'Which framework do you want to use?',
88
- choices: ['React', 'Vue'],
89
- default: config.framework
90
- },
91
- {
92
- type: 'list',
93
- name: 'cssPreprocessor',
94
- message: 'Which CSS preprocessor do you want to use?',
95
- choices: ['Sass', 'Less', 'Stylus', 'None'],
96
- default: config.cssPreprocessor
97
- },
98
- {
99
- type: 'input',
100
- name: 'serverPort',
101
- message: 'What port should the Go server run on?',
102
- default: config.serverPort
103
- }
104
- ]);
105
-
106
- config.framework = answers.framework;
107
- config.cssPreprocessor = answers.cssPreprocessor;
108
- config.serverPort = answers.serverPort;
109
- }
110
-
111
- console.log(chalk.blue('\nCreating project...'));
112
-
113
- // Copy templates
114
- await copyTemplates(projectName, config);
115
-
116
- console.log(chalk.green('\n✓ Project created successfully!'));
117
- console.log(chalk.cyan('\nNext steps:'));
118
- console.log(chalk.white(` cd ${projectName}`));
119
- console.log(chalk.white(' # Start frontend:'));
120
- console.log(chalk.white(' cd miniprogram && npm install && npm run dev:weapp'));
121
- console.log(chalk.white(' # Start backend:'));
122
- console.log(chalk.white(' cd server && go run main.go'));
123
-
124
- } catch (error) {
125
- console.error(chalk.red('Error creating project:'), error);
126
- process.exit(1);
127
- }
52
+ // Generate app.config.ts
53
+ const ps = pages.map(p => ` '${p}'`).join(',\n');
54
+ let ts = ''; if (tabbar.length) { const tl = tabbar.map(t => ` { ${Object.entries(t).map(([k,v])=>`${k}: '${v}'`).join(', ')} }`).join(',\n'); ts = `\n tabBar: {\n color: '#999999', selectedColor: '#1890ff', backgroundColor: '#ffffff', borderStyle: 'black',\n list: [\n${tl},\n ],\n },`; }
55
+ await fs.writeFile(path.join(mDir, 'src/app.config.ts'), `export default defineAppConfig({\n pages: [\n${ps},\n ],${ts}\n window: { backgroundTextStyle: 'light', navigationBarBackgroundColor: '#ffffff', navigationBarTitleText: 'Mini Scaffold', navigationBarTextStyle: 'black' },\n})\n`);
56
+ // Update names
57
+ const pj = await fs.readJson(path.join(mDir, 'package.json')); pj.name = name + '-miniprogram'; await fs.writeJson(path.join(mDir, 'package.json'), pj, { spaces: 2 });
58
+ const pc = await fs.readJson(path.join(mDir, 'project.config.json')); pc.projectname = name; await fs.writeJson(path.join(mDir, 'project.config.json'), pc, { spaces: 2 });
59
+ // Server
60
+ await fs.copy(path.join(tDir, 'server'), path.join(dir, 'server'));
61
+ let gm = await fs.readFile(path.join(dir, 'server/go.mod'), 'utf8'); await fs.writeFile(path.join(dir, 'server/go.mod'), gm.replace('module mini-scaffold-server', `module ${name}-server`));
62
+ const ep = path.join(dir, 'server/.env.example'); if (await fs.pathExists(ep)) { let e = await fs.readFile(ep, 'utf8'); e = e.replace('PORT=8080', `PORT=${cfg.port}`); await fs.writeFile(path.join(dir, 'server/.env'), e); await fs.writeFile(ep, e); }
63
+ // README
64
+ const nm = { 'header-tabbar': 'HeaderTabBarLayout', 'tabbar': 'TabBarLayout', 'fullscreen': 'FullscreenLayout', 'all': '全部布局' };
65
+ await fs.writeFile(path.join(dir, 'README.md'), `# ${name}\n\nTaro + Go 小程序。\n\nLayout: \`${cfg.layout}\` ${nm[cfg.layout]}\n\n## Start\n\n\`\`\`bash\ncd miniprogram && npm install && npm run dev:weapp\ncd server && go mod tidy && go run main.go\n\`\`\`\n`);
66
+ console.log(chalk.green('\n✓ Done!')); console.log(chalk.cyan(` Layout: ${cfg.layout}`)); console.log(chalk.white(`\n cd ${name} && cd miniprogram && npm install && npm run dev:weapp`));
67
+ } catch (e) { console.error(chalk.red('Error:'), e); process.exit(1); }
128
68
  });
129
-
130
- async function copyTemplates(projectName, config) {
131
- const targetDir = path.join(process.cwd(), projectName);
132
- const templateDir = path.join(__dirname, '..', '..', 'templates');
133
-
134
- // Create project structure
135
- await fs.ensureDir(path.join(targetDir, 'miniprogram'));
136
- await fs.ensureDir(path.join(targetDir, 'server'));
137
-
138
- // Copy miniprogram template
139
- await copyMiniprogramTemplate(targetDir, config);
140
-
141
- // Copy server template
142
- await copyServerTemplate(targetDir, config);
143
-
144
- // Create root README
145
- await createRootReadme(targetDir, projectName, config);
146
- }
147
-
148
- async function copyMiniprogramTemplate(targetDir, config) {
149
- const templateDir = path.join(__dirname, '..', '..', 'templates', 'miniprogram');
150
- const targetMiniprogramDir = path.join(targetDir, 'miniprogram');
151
-
152
- // Copy all template files
153
- await fs.copy(templateDir, targetMiniprogramDir);
154
-
155
- // Update package.json with correct name
156
- const packageJsonPath = path.join(targetMiniprogramDir, 'package.json');
157
- const packageJson = await fs.readJson(packageJsonPath);
158
- packageJson.name = path.basename(targetDir) + '-miniprogram';
159
- await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
160
-
161
- // Update project.config.json
162
- const projectConfigPath = path.join(targetMiniprogramDir, 'project.config.json');
163
- const projectConfig = await fs.readJson(projectConfigPath);
164
- projectConfig.projectname = path.basename(targetDir);
165
- await fs.writeJson(projectConfigPath, projectConfig, { spaces: 2 });
166
- }
167
-
168
- async function copyServerTemplate(targetDir, config) {
169
- const templateDir = path.join(__dirname, '..', '..', 'templates', 'server');
170
- const targetServerDir = path.join(targetDir, 'server');
171
-
172
- // Copy all template files
173
- await fs.copy(templateDir, targetServerDir);
174
-
175
- // Update go.mod with correct module name
176
- const goModPath = path.join(targetServerDir, 'go.mod');
177
- let goModContent = await fs.readFile(goModPath, 'utf8');
178
- goModContent = goModContent.replace('module mini-scaffold-server', `module ${path.basename(targetDir)}-server`);
179
- await fs.writeFile(goModPath, goModContent);
180
-
181
- // Update .env with correct port
182
- const envPath = path.join(targetServerDir, '.env');
183
- let envContent = await fs.readFile(envPath, 'utf8');
184
- envContent = envContent.replace('PORT=8080', `PORT=${config.serverPort}`);
185
- await fs.writeFile(envPath, envContent);
186
-
187
- // Update .env.example with correct port
188
- const envExamplePath = path.join(targetServerDir, '.env.example');
189
- let envExampleContent = await fs.readFile(envExamplePath, 'utf8');
190
- envExampleContent = envExampleContent.replace('PORT=8080', `PORT=${config.serverPort}`);
191
- await fs.writeFile(envExamplePath, envExampleContent);
192
- }
193
-
194
- async function createRootReadme(targetDir, projectName, config) {
195
- const readmeContent = `# ${projectName}
196
-
197
- A mini program built with Taro (frontend) and Go (backend).
198
-
199
- ## Project Structure
200
-
201
- \`\`\`
202
- ${projectName}/
203
- ├── miniprogram/ # Taro frontend
204
- │ ├── src/ # Source code
205
- │ ├── config/ # Taro config
206
- │ └── package.json
207
- ├── server/ # Go backend
208
- │ ├── main.go # Entry point
209
- │ ├── handler/ # HTTP handlers
210
- │ ├── go.mod # Go module
211
- │ └── go.sum # Go dependencies
212
- └── README.md
213
- \`\`\`
214
-
215
- ## Getting Started
216
-
217
- ### Prerequisites
218
-
219
- - Node.js >= 16
220
- - Go >= 1.21
221
- - WeChat Developer Tools
222
-
223
- ### Frontend (Taro)
224
-
225
- 1. Install dependencies:
226
- \`\`\`bash
227
- cd miniprogram
228
- npm install
229
- \`\`\`
230
-
231
- 2. Start development server:
232
- \`\`\`bash
233
- npm run dev:weapp
234
- \`\`\`
235
-
236
- 3. Open WeChat Developer Tools and import the \`miniprogram\` directory.
237
-
238
- ### Backend (Go)
239
-
240
- 1. Install dependencies:
241
- \`\`\`bash
242
- cd server
243
- go mod tidy
244
- \`\`\`
245
-
246
- 2. Start the server:
247
- \`\`\`bash
248
- go run main.go
249
- \`\`\`
250
-
251
- The server will run on port ${config.serverPort}.
252
-
253
- ## API Endpoints
254
-
255
- - \`GET /api/hello\` - Returns a hello world message
256
-
257
- ## Development
258
-
259
- ### Frontend Development
260
-
261
- The frontend is built with Taro and React. Key files:
262
-
263
- - \`src/app.tsx\` - App entry point
264
- - \`src/pages/index/index.tsx\` - Main page
265
- - \`config/index.ts\` - Taro configuration
266
-
267
- ### Backend Development
268
-
269
- The backend is built with Go and Fiber. Key files:
270
-
271
- - \`main.go\` - Server entry point
272
- - \`handler/hello.go\` - Hello world handler
273
- - \`router/router.go\` - Route definitions
274
-
275
- ## Building for Production
276
-
277
- ### Frontend
278
-
279
- \`\`\`bash
280
- cd miniprogram
281
- npm run build:weapp
282
- \`\`\`
283
-
284
- ### Backend
285
-
286
- \`\`\`bash
287
- cd server
288
- go build -o server main.go
289
- ./server
290
- \`\`\`
291
-
292
- ## Configuration
293
-
294
- ### Frontend Configuration
295
-
296
- Edit \`miniprogram/config/index.ts\` to configure Taro settings.
297
-
298
- ### Backend Configuration
299
-
300
- Edit \`server/.env\` to configure server settings:
301
-
302
- \`\`\`env
303
- PORT=8080
304
- GIN_MODE=release
305
- \`\`\`
306
-
307
- ## License
308
-
309
- MIT
310
- `;
311
-
312
- await fs.writeFile(path.join(targetDir, 'README.md'), readmeContent);
313
- }
314
-
315
- program.parse();
69
+ program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-miniprogram-scaffold",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Create Taro + Go mini program projects",
5
5
  "repository": {
6
6
  "type": "git",