通過下列方式可以安裝最新版本的 Vue CLI(注釋:sudo 自行選擇)
sudo npm install -g @vue/cli
然后通過下列命令創建項目:
vue create demo
這時候,會詢問你是否使用 taobao 的 registry
Your connection to the default npm registry seems to be slow.Use https://registry.npm.taobao.org for faster installation?
然后選擇 Yes 后,發現在用戶的根目錄中出現了一個 .vuerc
文件,內容如下:
{"useTaobaoRegistry": true
}
本文從源碼設計角度看一下背后的實現:
在新版本 Vue CLI 中目錄結構變動了,我們找到了如下幾個文件:
@vue/cli/lib/util/shouldUseTaobao.js
這個文件的函數只會執行一次
:設置了變量 checked
、result
let checked
let result
在函數內部一上來就會判斷
if (checked) return result
第一步:需要在命令行以詢問方式:
一般多會采用 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 個映射關系,里面就有官方 registry
和 taobao
的
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-utils
的 request
方法
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 requireconst request = require('request-promise-native')const reqOpts = {method: 'GET',resolveWithFullResponse: true,json: true,uri}return request(reqOpts)}}
第三步:寫入一個 .vuerc 文件
定義了 save 函數,代碼實現如下:
const save = val => {result = valsaveOptions({ 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 thatreturn 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...