深入探究npm run的底层原理

起因

某一天,我正在很悠闲的喝着小茶,无所事事浏览着技术文章,忽然看到一篇文章成功的吸引了我的眼球------你真的了解npm run吗,看完之后打开了一扇新世界的大门。

我陷入了沉思之后,有那么一瞬间感觉到了不可思议。惯性思维下,我们已经习惯性的认为命令就是要通过npm run的方式进行执行,而没有进一步思考为什么是这样的。大多数可能跟我一样,第一反应是:难道不是因为在 package.json 中定义了各种的 script 命令,然后我们通过npm run xxx的方式进行执行吗?

揭开事情的迷雾,我们抱着打破沙锅问到底的心态来思考一下:

我们为什么要执行 npm run start 命令,而不是直接执行 react-scripts start 呢?

难道不是因为使用方便吗

这是我的第一反应,但是,实际上可能不是的。为了验证一下两者的区别,我立马跑去打开我的测试项目,分别使用了两种方式。意外的发现直接执行命令的方式竟然报错了,而通过npm run 的方式执行的时候一如既往的Ok。

为什么命令会不存在呢

报错信息很明显,直接执行命令的时候,系统报错:react-scripts 命令不存在。

这个时候我就感到有点不可思议了。

既然命令不存在,凭什么npm run就可以执行呢?

不知道大家在windows上安装node的时候,需要将node配置到系统环境变量里面去了,然后我们可以全局通过 node -v 来验证node是否安装成功和查询当前node版本信息。难道说 npm run 的玄机跟node配置过环境变量有关系吗?

抱着怀疑的态度,我在node文件夹中一通翻找(我是基于nvm进行node管理的,可能跟直接使用node的目录结构有所出入),终于找到了问题的关键信息:安装依赖的时候,会在这里创建几个命令文件。

经过几次反复的安装、删除依赖操作之后,终于确认了我的想法。每次我们通过 npm i xxx -g 安装某个依赖的时候,除了在node下的node_modules文件夹中安装对应的依赖包之外,还会在node下创建这个依赖的可执行文件(对应不同的环境,会有好几个不同的命令文件)。

这个时候,我忽然想起来了linux上的操作,在linux上安装全局依赖的时候,我们安装完依赖之后,还需要手动创建软连接。两相印证,事实的真相已经很明显了。

bash 复制代码
    ln -s /usr/local/src/nodejs/bin/node /usr/local/bin/node

    ln -s /usr/local/src/nodejs/bin/npm /usr/local/bin/npm

安装依赖的时候,会在bin目录下创建一个对应的可行性文件,这个其实就跟我们node文件夹下创建的这个npm文件夹的性质是一样的。

npm run 命令可执行总结

我们经过一番摸索终于弄清楚了,这里我们再一起来总结一下:

  1. 我们安装依赖的时候,在对应的文件夹下创建了对应的可行性命令;
  2. 我们执行npm run命令的时候会在当前目录中查找相关命令,如果找到的话,直接运行对应的命令;
  3. 如果没有找到的话,会到全局的node文件夹下查找相关的命令,如果找到的话,直接运行对应的命令;
  4. 如果依然没有找到的话,就会报错误信息了

为什么会创建多个可执行文件呢

前面我们说到了,创建的可执行文件是有多个。细心的你可能已经注意到其中的一个可执行文件xxx.cmd了,它的类型很明显已经告诉我们它是什么了 ------ Windows 命令脚本。大胆的猜测一下:另外几个分别对应的是不同环境的可执行命令,比方说:没有文件后缀的可执行文件,其实就是我们前面说到的在linux中安装的软链接的方式。

我们大致看一下其中一个cross-env.cmd的可执行命令的内容(假装可以看得懂)。

vbnet 复制代码
    @ECHO off
    SETLOCAL
    CALL :find_dp0

    IF EXIST "%dp0%\node.exe" (
      SET "_prog=%dp0%\node.exe"
    ) ELSE (
      SET "_prog=node"
      SET PATHEXT=%PATHEXT:;.JS;=;%
    )

    "%_prog%"  "%dp0%\node_modules\cross-env\src\bin\cross-env.js" %*
    ENDLOCAL
    EXIT /b %errorlevel%
    :find_dp0
    SET dp0=%~dp0
    EXIT /b

虽然看不懂,但是其中很重要的一个点我们其实还是可以猜出来的 "%_prog%" "%dp0%\node_modules\cross-env\src\bin\cross-env.js" %*将可执行命令 cross-env 指向对应的依赖的bin文件 bin\cross-env.js。

这里其实变相的给我们解释了另外一个问题。

为什么安装依赖可以创建可执行命令呢

在依赖的package.json中配置了bin属性,定义了可执行命令的名字和可执行命令的文件,当我们通过npm安装依赖的时候,npm就会根据声明的bin属性来创建对应的可执行文件。

json 复制代码
    "bin": {
        "cross-env": "src/bin/cross-env.js",
        "cross-env-shell": "src/bin/cross-env-shell.js"
    },

相信看到这里之后,大家应该心里已经很清楚npm run的底层原理了。

打完收功

好了,有关npm run的内容暂时就这么多了,希望对大家有所帮助。

欢迎大家在下方进行留言交流。

相关推荐
我命由我123458 小时前
CesiumJS 笔记 - 获取容器中心点、Cartesian3 clone 方法、修改 Cartesian3 对象的高度
前端·javascript·css·前端框架·html·html5·js
抱抱宝9 小时前
Agent-study项目教程(03):手写 Mini-ReAct Agent(不依赖框架)
javascript·人工智能·gpt·react.js·prompt·agent
用户938515635079 小时前
Next.js 笔记系统(二):Redis 数据服务与侧边栏组件拆分实战
javascript·全栈
Heo13 小时前
大厂前端调试不能只会debugger
前端·javascript·面试
Lyra_Infra13 小时前
OpenClaw 升级及 Channel 安装故障排查与遗留问题分析
后端·npm
windliang14 小时前
Claude Code 源码分析(十二):错误处理与自动恢复:让 Agent 稳定运行
前端·javascript·面试
默_笙14 小时前
🛬 前端路由的"高级玩法":懒加载、404、鉴权路由,一个都不能少(下篇)
前端·javascript
sunly_14 小时前
TypeScript:3、类型声明与类型推断
javascript·ubuntu·typescript
奥莱维16 小时前
【无标题】
java·前端·javascript
黄金决明子17 小时前
浏览器Window底层操作全解
前端·javascript