问题形容

  • 日常开发中,咱们前端在联调接口时,经常会遇到须要在多个后端ip服务切换的状况
  • 举个例子,一个前端要别离和三个后端 甲、乙、丙 联调其对应的本地接口
  • 前端须要先在vite.config.js(vue.config.js)文件中的proxytarget改成ip服务地址
  • 甲的本地接口联调结束当前,须要把proxy的target再改成的,完了再改成的,如下图:

  • 那咱们就想,能不能写一个脚本,在咱们启动我的项目执行"npm run dev"的时候,依据咱们的需要,主动帮忙咱们批改呢?相似于命令行的下拉框抉择的感觉那种(脚本批改代理转发,总比手动批改效率高一些)

咱们先看一下最终的效果图gif图

解决问题效果图

上述gif就能清晰的看到最终想要成果(省去了手动批改的步骤了,略微了晋升了一点点开发效率)

  • 那具体如何实现的呢?
  • 莫焦急,咱们先来温习(学习)一下几个常识

常识温习

1. inquirer命令行交互工具

  • inquirer是一款十分优良的命令行交互工具
  • 很多的框架、我的项目、程序都用到了这个工具,比方vue-cli的脚手架
  • 如下截图:

说到这里,大家应该就明确了,inquirer工具,能够做很多交互成果,比方:

  1. '输入框'
  2. '下拉框'
  3. '确认框'
  4. '明码框'
  5. 等等...

具体大家能够去官网粗疏学习一下:inquire官网

本例中,就是用到'下拉抉择框'

2. package.json文件中增加本人的脚本

问题一:如何在package.json增加本人的脚本命令,并管制执行程序?

原来的脚本

  "scripts": {    "start": "npm run dev",    "dev": "vite --host",    "build": "vite build",    "preview": "vite preview"  },
这个start脚本,相当于给npm run dev起一个别名,即执行npm start会调用npm run dev命令

加上本人的脚本

  "scripts": {    "start": "npm run dev",    "dev": "node ./startDevConf.js && vite --host",    "build": "vite build",    "preview": "vite preview"  },
  • 咱们在原有的vite --host命令前,加上本人想要执行脚本文件的命令node ./startDevConf.js,并通过&&进行分隔
  • 示意先把后面的node ./startDevConf.js执行结束,再去执行后边的vite --host

问题二:如何给本人写的脚本传递参数,并接管参数

比方咱们在package.json文件中,再加一个脚本,并附上参数helloWord

  "scripts": {    "start": "npm run dev",    "dev": "node ./startDevConf.js && vite --host",    "build": "vite build",    "preview": "vite preview",    "params": "node ./paramsConf.js helloWord"  },

当咱们执行npm run params的时候,在对应的paramsConf.js文件中,有两种形式能够接管:

// paramsConf.js// 两种形式,拿到脚本执行传递进来的参数 /** * 获取脚本参数形式一:process.argv.at(-1) * */console.log('process.argv是数组--->', process.argv); // [ 'C:\\Program Files\\nodejs\\node.exe',  'D:\\study\\9.6文章\\paramsConf.js', 'helloWord' ]console.log('第一项是Node.js过程所在的绝对路径--->', process.argv[0]);console.log('第二项是脚本文件所在的绝对路径--->', process.argv[1]);console.log('第三项脚本执行附带的参数--->', process.argv[2]); // helloWord/** * 获取脚本参数形式二:process.env.npm_lifecycle_script截取 * */let fullScriptStatement = process.env.npm_lifecycle_scriptlet params = fullScriptStatement.split(' ').at(-1) // helloWordconsole.log('通过截取也能够拿到哦', params);

3. 几个常见的转义字符

  • \n 换行符
  • \r 回车符
  • \t tab缩进符
  • \' 本义'
  • \" 本义"
可用于给文件写入字符串内容,依据状况适当增加转义字符

