通过下列方式可以安装最新版本的 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

这个文件的函数只会执行一次:设置了变量 checkedresult

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 个映射关系,里面就有官方 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 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...

[Vue CLI 3] 源码系列之useTaobaoRegistry相关推荐

  1. [Vue CLI 3] 源码之 webpack-chain

    我们看一下 webpack-chain 到底做什么? Use a chaining API to generate and simplify the modification of Webpack v ...

  2. 源码解读_入口开始解读Vue源码系列(二)——new Vue 的故事

    作者:muwoo 转发链接:https://github.com/muwoo/blogs/blob/master/src/Vue/2.md 目录 入口开始解读Vue源码系列(一)--造物创世 入口开始 ...

  3. Vue源码系列 - 前言

    Vue源码系列 前言 - Why 离职前立了 flag,希望正式入职之后可以在组内进行一次 Vue 的源码分享.为了让小旗子不要那么容易就倒下,也希望自己能有所收获,努力来总结一些自己的心得. 参考资 ...

  4. 大白话Vue源码系列(01):万事开头难

    阅读目录 Vue 的源码目录结构 预备知识 先捡软的捏 Angular 是 Google 亲儿子,React 是 Facebook 小正太,那咱为啥偏偏选择了 Vue 下手,一句话,Vue 是咱见过的 ...

  5. 简单介绍Vue之vue.$set()方法源码案例

    这篇文章主要介绍了Vue之vue.$set()方法源码案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下 在使用vue开发项目的过程中,经常会遇到这样 ...

  6. SpringMVC源码系列:HandlerMapping

    SpringMVC源码系列:HandlerMapping SpringMVC源码系列:AbstractHandlerMapping HandlerMapping接口是用来查找Handler的.在Spr ...

  7. 美工一流的个人网站源码系列(2),不漂亮你可以不下载!

    美工一流的个人网站源码系列(2),不漂亮你可以不下载! 后台用户名和密码都是admin 下载地址: [url]http://down.599cn.com/599cndown/aspdown/soft2 ...

  8. c++ map 获取key列表_好未来Golang源码系列一:Map实现原理分析

    分享老师:学而思网校 郭雨田 一.map的结构与设计原理 golang中map是一个kv对集合.底层使用hash table,用链表来解决冲突 ,出现冲突时,不是每一个key都申请一个结构通过链表串起 ...

  9. Spring源码系列:依赖注入(二)createBean

    在Spring源码系列:依赖注入(一)(AbstractBeanFactory-getBean)最后说道getBean是依赖注入的起点,bean的创建都是通过createBean来完成具体的创建的.c ...

最新文章

  1. 页面切换语言包使用session不用cookie
  2. java执行jar中的main_浅谈java 执行jar包中的main方法
  3. 项目管理 - 学习总目录
  4. xcode10 自定义代码块
  5. 帮你少写一大半参数校验代码的小技巧
  6. MySQL去重保留最大的那条记录(取最新的记录)
  7. 你觉得一个人有几个手机号合适?
  8. 微软员工揭秘 Windows 的 Linux 子系统研发全过程
  9. Objective-C内存管理
  10. python 操作进程_python进程简单操作
  11. Modbus转Profinet网关与ARX-MA100微型空气质量监测系统配置案例
  12. 5--残差网络(ResNet)
  13. apache如何支持php,apache支持php吗
  14. Linux添加WIFI驱动
  15. 倍福TwinCAT3伺服控制常用功能块的实现
  16. Java计算器编程代码
  17. Flash设置(各种版本浏览器包括低版本IE)
  18. c语言怎样把除法转为乘法,怎样代替除法指令
  19. 视频教程-大牛带你全面剖析Python高频面试真题-Python
  20. 计算机蓝屏代码0x000000ED,蓝屏代码0x000000ed的4大解决方法详解!蓝屏0x000000ed的原因和解决方法!...

热门文章

  1. python语言打印菱形_Python打印菱形
  2. Qt之程序发布以及打包成exe安装包
  3. Kalman Filter
  4. Tools: geos 使用指南
  5. python numpy中sum()时出现负值
  6. 自定义能够for each的类,C#,Java,C++,C++/cli的实现方法
  7. oracle exacc,【学习笔记】Oracle 11GR2新特性Adaptive Cursor Sharing(ACS)
  8. 支持java虚拟主机_为何缺乏支持Java的虚拟主机
  9. linux内核结构介绍
  10. 全国计算机等级考试题库二级C操作题100套(第27套)