从npm版本依赖到Monorepo大仓项目

简介: 前端的发展很快,自从node.js的出现,打开前端新的大门,npm让js有了自己的包管理能力,能够让前端项目工程化,从而能够处理更加复杂的前端项目。

背景


前端的发展很快,自从node.js的出现,打开前端新的大门,npm让js有了自己的包管理能力,能够让前端项目工程化,从而能够处理更加复杂的前端项目。

但是随之而来的是,同一个项目的npm依赖越来越多,有些是开源的,有些是自研的,尤其在同一个团队,当你开发一个新的npm包的时候,只是为了服务特定几个项目,但是这几个项目不在你管理范围内,当你需要更新的时候需要通知到他们,有时候会出现版本依赖问题,然后反复沟通和测试,最终达到协调。但是下次更新的时候又再次遇到这个问题,重复一次。

npm依赖


npm是什么


npm,Node Package Manager的缩写,也就是“Node的包管理器”。 npm(“Node 包管理器”)是 JavaScript 运行时 Node.js 的默认程序包管理器。

通俗的说,npm是管理js包的工具,它包括以下几个部分:

  1. npm源,存放各类npm包的网站,可以注册,上传npm包
  2. npm-cli 命令工具,允许你自由下载任何npm包

npm如何管理包


那么npm是如何管理包的呢?主要项目下package.json对npm进行描述,主要有以下几个属性:

  • name:JavaScript 项目或库的名称。
  • version:项目的版本。
  • scripts: 当作在项目本地运行的命令行工具
  • dependencies:当项目被人依赖的时候,需要安装的npm包,描述:npm包名: npm包版本
  • devDependencies:本地开发的时候,需要安装的npm包,描述:npm包名: npm包版本

同时package-lock.json文件描述了 npm JavaScript 项目中使用的依赖项的确切版本,确保下次安装项目依赖的npm包升级版本后导致项目无法运行(这个是很多新手安装npm包的时候会遇到的一个错误)。

npm版本


npm包版本遵循major.minor.patch版本模型规范,什么是major.minor.patch版本模型规范,下面引用一下说明:

APR版本规范,major是当前的主版本号,minor则是次版本号,patch对应的则是APR的补丁号,同时还有版本所处阶段base, alpha, beta, RC, release

因此在package.json描述的依赖npm包的版本号,如:~1.0.0^1.0.0,几个符号代表的意思如下:

  • ^:表示最新的次版本,例如, ^1.0.4  可能会安装主版本系列  1 的最新次版本 1.3.0
  • :表示最新的补丁程序版本,与  ^  类似, 〜1.0.4  可能会安装次版本系列 1.0  的最新次版本1.0.7

npm包版本依赖问题


即使有package-lock.json或者yarn.lock等约束文件解决项目依赖包的版本的问题,但是当项目越来越庞大,拆分的公共npm包越来越多,这些npm管理难度和数量成正比提升,团队需要面临npm包版本问题也越来越多,尤其当微前端概念提出,当大项目被拆分成N个子项目的时候,团队成员需要面临以下几个问题:

  • 公共包npm更新了,如何通知到其他子项目依赖的npm包更新版本
  • 子项目有些公共的代码需要抽象到公共一起维护,是抽离成npm包,但是又需要新起一个项目
  • 公共npm越来越多,子项目也越拆越多,如何管理这些项目的开发、测试和持续发布
  • 其他各种开发细节问题...

因此,大家迫切需要去一个标准去统一维护管理这些项目,因此Monorepo统一项目管理规范,就是我们的最佳选择。

Monorepo


是什么


Monorepo是包含多个不同项目的单一存储库,具有明确定义的关系。

通俗的讲,Monorepo就是将几个不同项目放到一个git仓库里,通过制定一个大家遵循的管理规范和子项目之间依赖关系。

Monorepo大仓项目与monolithic单体巨石项目还是有很大的区别,下面简单说明:

  • 1.Monorepo !== 单体巨石项目,monorepos 简化了代码共享和跨项目重构,它们显着降低了创建库、微服务和微前端的成本,不需要做到一起发布
  • 2.能够有效解决子项目与子项目的之间版本依赖关系,而不是单纯将几个项目放在一起形成一堆代码山

为了更好的了解Monorepo大仓,可以和对立面Polyrepo多个标准式项目 作对比:

7324f33e75533891abab328798f1506.png

monorepo 工具


Monorepos 有很多优势,但要使它们发挥作用,您需要拥有合适的工具。随着工作空间的扩大,工具必须帮助您保持快速、易于理解和管理。

市面上主流的Monorepo管理工具有:

  • Bazel(谷歌)
  • Gradle Build Tool(Gradle, Inc)
  • Lage(微软)
  • Lerna
  • Nx(Nrwl)
  • Pants(Pants Build 社区)
  • Rush(由 Microsoft)
  • Turborepo(由 Vercel)

