【源碼解析】taro-cli(1)- 建立、診斷、info、更新

taro-cli解析

前言

taro 腳手架分別有:javascript

  • init // 初始化項目
  • create // 建立頁面
  • doctor // 診斷項目
  • info // 查看系統信息和版本信息等
  • update // 更新依賴
  • convert // 小程序轉taro
  • build // 編譯taro項目

本章主要講解前面五個的功能和實現,而buildconvert則會放在taro-cli原理系列的二和三,敬請期待~ 因爲 官方也在維護,代碼可能會更新,所以文中的代碼不免會與最新源碼有出入, 本文所解析taro-cliversion1.3.21,將來若是某些功能的分析文章與源碼若是出入過大,則會更新對應的文章。css

cli目錄

首先咱們看一下taro-cli的目錄,該工程位於taro的packages目錄下。當咱們安裝taro-cli後,會生成taro 命令。 html

用到的核心庫
  • tj/commander.js Node.js - 命令行接口全面的解決方案,靈感來自於 Ruby's commander。能夠自動的解析命令和參數,合併多選項,處理短參等等,功能強大,上手簡單。
  • jprichardson/node-fs-extra - 在 Node.js 的 fs 基礎上增長了一些新的方法,更好用,還能夠拷貝模板。
  • chalk/chalk - 能夠用於控制終端輸出字符串的樣式。
  • SBoudrias/Inquirer.js - Node.js 命令行交互工具,通用的命令行用戶界面集合,能夠和用戶進行交互。
  • sindresorhus/ora - 實現加載中的狀態是一個 Loading 加前面轉起來的小圈圈,成功了是一個 Success 加前面一個小鉤鉤。
  • SBoudrias/mem-fs-editor - 提供一系列 API,方便操做模板文件。
  • shelljs/shelljs - ShellJS 是 Node.js 擴展,用於實現 Unix shell 命令執行。
  • Node.js child_process - 模塊用於新建子進程。子進程的運行結果儲存在系統緩存之中(最大 200KB),等到子進程運行結束之後,主進程再用回調函數讀取子進程的運行結果。

如何在命令行中使用Taro

當咱們在命令行中輸入Taro時,會有如下的輸出:vue

�👽 Taro v1.2.13

Usage: taro <command> [options]                                                                                            ource\\todoList-Redux\\

Options:                                                                                                                   de
  -V, --version       output the version number
  -h, --help          output usage information

Commands:                                                                                                                   postinstall || echo \" init [projectName] Init a project with default templete build Build a project with options update Update packages of taro convert Convert weapp to taro info Diagnostics Taro env info help [cmd] display help for [cmd] 複製代碼

那麼,像@vue/cli@wepy/cli等,是如何讓咱們能夠直接在命令行中使用呢?
緣由在於, @taro/taro-clipackage.json中的bin字段:java

"bin": {
    "taro": "bin/taro"
  }
複製代碼

上面代碼指定,taro 命令對應的可執行文件爲 bin 子目錄下的 taro.js。Npm會尋找這個文件,在node_modules/.bin/目錄下創建符號連接。在上面的例子中,taro.js會創建符號連接npm_modules/.bin/taro。因爲node_modules/.bin/目錄會在運行時加入系統的PATH變量,所以在運行npm時,就能夠不帶路徑,直接經過命令來調用這些腳本。若是隻有一個命令,也能夠直接簡寫成string,前提是命令名稱和模塊名稱同樣node

{ 
    "name": "taro",
    "version": "1.2.5",
    "bin": "bin/taro"
}
複製代碼

Taro Init

使用命令建立模板項目git

taro init myApp
// npx @tarojs/cli init myApp
複製代碼

其中用到了commander這個庫,能夠自動的解析命令和參數,合併多選項,處理短參等等。讓咱們來看一下它在init命令中的用法:github

// taro-cli/bin/taro-init
const program = require('commander')
program
  .option('--name [name]', '項目名稱')
  .option('--description [description]', '項目介紹')
  .option('--typescript', '使用TypeScript')
  .option('--no-typescript', '不使用TypeScript')
  .option('--template-source [templateSource]', '項目模板源')
  .option('--clone [clone]', '拉取遠程模板時使用git clone')
  .option('--template [template]', '項目模板')
  .option('--css [css]', 'CSS預處理器(sass/less/stylus/none)')
  .parse(process.argv)
