hoyong

导航

彻底理解并解决 'webpack' 不是内部或外部命令,也不是可运行的程序或批处理文件(转)

彻底理解并解决 'webpack' 不是内部或外部命令,也不是可运行的程序或批处理文件

版权声明:本文为回眸一笑原创作品,欢迎关注「前端集锦」公众号。 https://blog.csdn.net/weixin_44135121/article/details/90513634

彻底理解并解决 'webpack' 不是内部或外部命令,也不是可运行的程序或批处理文件

一、问题描述

在安装 npm 包模块的时候,不管是 Webpack 、React 还是 Vue,都需要全局安装,即执行 npm install webpack -g 或者 npm install @vue/cli -g,否则在使用命令(比如查看版本,webpack -v)的时候就会报错 ‘webpack’ 或者 ‘vue’ 不是内部或外部命令,也不是可运行的程序或批处理文件,很多人都是靠全局安装去解决这个问题,那么你知道为什么全局安装可以解决这个问题,或者有没有其他更优的方案吗。今天就给大家分享一下出现这个问题的原因及更好的解决办法。

二、分析原因

在解释这个原因之前先普及一下基本知识。

  1. 在 windows 环境下执行命令是通过 cmd 文件。比如查看 webpack 版本,执行 webpack -v 命令。那么必定有个 webpack.cmd 文件。如果没有就会报以上错误。( ‘webpack’ 不是内部或外部命令,也不是可运行的程序或批处理文件)。
  2. cmd 执行文件中文件目录格式为"%~dp0…\webpack\bin\webpack.js"。
    其中 “%~dp0” 表示该 cmd 文件所在的当前目录。"…\ "表示上级目录。
  3. 举例说明以上两点。
    有个文件夹为 a,
    在 a 目录下有个文件夹 b 和 index.js。
    在 b 目录下有个 index.js 和 test.cmd 执行文件,
    那么在 b 目录下输入 test 命令就会执行 a 目录的 index.js 的内容。

注意
a 目录下面有 b 和 index.js ,即 b 和 index.js 是同级目录
在这里插入图片描述
b 目录下面也有 index.js 及 test.cmd
在这里插入图片描述
a 目标下的 index.js 内容如下:

console.log('hello world a');
  • 1

b 目录下的 index.js 内容如下:

console.log('hello world b');
  • 1

test.cmd 内容如下:

node  "%~dp0\..\index.js" %*
  • 1

在当前根目录,也就是 a 目录下执行 test 命令,出现如下报错
在这里插入图片描述
因为 a 目录下并没有 test.cmd 文件,而 test.cmd 文件是在 b 目录下。所以切换到 b 目录下执行 test 命令,打印出 ‘hello world a’
在这里插入图片描述
那么如果我们想打印出 ‘hello world b’ 怎么办昵,就需要分析一下该 index.js 文件的路径了,可以看到该文件直接在 a 目录下。所以需要修改 test.cmd 文件的执行文件(需要执行的那个 js)路径为

node  "%~dp0\index.js" %*
  • 1

修改后再次执行 test 得到结果
在这里插入图片描述
看到这里就不难猜出报以上错误的原因:

  1. 在需要执行命令的目录下(比如项目目录)没有 cmd 执行文件。
  2. 需要确保 cmd 执行文件中要执行的 js 文件路径无误。

三、解决方案

有了以上知识的普及,现在我们定位到具体的项目中。如果没有全局安装模块,只是将模块安装在了当前目录下,而我们执行命令的时候,却总是在项目目录下执行。我们的项目目录下并没有 cmd 执行文件。所以就报了以上错误。现在就基于以上分析的没有 cmd 文件和要执行的文件路径有误这两点说说几种解决方案。

1. 全局安装模块

这个是众所周知的解决方案,基于以上的知识点我们再来分析能解决这个问题的原因。

  • 首先执行 npm get prefix 命令得到 npm 的安装路径。一般在C:\Users\xpwu\AppData\Roaming\npm。打开该目录,只要是全局安装的模块,在该目录下都会有相应的 cmd 执行文件,所以在这里我们可以看到webpack.cmd。因此不会报 ‘webpack’ 不是内部或外部命令,也不是可运行的程序或批处理文件的错误。
  • 打开 webpack.cmd 文件,判断如果当前目录下有 node.exe 程序,就使用 当前目录下的 node.exe 程序执行文件,否则使用环境变量中的 node.exe 程序来执行文件,显然不会将 node 安装在当前目录下,而是使用环境变量。
