8分钟阅读

MonorePos指南前端代码

Alexander是一家经验丰富的前端开发人员,建立了电子商务和企业网站以及Web和移动应用程序。

mon是一个讨论的热门话题。最近有很多文章是关于为什么你应该也不应该使用这种类型的架构来为您的项目使用,但大多数人都以某种方式偏见。本系列是尝试收集和解释尽可能多的信息,以了解如何以及何时使用Monorepos。

A MonorePository. 是一个架构概念,基本上包含其标题中的所有含义。您可以在一个存储库中保留所有孤立的代码部分,而不是管理多个存储库。记住这个词 隔离的-it意味着Monorepo与单片应用程序没有任何共同之处。您可以在一个回购内保存多种逻辑应用程序;例如,网站及其iOS应用程序。

Monorepo,单次repo和多回收的比较

这个概念比较古老,大约十年前出现了。谷歌是第一批采用这种管理其码级方法的公司之一。你可能会问,如果它已经存在了十年,那么为什么现在只是一个如此热门话题?主要是,在过去的5 - 6年的过程中,许多事情发生了巨大的变化。 ES6,SCSS预处理器,任务管理器,NPM等 - 现在,要维护基于事故的应用程序,您必须处理Project Bundlers,Test Suites,CI / CD脚本,Docker配置以及谁知道其他内容。现在想象一下,而不是一个小型应用程序,你需要维护一个由许多功能区域组成的巨大平台。如果您正在考虑体系结构,您将想做两个主要的东西:单独的问题并避免代码欺骗。

为了实现这一目标,您可能希望将大功能隔离为某些包,然后通过主应用程序中的单个入口点使用它们。但是你如何管理这些包裹?每个包都必须拥有自己的工作流环境配置,这意味着每次要创建新包时,您都必须配置新的环境,复制所有配置文件,等等。或者,例如,如果您必须在构建系统中更改某些内容,则必须转到每个repro,执行提交,创建拉请求,并等待每个构建,从而减慢您的速度。在这一步,我们正在遇到Monorepos。

我们只拥有自己的配置,而不是拥有许多存储库,我们将只有一个真相来源 - monorepo:一个测试套件runner,一个docker配置文件和webpack的一个配置。您仍然具有可伸缩性,机会分开关注,与常见包的代码共享,以及许多其他专业人员。听起来不错,对吧?好吧,它是。但是还有一些缺点。让我们仔细看看在野外使用Monorepo的确切优势和缺点。

MONOREPO优势:

  • 一个存储所有配置和测试的地方。 由于一切都位于一个回购内,因此您可以配置CI / CD和Bundler一次,然后重新使用Configs以在将它们发布到远程之前构建所有包。同样用于单位,E2E和集成测试 - 您的CI将能够启动所有测试,而无需处理其他配置。
  • 使用原子提交轻松重新推荐全局功能。 而不是为每个repro进行拉拔请求,而是弄清楚要建立更改的命令,您只需要制作一个原子拉出请求,该请求将包含与您正在努力工作的功能相关的所有提交。
  • 简化包发布。 如果计划在依赖于具有共享代码的另一个程序包的包内实现新功能,则可以使用单个命令执行。它是一种需要一些额外配置的函数,后来将在本文的工具审查部分中讨论。目前,有丰富的工具选择,包括Lerna,Yarn工作区和Bazel。
  • 更轻松的依赖管理。 只有一个 package.json.。无需在每次想要更新依赖项时重新安装每个回购中的依赖项。
  • 重复使用与共享包的代码,同时仍将它们隔离。 MONOREPO允许您将软件包重用其他软件包,同时将它们彼此隔离。您可以使用对远程包的引用并通过单个入口点使用它们。要使用本地版本,您可以使用本地符号链接。此功能可以通过Bash脚本或通过引入Lerna或Yarn等其他工具来实现。

Monorepo缺点:

  • 无法限制访问应用程序的某些部分的访问。 不幸的是,您无法仅分享您的MONOREPO的一部分 - 您必须访问整个代码库,这可能会导致某些安全问题。
  • 在大规模项目上工作时的Git性能不佳。 此问题仅启动仅显示 巨大的 拥有超过一百万个提交的应用程序和数百名Devs每天在同一次押金中同时进行工作。随着GIT使用定向的非循环图(DAG)来表示项目的历史,这变得特别麻烦。随着大量提交,随着历史深化的任何散步图形的命令可能会变慢。由于refs的数量(即,分支机构或标签,通过删除refs的标签来解决您不再需要的refors)以及跟踪的文件量(以及它们的权重,即使可以使用重型文件问题 git lfs.)。

    笔记: 如今,Facebook试图解决VCS可扩展性的问题 通过修补mercurial. 而且,可能很快,这并不是那么大问题。

  • 更高的建筑时间。 因为你将在一个地方拥有很多源代码,所以它将需要更多的时间来运行一切才能批准每个公关。

工具评论

管理Monorepos的一组工具不断增长,目前,在Monorepos的所有建筑系统中都很容易丢失。您可以通过使用始终了解流行的解决方案 这个回购。但是,现在,让我们快速查看现在使用JavaScript的大量使用的工具:

  • Bazel. 是谷歌的蒙诺核化的构建系统。更多关于Bazel: 令人敬畏的博基
  • 是一个javascript依赖关系管理工具,它通过工作空间支持monorepos。
  • 勒纳 是一个用于管理具有多个包的JavaScript项目的工具,构建在纱线上。

