Monorepo - режим разработки многоупаковочного единого склада

Архитектура
Monorepo - режим разработки многоупаковочного единого склада

1. Введение

What Is a Monorepo?: Monorepo is a unified source code repository used by an organisation to host as much of its code as possible.

MonorepoЭто способ управления командным кодом, который отказывается от одного модуля и одного склада и вместо этого максимально управляет всеми модулями в одном складе.

В процессе командной разработки мы обычно создаем несколько репозиториев для управления разными проектами, но поскольку между каждым проектом существует взаимная ссылка, у нас будет много проблем каждый раз, когда мы его модифицируем.Мы используем пакет Package A и Это, например, зависимости пакета пользовательского интерфейса, их процесс разработки должен быть таким:

mutilrepo的开发流

Разумеется, в этот процесс также вовлечено управление разрешениями на хранение и публикацию.UI PackageЧтобы соответствовать требованиям, он должен получить тест-набор,npm installЭтот эффект можно увидеть только локально, если он все же захочет его проверитьconsole.logЧтобы увидеть эффект, он может только побеспокоить Джерри, чтобы он добавил в код новый пакет.

Итак, если мы используем режим Monorepo для разработки, какой будет эффект:

monorepo开发流

Нашим одноклассникам Тому нужно только подтянуть ветку, которую разрабатывает Джерри, к локалке, и написать что хотят.

Прежде чем начать его использовать, выслушайте минусы

  • По мере того, как проект повторяется,Monorepoкаждый изpackageбудет огромным и сложной задачей для создания инструментов. (Существующие в настоящее время решения: такие как GoogleBazel, ФейсбукBuckи твиттерPants, но ни один из них не поддерживается должным образомJSПакет)
  • Поскольку проекты взаимозависимы, вы всегда должны обеспечивать хорошую структуру кода, спецификации компиляции и тестовые примеры.
  • В дополнение к проблемам с инструментом сборки, когда проект достигает определенного размера, IDE может столкнуться с поломкой.

Конечно, такие какBabel,React,Vue-nextи так далее известные проекты с открытым исходным кодом используютMonorepoСпособ управления исходным кодом, когда вы в это время не садитесь в машину.

Команда Babel высказала свое мнение:Why is Babel a monorepo?

2. Рабочее пространство lerna & yarn — зрелое решение для управления Menorepo

2-1."Уху, взлетай" - инициализация проекта

Сначала воспользуемсяlernaдля инициализации проекта:

// Step 1
npm install -g lerna

// Step 2
git init learn-lerna

// Step 3
cd learn-lerna && lerna init

После запуска мы видимlearn-lerna/В папке будет создана следующая структура:

вlerna.jsonдляlernaфайл конфигурации,packages/Папка для хранения проекта. На основании плана последующего автоматизированного построения создаем новый в корневом каталогеexamplesпапку, что касается причин и преимуществ этого, давайте медленно посмотрим вниз.

Открытьlerna.json, добавьте некоторую конфигурацию:

{
  // 定义各个项目存放的位置,这里我们新增一个examples/
	"packages": ["packages/*", "examples/*"],
  // 当前的版本号
  "version": "0.0.0",  
  /* 以下为新增 */
  // 执行命令的client,默认为npm,这里我们需要配置为yarn
	"npmClient": "yarn",
  // 是否使用workspace工作模式
	"useWorkspaces": true
}

дляlernaПо своей основной функции этоконтроль версийа такжевыпускать, поэтому он также должен соответствоватьnpm,yarnа такжеgitиспользоваться вместе. в то же время,lernaТакже поддерживаются фиксированные/заблокированные и независимые режимы:

  • Фиксированный режим (по умолчанию): все пакеты имеют общий номер версии, и выпуск будет записан в корневой каталог после каждого выпуска.changelogсередина
  • Автономный режим: каждый пакет управляет своей версией

