业务代码编写过程中如何「优雅的」配置隔离
思考
不同的处理方式
1.常规的处理方式,通过某种规则判断区分代码环境
// 获取环境标识
const env = getCurrentEnv();if (env === 'dev') {// do something
} else if (env === 'test') {// do something
} else if (env === 'prod') {// do something
}
分析:
1.此种方式强依赖 getCurrentEnv 方法区分环境,这里是_重点_;
2.强依赖 if else 中对于不同环境的处理逻辑;缺点:
1.环境区分_强依赖代码逻辑_,并且各个_环境配置代码均存在于构建产物中_,
2.环境判断隔离,很难发现其他环境中的问题,代码出错或者改错,不易发现;
2.process.env.NODE_ENV
通过 node 运行时环境变量构建时区分代码环境
// 获取环境标识
const env = process.env.NODE_ENV;if (env === 'dev') {// do something
} else if (env === 'test') {// do something
} else if (env === 'prod') {// do something
}
分析:
1.此情况依赖构建脚本,不同环境增加构建环境变量,以此区分环境
2.其他情况_同上一条_缺点:
1.需要多定制一次构建脚本,区分不同环境,也可使用
cross-env
追加环境脚本;
2.其他缺点_同上一条_
3.拆分环境配置代码到不同的配置文件,通过打包方式,固定只获取某个环境配置文件
/** 构建运行时环境配置 */
// $ cross-env ENV=test npm run build
// $ cross-env ENV=pre npm run build
// $ cross-env ENV=prod npm run build// TEST:test.config.js
// PRE:test.config.js
// PROD:prod.config.js// 这里需要改造打包代码,动态读取对应配置文件到某个全局变量中
const env = process.env.ENV;
// 动态读取对应环境配置文件
const config = require(`./config/${env}.config.js`);// todo 通过编写构建代码动态添加到全局变量中
分析:
1.此种情况_隔离了不同环境配置_,构建产物仅存在当前环境的代码配置,无冗余;
2.一次编写构建配置,永久生效,仅需要维护不同环境配置文件即可,互不干扰;缺点:
1.需要_定制构建代码_,_动态获取配置到全局变量_中,编写成本较高;
2.不利于运行时环境配置变更,每次改动配置需要重启构建脚本;
4.拆分环境配置代码到不同的配置文件,通过_动态生成各个环境配置文件_到本地_固定代码文件_中,在其他业务代码中固定引用此文件
/** 1. 定制脚本动态生成固定配置文件,此处需要定制 config 脚本,*.config.js 为环境配置文件,-s 对应源文件,-o 对应输出文件 */
// $ config -e dev -s ./config/dev.config.js -o src/config.js
// $ config -e test -s ./config/test.config.js -o src/config.js
// $ config -e prod -s ./config/prod.config.js -o src/config.js// 读取生成的配置文件
import config from './config.js';
分析:
1.此情况唯一的难点在于_定制脚本动态生成不同的环境配置文件_;
2.生成的配置文件与其他环境解耦,且纯粹无冗余,并且有良好的运行时支持;缺点:
1.定制脚本有些难度
思路小结
综上总结,为了解决冗余问题、环境干扰问题、维护变更问题、构建运行时问题等等,我比较推荐第 4 种方式,虽然有些定制难度,不过拆解下实现思路,其实还是有迹可循的:
1.定制一个_脚本_入口,可以_读取命令行中定义的入参_;
2._动态读取_配置文件,并_重写配置文件_到固定文件中;
3.应用;下面我们就来一步一步实现该思路
实现
下面让我们来实现此功能
1. 定制脚本入口
这里需要完成几个功能点:
1.指定入口脚本文件
2.能够解析脚本入参
1.创建一个 config.js
console.log('> config 入口');
console.log('> ', process.argv); // 打印入参
2.解析脚本入参,比如执行 node ./lib/config.js -e dev -o dist/config.js
> node ./lib/config.js -e dev -o dist/config.js> config 入口
>['/usr/local/bin/node','/Users/fosunhealth/Documents/ME/learning-tools/packages/config/lib/config.js','-e','dev','-o','dist/config.js'
]
观察以上打印即可根据出参匹配脚本入参规则,读取到自己想要的参数
- 3.这里推荐下
commander
工具,封装了很多辅助功能,可以偷个懒
const program = require('commander');
const { version } = require('../package.json');program.version(version)// .command('config') // 这里用作指定脚本名称,调试阶段可先注释.usage('-e <env> -o <output>').description('🍈 生成配置文件').option('-e, --env <env>', '当前环境').option('-o, --output <output>', '输出路径').action(({ output, env }) => {console.log('> 当前环境', env);console.log('> 输出路径', output);});// 解析脚本入参
program.parse(process.argv);
此时再执行脚本,得到输出结果如下:
得到了我们需要指定的环境变量,以及需要输出的路径,这阶段宣告完成
> node ./lib/config.js -e dev -o dist/config.js> 当前环境 dev
> 输出路径 dist/config.js
2. 动态读取配置文件,并生成到固定文件
接上一步,此阶段需要处理入参并动态输出配置文件:
1.根据 env 读取对应配置文件内容
2.写入到固定文件中
// 文件处理工具
const { existsSync, outputFileSync, mkdirSync, writeFileSync } = require('fs-extra');/** 自定义规则读取本地的配置文件 */
const rootPath = process.cwd(); // 当前上下文根路径,这个很重要,需要基于当前上下文去寻找文件
const configPath = join(rootPath, `./config/${env}.config.js`); // 本地环境配置文件
const outputPath = join(rootPath, output || './src/config.ts'); // 生成配置路径if (!existsSync(configPath)) {throw new Error(`${env} 环境配置文件不存在`);
}try {// 读取配置内容const content = readFileSync(configPath, { encoding: 'utf-8' });// 写入配置内容writeFileSync(outputPath, content, { encoding: 'utf-8' });console.log('> 生成配置文件成功.');
} catch (error) {console.error('> 生成配置文件异常', error);
}
如下图执行流程,即可动态生成所需环境配置了
1.这样实现具体的配置文件读取规则就可以自定义拉,也能在_业务代码构建过程中动态生成_了
2.使用方式还可以通过_封装到私库中_,通过脚本引用,这样就能当做一个_团队工具_使用了源码参考:github.com/howieyi/lea…
基于以上,其实还有很多场景可以扩展,这里更多的是提供一种思路,希望对大家有所帮助。
最后
最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。
有需要的小伙伴,可以点击下方卡片领取,无偿分享
相关文章:

