npm命令行参数动态配置webpack代理

144 阅读2分钟

 今天本地开发一个新项目的时候,遇到了一点问题:项目本地启动之后的localhost页面,请求服务端接口,报跨域错误。

 搜索了一下,这个问题网上的解决办法已经很明确了:配置webpack proxy,在webpack配置文件中添加以下配置即可:

{
  devServer: {
    proxy: {
      "/api": {
        target: "htttp://www.expample.com/",
        changeOrigin: true
      }
    }
  }
}

 这样本地启动之后,再请求就不会报跨域错误了。

 但是,因为我们起码有两个环境:测试环境和生产环境,经常需要代理到不同环境的服务。

 如果使用以上配置,需要经常修改devServer.proxy.target配置的值,这有点麻烦。那能不能在启动项目时通过命令行参数指定想要代理到的服务呢? 比如这样:

npm run dev --devproxy=http://www.example.com/

Step 1

 首先,需要把devproxy参数设置到node的环境变量中,$npm_config_devproxy会读取到我们在命令行参数中传递的devproxy的值,随后我们把它赋给DEVPROXY环境变量。

 这样,后续我们就可以在webpack配置文件中通过process.env.DEVPROXY读取devproxy参数的值了。

 此外,为了跨平台的兼容性考虑,最好加上cross-env

//之前的dev命令
{
  "scripts": {
     "dev": "nfes-nmf start",
   }
}

//在dev命令中设置devproxy参数到node的环境变量
{
  "scripts": {
     "dev": "cross-env DEVPROXY=$npm_config_devproxy nfes-nmf start",
   }
}

Step 2

 在webpack配置文件中读取devproxy参数。并用于配置devServer.proxy.target

{
  devServer: {
    proxy: {
      "/api": {
        target: process.env.DEVPROXY,
        changeOrigin: true
      }
    }
  }
}

Step 3

 到这里,已经可以通过--devproxy=来配置webpack代理。我们最后再做一点锦上添花的小工作:在配置代理、启动项目之后,我们有时候想知道现在是代理到了哪个服务端环境? 最终实际请求的url是什么样的?

 所以我们可以在每个请求的响应头 (Response Headers) 加上一个X-Real-Url字段,表示这个请求实际的url。

 添加配置项onProxyRes

{
  devServer: {
    proxy: {
      "/api": {
        target: process.env.DEVPROXY,
        changeOrigin: true,
        onProxyRes: function (proxyRes, req) {
          proxyRes.headers["X-Real-Url"] = `${process.env.DEVPROXY}${req.url}`;
        },
      }
    }
  }
}

 效果请看下图,在Devtool Network找到某一个被代理的请求:

image.png

 至此,就完成了所有的配置~

Q&A

 做这个配置期间,遇到一点小问题:process.argv可以直接读取到命令行传入的参数,那么为什么我们这里还要用process.env呢?

 因为我的npm scripts里,dev命令是这样的:

{
  "scripts": {
     "dev": "nfes-nmf start",
   }
}

 实际运行的是一个第三方包的命令,它没有直接运行webpack配置文件,所以等到运行项目内的webpack配置文件时,读取process.argv得到的只有:

["node", "运行的js文件路径", "start"]

 拿不到devproxy的值,所以我选择了用 赋值环境变量、再读取的方式来代替process.argv