из-заUI Packageа такжеUtils PackageКак правило, он выпускается самостоятельно, поэтому нам нужно вручную настроить проект в независимый режим (изменить конфигурацию вversionизменить наindependentЕсли вы хотите узнать больше о разнице между этими двумя режимами, вы можете обратиться кlernaОфициальная документацияРазница между фиксированным режимом и независимым режимом.

несмотря на то чтоlernaВы также можете установить некоторые зависимости (фактически функция его установки будет переданаyarnилиnpmобработки), но поскольку он не может выполнять такие задачи, как сборка и тестирование, мы предпочитаем, чтобы он сосредоточился на контроле версий и выпуске в сочетании сnpmа такжеyarnдля выполнения других задач

открыть следующийpackage.json, настроим наше рабочее пространство:

{
  "name": "root",
  "private": true,
  "devDependencies": {
    "lerna": "^3.22.0"
  },
  /*新增,定义工作区*/
  "workspaces": [
    "packages/*",
    "examples/*"
  ]
}

дляyarnЧто касается этого, помимо того, что это инструмент управления пакетами, время установки зависимостей больших проектов будет медленнее, чемnpmбыстрее, покаyarnизначально поддерживаетсяMonorepoРежим управления пакетами, который также позволяет нам более плавно устанавливать зависимости (будь то локальные или удаленные).

Monorepo工具的功能交集:红色部分的`yarn workspace`和`lerna`都可以作为`Monorepo`的管理工具,但他们都依赖`yarn`或`npm`

Подводя итог, мы рекомендуем использоватьlernaВ качестве инструмента управления выпуском и контролем версий используйтеyarn+yarn workspaceСведения об инструментах управления пакетами, сборки и тестирования, а также о дополнительных преимуществах этой опции см.Why Lerna and Yarn Workspaces is a Perfect Match for Building Mono-Repos?.

2-2, "вверх, вниз, влево и вправо БАБА" - установление многопакетных зависимостей

Далее мыpackegs/инициализирован вuiтак же какutilsпроект, вexamples/инициализирован вblogпроект:

目录结构

Тогда это нашyarn workspaceВыходите на сцену, добавьте зависимости для каждого пакета:

  • Добавить внешние зависимости

    // 为 blog 添加 react、react-dom 依赖
    yarn workspace blog add react react-dom --save
    
  • добавить локальные зависимости

    Следует отметить, что при добавлении локальных зависимостей нам нужно добавить номер версии после пакета, иначеyarnбудет искать удаленный реестр вместо пакетов рабочей области

    // 为 blog 添加 本地依赖,@zg/ui 为包名
    yarn workspace blog add @zg/ui@1.0.0 --save
    
  • добавить глобальные зависимости

    // 为全局添加 babel dev依赖
    yarn add -W babel --dev
    

удалить операцию, нужно толькоaddизменить наremoveВот и все.

После этих операций мы можем обнаружить, что все зависимости устанавливаются не в каждый проект отдельно, аnode_modulesУнифицированное управление в корневом каталоге, эффективно избегающееЗависит от повторной установкипроблема; в то время как наши локальные зависимостисимволическая ссылкасоответствуетpackages/Каждый предмет:

多包依赖

2-3."Вино вставляй, пей не переставай" - добавление строительных инструментов

构建与编译

дляbabelВ настоящее время в Интернете есть различные зрелые конфигурации, поэтому я не буду их здесь повторять. И дляMonorepoС точки зрения проектов, мы действительно можем использоватьbabelизoverridesСвойства для индивидуальной настройки для каждого проекта:

// .babelrc
{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react"
  ],
  // 为每个项目进行个性化配置
  "overrides": [
    {
      "test": ["packages/ui"],
      "plugins": [
        ["import", {
          "libraryName": "antd",
        	"libraryDirectory": "es",
        	"style": "css"
        }]
      ]
    },
    {
      "test": ["packages/utils"],
      "plugins": [
        ["module-resolver", {
        	"alias": { "~": "./src/scripts" }
      	}]
      ]
    }
  ]
}

В передней мы продали пропуск и установили два рабочих местаpackages/а такжеexamples/. Я полагаю, что некоторые студенты увидели подсказку, мы находимся вpackages/Хранится вuiа такжеuitls, экспортируются как статические библиотеки, а вexamples/, мыSPAзаявлениеblog. Поскольку они предназначены для размещения в разных рабочих областях, мы можем использовать разные инструменты для этого разделения. противSPAприложение, нам нужны инструменты, которые могут поддерживать горячую замену модуля (HMR), чтобы помочь нам в разработке, поэтому мы можем использоватьwebpackУпаковка; для разработки статических библиотек мы выбираем более быструю упаковку и меньший объем сжатия.rollupjsстроить.