const { template, templateSource, clone, description, name, css } = program;

const project = new Project({
  projectName,
  projectDir: process.cwd(),
  templateSource,
  clone,
  template,
  description,
  typescript,
  css
})
複製代碼

代碼較短,相信你們看了也是一目瞭然。這裏就不詳細說明。 重點講一下,new Projectproject.create()所作的事情。typescript

// taro-cli/src/create/project.ts
class Project extends Creator {
    constructor (options: IProjectConf) {
        super(options.sourceRoot)
        this.conf = Object.assign({
            projectName: '',
            projectDir: '',
            template: '',
            description: ''
        }, options)
    }
}
複製代碼

new Project時,在構造函數中傳進咱們經過命令行輸入的參數,好比 -- description。緊接着咱們看一下create作了什麼事情。shell

create () {
    this.fetchTemplates()
      .then((templateChoices: string[]) => this.ask(templateChoices))
      .then(answers => {
        const date = new Date()
        this.conf = Object.assign(this.conf, answers)
        this.conf.date = `${date.getFullYear()}-${(date.getMonth() + 1)}-${date.getDate()}`
        this.write()
      })
      .catch(err => console.log(chalk.red('建立項目失敗: ', err)))
  }
複製代碼
  1. 獲取模板。先從taroconfig中查看是否有模板的地址(templateSource),若是沒有的話則使用默認的模板組,並經過git clone的方式下載(這裏是使用了download-git-repo這個庫)

1.3.9 開始 Taro 會在用戶根目錄下建立 .taro 文件夾,其中 .taro/index.json 用於存放 CLI 相關配置。 開發者可使用 taro config 命令對配置項進行一系列操做。說明

  1. ask(詢問),便是經過inquirer模塊,創造命令行交互,肯定(項目名,描述,是否用ts, css預處理器,模板)
  2. 肯定所需的選項後,使用mem-fs-editorcopyTpl拷貝模板,模板使用ejs,並將所須要的選項傳遞進去。好比修改package.json中的name和description。

4. 在建立完項目後,是使用child_process來執行 git init初始化倉庫和 npm install來安裝依賴(固然,也多是使用yarn源或者cnpm來安裝),如下是判斷使用哪一個registry的代碼

if (shouldUseYarn) {
    command = 'yarn install'
  } else if (helper.shouldUseCnpm()) {
    command = 'cnpm install'
  } else {
    command = 'npm install'
  }
export function shouldUseYarn (): boolean {
  try {
    execSync('yarn --version', { stdio: 'ignore' })
    return true
  } catch (e) {
    return false
  }
}
複製代碼

Taro create

快速建立新頁面

Taro create --name [頁面名稱]
複製代碼

可以在當前項目的pages目錄下快速生成新的頁面文件,並填充基礎代碼,是一個提升開發效率的利器。

create的過程與init相似,這裏就不作過多的闡述.

Taro doctor

在taro中,提供了5個Validator,分別是:

  • configValidator,
  • packageValidator,
  • recommandValidator,
  • eslintValidator,
  • abilityXMLValidator (這個是用來檢查原子化服務規範) 下面,咱們分別講講各個validator的功能與實現:

1. configValidator

使用joi(The most powerful data validation library for JS),對config目錄下的配置作校驗。

/**
 *projectConfig: config文件夾下的配置
 *configSchema: joi配置
 */
export default async function ({ configPath, projectConfig }) {
  const { error } = Joi.validate(projectConfig, configSchema, { abortEarly: false })
  return buildReport(configPath, error)
}
複製代碼

這裏咱們也看一下JOI的簡單用法。如下兩個字段示例,定義了類型,以及是否必填

const schema = Joi.object().keys({
  'projectName': Joi.string().required(),
  'date': Joi.date()
})
複製代碼

2. packageValidator

依賴檢查主要有三個方面:

  • 包是否已經安裝
  • 檢測是否有新版本
  • 檢測cli版本是否一致
