Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): 支持更改 CLI 展示的模板名称 #15940

Merged
merged 1 commit into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Node 18 应该可以用 fetch 了吧

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3.x还支持node16,4.x可以吧这个去掉

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是的,但这块的代码逻辑是 4.x 里面的,只是同步一下,后续可以优化一下,没必要用 axios

"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
Loading