Skip to content

Commit

Permalink
perf: 更友好的错误提示及操作指引
Browse files Browse the repository at this point in the history
  • Loading branch information
Ten-K committed Nov 18, 2022
1 parent 1bb1c57 commit a88e087
Show file tree
Hide file tree
Showing 10 changed files with 130 additions and 70 deletions.
2 changes: 1 addition & 1 deletion README.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@
- Or, you want to create a project through interactive selection template:

```bash
pure create myproject
pure create
```
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@
- 或者,你想通过交互式选择模板创建项目:

```bash
pure create myproject
pure create
```
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"main": "bin/www.js",
"scripts": {
"dev": "pnpm build && pure init thin demo",
"devc": "pnpm build && pure init aa demo",
"build": "tsup",
"typecheck": "tsc --noEmit",
"lint:eslint": "eslint --cache --max-warnings 0 \"{src,mock}/**/*.{vue,ts}\" --fix",
Expand Down
9 changes: 5 additions & 4 deletions src/create-dir/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import pc from 'picocolors'
import ora, { Ora } from 'ora'
import { Ioptions } from '../types'
import { isOverwriteDir } from '../prompt'
import { clg } from '../utils'

const spinner: Ora = ora()

Expand All @@ -23,16 +24,16 @@ export const isExistsFile = async (projectName: string, options: Ioptions) => {
const isOverwrite = await isOverwriteDir()
// 选择 Cancel
if (!isOverwrite) {
console.log(pc.green('Cancel'))
clg(pc.green('取消成功'))
return true
} else {
// 选择 Overwirte ,先删除掉原有重名目录
try {
spinner.start('removing')
spinner.start('删除中...')
await fs.remove(targetDirectory)
spinner.succeed(`Success remove ${pc.gray(projectName)}`)
spinner.succeed(`成功删除 ${pc.gray(projectName)}`)
} catch (error) {
spinner.fail('Overwrite fail, Please try again')
spinner.fail('覆盖失败, 请重试')
process.exit(1)
}
return false
Expand Down
24 changes: 13 additions & 11 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { create } from './template'
import { templates } from './constants'
import { TTemplateName } from './types'
import { isExistsFile } from './create-dir'
import { hasTemplate, clg } from './utils'
import { inputProjectName } from './prompt'

// eslint-disable-next-line @typescript-eslint/no-var-requires
const version: string = require('../package.json').version
Expand All @@ -13,25 +15,27 @@ const cli = cac('pure')
cli.version(version)

cli
.command('create <project-name>', 'create a new project') // 增加创建指令
.option('-f, --force', 'overwrite target directory if it exists') // 强制覆盖
.action(async (projectName, cmd) => {
.command('create', '创建一个新项目') // 增加创建指令
.option('-f, --force', '如果目标文件存在,则强制覆盖') // 强制覆盖
.action(async (cmd) => {
const projectName = await inputProjectName()
const isExists = await isExistsFile(projectName, cmd)
if (isExists) return
create(projectName)
})

cli
.command('init <template-name> <project-name>', 'create a new project') // 增加创建指令
.option('-f, --force', 'overwrite target directory if it exists') // 强制覆盖
.command('init <template-name> <project-name>', '创建一个新项目') // 增加创建指令
.option('-f, --force', '如果目标文件存在,则强制覆盖') // 强制覆盖
.action(async (templateName, projectName, cmd) => {
if (!hasTemplate(templateName)) return
const isExists = await isExistsFile(projectName, cmd)
if (isExists) return
create(projectName, templateName)
})

cli.help(() => {
console.log(
clg(
'\r\n' +
figlet.textSync('pure', {
font: '3D-ASCII',
Expand All @@ -41,14 +45,12 @@ cli.help(() => {
whitespaceBreak: true
})
)
console.log()
console.log(`Run ${pc.cyan('pure <command> --help')} for detailed usage of given command.`)
console.log()
clg(`运行 ${pc.cyan('pure <command> --help')} 查看有关命令的详细用法. \r\n`)
})

cli.command('list', 'view all available templates').action(() => {
cli.command('list', '查看所有模板类型').action(() => {
Object.keys(templates).forEach((key: string) => {
console.log(`${key} ${templates[key as TTemplateName].description}`)
clg(`${key} ${templates[key as TTemplateName].description}`)
})
})

Expand Down
11 changes: 11 additions & 0 deletions src/prompt/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ export const chooseTemplate = async () => {
return template
}

export const inputProjectName = async () => {
const { projectName } = await inquirer.prompt([
{
name: 'projectName',
type: 'input',
message: '请输入项目名称'
}
])
return projectName
}

export const isOverwriteDir = async () => {
const { isOverwrite } = await inquirer.prompt([
// 返回值为promise
Expand Down
4 changes: 3 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ export interface Ioptions {
interface ITemplatesItem {
downloadUrl: string
description: string
branch: string
}

export interface ITemplates {
thin: ITemplatesItem
i18n: ITemplatesItem
tauri: ITemplatesItem
electron: ITemplatesItem
admin: ITemplatesItem
}

export type TTemplateName = 'thin' | 'i18n' | 'tauri' | 'admin'
export type TTemplateName = 'thin' | 'i18n' | 'tauri' | 'electron' | 'admin'
75 changes: 75 additions & 0 deletions src/utils/clone.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { log, clg } from './log'
import pc from 'picocolors'
import ora, { Ora, Options } from 'ora'
import { TTemplateName } from '../types'
import { templates } from '../constants'
import simpleGit, { SimpleGit, SimpleGitOptions, SimpleGitProgressEvent } from 'simple-git'

const oraOptions: Options = {
spinner: 'runner'
}
const spinner: Ora = ora(oraOptions)

const progress = ({ progress }: SimpleGitProgressEvent) => {
const proText = `进度: ${pc.cyan(progress + '%')}`
spinner.start().text = proText
if (progress === 100) {
spinner.start().text = proText + pc.green(' 下载完成')
}
}

const gitOptions: Partial<SimpleGitOptions> = {
baseDir: process.cwd(),
binary: 'git',
maxConcurrentProcesses: 6,
progress
}

// https://git-scm.com/docs/git-clone#Documentation/git-clone.txt
export const clone = async (
repo: string,
projectName: string,
options: string[],
templateName: TTemplateName
): Promise<any> => {
const git: SimpleGit = simpleGit(gitOptions)
try {
clg(`项目下载自 ${pc.cyan(repo)}`)
await git.clone(repo, projectName, options)
} catch (err) {
spinner.fail()
log.err('请求失败, 请重试')
}

spinner.succeed() // 下载成功提示
// 模板使用提示
clg(`\r\n 已成功创建项目 ${pc.cyan(projectName)}`)
clg(`\r\n cd ${pc.cyan(projectName)}`)
clg(' pnpm install \r\n')
if (templateName === 'tauri') {
return clg(' pnpm tauri:dev \r\n')
}
clg(' pnpm dev \r\n')
}

/**
* 判断当前模板类型是否存在
* @param templateName 模板类型
* @returns { boolean }
*/
export const hasTemplate = (templateName: TTemplateName): boolean => {
const templateKeys = Reflect.ownKeys(templates)
const hasTemplate = templateKeys.includes(templateName)
if (!hasTemplate) {
log.err(`当前模板类型 ${pc.cyan(`${templateName}`)} 不存在 \r\n `)
log.info(`请输入以下其中一种模板类型: `)
templateKeys.forEach((key) => {
clg(
pc.bold(
pc.green(`${key as string} `) + pc.gray(`${templates[key as TTemplateName].description}`)
)
)
})
}
return hasTemplate
}
54 changes: 2 additions & 52 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,2 @@
import pc from 'picocolors'
import logSymbols from 'log-symbols'
import ora, { Ora, Options } from 'ora'
import { TTemplateName } from '../types'
import simpleGit, { SimpleGit, SimpleGitOptions, SimpleGitProgressEvent } from 'simple-git'

const oraOptions: Options = {
spinner: 'runner'
}
const spinner: Ora = ora(oraOptions)

const progress = ({ progress }: SimpleGitProgressEvent) => {
const proText = `Progress: ${pc.cyan(progress + '%')}`
spinner.start().text = proText
if (progress === 100) {
spinner.start().text = proText + pc.green(' Download Completed')
}
}

const gitOptions: Partial<SimpleGitOptions> = {
baseDir: process.cwd(),
binary: 'git',
maxConcurrentProcesses: 6,
progress
}

// https://git-scm.com/docs/git-clone#Documentation/git-clone.txt
export const clone = async (
repo: string,
projectName: string,
options: string[],
templateName: TTemplateName
): Promise<any> => {
const git: SimpleGit = simpleGit(gitOptions)
try {
console.log(`download from ${pc.cyan(repo)}`)
await git.clone(repo, projectName, options)
} catch (err) {
spinner.fail()
console.log(logSymbols.error, pc.red('Request fail, Please try again'))
}

spinner.succeed() // 下载成功提示
// 模板使用提示
console.log(`\r\n Successfully created project ${pc.cyan(projectName)}`)
console.log(`\r\n cd ${pc.cyan(projectName)}`)
console.log(' pnpm install \r\n')
if (templateName === 'tauri') {
return console.log(' pnpm tauri:dev \r\n')
}
console.log(' pnpm dev \r\n')
}
export * from './log'
export * from './clone'
18 changes: 18 additions & 0 deletions src/utils/log.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import pc from 'picocolors'
import logSymbols from 'log-symbols'

export const clg = console.log

export const log = {
err: (msg: string) => {
clg(logSymbols.error, pc.red(msg))
},
warning: (msg: string) => {
clg(logSymbols.warning, pc.yellow(msg))
},
info: (msg: string) => {
clg(logSymbols.info, pc.bold(msg))
}
}

export default log

0 comments on commit a88e087

Please sign in to comment.