工具应该具备以下几点能力:

  • 1.本地计算缓存,能够提供本地构建缓存、单元测试缓存等能力
  • 2.本地任务编排,能够以正确的顺序并行运行任务
  • 3.分布式计算缓存,跨不同环境共享缓存工件的能力。这意味着你的整个组织,包括 CI 代理,永远不会构建或测试相同的东西两次。
  • 4分布式任务执行,在多台机器上分发命令的能力,同时在很大程度上保留在单台机器上运行它的开发人体工程学。
  • 5.透明远程执行,在本地开发时在多台机器上执行任何命令的能力。
  • 6.检测受影响的项目/包,确定更改可能会影响什么,以仅运行构建/测试受影响的项目。
  • 7.工作区分析,无需额外配置即可理解工作区项目图的能力。
  • 依赖图可视化,可视化项目和/或任务之间的依赖关系。可视化是交互式的,这意味着您可以搜索、过滤、隐藏、聚焦/突出显示和查询图中的节点。
  • 8.源码分享,促进分散的源代码片段的共享。
  • 9.一致的工具,无论您使用什么来开发项目,如JavaScript 框架、Go、Rust、Java 等,工具都可以帮助您获得一致的体验
  • 10.代码生成,本机支持生成代码
  • 11.项目限制和可见性,支持定义规则以限制 repo 中的依赖关系。例如,开发人员可以将某些项目标记为他们团队的私有项目,这样其他人就无法依赖它们。开发人员还可以根据使用的技术(例如 React 或 Nest.js)标记项目,并确保后端项目不会导入前端项目。

monorepo单一原则


单一原则指的是单一版本(One Version)原则,具体定义如下:

单一版本(One Version)原则,是指在任意时间,代码库内的每一份组件、每一个依赖只有一个版本。

对内部库而言,这意味着使用主干开发(见下),并且必须在主干 HEAD 上依赖。这是一个非常强的约束——这意味着除了终端制品,任何一个内部被依赖的库都不能通过分支发布,而必须保持自己在单仓的主干上一直是发布状态。

对外部依赖而言,同一个第三方库在单仓中永远只会引入一个版本。

为什么?

因为原来的git flow开发流,从feature->dev->master,每个分支里面的依赖版本都可能会不一样,从而导致依赖版本难以维护。

monorepo挑战


  • 并非所有服务都适用于 monorepos
  • 需要更复杂的 CI 设置
  • 需要考虑代码架构大规模的改变

monorepo实战


作为前端开发者,Lerna框架是肯定要尝试一番,同时功能比较齐全的Nx框架要去体验一番。

但是其实两者的关系非常紧密,都是同一个公司Nrwl开发的,所以有很多类似点。

Lerna


快速开始安装

npx lerna init

PS: npx是什么?

  • npx:Node Package Execute 即node包执行器
  • npx 是npm v5.2.0版本之后随npm 一起打包安装的一个包执行器。
  • 它会自动去寻找二进制命令文件且不必全局安装依赖包。
  • npx 可以在不指定项目中的确切位置或使用别名的情况下运行正确版本的工具,比如npx lerna init命令会执行去npm源安装lerna-cli命令工具到本地,然后执行lerna init命令

安装完以后,项目的初始化架构如下:

packages/
    header/
        src/
            ...
        package.json
        rollup.config.json
        jest.config.js
    footer/
        src/
            ...
        package.json
        rollup.config.json
        jest.config.js
    remixapp/
        app/
            ...
        public/
        package.json
        remix.config.js
package.json
lerna.json # 需要自己手动新建, 用来描述

修改package.json,去添加一个npm/yarn/pnpm workspace

{
  "name": "root",
  "private": true,
  "workspaces": ["packages/*"],
  "devDependencies": {
    "lerna": "6.0.1"
  }
}

常用的命令


  • lerna run xxx: 统一执行所有子项目的scripts命令,如:lerna run build
  • npx nx graph:查看项目依赖图
  • npx lerna add-caching:设置子项目的一些缓存设置,会在根目录下生成nx.json
  • npx lerna publish --no-private: 统一发布npm包
  • npx lerna run xxx --scope=header:允许只针对某个子项目header执行命令

其他命令可以到官网查看, Lerna命令

NX


官网里定义是:

NX是一个智能、快速和可扩展的构建系统,具有一流的Monorepo支持和强大的集成。

实战步骤如下:

创建一个新工作区:

npx create-nx-workspace@latest package-based --preset=npm

然后在packages创建自己的子项目:

package-based/
├── packages/
│   └── is-even/
│       ├── index.ts
│       └── package.json
│   └── is-odd/
│       ├── index.ts
│       └── package.json
├── nx.json
└── package.json