errorLines = _.concat(errorLines, pkgsNotInstalled(pkgs))
  errorLines = _.concat(errorLines, taroShouldUpdate(taroPkgs))
  errorLines = _.concat(errorLines, taroCliVersionNotMatch(taroPkgs))
複製代碼

3. recommandValidator

recommandValidator 檢查的是一些常見的推薦內容。主要有:

  • .editconfig配置
  • .gitignore 配置
  • Readme
  • ESLint
  • 測試依賴

前三項文件配置的檢查,是經過fs.readdirSync('./')獲取項目文件,並匹配。而eslint和測試的檢查,則是經過檢查是否有安裝了相關的依賴包。

4. eslintValidator

檢查 ESLint,該Validator是對代碼作了一遍eslint的檢查。使用eslint的 CLIEngine模塊

import { CLIEngine } from 'eslint'
const eslintCli = new CLIEngine({
    cwd: process.cwd(),
    useEslintrc: false,
    configFile
})
...
const report = eslintCli.executeOnFiles([sourceFiles])
const formatter = eslintCli.getFormatter()
複製代碼

5. abilityXMLValidator

這個validator是用於對華爲原子服務定義文件的校驗。快應用這一塊小編並不瞭解,想詳細學習的能夠去developer.huawei.com看一下。
檢查是否有project.quickapp.json文件,若是有的話則對ability.xml作檢驗。如下是abilityXMLValidator.ts中的註釋,小編就直接CV過來啦~~~

Taro Info

Taro 提供了命令來一鍵檢測 Taro 環境及依賴的版本等信息,方便你們查看項目的環境及依賴,排查環境問題。在提 issue 的時候,請附上 taro info 打印的信息,幫助開發人員快速定位問題。

如下是taro info的核心代碼,主要是使用到了envinfo這個庫

async function info (options) {
  const info = await envinfo.run(Object.assign({}, {
    System: ['OS', 'Shell'],
    Binaries: ['Node', 'Yarn', 'npm'],
    npmPackages,
    npmGlobalPackages: ['typescript']
  }, options), {
    title: `Taro CLI ${getPkgVersion()} environment info`
  })
  console.log(info)
}
複製代碼

envinfo.run這個方法接受須要的env Info的參數,返回具體的參數值。

Taro update

更新項目中 Taro 相關的依賴

taro update project
複製代碼

1. 獲取 Taro 的最新版本

const getLatestVersion = require('latest-version')
複製代碼

2.更新項目 package.json 裏面的 Taro 依賴信息到最新版本

// 寫入package.json
  try {
    await fs.writeJson(pkgPath, packageMap, {spaces: '\t'})
    console.log(chalk.green('更新項目 package.json 成功!'))
    console.log()
  } catch (err) {
    console.error(err)
  }
複製代碼

3. 運行 npm install

let command
  if (shouldUseYarn()) {
    command = 'yarn'
  } else if (shouldUseCnpm()) {
    command = 'cnpm install'
  } else {
    command = 'npm install'
  }

  const child = exec(command)

  const spinner = ora('即將將項目全部 Taro 相關依賴更新到最新版本...').start()

  child.stdout.on('data', function (data) {
    spinner.stop()
    console.log(data)
  })
  child.stderr.on('data', function (data) {
    spinner.stop()
    console.log(data)
  })
複製代碼

這裏的exec使用了child_process模塊,exce也提供了回調,所以,也能夠這樣子寫:

exec(command, (error, stdout, stderr) => {
    if (error) {
      console.log(error)
    } else {
      console.log(`${stderr}${stdout}`)
    }
  })
複製代碼

總結

關於taro-cli的實現:
咱們藉助nodejs,經過用戶輸入的命令和命令行與用戶的交互,來建立文件建立頁面項目診斷編譯更新等等。其中,由commanderinquire模塊來處理輸入參數。
taro-cli的亮點,是多了一個doctor的東西,按照以往的經驗,根據一個推薦化的配置來檢查項目,減小咱們的犯錯機會,這是十分值得稱讚的。這其中不少技術細節值得咱們去深刻挖掘~

下一篇預告: 【源碼解析】taro-cli(2) - build

相關文章
相關標籤/搜索