[Vue CLI 3] 源码系列之init

news/2024/6/17 22:48:50

用惯老版本 Vue CLI 的同学一般多会选择使用如下命令来创建模板项目:

vue init webpack demo

但是在新版中,推荐使用 vue create,官方也提到了:

因为使用了同样一个 vue 命令,所以之前的会被覆盖,如果还需要使用,需要自行安装:

npm install -g @vue/cli-init

我们先看一下,如果本地已经安装了最新版本的 Vue CLI,执行之前的 vue init 会出现什么?

命令行会提示你如下内容:

Command vue init requires a global addon to be installed.

Please run npm install -g @vue/cli-init and try again.

那它背后的设计是如何的呢?

1、首先还是 vue 的一个扩展命令:

我们还是找到 @vue/cli/bin/vue.js,我们发现如下代码:

之前我们也提到过,命令行最核心的基础包是:commander

const program = require('commander')

这里配置了 command、description、option 和 action

program

.command('init <template> <app-name>')

.description('generate a project from a remote template (legacy API, requires @vue/cli-init)')

.option('-c, --clone', 'Use git clone when fetching remote template')

.option('--offline', 'Use cached template')

.action(() => {

loadCommand('init', '@vue/cli-init')

})

然后调用了 loadCommand,传入了 2 个参数,我们看一下 @vue/cli/lib/util/loadCommand

文件对外暴露一个 loadCommand 函数,接受 2 个参数

module.exports = function loadCommand (commandName, moduleName) {

// ...

}

内部会通过 try catch 加载对应的第二个参数 moduleName,这里为 @vue/cli-init

try {
return require(moduleName);
}

这里因为我们本地没有,会报错进入 catch:

Error: Cannot find module '@vue/cli-init'

我们看一下 catch 的处理:

因为有 2 个地方会判断 err 所以复用了一个函数: isNotFoundError

const isNotFoundError = err => {
return err.message.match(/Cannot find module/)
}

注意这里有一个策略,在判断没有之后,会再次 try catch 到全局里面看

catch (err) {
if (isNotFoundError(err)) {
//...
} else {
throw err
}
}

代码实现如下,用来一个工具包:import-global

try {
return require('import-global')(moduleName)
}

如果再失败,就只能出提示了,就是上面一开始我们看到的:

这里用了工具包 chalk 来给文字做样式,同时还有一个有用的:

会判断你是否安装了yarn,如果有,就推荐你用它来全局安装 @vue/cli-init

判断函数来自我们之前 config 一直打交道的 @vue/cli-shared-utils

函数名 hasYarn

const { hasYarn } = require('@vue/cli-shared-utils')

我们看一下具体实现:源码在 @vue/cli-shared-utils/lib/env.js

外层有一个变量: _hasYarn

let _hasYarn

函数结构:

exports.hasYarn = () => {

}

会做几层判断:

先看这个 env 变量

if (process.env.VUE_CLI_TEST) {
return true
}

然后再看那个变量,有值就直接返回

if (_hasYarn != null) {
return _hasYarn
}

最核心的来了:

使用核心模块 child_process

const { execSync } = require('child_process')

执行 yarnpkg 命令

execSync('yarnpkg --version', { stdio: 'ignore' })

然后分别给变量赋值,有就是 true,否则是 false

------------------------------- 分割线 ----

我们参照建议,全局安装之后,我们查看 @vue/cli-init/index.js

代码一共这么多行:作者在 readme 也提示的很清晰

This is simply an alias to the old vue-cli@2.x.

核心是使用 execa 工具包,执行老版本的 vue-cli/bin/vue-init,传入了命令行上面的参数(这里没有用工具包)

const execa = require('execa')
const binPath = require.resolve('vue-cli/bin/vue-init')
execa(
binPath,
process.argv.slice(process.argv.indexOf('init') + 1),
{ stdio: 'inherit' }
)

我们看一下在命令行输入:vue init webpack demo 之后,process.argv 是什么?

[ '/usr/local/bin/node','/usr/local/bin/vue',
'init',
'webpack',
'demo' ]

process.argv.indexOf('init') + 1 返回的是:

3

process.argv.slice(3) 返回的是:

[ 'webpack', 'demo' ]

------ 分割线 -----

本文来自微信公众号:[前端新视野]的原创文章

http://www.niftyadmin.cn/n/4151238.html

相关文章

网络管理--IP地址规划

IP地址&#xff1a; 它们可唯一标识IP 网络中的每台设备 每台主机&#xff08;计算机、网络设备、外围设备&#xff09;必须具有唯一的地址 IP地址由两部分组成&#xff1a;    网络ID&#xff1a;     标识网络     每个网段分配一个网络ID    主机ID&#xff1a;…

jpa .save怎么返回int_C++的多个返回值

对于复杂的应用程序&#xff0c;具有不仅仅返回一个值的函数通常很方便。从C 使用结构到利用最新的C 11元组类模板&#xff0c;有很多不同的方法可以用C 实现。在很多情况下&#xff0c;返回对象的明显选择似乎有些过大。首先&#xff0c;您需要声明结构。很少有这种结构需要供…

C++语言学习(二十)——自定义内存管理

C语言学习&#xff08;二十&#xff09;——自定义内存管理 一、统计类对象中成员变量的访问次数 mutable是为了突破const函数的限制而设计的&#xff0c;mutable修饰的成员变量将永远处于可改变的状态。mutable成员变量破坏了只读对象的内部状态&#xff0c;而const成员函数保…

python 两个列表相互映射_自学python,必须要懂得四种数据结构,看完快速掌握...

01、数据结构是相互之间存在一种或多种特定关系的数据元素的集合今天要讲python的四个内置数据结构&#xff1a;分别是列表、元组、集合和字典&#xff0c;每种结构数据都有自己的特点&#xff0c;应用于不同情况1、(list)列表中的元素是有序的&#xff0c;元素内容可以修改。列…

mysql如何处理亿级数据的SQL 注意事项

2019独角兽企业重金招聘Python工程师标准>>> 1、应尽量避免在 where 子句中使用!或<>操作符&#xff0c;否则将引擎放弃使用索引而进行全表扫描。 2、对查询进行优化&#xff0c;应尽量避免全表扫描&#xff0c;首先应考虑在 where 及 order by 涉及的列上建立…

lua 如何获取当前星期的周六_lua学习前5章解惑

lua学习前5章解惑基础概念-l 参数-- a&#xff0c;b文件均需放到 lua.exe 所在的文件目录 -- a.lua 文件 x 5 -- b.lua 文件 print(x) -- 交互模式中输入 lua -la -lb -- 先运行 a.lua &#xff0c;再运行 b.lua -- 结果为 5表达式链表list nil local rows 1 list_next ni…

前端基础10:匿名函数

function 函数类型的作用&#xff1a;- 1.具有封装性&#xff08;防止冲突和覆盖&#xff09; - 2.减少冗余代码&#xff0c;把实现相同功能的代码都写在一个函数里&#xff0c;等下次需要实现这个功能时&#xff0c;只需要执行这个函数即可 复制代码 函数的定义:function 函数…

javascript 设计模式_开发人员都应该了解的 7 种 JavaScript 设计模式

开发人员将 JavaScript 设计模式作为解决问题的模板是很合适的&#xff0c;但并不是说这些模式可以代替开发人员的工作。通过设计模式&#xff0c;我们可以将许多开发人员的经验结合起来&#xff0c;以优化过的方式来构造代码&#xff0c;从而解决我们所面对的问题。设计模式还…