npm run dev做了什么
执行后,会去找package.json中定义的内容:
也就是执行vue-cli-service脚本的内容。所有执行的脚本都在/mode-modules/.bin文件夹内,位置如下:
这个脚本的内容是什么呢?如下:
js
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../@vue/cli-service/bin/vue-cli-service.js" "$@"
ret=$?
else
node "$basedir/../@vue/cli-service/bin/vue-cli-service.js" "$@"
ret=$?
fi
exit $ret
这个脚本的意思是什么,一下是豆包的逐行解释:
js
以下是对该脚本逐行的详细分析:
### 1. `#!/bin/sh`
这是脚本的 shebang 行,它告诉系统使用 `/bin/sh` 这个 shell 解释器来执行该脚本。`/bin/sh` 通常是系统默认的 shell 解释器,不同的系统可能有所不同,但一般会指向一个兼容 POSIX 标准的 shell。
### 2. `basedir=$(dirname "$(echo "$0" | sed -e 's,,/,g')")`
- `$0`:在 shell 脚本中,`$0` 表示当前脚本的名称,包含完整的路径。
- `echo "$0"`:将 `$0` 的值输出。
- `sed -e 's,,/,g'`:`sed` 是一个流编辑器,`-e` 选项用于指定要执行的脚本命令。`s,,/,g` 是一个替换命令,将输入中的所有反斜杠 `` 替换为正斜杠 `/`。这一步主要是为了处理 Windows 路径中的反斜杠,使其符合 Unix 风格的路径格式。
- `dirname ...`:`dirname` 命令用于获取文件路径中的目录部分。
- 整行的作用是获取当前脚本所在的目录,并将其赋值给变量 `basedir`。
### 3. `case `uname` in`
- `uname`:这是一个用于获取操作系统名称的命令。执行 `uname` 会返回当前操作系统的内核名称,例如在 Linux 系统上返回 `Linux`,在 macOS 上返回 `Darwin`,在 Windows 的 Cygwin、MinGW 或 MSYS 环境中会返回包含 `CYGWIN`、`MINGW` 或 `MSYS` 的字符串。
- `case ... in`:这是 shell 中的条件判断语句,用于根据 `uname` 的输出结果进行不同的处理。
### 4. `*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;`
- `*CYGWIN*|*MINGW*|*MSYS*`:这是 `case` 语句的匹配模式,表示如果 `uname` 的输出包含 `CYGWIN`、`MINGW` 或 `MSYS`,则执行后面的命令。
- `cygpath -w "$basedir"`:`cygpath` 是 Cygwin 环境中的一个工具,用于在 Unix 风格路径和 Windows 风格路径之间进行转换。`-w` 选项表示将 Unix 风格的路径转换为 Windows 风格的路径。
- `;;`:表示该匹配模式的处理结束。
### 5. `if [ -x "$basedir/node" ]; then`
- `[ -x ... ]`:这是 shell 中的条件测试语句,`-x` 选项用于检查文件是否存在且具有可执行权限。
- 整行的作用是检查 `$basedir` 目录下是否存在名为 `node` 的可执行文件。
### 6. `"$basedir/node" "$basedir/../@vue/cli-service/bin/vue-cli-service.js" "$@"`
- 如果 `$basedir` 目录下存在可执行的 `node` 文件,则使用该 `node` 解释器来执行 `$basedir/../@vue/cli-service/bin/vue-cli-service.js` 脚本。
- `"$@"`:表示将脚本接收到的所有参数原封不动地传递给 `vue-cli-service.js` 脚本。
### 7. `ret=$?`
- `$?`:在 shell 中,`$?` 表示上一个命令的退出状态码。退出状态码为 0 通常表示命令执行成功,非 0 表示执行失败。
- 这行代码将 `node` 执行 `vue-cli-service.js` 脚本后的退出状态码赋值给变量 `ret`。
### 8. `else`
- 当 `$basedir` 目录下不存在可执行的 `node` 文件时,执行 `else` 后面的代码块。
### 9. `node "$basedir/../@vue/cli-service/bin/vue-cli-service.js" "$@"`
- 使用系统默认的 `node` 解释器来执行 `$basedir/../@vue/cli-service/bin/vue-cli-service.js` 脚本,并将脚本接收到的所有参数传递给它。
### 10. `ret=$?`
- 同样,将系统默认 `node` 执行 `vue-cli-service.js` 脚本后的退出状态码赋值给变量 `ret`。
### 11. `exit $ret`
- `exit` 命令用于终止当前脚本的执行,并返回指定的退出状态码。这里将之前保存的退出状态码 `ret` 作为脚本的退出状态码返回,这样调用该脚本的程序可以根据这个状态码判断脚本是否执行成功。
### 总结
这个脚本的主要功能是执行 `@vue/cli-service/bin/vue-cli-service.js` 脚本。它会优先使用 `$basedir` 目录下的 `node` 解释器,如果该解释器不存在,则使用系统默认的 `node` 解释器。同时,脚本还会处理 Windows 环境下的路径格式问题。
看完上述解释,我们会发现,第8行到第12行的内容是:如果文件夹下有node解释器就用,否则用系统默认的 node
解释器。我的文件夹里是没有node解释器的,这里不做截图解释。
那么,系统默认的 node
解释器在哪里呢? 我本地用nvm管理node版本,本项目适用v14版本。所以我的地址在/用户/xxx/.nvm/versions/node/v14.x.x/bin/node解释器。
脚本最终执行的是@vue里的vue-cli-service.js文件,文件路径如下: @vue/cli-service/bin/vue-cli-service.js的文件内容如下:
js
#!/usr/bin/env node
const semver = require('semver')
const { error } = require('@vue/cli-shared-utils')
const requiredVersion = require('../package.json').engines.node
if (!semver.satisfies(process.version, requiredVersion)) {
error(
`You are using Node ${process.version}, but vue-cli-service ` +
`requires Node ${requiredVersion}.
Please upgrade your Node version.`
)
process.exit(1)
}
const Service = require('../lib/Service')
const service = new Service(process.env.VUE_CLI_CONTEXT || process.cwd())
const rawArgv = process.argv.slice(2)
const args = require('minimist')(rawArgv, {
boolean: [
// build
'modern',
'report',
'report-json',
'watch',
// serve
'open',
'copy',
'https',
// inspect
'verbose'
]
})
const command = args._[0]
service.run(command, args, rawArgv).catch(err => {
error(err)
process.exit(1)
})
文件分析结束。
万恶之源,为啥看这个?
主要分享本次解决bug的思路历程,bug本身是没有技术含量的。
我clone了一个项目,install的时候一直报错,所以直接拿了node-modules包过来,run dev还是失败了,报错是sh: vue-cli-service: command not found。
熟悉的sh报错,意思是脚本没执行成,vue-cli-service找不到。但是我在.bin目录里确实找到了这个脚本,所以怀疑是环境PATH没对上。这个时候我们可以cmd里输出环境PATH,或者用户文件夹里找.profile相关的文件,看有没有本项目的.bin地址。
但是我偷懒了,直接打开了cmd报错的最后一行:找到记录失败信息的log,然后让AI分析它。bug.log内容如下(懒得看可以跳过,直接看下面的AI分析):
js
0 info it worked if it ends with ok
1 verbose cli [
1 verbose cli '/Users/张三/.nvm/versions/node/v14.18.3/bin/node',
1 verbose cli '/Users/张三/.nvm/versions/node/v14.18.3/bin/npm',
1 verbose cli 'run',
1 verbose cli 'dev'
1 verbose cli ]
2 info using [email protected]
3 info using [email protected]
4 verbose run-script [ 'predev', 'dev', 'postdev' ]
5 info lifecycle [email protected]~predev: [email protected]
6 info lifecycle [email protected]~dev: [email protected]
7 verbose lifecycle [email protected]~dev: unsafe-perm in lifecycle true
8 verbose lifecycle [email protected]~dev:
PATH:
/Users/张三/.nvm/versions/node/v14.18.3/lib/node_modules/npm/node_modules/npm-lifecycle/node-gyp-bin:
/Users/张三/Desktop/我的项目包裹/myProjectName/node_modules/.bin:
/Users/张三/.nvm/versions/node/v14.18.3/bin:
/Users/张三/.volta/bin:
/usr/local/bin:
/usr/local/sbin:
/Library/Frameworks/Python.framework/Versions/3.11/bin:
/Users/张三/.volta/bin:
/usr/local/bin:
/usr/local/sbin:
~/bin:
/usr/local/bin:
/usr/bin:
/bin:
/usr/sbin:
/sbin
9 verbose lifecycle [email protected]~dev: CWD: /Users/张三/Desktop/我的项目包裹/myProjectName
10 silly lifecycle [email protected]~dev: Args: [ '-c', 'vue-cli-service serve' ]
11 info lifecycle [email protected]~dev: Failed to exec dev script
12 verbose stack Error: [email protected] dev: `vue-cli-service serve`
12 verbose stack spawn ENOENT
12 verbose stack at ChildProcess.<anonymous> (/Users/张三/.nvm/versions/node/v14.18.3/lib/node_modules/npm/node_modules/npm-lifecycle/lib/spawn.js:48:18)
12 verbose stack at ChildProcess.emit (events.js:400:28)
12 verbose stack at maybeClose (internal/child_process.js:1058:16)
12 verbose stack at Process.ChildProcess._handle.onexit (internal/child_process.js:293:5)
13 verbose pkgid [email protected]
14 verbose cwd /Users/张三/Desktop/我的项目包裹/myProjectName
15 verbose Darwin 21.6.0
16 verbose argv "/Users/张三/.nvm/versions/node/v14.18.3/bin/node" "/Users/张三/.nvm/versions/node/v14.18.3/bin/npm" "run" "dev"
17 verbose node v14.18.3
18 verbose npm v6.14.15
19 error code ELIFECYCLE
20 error syscall spawn
21 error file sh
22 error errno ENOENT
23 error [email protected] dev: `vue-cli-service serve`
23 error spawn ENOENT
24 error Failed at the [email protected] dev script.
24 error This is probably not a problem with npm. There is likely additional logging output above.
25 verbose exit [ 1, true ]
这里推荐一个Vscode免费AI插件Copilot,直接编译器内搜名字安装就行。
AI Copilot分析如下:(懒得看AI分析也可以,直接看下面的综述)
js
这个日志文件显示了在运行 npm run dev 命令时发生的错误。以下是逐行分析:
1). 1 verbose cli 'run', 'dev' 表示运行了 npm run dev 命令。
2). 2 info using [email protected] 和 3 info using [email protected] 表示使用的 npm 和 Node.js 版本。
3). 4 verbose run-script [ 'predev', 'dev', 'postdev' ] 表示将依次运行 predev、dev 和 postdev 脚本。
4). 5 info lifecycle [email protected]~predev: [email protected] 和 6 info lifecycle [email protected]~dev: [email protected] 表示进入了 predev 和 dev 生命周期钩子。
5). 7 verbose lifecycle [email protected]~dev: unsafe-perm in lifecycle true 表示在生命周期中使用了 unsafe-perm 选项。
6). 8 verbose lifecycle [email protected]~dev: PATH: ... 表示当前的 PATH 环境变量。
7). 9 verbose lifecycle [email protected]~dev: CWD: /Users/xiehuimin/Desktop/改需求项目/changqing-vue 表示当前工作目录。
8). 10 silly lifecycle [email protected]~dev: Args: [ '-c', 'vue-cli-service serve' ] 表示运行 vue-cli-service serve 命令。
9). 11 info lifecycle [email protected]~dev: Failed to exec dev script 表示执行 dev 脚本失败。
10). 12 verbose stack Error: [email protected] dev: vue-cli-service serve 和 12 verbose stack spawn ENOENT 表示发生了 ENOENT 错误,意味着找不到 vue-cli-service 命令。
总结:问题的根本原因是 vue-cli-service 命令未找到。可能的解决方案包括:
1). 确认 vue-cli-service 是否已安装在项目的 node_modules 中。
2). 确认 .bin 是否在 PATH 环境变量中。
3). 重新安装依赖:运行 npm install 或 yarn install。
综上所述,造成vue-cli-service 命令未找到的原因可能有3个,我们逐个解决。
-
确认 vue-cli-service 是否已安装在项目的 node_modules 中。
我们可以在文件夹中手动找到这个文件夹,肉眼能看到它。
-
确认 .bin 是否在 PATH 环境变量中。
其实log文件中已经写了PATH内容了,但我们还是可以cmd里echo $PATH看看输出内容,或者根据你使用的 shell,不同的配置文件可能是 ~/.bashrc, ~/.zshrc, ~/.profile 等找到环境配置文件直接看PATH定义。我本地的PATH是配置过动态的(具体理解可以自己AI):
js
export VOLTA_HOME="$HOME/.volta"
export PATH="$VOLTA_HOME/bin:$PATH"
export NVM_DIR="$HOME/.nvm"
[ -s "/usr/local/opt/nvm/nvm.sh" ] && . "/usr/local/opt/nvm/nvm.sh" # This loads nvm
[ -s "/usr/local/opt/nvm/etc/bash_completion.d/nvm" ] && . "/usr/local/opt/nvm/etc/bash_completion.d/nvm" # This loads nvm bash_completion
证明PATH地址没出问题。
- 重新安装依赖:运行 npm install 或 yarn install
问题出在这里,我mode-modules包拿到后,跟本地项目没对上,具体原因没分析出来,可能是某个配置或解析?
总之,需要删除lock文件,重新install就好了。
HE~!