[Vue CLI 3] 源碼系列之useTaobaoRegistry

經過下列方式能夠安裝最新版本的 Vue CLI(註釋:sudo 自行選擇)javascript

sudo npm install -g @vue/cli

而後經過下列命令建立項目:前端

vue create demo

這時候,會詢問你是否使用 taobao 的 registryvue

Your connection to the default npm registry seems to be slow.

Use https://registry.npm.taobao.org for faster installation?

而後選擇 Yes 後,發如今用戶的根目錄中出現了一個 .vuerc文件,內容以下:java

{

  "useTaobaoRegistry": true
}

本文從源碼設計角度看一下背後的實現:vue-cli

在新版本 Vue CLI 中目錄結構變更了,咱們找到了以下幾個文件:npm

@vue/cli/lib/util/shouldUseTaobao.jsjson

這個文件的函數只會執行一次:設置了變量 checkedresultpromise

let checked
let result

在函數內部一上來就會判斷微信

if (checked) return result

第一步:須要在命令行以詢問方式:async

通常多會採用 inquirer 這個工具包,先加載:

const inquirer = require('inquirer')

而後調用 prompt 方法,注意這裏設置了 type confirm 的方式

而後用 chalk 這個工具包來在命令行改變字顏色

const chalk = require('chalk')

最核心的代碼片斷以下:

定義了 name、type 和 message 字段:

const { useTaobaoRegistry } = await inquirer.prompt([

    {

      name: 'useTaobaoRegistry',

      type: 'confirm',

      message: chalk.yellow(

        ` Your connection to the default npm registry seems to be slow.\n` +

          `   Use ${chalk.cyan(registries.taobao)} for faster installation?`

      )

    }

  ])

第二步:判斷 register 的速度

定義一個變量 faster

let faster

這裏使用了 Promise.race 函數(返回一個 promise,一旦迭代器中的某個promise 解決或拒絕,返回的 promise就會解決或拒絕。)

try {

    faster = await Promise.race([

      ping(defaultRegistry),

      ping(registries.taobao)

    ])

  } catch (e) {}

這裏的變量就是:

const registries = require('./registries')

如上,來自一個同級的 registries.js 文件

const defaultRegistry = registries.npm

registries 在 @vue/cli/lib/util/registries.js

源碼內容以下:維護了 3 個映射關係,裏面就有官方 registrytaobao

const registries = {

  npm: 'https://registry.npmjs.org',

  yarn: 'https://registry.yarnpkg.com',

taobao: 'https://registry.npm.taobao.org'

}

module.exports = registries

咱們看一下最核心的 ping 函數:

使用了 @vue/cli-shared-utilsrequest 方法

async function ping (registry) {

  await request.get(`${registry}/vue-cli-version-marker/latest`)

  return registry

}

@vue/cli-shared-utils/lib/request.js 看一下源碼:

對外暴露了 get 方法,內部依賴 request-promise-native 工具包(uses native ES6 promises),傳入了一個對象:

  • method 方法爲 'GET'
  • resolveWithFullResponse
  • json
  • uri 請求地址

核心代碼以下:

exports.request = {

  get (uri) {

    // lazy require

    const request = require('request-promise-native')

    const reqOpts = {

      method: 'GET',

      resolveWithFullResponse: true,

      json: true,

      uri

    }



    return request(reqOpts)

  }

}

第三步:寫入一個 .vuerc 文件

定義了 save 函數,代碼實現以下:

const save = val => {

    result = val

    saveOptions({ useTaobaoRegistry: val })

    return val

  }

saveOptions 在 @vue/cli/lib/options.js 中定義:

exports.saveOptions = toSave => {

  // 實如今下面

}

在裏面定義了一個 defaults 的對象,裏面默認設置了 useTaobaoRegistry 爲 undefined:

exports.defaults = {

  useTaobaoRegistry: undefined

}

核心是採用了 fs.writeFileSync 往指定目錄寫文件:

註釋:關於寫入路徑能夠看一下 rcPath.js 文件提供的 getRcPath

const rcPath = exports.rcPath = getRcPath('.vuerc')

注意:下面的 JSON.stringify 的第三個參數,也是經過 try catch 的方式:

fs.writeFileSync(rcPath, JSON.stringify(options, null, 2))

那若是用戶本地已經設置了呢,先獲取本地的設置:

核心是使用了 execa 這個工具包:

const execa = require('execa')

定義了一個參數 userCurrent ,傳入了命令和參數:

(await execa(`npm`, ['config', 'get', 'registry'])).stdout

比較兩個路徑:

if (removeSlash(userCurrent) !== removeSlash(defaultRegistry)) {

    // user has configured custom regsitry, respect that

    return save(false)

}

removeSlash 的實現以下:

function removeSlash (url) {

  return url.replace(/\/$/, '')

}

第三個問題:用戶第一次設置以後,後面的建立項目操做是如何處理的呢?

在 @vue/cli/lib/util/shouldUseTaobao.js 內部,會調用 loadOptions 函數(下面會提到)

const saved = loadOptions().useTaobaoRegistry

@vue/cli/lib/options.js

會定義一個變量:

let cachedOptions

對外暴露了 loadOptions 函數:

exports.loadOptions = () => {

}

在 loadOptions 函數內部:

第一步:會先看 cachedOptions 是否有值:

if (cachedOptions) {

    return cachedOptions

}

而後會讀取配置文件內容:經過 fs.readFileSync 方法,而後用 JSON.parse 轉成對象

// 判斷配置文件是否存在

if (fs.existsSync(rcPath)) {}

內部使用 try catch,給 cacheOptions 賦值

JSON.parse(fs.readFileSync(rcPath, 'utf-8'));

因此第二次這裏由於 .vuerc 文件已經寫入了內容,因此第一步就返回了

本文原創來自微信公衆號:前端新視野

擴展連接:

https://developer.mozilla.org...

https://www.npmjs.com/package...

相關文章
相關標籤/搜索