业务代码编写过程中如何「优雅的」配置隔离
思考 不同的处理方式 1.常规的处理方式,通过某种规则判断区分代码环境 // 获取环境标识 const env getCurrentEnv();if (env dev) {// do something } else if (env test) {// do something } else if (env prod) {// do something } 分析: 1.此种…...

English Learning - L2-2 英音地道语音语调 2023.02.23 周四
English Learning - L2-2 英音地道语音语调 2023.02.23 周四查音标的工具怎么练习效果好准备工作大小声练习大元音开口度的对比舌位对比复习后元音 /ɑː/ /ɔː/ /uː//ɑː//ɔː//uː/前元音 /iː/发音技巧对应单词的发音对应句子的发音常见的字母组合中元音 /ɜː/发音技巧…...
java:线程等待与唤醒 - Object的wait()和notify()
java:线程等待与唤醒 - Object的wait()和notify() 1 前言 java使用Object类的wait()和notify()方法,可以实现线程等待和唤醒(Object类为所有类的父类,即所有类天然具有线程等待和唤醒的方法,一般使用Object类的wait(…...

实现弹窗功能并修改其中一个系数
把鼠标放在number-info上面,会是一个delon/chart的类库,可以在NG-ALAIN上找到阅读NG ALAIN的图表,以及number-info样式,数据文本 它拥有[title] [subtitle]两个可以是TemplateRef类型的,而template可以在里面放一些东西,比如按钮,所以可以放一个修改按钮 这里刚开始把template放…...

vue-draggable浏览器拖拽event事件对象拖动时 DragEvent path undefined
场景: 在做组件拖拽过程中,需要获取到触发元素冒泡过程中的所有元素,所以使用了event.path属性。在Chrome下正常运行,但是在FireFox下测试时发现,完犊子,失效了,通过问题排查,发现了…...

【云原生】搭建k8s高可用集群—20230225
文章目录多master(高可用)介绍高可用集群使用技术介绍搭建高可用k8s集群步骤1. 准备环境-系统初始化2. 在所有master节点上部署keepalived3.1 安装相关包3.2 配置master节点3.3 部署haproxy错误解决3. 所有节点安装Docker/kubeadm/kubelet4. 部署Kuberne…...
LeetCode121_121. 买卖股票的最佳时机
LeetCode121_121. 买卖股票的最佳时机 一、描述 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最…...

收割不易,五面Alibaba终拿Java岗offer
前言 前段时间有幸被阿里的一位同学内推,参加了阿里巴巴Java岗位的面试,本人19年双非本科软件工程专业,目前有一年半的工作经验,面试前就职于一家外包公司。如果在自己本人拿到offer之前,如果有人告诉我一年工作经验可…...

【离线数仓-4-数据仓库设计-分层规划构建流程】
离线数仓-4-数据仓库设计-分层规划&构建流程离线数仓-4-数据仓库设计-分层规划&构建流程1.数据仓库分层规划2.数据仓库构建流程1.数据调研1.业务调研2.需求分析3.总结2.明确数据域3.构建业务总线矩阵&维度模型设计4.明确统计指标1.指标体系相关概念1.原子指标2.派生…...

SQL零基础入门学习(十一)
SQL零基础入门学习(十) SQL NOT NULL 约束 NOT NULL 约束强制列不接受 NULL 值。 NOT NULL 约束强制字段始终包含值。这意味着,如果不向字段添加值,就无法插入新记录或者更新记录。 下面的 SQL 强制 “ID” 列、 “LastName” …...

排序基础之插入排序
目录 前言 一、什么是插入排序 二、实现插入排序 三、插入排序优化 四、插入排序的特性 前言 上一篇中我们说到了《排序基础之选择排序》,这一篇我们来学习一下排序算法中的另一种基础排序算法——插入排序。 一、什么是插入排序 简单来说就是:每…...

LabVIEW控制DO通道输出一个精确定时的数字波形
LabVIEW控制DO通道输出一个精确定时的数字波形如何使用数据采集板卡的DO通道输出一个精确定时的数字波形?解答:产生一个数字波形首先需要创建一个布尔数组,把波形序列信息放到该布尔数组中,然后通过一个布尔数组至数字转换vi来产生数字波形。…...

openpnp - 零碎记录
文章目录openpnp - 零碎记录概述笔记配置文件保存无效必须在查找问题之后, 才能保存配置文件如果想找出配置动作引起的配置内容变化, 还是要尝试保存后, 比对变化才行ENDopenpnp - 零碎记录 概述 这段时间, 正在配置校准手头的openpnp设备, 用的官网最新的openpnp2.0. 由于o…...

Qt编写微信支付宝支付
文章目录一 微信支付配置参数二 支付宝支付配置参数三 功能四 Demo效果图五 体验地址一 微信支付配置参数 微信支付API,需要三个基本必填参数。 微信公众号或者小程序等的appid;微信支付商户号mchId;微信支付商户密钥mchKey; 具…...
LeetCode 剑指 Offer 64. 求1+2+…+n
求 12…n ,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。 示例 1: 输入: n 3 输出: 6 限制: 1 < n < 10000 解法一:利用逻辑运算符的短路…...

Mapper代理开发
MyBatis快速开发https://blog.csdn.net/weixin_51882166/article/details/129204439?spm1001.2014.3001.5501 使用Mapper代理方式完成 定义与SQL映射文件同名的Mapper接口 ,将Mapper接口和SQL映射文件放置同一目录结构 新建接口和包: 将Mapper接口和…...
为什么在连接mysql时,设置 SetConnMaxIdleTime 没有作用
目录测试1go 1.15.15go 1.17.12测试2go 1.15.15go 1.17.12参考在使用golang 连接 mysql时,为了节省连接资源,在连接使用过后,希望在指定长度时间不再使用后,自动关闭连接。 这时,经常会使用SetConnMaxLifetime()&#…...
嵌入式开发利器
前言 俗话说,工欲善其事必先利其器,做嵌入式开发首先需要选择好的工具,对的工具,工具选对了能事半功倍,节省很多时间,那些开发大佬一般都会使用各种各样的工具,不同的环节使用不同的工具&#…...
Qt 的QString类的使用
Qt的QString类提供了很方便的对字符串操作的接口。 使某个字符填满字符串,也就是说字符串里的所有字符都有等长度的ch来代替。 QString::fill ( QChar ch, int size -1 ) 例: QString str "Berlin";str.fill(z);// str "zzzzzz"…...

django项目部署(腾讯云服务器centos)
基本步骤: 购买腾讯云服务器并配配置好 >> 本地项目依赖收集准备 >> 上传项目等文件到服务器 >> 服务器安装部署软件和python环境 >> 开始部署(全局来看就这5个步骤) 目录 目录 1. 购买腾讯云服务器并配配置好 …...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...

PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
前端调试HTTP状态码
1xx(信息类状态码) 这类状态码表示临时响应,需要客户端继续处理请求。 100 Continue 服务器已收到请求的初始部分,客户端应继续发送剩余部分。 2xx(成功类状态码) 表示请求已成功被服务器接收、理解并处…...