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.
- package/bin/cli.js +59 -305
- 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
|
-
|
|
12
|
-
.
|
|
13
|
-
.
|
|
14
|
-
.
|
|
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
|
-
|
|
24
|
-
if (
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (await fs.pathExists(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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();
|