gridsum-vue3-pc 1.0.8 → 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
 
@@ -152,52 +145,13 @@ function runCommand(command, options = {}) {
152
145
  stdio: 'inherit',
153
146
  });
154
147
 
155
- if (result.status != null && result.status > 0) {
156
- process.exit(result.status);
157
- }
158
-
159
148
  if (result.error) {
160
- console.error(`\n${pc.red('Error:')} ${result.error.message}\n`);
161
- process.exit(1);
149
+ throw new Error(`Failed to execute "${cmd}": ${result.error.message}`);
162
150
  }
163
- }
164
151
 
165
- function runCommandAsync(command, options = {}) {
166
- const [cmd, ...args] = command;
167
- return new Promise((resolve, reject) => {
168
- const child = spawn(cmd, args, {
169
- stdio: ['ignore', 'pipe', 'pipe'],
170
- windowsHide: false,
171
- ...options,
172
- });
173
-
174
- child.stdout.on('data', () => {});
175
- let stderr = '';
176
- child.stderr.on('data', (chunk) => { stderr += chunk.toString(); });
177
-
178
- let i = 0;
179
- const timer = setInterval(() => {
180
- process.stdout.write(`\r${pc.cyan(SPINNER_FRAMES[i])} Installing dependencies...`);
181
- i = (i + 1) % SPINNER_FRAMES.length;
182
- }, 100);
183
-
184
- child.on('close', (code) => {
185
- clearInterval(timer);
186
- process.stdout.write('\r\x1b[K');
187
- if (code !== null && code > 0) {
188
- if (stderr) process.stderr.write(stderr);
189
- reject(new Error(`exit code ${code}`));
190
- } else {
191
- resolve();
192
- }
193
- });
194
- child.on('error', (err) => {
195
- clearInterval(timer);
196
- process.stdout.write('\r\x1b[K');
197
- if (stderr) process.stderr.write(stderr);
198
- reject(err);
199
- });
200
- });
152
+ if (result.status != null && result.status > 0) {
153
+ throw new Error(`"${cmd}" exited with code ${result.status}`);
154
+ }
201
155
  }
202
156
 
203
157
  function checkNodeVersion() {
@@ -216,7 +170,7 @@ Please upgrade Node.js:
216
170
 
217
171
  function parseArgs() {
218
172
  const argv = mri(process.argv.slice(2), {
219
- 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'],
220
174
  string: ['name', 'title', 'cicd'],
221
175
  alias: {
222
176
  h: 'help',
@@ -251,25 +205,37 @@ function scaffoldProject(root, answers, packageName) {
251
205
 
252
206
  const pkgPath = path.join(root, 'package.json');
253
207
  if (fs.existsSync(pkgPath)) {
254
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
255
- pkg.name = packageName;
256
- 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
+ }
257
215
  }
258
216
 
259
- ['.env', '.env.production'].forEach(file => {
217
+ for (const file of ['.env', '.env.production']) {
260
218
  const filePath = path.join(root, file);
261
219
  if (fs.existsSync(filePath)) {
262
- let content = fs.readFileSync(filePath, 'utf-8');
263
- content = content.replace(/VITE_APP_TITLE=.*/, `VITE_APP_TITLE=${answers.title}`);
264
- 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
+ }
265
227
  }
266
- });
228
+ }
267
229
 
268
230
  const indexPath = path.join(root, 'index.html');
269
231
  if (fs.existsSync(indexPath)) {
270
- let content = fs.readFileSync(indexPath, 'utf-8');
271
- content = content.replace(/<title>[^<]*<\/title>/, `<title>${answers.title}</title>`);
272
- 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
+ }
273
239
  }
274
240
  }
275
241
 
@@ -281,7 +247,11 @@ function validateOptions(options) {
281
247
  }
282
248
 
283
249
  if (options.cicd && !VALID_CICD.includes(options.cicd)) {
284
- 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)');
285
255
  }
286
256
 
287
257
  return errors;
@@ -409,11 +379,6 @@ async function main() {
409
379
  cicd: argv.cicd || 'none',
410
380
  };
411
381
 
412
- if (argv.title && !/^[a-zA-Z0-9_\-\u4e00-\u9fa5 ]+$/.test(argv.title)) {
413
- console.error(`\n${pc.red('Error:')} Project title contains invalid characters\n`);
414
- process.exit(1);
415
- }
416
-
417
382
  if (isInteractive) {
418
383
  const title = await prompts.text({
419
384
  message: 'Project title:',
@@ -480,8 +445,15 @@ async function main() {
480
445
 
481
446
  if (autoInstall && !process.env._CREATE_VUE3_PC_TEST) {
482
447
  process.stdout.write(`\r\x1b[K${pc.dim('Installing dependencies...')}\n`);
483
- runCommand(getInstallCommand(pkgManager), { cwd: root });
484
- 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
+ }
485
457
  }
486
458
 
487
459
  if (autoStart) {
@@ -490,20 +462,24 @@ async function main() {
490
462
  return;
491
463
  }
492
464
 
493
- const cdProjectName = path.relative(process.cwd(), root);
494
- let doneMessage = '';
465
+ const cdPath = path.relative(process.cwd(), root);
466
+ const lines = [];
495
467
 
496
468
  if (root !== process.cwd()) {
497
- 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}`);
498
471
  }
499
472
 
500
473
  if (!autoInstall) {
501
- 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)}`);
502
477
  }
503
478
 
504
- 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))}`);
505
481
 
506
- prompts.outro(`${pc.green('Done!')} Now run:${doneMessage}`);
482
+ prompts.outro(`${pc.green('Done!')} Now run:\n${lines.join('\n')}`);
507
483
  }
508
484
 
509
485
  main().catch((e) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gridsum-vue3-pc",
3
- "version": "1.0.8",
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,