接下来就是配置 nx.json,子项目之间的依赖,已经任务执行顺序:

// nx.json
{
  ...
  "targetDefaults": {
    "build": {
      "dependsOn": ["^build"]
    }
  }
}

执行构建命令npx nx build is-odd 可以看到要先构建is-event项目

最后是构建全部项目npx nx run-many --target=build

CI/CD构建流程改造


这个按照各自团队的CI/CD构建流程去改造,但是主要有以下几点:

  • CI/CD流水线职责分离
  • 统一镜像NPM凭证管理
  • 手动触发CD流水线发布,使用统一版本进行管理发布

参考资料


Monorepo Explain

目录
相关文章
|
3月前
|
缓存 资源调度 持续交付
在清空NPM缓存后,检查是否所有依赖都已正确安装
在清空NPM缓存后,检查是否所有依赖都已正确安装
|
1月前
|
移动开发 小程序 数据可视化
基于npm CLI脚手架的uniapp项目创建、运行与打包全攻略(微信小程序、H5、APP全覆盖)
基于npm CLI脚手架的uniapp项目创建、运行与打包全攻略(微信小程序、H5、APP全覆盖)
213 3
|
1月前
|
缓存 资源调度 持续交付
在清空NPM缓存后,我如何检查是否所有依赖都已正确安装?
【10月更文挑战第5天】在清空NPM缓存后,我如何检查是否所有依赖都已正确安装?
|
25天前
|
缓存 前端开发 JavaScript
前端架构思考:代码复用带来的隐形耦合,可能让大模型造轮子是更好的选择-从 CDN 依赖包被删导致个站打不开到数年前因11 行代码导致上千项目崩溃谈谈npm黑洞 - 统计下你的项目有多少个依赖吧!
最近,我的个人网站因免费CDN上的Vue.js包路径变更导致无法访问,引发了我对前端依赖管理的深刻反思。文章探讨了NPM依赖陷阱、开源库所有权与维护压力、NPM生态问题,并提出减少不必要的依赖、重视模块设计等建议,以提升前端项目的稳定性和可控性。通过“left_pad”事件及个人经历,强调了依赖管理的重要性和让大模型代替人造轮子的潜在收益
|
2月前
|
JavaScript
使用npm,快速构建第一个vue项目
本文介绍了如何使用npm快速构建第一个Vue项目。步骤包括确保安装了Node.js并且配置了正确的环境变量,创建一个空文件夹并使用VSCode打开,通过VSCode的终端执行`npm init vue@latest`命令以初始化项目,选择默认配置即可。接着安装项目依赖并启动开发服务器,最后通过浏览器访问开发服务器提供的本地地址查看项目运行结果。文章还提供了相关代码和操作截图。
|
2月前
|
缓存 JavaScript 前端开发
8种方法解决vue创建项目报错:command failed: npm install --loglevel error
该文章提供了八种解决Vue项目创建时遇到的`command failed: npm install --loglevel error`错误的方法,包括清理缓存、更换npm源、重新安装Node.js等措施。
8种方法解决vue创建项目报错:command failed: npm install --loglevel error
|
3月前
|
缓存 资源调度 持续交付
在清空NPM缓存后,如何检查是否所有依赖都已正确安装
在清空NPM缓存后,如何检查是否所有依赖都已正确安装
|
3月前
|
缓存 JavaScript 前端开发
成功解决:npm 版本不支持node.js。【 npm v9.1.2 does not support Node.js v16.6.0.】
这篇文章介绍了如何解决npm版本与Node.js版本不兼容的问题,提供了查看当前npm和Node.js版本的步骤,以及如何根据Node.js版本选择合适的npm版本并进行升级的详细指导。
成功解决:npm 版本不支持node.js。【 npm v9.1.2 does not support Node.js v16.6.0.】
|
4月前
|
运维 Kubernetes Java
阿里云云效操作报错合集之npm包已经发布到了制品仓库,但流水线中拉取依赖时出现404错误,该如何排查
本合集将整理呈现用户在使用过程中遇到的报错及其对应的解决办法,包括但不限于账户权限设置错误、项目配置不正确、代码提交冲突、构建任务执行失败、测试环境异常、需求流转阻塞等问题。阿里云云效是一站式企业级研发协同和DevOps平台,为企业提供从需求规划、开发、测试、发布到运维、运营的全流程端到端服务和工具支撑,致力于提升企业的研发效能和创新能力。
阿里云云效操作报错合集之npm包已经发布到了制品仓库,但流水线中拉取依赖时出现404错误,该如何排查
|
3月前
|
存储 安全 Java
阿里云云效产品使用合集之怎么设置使用npm私有仓库进行流水线拉取依赖
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。