Web前端依赖版本管理最佳实践

本文需要读者懂一点点前端的构建知识:
1. package.json文件的作用之一是管理外部依赖;
2. .npmrc是npm命令默认配置,放在工程根目录。
Web前端构建一直都是一个不难,但是非常烦人的问题,在DevOps、CI/CD领域。
烦人的是偶尔发生这样的事情:
1. 开发在本地构建通过,但是流水构建失败。这时前端开发人员会经常报怨Pipeline不稳定;
2. 流水线构建通过,但是在生产环境上启动不了,或者出现运行错误;
3. 不使用Docker可以启动,但是打包成Docker镜像后启动就失败。
这类问题,不是今天解决了,明天就不会发生。而是你根本不知道它什么时候又发生。
据我观察,绝大多数时候都是依赖版本管理没有做好导致的。
Web前端的依赖版本管理包括以下几个维度:
1. node的版本
2. 外部依赖的版本
我们需要在开发环境,构建环境,运行环境保证它们的版本是一致的。这样,在本地开发环境测试通过,那么,在其它环境就理论上也应该能通过。
接下来是具体的最佳实践。
保证Node版本一致
要保证Node版本一致,就要保证所有的环境使用同一个版本的node。而且是要具体到某一个精确的版本,如v20.11.1,而不是20这样一个粗略版本。
以下是我们以v20.11.1为例。
设置开发环境
设置开发环境的node的版本,需要在package.json中加入:
{"engines": {"node": "v20.11.1","npm": "10.2.4"},
} 这时,如果存在开发环境与配置的版本不匹配的情况,执行npm install,会出现以下警告,但是命令还是会继续执行:
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE package: 'gpt@0.0.1',
npm WARN EBADENGINE required: { node: 'v20.10.1', npm: '10.2.4' },
npm WARN EBADENGINE current: { node: 'v20.11.1', npm: '10.2.4' }
npm WARN EBADENGINE } 希望强制要求版本一致,就在根目录的.npmrc文件加入:
engine-strict=true 发生版本不一致的情况,报错日志如下,且命令会停止执行:
npm ERR! code EBADENGINE
npm ERR! engine Unsupported engine
npm ERR! engine Not compatible with your version of node/npm: gpt@0.0.1
npm ERR! notsup Not compatible with your version of node/npm: gpt@0.0.1
npm ERR! notsup Required: {"node":"v20.10.1","npm":"10.2.4"}
npm ERR! notsup Actual: {"npm":"10.2.4","node":"v16.0.1"} 设置构建环境
我们以Github Actions为例。在设置node环境时,应设置为:
- name: Setup Nodeuses: actions/setup-node@v3with:node-version: '20.11.1' 设置运行环境
运行环境分两种:虚拟机环境、容器运行时。
在虚拟机环境下,要避免apt install node-20,尽量使用能指定精确node版本的方式安装NodeJS(比如从官网上下载20.11.1的包安装)。
容器运行时环境,选择的镜像的Tag要与构建环境的版本完全一致,而不是随便选一个20版本的。
保证外部依赖版本的一致
由于Node的依赖管理默认配置下非常的宽松,默认情况下使用的就是自动升级策略。
当开发在本地执行: npm i @babel/core,npm会在package.json文件中加入"@babel/core": "^7.11.6",。^代表将来再次执行npm i时,npm有权自动升级它的小版本。
这一行为,导致项目一开始构建是成功的,但是过一段时间又构建失败的偶尔事件。
这种偶发性,不仅给构建工程带来不必要的浪费,还让软件变得不可靠。想想建设在沙子上的大厦会是怎样。
所以,我们推崇以下管理方法。
限制依赖下载源
限制的方法是在.npmrc中加入配置:
registry=https://registry.npmjs.org 从源头就控制软件供应链的一致性。
默认使用准确版本
正如前文所述,在执行 npm install <package> 安装依赖时,默认情况下会在package.json文件中使用^符号来指定版本范围。不过,我们可以通过添加 --save-exact 参数来避免这种情况,即运行 npm install <package> --save-exact,这样package.json文件中就不会出现^符号,而是会锁定安装的精确版本号。
我们不可能让开发人员100%做到每次执行命令都加--save-exact参数。
所以,我们需要更改npm默认的行为,在.npmrc文件中增加配置:
save-exact=true 将package-lock.json加入到版本库中
package-lock.json文件是npm专门用于固定依赖版本的。如果你使用的是pnpm,相对应的文件就是:pnpm-lock.yaml。
node工程中,除了使用package-lock.json锁定版本,还可以使用npm-shrinkwrap.json。
它们具有相同格式,都放在项目的根目录,目的都是为了锁定依赖版本。区别是npm-shrinkwrap.json会被发布到制品库,而package-lock.json不会。且引用它的package会忽略这个文件。
而且当同一个工程根目录下,同时存在它们时,package-lock.json会被忽略。
使用PNPM代替npm?
这篇文章[1]对PNPM,npm和Yarn三个依赖管理工具进行对比,读者自行判断选择相应的工具。但是,可以确定的是不要使用cnpm。
不论使用哪种工具,以上的实践都是类似的。
后记
作者作为一个Web前端的外行写下本文,有不足的或者错误的,还请补充和指正,多谢。
引用链接
[1] 文章: https://hackernoon.com/choosing-the-right-package-manager-npm-yarn-or-pnpm
往期好文:
在你的心目中,优秀的DevOps工程师应该是什么样的?
谈 DevOps 平台落地:前端项目构建又失败了
谈DevOps平台落地:前端构建怎么这么变态
相关文章:
Web前端依赖版本管理最佳实践
本文需要读者懂一点点前端的构建知识: 1. package.json文件的作用之一是管理外部依赖;2. .npmrc是npm命令默认配置,放在工程根目录。 Web前端构建一直都是一个不难,但是非常烦人的问题,在DevOps、CI/CD领域。 烦人的是…...
多线程进阶
一.常见的锁策略 这里所讲的锁,不是一把具体的锁,而是锁的特性 1.乐观锁和悲观锁 悲观乐观是对锁冲突大小的预测 若预测锁冲突概率不大,就可能会少一些工作,那就是乐观锁;反之就是悲观锁 总是假设最坏的情况&…...
总结linux常用命令
Linux常用命令总结如下: 文件与目录操作: ls:列出目录内容cd:改变当前目录pwd:显示当前工作目录mkdir:创建新目录cp:复制文件或目录rm:删除文件或目录mv:移动或重命名文件…...
C++ 枚举
C 枚举 5.4.1普通枚举 枚举的定义:,枚举类型是通过enum关键字定义的,比如定义颜色类型 enum Color {RED, // 默认值为0GREEN, // 默认值为1BLUE // 默认值为2 }; Color myColor RED;注意: (1)括…...
Vue2在一个页面内动态切换菜单显示对应的路由组件
项目的需求是在一个页面内动态获取导航菜单,导航菜单切换的时候显示对应的路由页面,类似于tab切换的形式,切换的导航菜单和页面左侧导航菜单是同一个路由组件,只是放到了一个页面上,显示的个数不同,所有是动…...
执行任务赚积分C卷(JavaPythonC++Node.jsC语言)
现有N个任务需要处理,同一时间只能处理一个任务,处理每个任务所需要的时间固定为1。 每个任务都有最晚处理时间限制和积分值,在最晚处理时间点之前处理完成任务才可获得对应的积分奖励。 可用于处理任务的时间有限,请问在有限的时间内,可获得的最多积分。 输入描述 第一…...
接口测试之文件下载
在工作中对于下载接口,经常会有这样的疑问:这类接口一般功能比较稳定,但是又比较重要,需要占用回归测试时间,有没有可替代的方式? 答案肯定是有的,可以从接口测试/UI自动化测试介入,…...
算法思想总结:双指针算法
一、移动零 . - 力扣(LeetCode) 移动零 该题重要信息:1、保持非0元素的相对位置。2、原地对数组进行操作 思路:双指针算法 class Solution { public:void moveZeroes(vector<int>& nums){int nnums.size();for(int cur…...
python中的zip函数
1.zip()同时迭代多个列表、字典等 使用zip()可以同时迭代多个可迭代对象,如列表、字典。 注意:当若干个可迭代对象的长度不相等时,zip()函数会停止在最短的可迭代对象。 例子: # 定义可迭代对象 numbers …...
Element 选择季度组件
<template><el-dialogtitle"选择季度":show-close"false":close-on-click-modal"false":close-on-press-escape"false":visible"visiable"class"dialog list"append-to-body><div><div>&…...
4.MongoDB中16个常用CURD
基本的CURD 作为一个非专业的DBA,我们只需要会一些基本的curd就行,专业的内容还是需要专业的人去干的。CRUD 也就是增删改查,这是数据库最基本的功能,查询还支持全文检索,GEO 地理位置查询等。 01创建库 无需单独创…...
Tomcat数据源笔记
Tomcat数据源笔记 连接池的概念 连接池是一种由容器提供的机制,用于管理数据库连接对象的集合。连接池的主要作用是在应用程序需要与数据库进行交互时,提供可复用的连接对象,从而减少每次建立数据库连接的开销。 连接池的工作原理 连接池的…...
Spring-Kafka笔记整理
引入依赖<dependency><groupId>org.springframework.kafka</groupId><artifactId>spring-kafka</artifactId> </dependency>配置application.propertiesspring.kafka.bootstrap-servers192.168.99.51:9092编写kafka的配置类Configuration …...
已解决org.apache.hadoop.hdfs.protocol.QuotaExceededException异常的正确解决方法,亲测有效!!!
已解决org.apache.hadoop.hdfs.protocol.QuotaExceededException异常的正确解决方法,亲测有效!!! 目录 问题分析 报错原因 解决思路 解决方法 总结 博主v:XiaoMing_Java 问题分析 在使用Hadoop分布式文件系统&a…...
GitHub打不开的解决方案(超简单)
在国内,github官网经常面临打不开或访问极慢的问题,不挂VPN(梯子,飞机,魔法)使用体验极差,那有什么好办法解决github官网访问不了的问题?今天小布教你几招轻松访问github官网。 git…...
Unity开发一个FPS游戏之二
在之前的文章中,我介绍了如何开发一个FPS游戏,添加一个第一人称的主角,并设置武器。现在我将继续完善这个游戏,打算添加敌人,实现其智能寻找玩家并进行对抗。完成的效果如下: fps_enemy_demo 下载资源 首先是设计敌人,我们可以在网上找到一些好的免费素材,例如在Unity…...
STM32F103 CubeMX 使用USB生成鼠标设备
STM32F103 CubeMX 使用USB生成鼠标设备 1 配置cubeMX1.1配置外部晶振,配置debug口1.2 配置USB1.3 配置芯片的时钟1.4 生成工程 2. 编写代码2.1 添加申明2.2 main函数代码 1 配置cubeMX 1.1配置外部晶振,配置debug口 1.2 配置USB 1.3 配置芯片的时钟 需…...
HJXH-E1/U静态信号继电器 面板安装 辅助电源220VDC 启动电压220VDC JOSEF约瑟
HJXH系列静态信号继电器 HJXH-61/U静态信号继电器; HJXH-61/I静态信号继电器; HJXH-62/U静态信号继电器; HJXH-62/I静态信号继电器; HJXH-E1/U静态信号继电器; HJXH-E1/I静态信号继电器; HJXH-E2/U静态信号…...
SpringBoot3下Kafka分组均衡消费实现
首先添加maven依赖: <dependency><groupId>org.springframework.kafka</groupId><artifactId>spring-kafka</artifactId><version>2.8.11</version><exclusions><!--此处一定要排除kafka-clients,然…...
鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:GridItem)
网格容器中单项内容容器。 说明: 该组件从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。仅支持作为Grid组件的子组件使用。 子组件 可以包含单个子组件。 接口 GridItem GridItem(value?: GridItemOptions)…...
利用DiSEqC协议与AVR单片机驱动卫星天线电机改造户外设备
1. 项目概述:用卫星天线电机驱动一切如果你手头有一些需要承受风吹日晒、还得精确转动的设备,比如一个户外的大型定向天线,或者一个需要定期调整角度的太阳能板支架,甚至是一个坚固的监控云台,你可能会为驱动机构发愁。…...
打不开JupyterLab
因为安装某些依赖导致JupyterLab的依赖被动升级或降级,从而影响了JupyterLab的运行,此时可以SSH登录到实例,然后输入jupyter-lab命令进行确认,如果执行命令报错则说明是此问题,那么可以通过pip install jupyterlab再次…...
论文写作效率翻倍?okbiye 毕业论文 AI 功能全解析:从需求到终稿的规范路径
okbiye-免费查重复率aigc检测/开题报告/毕业论文/智能排版/文献综述/AI PPT毕业论文 - Okbiye智能写作https://www.okbiye.com/ai/bylw 一、从界面看本质:okbiye 毕业论文 AI 写作的设计逻辑 打开 okbiye 的毕业论文 AI 写作页面,首先能感受到的是清晰的…...
终极Node.js Mock工具:Mockery入门到精通实战教程
终极Node.js Mock工具:Mockery入门到精通实战教程 【免费下载链接】mockery Simplifying the use of mocks with Node.js 项目地址: https://gitcode.com/gh_mirrors/mock/mockery Mockery是Node.js生态中简化Mock使用的终极工具,它为开发者提供了…...
独立开发者利用taotoken模型广场为不同任务选择性价比最优模型
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 独立开发者利用taotoken模型广场为不同任务选择性价比最优模型 对于独立开发者而言,在有限的预算内高效完成多样化的开…...
【C++】零基础入门 · 第 6 节:数组
上一节我们学习了函数,知道了如何把代码封装起来方便复用。但在实际编程中,你很快就会遇到一个问题:如果要存储 100 个学生的成绩,难道要定义 100 个变量吗?这显然不现实。数组就是 C++ 给出的答案——它让我们能用一个变量名管理一组相同类型的数据。 1. 为什么需要数组…...
Facebook登录协议逆向解析:appsecret_proof与e2e加密机制
1. 这不是“爬虫教程”,而是一次对现代Web身份协议的解剖实验你有没有试过,在调试一个Facebook登录集成时,浏览器Network面板里突然冒出一串带sig、access_token、e2e、c_user的请求,参数长度动辄上千字符,加密方式五花…...
如何用Untrunc拯救损坏视频?2025年终极MP4修复工具完全指南
如何用Untrunc拯救损坏视频?2025年终极MP4修复工具完全指南 【免费下载链接】untrunc Restore a damaged (truncated) mp4, m4v, mov, 3gp video. Provided you have a similar not broken video. 项目地址: https://gitcode.com/gh_mirrors/unt/untrunc 当你…...
MaxEnt建模总失败?别急着换数据,先检查ArcGIS裁剪栅格这1个像素的坑
MaxEnt建模失败?ArcGIS栅格裁剪的1像素陷阱与精准修复指南当你花费数小时整理好WorldClim气候数据、本地DEM高程和物种分布数据,满心期待地点击MaxEnt的运行按钮时,屏幕上突然跳出"Error projecting, two layers have different geograp…...
PyKafka社区贡献指南:从问题报告到代码提交的完整流程
PyKafka社区贡献指南:从问题报告到代码提交的完整流程 【免费下载链接】pykafka Apache Kafka client for Python; high-level & low-level consumer/producer, with great performance. 项目地址: https://gitcode.com/gh_mirrors/py/pykafka 想要为PyK…...
