gridsum-vue3-pc 1.0.7 → 1.1.0

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.
@@ -45,7 +45,6 @@ ${pc.bold('Options:')}
45
45
  --auto-start Auto start dev server after creation
46
46
  --no-auto-install Skip automatic dependency installation
47
47
  --no-interactive Run in non-interactive mode
48
- --no-git Skip git initialization
49
48
  -h, --help Display this message
50
49
  -v, --version Display version number
51
50
 
@@ -60,13 +59,9 @@ ${pc.bold('Examples:')}
60
59
  ${pc.green('gsvue my-app')} ${pc.yellow('--no-interactive --name my-app --title "My App"')}
61
60
  `;
62
61
 
63
- const SPINNER_FRAMES = process.platform === 'win32'
64
- ? ['-', '\\', '|', '/']
65
- : ['⠋', '⠙', '⠹', '⠸', '', '⠴', '', '⠧', '', '⠏'];
66
-
67
- function formatTargetDir(targetDir) {
68
- const dir = targetDir.trim().replace(/\/+$/g, '');
69
- if (/[<>:"\\|?*\x00-\x1f]/.test(dir) || dir.includes('..') || dir.includes('/') || dir.includes('\\')) {
62
+ function formatTargetDir(input) {
63
+ const dir = input.trim().replace(/[\/\\]+$/g, '');
64
+ if (!dir || /[<>:"|?*\x00-\x1f]/.test(dir) || dir.includes('..') || dir.includes('/') || dir.includes('\\')) {
70
65
  return '';
71
66
  }
72
67
  return dir;
@@ -119,12 +114,10 @@ function copyDir(srcDir, destDir) {
119
114
  }
120
115
 
121
116
  function detectPackageManager() {
122
- const userAgent = process.env.npm_config_user_agent;
123
- if (!userAgent) return 'npm';
124
-
125
- if (userAgent.startsWith('pnpm')) return 'pnpm';
126
- if (userAgent.startsWith('yarn')) return 'yarn';
127
- if (userAgent.startsWith('bun')) return 'bun';
117
+ const ua = process.env.npm_config_user_agent || '';
118
+ if (ua.startsWith('pnpm')) return 'pnpm';
119
+ if (ua.startsWith('yarn')) return 'yarn';
120
+ if (ua.startsWith('bun')) return 'bun';
128
121
  return 'npm';
129
122
  }
130
123
 
@@ -134,6 +127,17 @@ function getInstallCommand(pkgManager) {
134
127
  return args;
135
128
  }
136
129
 
130
+ function getRunCommand(pkgManager, script) {
131
+ switch (pkgManager) {
132
+ case 'yarn':
133
+ case 'pnpm':
134
+ case 'bun':
135
+ return [pkgManager, script];
136
+ default:
137
+ return [pkgManager, 'run', script];
138
+ }
139
+ }
140
+
137
141
  function runCommand(command, options = {}) {
138
142
  const [cmd, ...args] = command;
139
143
  const result = spawn.sync(cmd, args, {
@@ -141,52 +145,13 @@ function runCommand(command, options = {}) {
141
145
  stdio: 'inherit',
142
146
  });
143
147
 
144
- if (result.status != null && result.status > 0) {
145
- process.exit(result.status);
146
- }
147
-
148
148
  if (result.error) {
149
- console.error(`\n${pc.red('Error:')} ${result.error.message}\n`);
150
- process.exit(1);
149
+ throw new Error(`Failed to execute "${cmd}": ${result.error.message}`);
151
150
  }
152
- }
153
151
 
154
- function runCommandAsync(command, options = {}) {
155
- const [cmd, ...args] = command;
156
- return new Promise((resolve, reject) => {
157
- const child = spawn(cmd, args, {
158
- stdio: ['ignore', 'pipe', 'pipe'],
159
- windowsHide: false,
160
- ...options,
161
- });
162
-
163
- child.stdout.on('data', () => {});
164
- let stderr = '';
165
- child.stderr.on('data', (chunk) => { stderr += chunk.toString(); });
166
-
167
- let i = 0;
168
- const timer = setInterval(() => {
169
- process.stdout.write(`\r${pc.cyan(SPINNER_FRAMES[i])} Installing dependencies...`);
170
- i = (i + 1) % SPINNER_FRAMES.length;
171
- }, 100);
172
-
173
- child.on('close', (code) => {
174
- clearInterval(timer);
175
- process.stdout.write('\r\x1b[K');
176
- if (code !== null && code > 0) {
177
- if (stderr) process.stderr.write(stderr);
178
- reject(new Error(`exit code ${code}`));
179
- } else {
180
- resolve();
181
- }
182
- });
183
- child.on('error', (err) => {
184
- clearInterval(timer);
185
- process.stdout.write('\r\x1b[K');
186
- if (stderr) process.stderr.write(stderr);
187
- reject(err);
188
- });
189
- });
152
+ if (result.status != null && result.status > 0) {
153
+ throw new Error(`"${cmd}" exited with code ${result.status}`);
154
+ }
190
155
  }
191
156
 
192
157
  function checkNodeVersion() {
@@ -205,7 +170,7 @@ Please upgrade Node.js:
205
170
 
206
171
  function parseArgs() {
207
172
  const argv = mri(process.argv.slice(2), {
208
- boolean: ['help', 'version', 'force', 'auto-start', 'no-interactive', 'no-auto-install', 'no-git'],
173
+ boolean: ['help', 'version', 'force', 'auto-start', 'no-interactive', 'no-auto-install'],
209
174
  string: ['name', 'title', 'cicd'],
210
175
  alias: {
211
176
  h: 'help',
@@ -240,25 +205,37 @@ function scaffoldProject(root, answers, packageName) {
240
205
 
241
206
  const pkgPath = path.join(root, 'package.json');
242
207
  if (fs.existsSync(pkgPath)) {
243
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
244
- pkg.name = packageName;
245
- fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
208
+ try {
209
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
210
+ pkg.name = packageName;
211
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
212
+ } catch (e) {
213
+ throw new Error(`Failed to update package.json: ${e.message}`);
214
+ }
246
215
  }
247
216
 
248
- ['.env', '.env.production'].forEach(file => {
217
+ for (const file of ['.env', '.env.production']) {
249
218
  const filePath = path.join(root, file);
250
219
  if (fs.existsSync(filePath)) {
251
- let content = fs.readFileSync(filePath, 'utf-8');
252
- content = content.replace(/VITE_APP_TITLE=.*/, `VITE_APP_TITLE=${answers.title}`);
253
- fs.writeFileSync(filePath, content);
220
+ try {
221
+ let content = fs.readFileSync(filePath, 'utf-8');
222
+ content = content.replace(/^VITE_APP_TITLE=.*$/m, `VITE_APP_TITLE=${answers.title}`);
223
+ fs.writeFileSync(filePath, content);
224
+ } catch (e) {
225
+ throw new Error(`Failed to update ${file}: ${e.message}`);
226
+ }
254
227
  }
255
- });
228
+ }
256
229
 
257
230
  const indexPath = path.join(root, 'index.html');
258
231
  if (fs.existsSync(indexPath)) {
259
- let content = fs.readFileSync(indexPath, 'utf-8');
260
- content = content.replace(/<title>[^<]*<\/title>/, `<title>${answers.title}</title>`);
261
- fs.writeFileSync(indexPath, content);
232
+ try {
233
+ let content = fs.readFileSync(indexPath, 'utf-8');
234
+ content = content.replace(/<title>[^<]*<\/title>/, `<title>${answers.title}</title>`);
235
+ fs.writeFileSync(indexPath, content);
236
+ } catch (e) {
237
+ throw new Error(`Failed to update index.html: ${e.message}`);
238
+ }
262
239
  }
263
240
  }
264
241
 
@@ -270,7 +247,11 @@ function validateOptions(options) {
270
247
  }
271
248
 
272
249
  if (options.cicd && !VALID_CICD.includes(options.cicd)) {
273
- errors.push(`Invalid cicd "${options.cicd}". Valid: ${VALID_CICD.join(', ')}`);
250
+ errors.push(`Invalid CI/CD type "${options.cicd}". Valid: ${VALID_CICD.join(', ')}`);
251
+ }
252
+
253
+ if (options.title && !/^[a-zA-Z0-9_\-\u4e00-\u9fa5 ]+$/.test(options.title)) {
254
+ errors.push('Project title contains invalid characters (allowed: letters, numbers, Chinese, spaces, dash, underscore)');
274
255
  }
275
256
 
276
257
  return errors;
@@ -398,11 +379,6 @@ async function main() {
398
379
  cicd: argv.cicd || 'none',
399
380
  };
400
381
 
401
- if (argv.title && !/^[a-zA-Z0-9_\-\u4e00-\u9fa5 ]+$/.test(argv.title)) {
402
- console.error(`\n${pc.red('Error:')} Project title contains invalid characters\n`);
403
- process.exit(1);
404
- }
405
-
406
382
  if (isInteractive) {
407
383
  const title = await prompts.text({
408
384
  message: 'Project title:',
@@ -457,26 +433,53 @@ async function main() {
457
433
  autoInstall = result;
458
434
  }
459
435
 
436
+ let autoStart = argv['auto-start'];
437
+ if (autoStart === undefined && isInteractive && autoInstall) {
438
+ const result = await prompts.confirm({
439
+ message: 'Start dev server now?',
440
+ initialValue: false,
441
+ });
442
+ if (prompts.isCancel(result)) return cancel();
443
+ autoStart = result;
444
+ }
445
+
460
446
  if (autoInstall && !process.env._CREATE_VUE3_PC_TEST) {
461
447
  process.stdout.write(`\r\x1b[K${pc.dim('Installing dependencies...')}\n`);
462
- runCommand(getInstallCommand(pkgManager), { cwd: root });
463
- process.stdout.write(`${pc.green('✓')} Dependencies installed!\n`);
448
+ try {
449
+ runCommand(getInstallCommand(pkgManager), { cwd: root });
450
+ process.stdout.write(`${pc.green('✓')} Dependencies installed!\n`);
451
+ } catch (e) {
452
+ process.stdout.write(`\n${pc.red('✗')} Installation failed\n`);
453
+ console.error(` ${pc.dim('You can retry manually:')}`);
454
+ console.error(` ${pc.cyan(`cd ${targetDir} && ${pkgManager} install${pkgManager === 'npm' ? ' --legacy-peer-deps' : ''}`)}\n`);
455
+ process.exit(1);
456
+ }
457
+ }
458
+
459
+ if (autoStart) {
460
+ prompts.log.step(`Starting dev server... (press ${pc.bold('Ctrl+C')} to stop)`);
461
+ runCommand(getRunCommand(pkgManager, 'dev'), { cwd: root });
462
+ return;
464
463
  }
465
464
 
466
- const cdProjectName = path.relative(process.cwd(), root);
467
- let doneMessage = '';
465
+ const cdPath = path.relative(process.cwd(), root);
466
+ const lines = [];
468
467
 
469
468
  if (root !== process.cwd()) {
470
- doneMessage += `\n ${pc.bold(pc.cyan('cd'))} ${cdProjectName.includes(' ') ? `"${cdProjectName}"` : cdProjectName}`;
469
+ const quoted = cdPath.includes(' ') ? `"${cdPath}"` : cdPath;
470
+ lines.push(` ${pc.bold(pc.cyan('cd'))} ${quoted}`);
471
471
  }
472
472
 
473
473
  if (!autoInstall) {
474
- doneMessage += `\n ${pc.bold(pc.cyan(pkgManager))} ${pkgManager === 'yarn' ? '' : 'install '}${pc.dim('--legacy-peer-deps')}`;
474
+ const cmd = pkgManager === 'yarn' ? pkgManager : `${pkgManager} install`;
475
+ const flag = pkgManager === 'npm' ? ' --legacy-peer-deps' : '';
476
+ lines.push(` ${pc.bold(pc.cyan(cmd))}${pc.dim(flag)}`);
475
477
  }
476
478
 
477
- doneMessage += `\n ${pc.bold(pc.cyan(pkgManager))} ${pkgManager === 'yarn' ? 'dev' : 'run dev'}`;
479
+ const runCmd = pkgManager === 'yarn' ? 'yarn dev' : `${pkgManager} run dev`;
480
+ lines.push(` ${pc.bold(pc.cyan(runCmd))}`);
478
481
 
479
- prompts.outro(`${pc.green('Done!')} Now run:${doneMessage}`);
482
+ prompts.outro(`${pc.green('Done!')} Now run:\n${lines.join('\n')}`);
480
483
  }
481
484
 
482
485
  main().catch((e) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gridsum-vue3-pc",
3
- "version": "1.0.7",
3
+ "version": "1.1.0",
4
4
  "description": "Gridsum Vue3 Vite PC Template Generator - 快速生成基于 Vue3 + Vite + TypeScript 的企业级 PC 端项目",
5
5
  "type": "module",
6
6
  "sideEffects": false,