@fuse-oo/cli
Version:
fuse内部脚手架工具
189 lines (167 loc) • 5.34 kB
JavaScript
const chalk = require('chalk')
const execa = require('execa')
const inquirer = require('inquirer')
const EventEmitter = require('events')
const loadRemotePreset = require('../lib/utils/loadRemotePreset')
const writeFileTree = require('../lib/utils/writeFileTree')
const copyFile = require('../lib/utils/copyFile')
const generateReadme = require('../lib/utils/generateReadme')
const {installDeps} = require('../lib/utils/installDeps')
const {
defaults
} = require('../lib/options')
const {
log,
error,
hasYarn,
hasGit,
hasPnpm3OrLater,
hasProjectGit,
logWithSpinner,
clearConsole,
stopSpinner,
exit
} = require('../lib/utils/common')
module.exports = class Creator extends EventEmitter {
constructor(name, context) {
super()
this.name = name
this.context = context
this.run = this.run.bind(this)
}
async create(cliOptions = {}, preset = null) {
const { run, name, context } = this
// ------- step 1 下载远程模版 ---------
if (cliOptions.preset) {
// fuse-cli create foo --preset mobx
preset = await this.resolvePreset(cliOptions.preset, cliOptions.clone)
} else {
preset = await this.resolvePreset(defaults.presets.default, cliOptions.clone)
}
// ------- step 2 cli信息打印 ---------
await clearConsole()
log(chalk.blue.bold(`Fuse CLI v${require('../package.json').version}`))
logWithSpinner(`🐼`, `正在创建项目 ${chalk.yellow(context)}.`)
this.emit('creation', { event: 'creating' })
stopSpinner()
// ------- step 3 基本信息配置 ---------
const { pkgVers, pkgDes } = await inquirer.prompt([
{
name: 'pkgVers',
message: `请输入项目版本号`,
default: '1.0.0',
},
{
name: 'pkgDes',
message: `请输入项目简介`,
default: 'project created by fuse-cli',
}
])
// 将下载的临时文件拷贝到项目中
const pkgJson = await copyFile(preset.tmpdir, preset.targetDir)
const pkg = Object.assign(pkgJson, {
version: pkgVers,
description: pkgDes
})
// 写入 package.json
log()
logWithSpinner('🐶', `生成 ${chalk.yellow('package.json')} 等模板文件`)
await writeFileTree(context, {
'package.json': JSON.stringify(pkg, null, 2)
})
// 获取包管理工具
const packageManager = (
(hasYarn() ? 'yarn' : null) ||
(hasPnpm3OrLater() ? '' : 'npm')
)
// 写入 readme 文档
await writeFileTree(context, {
'README.md': generateReadme(pkg, packageManager)
})
// ------- step 4 git 初始化 依赖下载 ---------
const shouldInitGit = this.shouldInitGit(cliOptions)
if (shouldInitGit) {
logWithSpinner(`🐸`, `初始化Git仓库`)
this.emit('creation', { event: 'git-init' })
await run('git init')
}
// 安装依赖
stopSpinner()
log()
logWithSpinner(`🐒`, `安装依赖中,请稍等...`)
await installDeps(context, packageManager, cliOptions.registry)
// commit initial state
let gitCommitFailed = false
if (shouldInitGit) {
await run('git add -A')
const msg = typeof cliOptions.git === 'string' ? cliOptions.git : 'init'
try {
await run('git', ['commit', '-m', msg])
} catch (e) {
gitCommitFailed = true
}
}
// ------- step 5 项目创建成功 ---------
stopSpinner()
log()
log(`🎉 项目创建成功 ${chalk.yellow(name)}.`)
if (!cliOptions.skipGetStarted) {
log(
`👉 请按如下命令,开始愉快开发吧!\n\n` +
(this.context === process.cwd() ? `` : chalk.cyan(` ${chalk.gray('$')} cd ${name}\n`)) +
chalk.cyan(` ${chalk.gray('$')} ${packageManager === 'yarn' ? 'yarn start' : packageManager === 'pnpm' ? 'pnpm run start' : 'npm start'}`)
)
}
log()
this.emit('creation', { event: 'done' })
if (gitCommitFailed) {
warn(
`因您的git username或email配置不正确,无法为您初始化git commit,\n` +
`请稍后自行git commit。\n`
)
}
}
// 拉取远程模版的方法
async resolvePreset (name, clone) {
let preset
logWithSpinner(`🐔`, `Fetching remote preset ${chalk.cyan(name)}...`)
this.emit('creation', { event: 'fetch-remote-preset' })
try {
preset = await loadRemotePreset(name, this.context, clone)
stopSpinner()
} catch (e) {
stopSpinner()
error(`Failed fetching remote preset ${chalk.cyan(name)}:`)
throw e
}
// 默认使用default参数
if (name === 'default' && !preset) {
preset = defaults.presets.default
}
if (!preset) {
error(`preset "${name}" not found.`)
exit(1)
}
return preset
}
run (command, args) {
if (!args) { [command, ...args] = command.split(/\s+/) }
return execa(command, args, { cwd: this.context })
}
// 是否能 git 初始化
shouldInitGit (cliOptions) {
if (!hasGit()) {
return false
}
// --git
if (cliOptions.forceGit) {
return true
}
// --no-git
if (cliOptions.git === false || cliOptions.git === 'false') {
return false
}
// default: true unless already in a git repo
return !hasProjectGit(this.context)
}
}