о большемrollupа такжеwebpackРазницу можно ткнуть по этой ссылке:Сводка: инструмент упаковки модулей ES следующего поколения.

дляrollupjsа такжеwebpackНастройка здесь не повторяется, можете сами погуглить. (ноrollupjsСоотношение пакетного анализаwebpackВыглядит намного лучше, нагляднее и понятнее)

Rollup的构建分析

И для позиции написания сценария,lernaа такжеyarn workspacesДанные предложения хранятся в корневом каталогеscripts/В папке:

脚本的存放位置,统一在根目录下管理

2-4, «Миссия завершена» — обновление версии и выпуск

  • обновление новой версии--lerna version

    lerna versionМожет легко помочь нам управлятьpackages/Записи об отправке версий каждого пакета в файле будут автоматически генерироваться в каждом каталоге пакета.changelog.

    Первое, что мы должны сделать, это следоватьОбщие требования к представлениюпровестиgit commit, конечно, более рекомендуется использоватьgit czСделайте форматированную отправку и выполните следующую команду после завершения отправки:

    // 根据commit提交信息自动生成package版本
    lerna version --conventional-commits
    

    Следующий,lernaСогласно нашим записям о представлении, преобразование будет осуществляться в соответствии со следующими правилами:

    тип фиксации Соответствующее преобразование номера версии (номер версииMAJOR.MINOR.PATCH)
    fix PATCHВыпуск + 1
    feat MINORВыпуск + 1
    BREAKING CHANGE Независимо от типа, он будет преобразован вMAJORВыпуск + 1

    lerna vserion

    нужно знать, это:

    1. дляlernaДругими словами, независимо от того, установлен ли он в независимый режим (независимый) или в фиксированный режим (фиксированный/заблокированный), при изменении пакета другие пакеты, зависящие от пакета, обновят его версию. Разница между двумя режимами в том, чтоMAJORРавномерно ли количество релизов.

    2. BREAKING CHANGEнужно написать вcommitизbodyилиfooterНачало, когда вы выполняетеgit commitдолжен быть в следующем формате:

      <type>(<scope>): <subject>
      // 空一行
      <body>
      // 空一行
      <footer>
      

      При использованииgit czОтправить, вы можете следовать инструкциям, чтобы автоматически выбрать, нужно лиBREAKING CHANGE

  • выпускать--lerna publish

    После вышеперечисленных операций мы отправили изменения в удаленный репозиторий, и вот, наконец, настал этот волнующий момент.

    Конечно, осведомленность об авторских правах не может быть меньше, нам нужно сначалаВыберите лицензию с открытым исходным кодом, и соответствующийLICENSEУстанавливается в корневой каталог проекта.

    Тогда, если вы опубликуетеscope package,Прямо сейчас@xxx/some-packageпакет формата, который должен быть включен в каждый пакетpackage.jsonПрисоединяйсяpublishConfig:

    {
      "name": "@xxx/some-package",
      "version": "2.0.0",
      "main": "index.js",
      "license": "MIT",
      /*以下为新增*/
      "publishConfig": {
        //指定范围包的访问权限 不设置public,就付钱升级npm账号吧!
    		"access": "public",
    		//指定发布的目录 可以配合.npmignore
    		"directory": ""
    	}
    }
    

    Наконец, вам нужно использоватьnpm loginвойти или использоватьnpm whoamiОпределите, успешно ли вы вошли в систему. Если проблем нет, торжественно введите следующую команду:

    lerna publish from-package
    

    Примечание: если вы используетеscope, убедитесь, что ваши организации ужеNPM, иначе вы можете столкнуться с такой ошибкой 403:

    lerna publish error

    Если он зарегистрирован, давайте сделаем это сноваpublishинструкция:

    版本发布

    Таким образом, мы успешно публикуем все пакеты в рабочей области наNPMНу давай же.

    Готово! 🎇🎉🎈🎈🎈🎉🎇

3. Резюме

MonorepoКонцепция , обеспечивает новый способ мышления для нашего развития Когда дело доходит до плюсов и минусов, разработчики должны учитывать прибыль и убытки. На самом деле, для примера в начале этой статьи вы также можетеMultirepoна основании прохожденияnpm-linkРешить, но неlerna + yarn workspacesЭто элегантно, с плавным процессом сборки и отладки и автоматизированнымchangelogВыпущено с обновлениями версии.