@IF EXIST "%~dp0\node.exe" (
 "%~dp0\node.exe"  "%~dp0\node_modules\webpack\bin\webpack.js" %*
) ELSE (
 @SETLOCAL
 @SET PATHEXT=%PATHEXT:;.JS;=;%
 node  "%~dp0\node_modules\webpack\bin\webpack.js" %*
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 上文有提到 “%~dp0” 表示当前路径,这里的当前路径指的就是C:\Users\xpwu\AppData\Roaming\npm。因为 webpack.cmd 文件就在这个目录下。所以该路径 “%~dp0\node_modules\webpack\bin\webpack.js”,指的就是C:\Users\xpwu\AppData\Roaming\npm\node_modules\webpack\bin\webpack.js。这个文件下的 webpack.js 是存在的,路径没有任何问题。所以全局安装模块满足了1.有 cmd 执行文件;2.要执行的文件路径是正确的这两个条件。

2. 在 cmd 执行文件下运行命令

  • 通过 npm install webpack --save 命令把模块安装到项目路径下之后,在项目路径下就会有 node_modules 文件夹,而在该文件夹下就可以找到该模块,是否全局安装可参考文章 npm 中 --save 与 --save-dev 的区别
  • 细心一点的童鞋可能知道,在 node_modules 文件夹下有个 .bin 文件夹。在该 .bin 文件夹下有 webpack.cmd 文件。
    在这里插入图片描述
    用编辑器打开该 cmd 文件,内容如下:
@IF EXIST "%~dp0\node.exe" (
  "%~dp0\node.exe"  "%~dp0\..\webpack\bin\webpack.js" %*
) ELSE (
  @SETLOCAL
  @SET PATHEXT=%PATHEXT:;.JS;=;%
  node  "%~dp0\..\webpack\bin\webpack.js" %*
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

再啰嗦一下,“%~dp0” 表示当前路径,也就是 .bin 目录,"…\ "表示上级项目,也就是 node_modules 目录,所以该文件路径也是正确的。问题就是每次只能在 项目路径/node_modules/.bin 目录下去使用 webpack 命令了。而我们一般情况下习惯直接在项目目录下去使用命令,那应该怎么做昵?

3.添加 cmd 文件,修改对应路径

  • 聪明的你肯定已经猜到,既然要在项目根目录下执行命令,那么就在项目根目录下添加一个 cmd 文件不就行了吗。
  • 真是这样吗?哈哈,对自己有点信心,的确如此,需要注意的是满足了第一个条件,第二个条件,执行文件路径是否正确也是需要考虑的,我们把全局环境下的 webpack.cmd 文件或者 .bin 目录下的 webpack.cmd 文件复制一份到项目目录下都可以,甚至自己手写也行,这里我们就以 .bin 目录下的 webpack.cmd 文件复制一份到项目目录下为例。
@IF EXIST "%~dp0\node.exe" (
 "%~dp0\node.exe"  "%~dp0\..\webpack\bin\webpack.js" %*
) ELSE (
 @SETLOCAL
 @SET PATHEXT=%PATHEXT:;.JS;=;%
 node  "%~dp0\..\webpack\bin\webpack.js" %*
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

那么这里的 “%~dp0"指的就是项目目录了,”…" 就到项目目录的上一级目录了,自然不是我们想要的,很显然项目目录下的 webpack.js 文件路径应该是 项目目录/node_modules/webpack/bin/webpack.js。(可能有些人的目录不一定是我这样的,你只需要找到你自己项目下的 webpack.js 文件路径即可)。那么这里就只需要把 “…” 改成 “node_modules” 就是 webpack.js 的正确路径了。即

@IF EXIST "%~dp0\node.exe" (
 "%~dp0\node.exe"  "%~dp0\node_modules\webpack\bin\webpack.js" %*
) ELSE (
 @SETLOCAL
 @SET PATHEXT=%PATHEXT:;.JS;=;%
 node  "%~dp0\node_modules\webpack\bin\webpack.js" %*
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

其实这跟全局下的 cmd 文件路径是一样的,所以如果从全局下复制过来的 webpack.cmd 文件就不用做任何修改了。

四、方案对比

以上3种方案中各有利弊,如果是全局安装,一般情况下肯定也会在项目目录下安装一份,这将造成每个模块都会安装两遍的内存消耗;而只在项目目录下安装并使用以上说的第二种方案每次都在 .bin 目录下执行命令无疑比较麻烦;所以第三种方案,直接复制一份 cmd 文件到项目目录下并修改相应的文件执行路径是最优方案。
在这里插入图片描述

posted on 2019-06-18 15:21  hoyong  阅读(1377)  评论(0编辑  收藏  举报