lizi-wxapp-cli
Version:
微信小程序快速创建cli脚手架
212 lines (195 loc) • 6.84 kB
text/typescript
import chalk from 'chalk'
import process, { ChildProcessWithoutNullStreams } from 'child_process'
import inquirer, { Answers, InputQuestion, ListQuestion } from 'inquirer'
import jsonFormat from 'json-format'
import ora, { Ora } from 'ora'
import path from 'path'
import { log } from '../ulits/log'
import { regAppId, regCn, regEn } from '../ulits/ulits'
import Base from './base'
import { CreatePageFs } from './create-page-fs'
interface CreateProjectInterface {
init(): void
create(): Promise<void>
}
export default class CreateProject extends Base implements CreateProjectInterface {
protected name: string = ''
protected depict: string = ''
protected appid: string = ''
protected mode: 'javascript' | 'typescript' = 'javascript'
protected css: 'wxss' | 'less' = 'wxss'
constructor() {
super()
}
public init(): void {
inquirer.prompt([
this.__projectName(),
this.__projectDescription(),
this.__projectAppId(),
this.__projectMode(),
this.__projectCss()
]).then(async ({name, depict, appid, mode, css}: Answers): Promise<void> => {
this.name = name
this.depict = depict
this.appid = appid
this.mode = mode
this.css = css
await this.create()
}).catch((err) => {
console.log(err)
})
}
public __projectName(): InputQuestion<Answers> {
const that = this
return {
type: 'input',
name: 'name',
message: '请输入项目名称:',
async validate(input: string): Promise<boolean | string> {
// 校验文件名是否符合规范
return new Promise<boolean | string>(async (resolve) => {
if (regEn.test(input) || regCn.test(input)) {
// 验证项目名是否符合规则
resolve(chalk.red('项目名不符合规则,请重新输入项目名!'))
} else if (await that.checkFileIsExists(path.join(that.projectRoot, input))) {
// 获取当前打开的目录,验证当前要创建的项目是否跟当前目录里的文件夹命名冲突
resolve(chalk.red('该项目已创建,请重新输入项目名!'))
}
resolve(true)
})
},
default: 'app'
}
}
public __projectDescription(): InputQuestion<Answers> {
return {
type: 'input',
name: 'depict',
message: '请输入项目描述:'
}
}
public __projectAppId(): InputQuestion<Answers> {
return {
type: 'input',
name: 'appid',
message: (answers) => `请输入[${answers.name}]的AppId:`,
async validate(input: string): Promise<boolean | string> {
return new Promise<boolean | string>((resolve) => {
if (!regAppId.test(input)) resolve(chalk.red('请输入正确的AppId!'))
resolve(true)
})
}
}
}
public __projectMode(): ListQuestion<Answers> {
return {
type: 'list',
name: 'mode',
message: '选择项目脚本语言:',
choices: [
'javascript',
'typescript'
]
}
}
public __projectCss(): ListQuestion<Answers> {
return {
type: 'list',
name: 'css',
message: '选择项目样式语言:',
choices: [
'wxss',
'less'
]
}
}
private async _copyTypeFiles(copyRoot, projectRoot, type): Promise<void> {
const root: string = path.join(copyRoot, type)
const files: string[] = await this.readDirs(root)
await this.copyFilesArr(root, projectRoot, files)
.catch(({result}) => this.fileIsRepeat(result))
}
public async create(): Promise<void> {
const loading: Ora = ora('creating project...').start()
// 创建项目文件夹
let projectRoot: string = path.join(this.projectRoot, this.name)
await this.makeDir(projectRoot)
// 获取模板文件
let tempRoot: string = path.join(this.templateRoot, 'project')
let files: string[] = await this.readDirs(tempRoot)
// 创建小程序默认文件
await this.copyFilesArr(tempRoot, projectRoot, files)
// 创建脚本文件
this._copyTypeFiles(tempRoot, projectRoot, this.mode)
// 创建样式文件
this._copyTypeFiles(tempRoot, projectRoot, this.css)
// 初始化npm项目
const bash: ChildProcessWithoutNullStreams = process.spawn('bash')
bash.on('error', () => loading.fail(chalk.red('初始化失败')))
bash.on('close', async () => {
loading.text = '初始化成功'
// 修改npm配置文件
await this._modifyPackageJson(projectRoot, 'package.json', loading)
// 修改小程序配置文件
await this._modifyProjectConfigJson(projectRoot, 'project.config.json', loading)
// 创建默认页面
let pageRoot: string = path.join(projectRoot, this.pageRoot)
await this.makeDir(pageRoot)
CreatePageFs.create({
root: projectRoot,
name: 'index'
}).then(() => {
loading.succeed(chalk.green(`项目【${this.name}】创建成功`))
log.table([
['项目名称', this.name],
['APPID', this.appid],
['项目描述', this.depict],
['项目路径', this.projectRoot],
['脚本语言', this.mode],
['样式语言', this.css],
['操作提示', `Please switch to the project directory!
Run ${chalk.bgWhite('cd ' + this.name)} to directory!
Run ${chalk.bgWhite('npm install')} to start!`]
], false)
})
})
bash.stdin.write(`cd ${this.name}\n`)
bash.stdin.write('npm init -y \n')
bash.stdin.end()
}
private async _modifyProjectConfigJson(path: string, file: string, loading: Ora): Promise<void> {
// 读取配置文件
let json = JSON.parse(await this.readFile(path, file))
let modify = {
miniprogramRoot: this.miniprogramRoot,
projectname: this.name,
projectmode: this.mode,
projectcss: this.css,
appid: this.appid
}
await this.writeFile(path, file, jsonFormat({...json, ...modify}))
loading.text = `修改${file}成功`
}
private async _modifyPackageJson(path: string, file: string, loading: Ora): Promise<void> {
// 读取文件
let json = JSON.parse(await this.readFile(path, file))
let modify = {
scripts: {
compile: './node_modules/typescript/bin/tsc',
tsc: 'node ./node_modules/typescript/lib/tsc.js'
},
description: this.depict ? this.depict : 'project depict...',
devDependencies: {
typescript: '^3.5.3'
},
dependencies: {
'miniprogram-api-typings': '^2.7.7',
'tslint-config-alloy': '^0.2.1',
'tslint-eslint-rules': '^5.4.0'
}
}
await this.writeFile(path, file, jsonFormat({...json, ...modify}))
loading.text = `修改${file}成功`
}
}
export const CreateProjectFs = new CreateProject()