事情是这样的,直接说面试官:npmrunxxx的时候发生了什么?越详细越好。我(心想,很简单):先是DNS解析,把域名解析成IP地址,然后是TCP连接,TCP三次握手...面试官:打住,我不是问从URL输入到页面会发生什么显示?,npmrunxxx时发生了什么。我(不好意思,条件反射地以为是八卦文):emmmm,我记得npmrunxxx的时候,会先去项目的package.json文件中找到scripts中对应的xxx,然后执行xxx的命令,例如在启动vue项目npmrunserve时,实际执行的是命令vue-cli-serviceserve。(很危险,幸好这个常识我还是懂的)。"package.json文件"{"name":"h5","version":"1.0.7","private":true,"scripts":{"serve":"vue-cli-serviceserve"},}面试官:嗯,是的,那为什么不直接执行vue-cli-serviceserve而是执行npmrunserve呢?我(犹豫):嗯,因为npmrunserve更短,也更容易写。面试官:再想想。我(啊?不是吗?是啊,我想起来了):因为如果直接执行vue-cli-serviceserve会报错,因为操作系统中没有命令vue-cli-service。采访者:哦,是的,是的,是的,是的,是的,是的!我(嘿嘿,稳了,这次要30k):嘻嘻!面试官:既然vue-cli-service命令在系统中没有运行,为什么执行npmrunserve就相当于执行了vue-cli-serviceserve?为什么这样就成功了,而且不报命令不存在的错误呢?我(啊?还是你还是把我当鲨鱼,我不想勉强自己回答):抱歉,这个我还没看懂。面试官:emmm,ok,没关系,我们做下一道算法题:.....这篇文章的内容与本文内容无关,就省略了。面试官:好的,面试到此结束,我们将在一周内回复您面试结果。哔哔哔……(电话挂断)。出色地。好像很冷。为什么执行npmrunserve就可以成功而不报命令不存在的错误呢?我连忙问朋友这个过程发生了什么?经过一番讨论,终于找到了答案。不服输的我赶紧拨回了面试官的电话。我:面试官你好,我已经找到答案了,麻烦你再听一遍好吗?面试官:嗯,是的,请告诉我。我:我们安装依赖的时候,是通过npmixxx来执行的,比如npmi@vue/cli-service,npm安装这个依赖的时候,会在node_modules/.bin/目录下创建vue-cli-servicenamed几个可执行文件。.bin目录,这个目录不是任何npm包。目录中的文件表明这是一个软链接。打开文件,可以看到文件最前面写着#!/bin/sh,说明这是一个脚本。由此可知,在使用npmrunserve执行vue-cli-serviceserve时,虽然没有安装vue-cli-service的全局命令,但npm会在./node_modules/中找到vue-cli-service文件。bin作为脚本执行,相当于执行./node_modules/.bin/vue-cli-serviceserve(最后一个serve作为参数传入)。面试官:是的,确实不错,但是我还是想继续问,你说.bin目录下的文件代表软链接,那么bin目录下的软链接文件是从哪里来的呢?它怎么知道的?这个软链接是在哪里执行的?我(我很高兴,我们刚刚讨论过这个):我们可以在新建的vue项目中直接搜索vue-cli-service,可以看到它存在于项目的最外层“package-lock.json”文件。从package-lock.json可以看出,当我们npmi整个新建的vue项目时,npm将bin/vue-cli-service.js声明为bin。所以npminstall时,npm读取配置后,软链接文件到./node_modules/.bin目录下,npm会自动将node_modules/.bin添加到$PATH中,这样就可以直接作为命令运行了依赖程序和开发依赖程序不需要全局安装。如果我们使用npminstall-gxxx来安装包,那么bin文件会被添加到全局,比如create-react-app和vue-cli,全局安装之后,可以直接使用比如vue-cliprojectName命令创建一个项目。面试官:搜索Karma,就是说npmi的时候,npm会帮我们配置这种软连接。其实这种软连接就相当于一个映射。当npmrunxxx执行时,会去node_modules/bin中找到对应的映射文件,然后再找到对应的js文件执行。我(狂点头):嗯嗯,对,就是这样。面试官:我有点好奇。刚看到在node_modules/bin下有3个vue-cli-service文件。为什么是三个文件?我:如果我们在cmd中运行,windows一般会调用vue-cli-service.cmd。这个文件是windows下的批处理脚本:@ECHOoffGOTOstart:find_dp0SETdp0=%~dp0EXIT/b:startSETLOCALCALL:find_dp0IFEXIST"%dp0%\node.exe"(SET"_prog=%dp0%\node.exe")ELSE(SET"_prog=node"SETPATHEXT=%PATHEXT:;.JS;=;%)endLocal&goto#_undefined_#2>NUL||title%COMSPEC%&"%_prog%""%dp0%\..\@vue\cli-service\bin\vue-cli-service.js"%*所以当我们运行vue-cli-serviceserve命令时,它相当于运行node_modules/.bin/vue-cli-service.cmd服务。然后这个脚本会使用node来运行js文件vue-cli-service.js。由于在node中可以使用一系列系统相关的API,所以很多事情都可以在这个js中完成,比如读取分析这个命令运行目录下的文件,根据模板生成文件等。#Unix是默认的可执行文件,必须输入完整的文件名vue-cli-service#windowscmd中默认的可执行文件,当我们不加后缀时,会自动根据pathext搜索文件vue-cli-service.cmd#WindowsPowerShell中的可执行文件可以跨平台vue-cli-service.ps1面试官:原来如此,还不错啊小伙子,短时间就掌握了。看来学习能力很强,不错,很看好你,会尽快催hr回复你。暂时就这些,再见。我(欣喜若狂,功夫不负有心人):行行,再见。哔哔哔……(电话挂断)。三十分钟过去了……今天是个好日子,心想事成,今天是个好日子,开门迎春风吧……(电话响)。我:你好你好。hr:您好,我是xxx公司的hr。根据你在面试中的出色表现,恭喜你获得我公司的offer。经过我最大的努力,我为你赢得了最大的薪水。工资是3500一个月。看到满意了吗?我:……哔哔哔……(挂断电话)。总结运行npmrunxxx时,npm会先在当前目录下的node_modules/.bin中搜索要执行的程序,如果找到就运行;如果没有找到,会从全局的node_modules/.bin中搜索,npmi-gxxx是安装到全局目录下;如果还是找不到全局目录,则从path环境变量中寻找其他同名的可执行程序。参考文章https://blog.51cto.com/u_15077533/4531157https://juejin.cn/post/6971723285138505765