4. process.env对象

  • process是程序运行过程对象的意思,其身上挂了很多属性
  • 比方最罕用的process.env
  • 笔者打印了一下process.env并截取罕用的一些属性如下:
{  LANG: 'zh_CN.UTF-8', // 以后语言:中文,UTF-8编码  NODE: 'C:\\Program Files\\nodejs\\node.exe', // node程序安装地位  NPM_CLI_JS: 'C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js', // npm脚手架装置地位  npm_command: 'run-script', // npm的命令 执行脚本  npm_config_cache: 'C:\\Users\\user\\AppData\\Local\\npm-cache', // npm缓存地位  npm_config_home: 'https://npmmirror.com', // npm配置镜像的源  npm_config_init_module: 'C:\\Users\\user\\.npm-init.js', // npm初始化的模块js文件  npm_lifecycle_event: 'dev', // 以后执行的npm脚本的名字 npm run dev/npm run build 【 dev 或 build 可用于辨别开发或者生产 】  npm_lifecycle_script: 'node ./startDevConf.js && vite --host', // 以后执行npm脚本的残缺语句  npm_package_json: 'D:\\study\\9.6文章\\package.json', // package.json文件的地位  npm_package_name: 'sou', // package.json文件的名字  npm_package_version: '0.0.0', // package.json文件的版本  NVM_HOME: 'C:\\Users\\user\\AppData\\Roaming\\nvm', // 笔者装置的node版本管理工具NVM的门路地位  SESSIONNAME: 'Console', // 以后会话的类型,Console示意是物理管制台上进行的交互式会话,而不是近程会话  TERM_PROGRAM: 'vscode', // 以后应用的vscode的程序  TERM_PROGRAM_VERSION: '1.81.1', // 以后应用的vscode程序的版本}

最罕用的两个:

  • npm_lifecycle_event: 'dev' // 以后执行的npm脚本的名字 npm run dev/npm run builddevbuild 可用于辨别开发或者生产 】
  • npm_lifecycle_script: 'node ./startDevConf.js && vite --host' // 以后执行npm脚本的残缺语句(能够截取脚本传递的参数,如果有的话)

成果实现

第一步 package.json增加脚本

  "scripts": {    "dev": "node ./startDevConf.js && vite --host",  },
  • 当咱们执行npm run dev的时候,在触发vite启动我的项目之前,先执行startDevConf.js文件中的脚本去操作跨域转发代理设置选项

第二步 应用inquirer配置选项

// startDevConf.jsimport inquirer from "inquirer";async function selectServe() {    try {        const choose = await inquirer.prompt([            {                type: 'list',                name: 'serve', // 就是选中的key                message: '请抉择开发环境下须要连贯的后端服务',                choices: [                    {                        name: '张三',                        value: "\t\t\t\ttarget: 'http://33.33.33.33:3333',",                    },                    {                        name: '李四',                        value: "\t\t\t\ttarget: 'http://44.44.44.44:4444',",                    },                    {                        name: '王二',                        value: "\t\t\t\ttarget: 'http://22.22.22.22:2222',",                    },                    {                        name: '麻子',                        value: "\t\t\t\ttarget: 'http://55.55.55.55:5555',",                    },                ]                default: choices[0].value            }        ])        // 假如选中的是麻子的后端服务        console.log('选中的选项', choose.serve) // \t\t\t\ttarget: 'http://55.55.55.55:5555',    } catch (error) {        console.log(`报错了--->: ${error}`)    }}selectServe()

接下来,咱们只须要把选中的选项的proxy的target数据写入到vite.config.js文件中去即可

第三步 把选中的数据替换到vite.config.js文件中去即可

  • 首先读取vite.config.js文件
  • 而后找到对应的proxy的target那一行的数据
  • 最初再替换一下写入vite.config.js文件就行了
import fs from "fs"; // vite写法// 在读取到的vue.config.js文件字符串中寻找target行的数据function findProxyTarget(file) {    let fileArr = file.split('\n') // 把文件字符串依据换行符转成数组    let proxyTarget = '' // 申请转发代理那一行的数据容器    for (let i = 0; i < fileArr.length; i++) { // 通过循环找到对应行        if (fileArr[i].includes('target:')) {            proxyTarget = fileArr[i] // 赋值一下,找到了            break        }    }    // 把找到的这一行数据吐进来    return proxyTarget // target: 'http://33.33.33.33:3333',}let file = fs.readFileSync('./vite.config.js', 'utf-8') // 读取vue.config.js文件let proxyTarget = findProxyTarget(file) // 找到proxy跨域代理申请转发target行的数据const newFile = file.replace(proxyTarget, choose.serve) // 换成咱们新选的后端服务地址fs.writeFileSync('./vite.config.js', newFile) // 写入更新vite.config.js文件即可

至此咱们的成果就实现啦

残缺代码

脚本startDevConf.js残缺代码

import fs from "fs"; // vite写法import inquirer from "inquirer"; // vite写法// const fs = require('fs') // webpack写法// const inquirer = require('inquirer') // webpack写法const scriptName = process.env.npm_lifecycle_event // dev buildconsole.log('process.env\n', process.env);// 后端的服务选项const choices = [    {        name: '张三',        value: "\t\t\t\ttarget: 'http://33.33.33.33:3333',",    },    {        name: '李四',        value: "\t\t\t\ttarget: 'http://44.44.44.44:4444',",    },    {        name: '王二',        value: "\t\t\t\ttarget: 'http://22.22.22.22:2222',",    },    {        name: '麻子',        value: "\t\t\t\ttarget: 'http://55.55.55.55:5555',",    },]// 在读取到的vue.config.js文件字符串中寻找target行的数据function findProxyTarget(file) {    let fileArr = file.split('\n') // 把文件字符串依据换行符转成数组    let proxyTarget = '' // 申请转发代理那一行的数据容器    for (let i = 0; i < fileArr.length; i++) { // 通过循环找到对应行        if (fileArr[i].includes('target:')) {            proxyTarget = fileArr[i] // 赋值一下,找到了            break        }    }    // 把找到的这一行数据吐进来    return proxyTarget // target: 'http://33.33.33.33:3333',}async function selectServe() {    try {        const choose = await inquirer.prompt([            {                type: 'list',                name: 'serve',                message: '请抉择开发环境下须要连贯的后端服务',                choices,                default: choices[0].value            }        ])        let file = fs.readFileSync('./vite.config.js', 'utf-8') // 读取vue.config.js文件        let proxyTarget = findProxyTarget(file) // 找到proxy跨域代理申请转发target行的数据        const newFile = file.replace(proxyTarget, choose.serve) // 换成咱们新选的后端服务地址        fs.writeFileSync('./vite.config.js', newFile) // 写入更新vite.config.js文件即可    } catch (error) {        console.log(`报错了--->: ${error}`)    }}selectServe()

仓库地址

为了不便大家看。特提供github仓库地址:https://github.com/shuirongshuifu/nodeForProject

思考

  • 如果nginx是在前端保护,咱们是不是也能够批改nginx的location的proxy_pass呢?毕竟有时候,生产要公布好几份?
  • 如果进一步细分,带有.env.development.env.production文件,咱们是不是能够在其中配置一些货色,从而批改呢?
  • 笔者的这篇文章,抛砖引玉,心愿可能让读者们有所播种感悟......