大多数工具使用了一个非常类似的方法,但有一些细微差别。

Monorepo git存储库的例证's CI/CD process

我们将深入进入Lerna工作流程以及本文第2部分中的其他工具,因为它是一个相当大的主题。现在,让我们概述内部的内容:

勒纳

此工具确实有助于处理语义版本,设置构建工作流程,推动您的软件包等。Lerna背后的主要想法是您的项目有一个包文件夹,其中包含所有孤立的代码部分。除了包,您还有一个主应用程序,例如可以居住在SRC文件夹中。 Lerna在Lerna中的所有操作都通过简单的规则 - 您遍历所有包,并对它们进行一些操作,例如,增加包版本,更新所有包的更新依赖性,构建所有包等。

使用Lerna,您有两个选择如何使用您的软件包:

  1. 不将它们推向遥控器(NPM)
  2. 将包裹推向遥控器

在使用第一种方法的同时,您能够为您的包使用本地引用,基本上并不真正关心解决它们的符号。

But if you are using the second approach, you are forced to import your packages from remote. (e.g., import { something } from @yourcompanyname/packagename;), which means that you will always get the remote version of your package. For local development, you will have to create symlinks in the root of your folder to make the bundler resolve local packages instead of using those that are inside your node_modules/. That’s why, before launching Webpack or your favorite bundler, you will have to launch lerna bootstrap,它将自动链接所有包。

在单个节点包中输入您的模块的插图

YARN最初是用于NPM包的依赖性管理器,最初不会构建以支持MONOREPOS。但在1.0版中, 纱线开发商 发布了一个调用的功能 工作区。在发布时间,它并不那么稳定,但过了一段时间,它变得可用于生产项目。

工作区 基本上是一个包装,有自己的包 package.json. 并且可以具有一些特定的构建规则(例如,单独的构建规则 tsconfig.json. 如果您在项目中使用打字条款。)。您实际上可以在不某种方式使用BASH的情况下管理纱线工作空间并具有完全相同的设置,但此工具有助于缓解安装和更新每个包依赖性的过程。

一目了然,纱线与其工作区提供以下有用功能:

  1. Single node_modules folder in the root for all packages. For example, if you have packages/package_a and packages/package_b—with their own package.json.—all dependencies will be installed only in the root. That is one of the differences between how Yarn and Lerna work.
  2. 依赖关系响应允许本地包开发。
  3. 所有依赖项的单锁密文件。
  4. Focused dependency update in case if you want to re-install dependencies for only one package. This can be done using the -focus flag.
  5. 与勒纳集成。您可以轻松地使纱线处理所有安装/次阵列,让Lerna负责发布和版本控制。这是迄今为止最受欢迎的设置,因为它需要更少的努力并且易​​于使用。

有用的链接:

Bazel.

Bazel.是大型应用程序的构建工具,可以处理多语言依赖性,并支持大量现代语言(Java,JS,Go,C ++等)。在大多数情况下,使用Bazel用于小于媒体JS应用程序是矫枉过正的,但大规模,它可能会提供很多好处,因为它的性能。

通过其性质,Bazel看起来类似于制作,Gradle,Maven和其他工具,允许基于文件构建的项目构建,其中包含构建规则和项目依赖项的描述。挥之克尔的同一个文件被称为 建造 并位于Bazel项目的工作区内。这 建造 文件使用它 星形,人类可读,高级别的构建语言,看起来很像Python。

通常,你不会与之交易 建造 因为有很多可以在网上轻松找到的水板,并且已经配置并准备好开发。每当您想要构建项目时,Bazel基本上都执行以下操作:

  1. 负荷建造 文件相关的文件。
  2. 分析 输入及其 依赖性,应用指定的构建规则,并生成一个 行动 graph.
  3. 执行 在生成最终构建输出之前输入的构建操作。

有用的链接:

结论

monorepos只是一个工具。是否有很多争论是未来与否的争论,但事实是在某些情况下,该工具以有效的方式执行其工作并处理它。在过去几年的过程中,这个工具已经发展,获得了更大的灵活性,克服了很多问题,并在配置方面删除了复杂性层。

难以弄清楚很多问题,就像糟糕的git性能,但希望,这将在不久的将来解决。

我推荐了学习为您的应用程序建立一个强大的CI / CD管道,我推荐 如何使用Gitlab CI构建有效的初始部署管道.

有关的: 增强的git流解释

理解基础知识

单片架构是什么意思?

软件开发中的单片架构意味着一种方法,您将应用程序实现为组成的一组紧密耦合的组件/功能。您不能在应用范围之外使用任何组件。

什么是源代码存储库?

存储库是存储和检索源代码的地方以安装/开发它。 Repos存储具有相关元数据的所有版本的数据,允许历史记录修订或在同一项目的单独并行版本上工作。

为什么模块化在编程中很重要?

松散耦合的代码已被证明是更可靠的,因为它允许我们在不害怕打破其他地方的情况下引入变化。这使得开发和简化重构更安全。

什么是符号链接?

Symlinks(符号链接)是参考相对或绝对路径形式的原始文件夹/文件而不是实际内容的文件。在这种情况下,它们用于影响Pathname解决方案到其适当的位置。

在JS中制作模块的最常见方式是什么?

现在将代码隔离为单独模块的最流行的方式是使用NPM包(可以通过纱线或NPM完成)。它们与自己的配置文件包装到文件夹中,然后按住远程服务器。