Skip to content

Commit

Permalink
feat(cli): 支持更改 CLI 展示的模板名称 (#15940)
Browse files Browse the repository at this point in the history
  • Loading branch information
koppthe committed Jun 20, 2024
1 parent a8ac196 commit c12054b
Show file tree
Hide file tree
Showing 4 changed files with 1,357 additions and 1,314 deletions.
3 changes: 2 additions & 1 deletion packages/taro-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@
"dependencies": {
"@tarojs/binding": "workspace:*",
"@tarojs/helper": "workspace:*",
"@tarojs/plugin-doctor": "^0.0.11",
"@tarojs/service": "workspace:*",
"@tarojs/shared": "workspace:*",
"@tarojs/plugin-doctor": "^0.0.11",
"adm-zip": "^0.4.13",
"axios": "^1.6.8",
"cli-highlight": "^2.1.11",
"download-git-repo": "^2.0.0",
"envinfo": "^7.8.1",
Expand Down
65 changes: 41 additions & 24 deletions packages/taro-cli/src/create/fetchTemplate.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { chalk, fs } from '@tarojs/helper'
import * as AdmZip from 'adm-zip'
import axios from 'axios'
import * as download from 'download-git-repo'
import * as ora from 'ora'
import * as path from 'path'
import * as request from 'request'

import { getTemplateSourceType, readDirWithFileTypes } from '../util'
import { TEMPLATE_CREATOR } from './constants'

export interface ITemplates {
name: string
value: string
platforms?: string | string[]
desc?: string
compiler?: string[]
}

const TEMP_DOWNLOAD_FOLDER = 'taro-temp'
Expand All @@ -20,8 +22,6 @@ export default function fetchTemplate (templateSource: string, templateRootPath:
const type = getTemplateSourceType(templateSource)
const tempPath = path.join(templateRootPath, TEMP_DOWNLOAD_FOLDER)
let name: string
let isFromUrl = false

// eslint-disable-next-line no-async-promise-executor
return new Promise<void>(async (resolve) => {
// 下载文件的缓存目录
Expand All @@ -47,23 +47,36 @@ export default function fetchTemplate (templateSource: string, templateRootPath:
} else if (type === 'url') {
// url 模板源,因为不知道来源名称,临时取名方便后续开发者从列表中选择
name = 'from-remote-url'
isFromUrl = true
const zipPath = path.join(tempPath, name + '.zip')
request
.get(templateSource)
.pipe(fs.createWriteStream(zipPath))
.on('close', () => {
// unzip
const zip = new AdmZip(zipPath)
zip.extractAllTo(path.join(tempPath, name), true)

spinner.color = 'green'
spinner.succeed(`${chalk.grey('拉取远程模板仓库成功!')}`)
resolve()
const unZipPath = path.join(tempPath, name)
axios.get<fs.ReadStream>(templateSource, { responseType: 'stream' })
.then(response => {
const ws = fs.createWriteStream(zipPath)
response.data.pipe(ws)
ws.on('finish', () => {
// unzip
const zip = new AdmZip(zipPath)
zip.extractAllTo(unZipPath, true)
const files = readDirWithFileTypes(unZipPath).filter(
file => !file.name.startsWith('.') && file.isDirectory && file.name !== '__MACOSX'
)

if (files.length !== 1) {
spinner.color = 'red'
spinner.fail(chalk.red(`拉取远程模板仓库失败!\n${new Error('远程模板源组织格式错误')}`))
return resolve()
}
name = path.join(name, files[0].name)

spinner.color = 'green'
spinner.succeed(`${chalk.grey('拉取远程模板仓库成功!')}`)
resolve()
})
ws.on('error', error => { throw error })
})
.on('error', async err => {
.catch(async error => {
spinner.color = 'red'
spinner.fail(chalk.red(`拉取远程模板仓库失败!\n${err}`))
spinner.fail(chalk.red(`拉取远程模板仓库失败!\n${error}`))
await fs.remove(tempPath)
return resolve()
})
Expand Down Expand Up @@ -96,13 +109,14 @@ export default function fetchTemplate (templateSource: string, templateRootPath:
const res: ITemplates[] = files.map(name => {
const creatorFile = path.join(templateRootPath, name, TEMPLATE_CREATOR)

if (!fs.existsSync(creatorFile)) return { name }

const { platforms = '', desc = '' } = require(creatorFile)
if (!fs.existsSync(creatorFile)) return { name, value: name }
const { name: displayName, platforms = '', desc = '', compiler } = require(creatorFile)

return {
name,
name: displayName || name,
value: name,
platforms,
compiler,
desc
}
})
Expand All @@ -112,15 +126,18 @@ export default function fetchTemplate (templateSource: string, templateRootPath:
await fs.move(templateFolder, path.join(templateRootPath, name), { overwrite: true })
await fs.remove(tempPath)

let res: ITemplates = { name, desc: isFromUrl ? templateSource : '' }
let res: ITemplates = { name, value: name, desc: type === 'url' ? templateSource : '' }

const creatorFile = path.join(templateRootPath, name, TEMPLATE_CREATOR)

if (fs.existsSync(creatorFile)) {
const { platforms = '', desc = '' } = require(creatorFile)
const { name: displayName, platforms = '', desc = '', compiler } = require(creatorFile)

res = {
name,
name: displayName || name,
value: name,
platforms,
compiler,
desc: desc || templateSource
}
}
Expand Down
88 changes: 50 additions & 38 deletions packages/taro-cli/src/create/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import {
TARO_CONFIG_FOLDER
} from '@tarojs/helper'
import { isArray } from '@tarojs/shared'
import axios from 'axios'
import * as inquirer from 'inquirer'
import * as ora from 'ora'
import * as path from 'path'
import * as request from 'request'
import * as semver from 'semver'

import { clearConsole, getPkgVersion, getRootPath } from '../util'
Expand All @@ -38,6 +38,7 @@ export interface IProjectConf {
sourceRoot?: string
env?: string
autoInstall?: boolean
hideDefaultTemplate?: boolean
framework: FrameworkType
compiler?: CompilerType
}
Expand All @@ -58,9 +59,9 @@ export default class Project extends Creator {

constructor (options: IProjectConfOptions) {
super(options.sourceRoot)
const unSupportedVer = semver.lt(process.version, 'v7.6.0')
const unSupportedVer = semver.lt(process.version, 'v18.0.0')
if (unSupportedVer) {
throw new Error('Node.js 版本过低,推荐升级 Node.js 至 v8.0.0+')
throw new Error('Node.js 版本过低,推荐升级 Node.js 至 v18.0.0+')
}
this.rootPath = this._rootPath

Expand Down Expand Up @@ -341,16 +342,17 @@ export default class Project extends Creator {
}

askTemplate: AskMethods = function (conf, prompts, list = []) {
const choices = [
{
const choices = list.map(item => ({
name: item.desc ? `${item.name}${item.desc})` : item.name,
value: item.value || item.name
}))

if (!conf.hideDefaultTemplate) {
choices.unshift({
name: '默认模板',
value: 'default'
},
...list.map(item => ({
name: item.desc ? `${item.name}${item.desc})` : item.name,
value: item.name
}))
]
})
}

if ((typeof conf.template as 'string' | undefined) !== 'string') {
prompts.push({
Expand Down Expand Up @@ -393,7 +395,8 @@ export default class Project extends Creator {
}

async fetchTemplates (answers: IProjectConf): Promise<ITemplates[]> {
const { templateSource, framework } = answers
const { templateSource, framework, compiler } = answers
this.conf.framework = this.conf.framework || framework || ''
this.conf.templateSource = this.conf.templateSource || templateSource

// 使用默认模版
Expand All @@ -407,17 +410,30 @@ export default class Project extends Creator {
const isClone = /gitee/.test(this.conf.templateSource) || this.conf.clone
const templateChoices = await fetchTemplate(this.conf.templateSource, this.templatePath(''), isClone)

const filterFramework = (_framework) => {
const current = this.conf.framework?.toLowerCase()

if (typeof _framework === 'string' && _framework) {
return current === _framework.toLowerCase()
} else if (isArray(_framework)) {
return _framework?.map(name => name.toLowerCase()).includes(current)
} else {
return true
}
}

const filterCompiler = (_compiler) => {
if (_compiler && isArray(_compiler)) {
return _compiler?.includes(compiler)
}
return true
}

// 根据用户选择的框架筛选模板
const newTemplateChoices: ITemplates[] = templateChoices
.filter(templateChoice => {
const { platforms } = templateChoice
if (typeof platforms === 'string' && platforms) {
return framework === templateChoice.platforms
} else if (isArray(platforms)) {
return templateChoice.platforms?.includes(framework)
} else {
return true
}
const { platforms, compiler } = templateChoice
return filterFramework(platforms) && filterCompiler(compiler)
})

return newTemplateChoices
Expand Down Expand Up @@ -451,27 +467,23 @@ export default class Project extends Creator {
}
}

function getOpenSourceTemplates (platform) {
function getOpenSourceTemplates (platform: string) {
return new Promise((resolve, reject) => {
const spinner = ora({ text: '正在拉取开源模板列表...', discardStdin: false }).start()
request.get('https://gitee.com/NervJS/awesome-taro/raw/next/index.json', (error, _response, body) => {
if (error) {
axios.get('https://gitee.com/NervJS/awesome-taro/raw/next/index.json')
.then(response => {
spinner.succeed(`${chalk.grey('拉取开源模板列表成功!')}`)
const collection = response.data
switch (platform.toLowerCase()) {
case 'react':
return resolve(collection.react)
default:
return resolve([NONE_AVAILABLE_TEMPLATE])
}
})
.catch(_error => {
spinner.fail(chalk.red('拉取开源模板列表失败!'))
return reject(new Error())
}

spinner.succeed(`${chalk.grey('拉取开源模板列表成功!')}`)

const collection = JSON.parse(body)

switch (platform) {
case 'react':
return resolve(collection.react)
case 'vue':
return resolve(collection.vue)
default:
return resolve([NONE_AVAILABLE_TEMPLATE])
}
})
})
})
}
Loading

0 comments on commit c12054b

Please sign in to comment.