我正在参加「掘金·启航计划」
背景
最近在从0到1写一个脚手架,如果只是按照教程实现一下,那也很简单,花不了多少时间。而真正费时间的是弄懂背后的原理,原理很重要,如果我们不弄懂,那么知识就会很零散,很容易忘记。我们总不能在脑子里装一大堆的使用方法吧,你说呢
前置知识
环境变量的作用
你可能有个疑问,我们在Shell命令行中输入一个命令,Shell是如何知道去哪找到这个命令所对应的执行文件,然后去执行它?
这通常是通过环境变量PATH来进行搜索的,熟悉window的同学可能知道有这么一个叫PATH的环境变量。这个环境变量保存了Shell中执行的命令所对应的可执行文件的路径。
那环境变量存放在哪里呢? 我们可以通过echo $PATH
来查看:
可以看到环境变量PATH有好几个路径,当我们在终端输入一个命令的时候,电脑就会依次按照PATH中设定的路径来到目录中查找,如果存在同名的环境变量,则执行先找到的那个。
接下来我们进入到比较熟悉的
/usr/local/bin
然后在命令行输入ll
命令
这里面的文件都是一些链接问答那个,他们链接到真正执行的文件。
如何添加环境变量
现在你安装了mongodb的文件,在/usr/local/mongodb/bin
路径下,一般你需要进入到这个路径才能启动mongodb,但是每次都要进入到这个文件太麻烦了,我能不能在任何地方输入mongodb都能启动程序呢?
通过设置环境变量即可完成,也就是把/usr/local/mongodb/bin
路径添加到PATH上就行了,当你在命令行输入mongodb时,操作系统会从PATH上找到对应的路径,然后执行可执行文件。
vi .bash_profile
// 输入:
export PATH=$PATH://usr/local/mongodb/bin ($PATH代表已经存在的路径,它可以放前面或者后面)
// 立即生效
source .bash_profile
【注意】vi .bash_profile
表示在用户主目录下设置,针对当前特定的用户起作用的环境变量。你也可以设置系统目录下的profile
文件,那么将会对所有用户都生效。
bin文件夹介绍
在文章中我们会多次提到一个文件名bin
,bin
文件夹是用来干什么的呢
bin是单词binary的缩写 是二进制的意思
由于一些约定俗成的原因我们一般都将可执行文件放到 bin 目录中.
npm install 的时候发生了什么?
npm install
后会根据package.json
中配置的需要下载的依赖,或者命令后面的参数把包下载到本地,但是肯定不止下载包这么简单。如果你下载的包的package.json
中,有bin
属性的话,那么会把库目录中bin
文件里面的内容,放到node_modules/.bin
中。
举个例子
比如我使用npm install
下载lerna
包后
然后我们在.bin
目录中使用ls -al
查看lerna.js软连接对应的真实链接
会看到指向真实的node_module包的lerna/cli.js
文件
npm install
的时候,npm
就帮我们把这种软连接配置好了,其实这种软连接相当于一种映射,执行npm run xxx
的时候,就会到 node_modules/bin
中找对应的映射文件,然后再找到相应的js
文件来执行。
为什么会把库目录中bin
文件里面的内容,放到node_modules/.bin
中?
因为node_modules/.bin
中的js文件就像快捷方式,你执行快捷方式,就会访问库中的bin
目录下的文件
为什么直接执行js文件不能执行?
因为$PATH
中没有你这个命令呀,你在命令行输入的东西,他都会把你当成一个命令
我们在桌面上创建一个test.js文件,如何通过命令执行他
如果要想直接执行js
文件
- 第一: 需要映射软连接
首先我们输入一个echo $PATH
命令找到bin目录,只要在bin
目录下创建一个软连接指向我们创建的js
文件,那么我们执行命令,就是在执行这个js文件
- 第二: 需要在文件头部加上
#!/usr/bin/env node
这句话的意思就是直接去环境变量中找node
命令
所以/usr/bin/env node test.js
=== node test.js
npm install -g的时候发生了什么?
和npm install
差不多, 只是会在全局的node_module
文件的bin
目录下创建软连接,软连接指向库中的实际文件。并注册到全局的$PATH
中
而我们在npm install -g
的时候,其实是将相关文件安装在/usr/local/lib/node_modules
目录下,同时,在/usr/local/bin
目录下会有一个映射脚本,将其指向/usr/local/lib/node_modules
下的真实文件。
/usr/local/bin
目录
/usr/local/lib/node_modules
目录
什么时候使用npm install,什么时候使用npm install -g呢?
- 如果需要在命令行执行任务的时候就需要全局安装
我们在命令行执行命令的时候,都是通过环境变量查找的,所以只有全局安装才会放到环境变量中,如果只是在本地安装,执行全局命令会报错的,因为找不到, 比如webpack包,如果你没有全局安装,那么你想执行本地包的话,那么只能node ./node_modules/webpack/bin/index.js
- 如果需要require的时候就需要在本地安装
require
加载npm
包的时候,只会在本地node_module
里面去找,如果没有就会报错,所以就算你全局有安装,本地没有安装,也会报错的, 关于require的加载原理,大家可以看我的另一篇文章require源码(小白级教程)
npm run xxx 的时候发生了什么
经过上面的学习我们就很好懂了
{
// ...
"scripts": {
"start": "node ./src/index.js",
"build": "react-scripts build",
},
// ...
}
当我们执行
npm run build
的时候
- 首先执行
package.json
中的script
中的build
命令 - 然后开始执行
react-scripts
命令 - 此时在环境变量
$PATH
中查找是否存在react-scripts
命令,如果存在则返回实际链接文件,如果不存在则查找本地node_modules/bin
中是否存在react-script.js
文件, 如果都不存在则返回not found
- 如果在全局找到的,那么会指向全局安装的
node_modules
中库的实际执行文件,如果是在本地node_modules/bin
中找到链接,那么会在本地node_modules
中库的实际执行文件 - 通过
/usr/bin/env node
执行文件
使用npm run xxx的好处是什么?
"scripts": {
"start": "webpack -v"
},
因为好多包我们全局并没有安装,就算是下载别人的项目,我们也是安装到本地node_modules
中,而不是全局,所以npm run xxx
可以让我们执行本地包的命令
npm link的时候发生了什么
我们在自己写脚手架的时候会常常用到npm link
作用
用于设置软连接,自己进行测试
为什么可以
npm link
可以帮助我们模拟包安装后的状态,它会在系统中做一个快捷方式映射,让本地的包就好像install
过一样,可以直接使用。
在MAC中,我们在终端可以直接敲命令,其实是在执行/usr/local/bin
目录下的脚本,这个目录可以认为是我们的全局命令所在的地方。
而npm link
做的事也差不多,只不过它在/usr/local/lib/node_modules
里存的不是真实的文件,而是存了一个快捷方式,指向你当前执行npm link
的目录。如果开发的是node包,则执行的命令名和真实执行的文件入口,会通过项目的package.json
里bin
的配置来获取。