На работе мы иногда пишем некоторые часто используемые библиотеки, такие как определение типа данных,cookie
Библиотека инструментов для хранения модулей и т. д., но в некоторых бизнес-сценариях требуются не все модули.
Обычно мы разбиваем эту библиотеку на несколько и создаем их отдельно.git
склад, упакованы и загружены вnpm
, что не кажется проблемой.
Но когда есть зависимости между несколькими библиотеками, проблема обнаружится, нужно упаковать и выпустить модифицированную библиотеку, а также нужно изменить номера версий всех зависимых библиотек и перевыпустить пакет.
Можно себе представить, насколько громоздким станет этот процесс, когда будет больше библиотек.
Итак, каков хороший способ решить эту проблему?LernaОн подходит для таких сценариев применения.
что такое лерна
Lerna — это инструмент для управления проектами JavaScript с несколькими пакетами с использованиемmonorepo
(Однократный репозиторий) Подход к управлению.
Все актуальноmodule
repo
, каждыйmodule
Независимый выпуск, напримерBabel,Reactа такжеjestИ т. Д.), Проблема и PR сосредоточены в репо.
Вам не нужно вручную поддерживать зависимости каждого пакета.При выпуске номер версии соответствующего пакета будет автоматически обновлен и выпущен автоматически.
Структура файла проекта Lerna:
├── lerna.json
├── package.json
└── packages
├── package-a
│ ├── index.js
│ └── package.json
└── package-b
├── index.js
└── package.json
что в основном делает lerna
- пройти через
lerna bootstrap
Команда устанавливает зависимости и переносит кодовую базу вnpm link
. - пройти через
lerna publish
Публикация последних изменений в библиотеке
как использовать
Установить
npm install --global lerna
#or
yarn global add lerna
инициализировать проект
mkdir demo
cd demo
lerna init
После выполнения будет сгенерирован следующий каталог:
├── lerna.json # lerna配置文件
├── package.json
└── packages # 包存放文件夹
В Lerna есть два режима управления проектами: фиксированный режим или автономный режим.
Фиксированный режим
Фиксированный режим является режимом по умолчанию, номер версии используетlerna.json
в файлеversion
Атрибуты. воплощать в жизньlerna publish
Когда код обновляется, значение этого номера версии автоматически обновляется.
Автономный режим
Независимый режим, который позволяет сопровождающим независимо увеличивать и изменять версию каждого пакета.Каждый раз, когда пакет выпускается, всем измененным пакетам будет предложено ввести указанный номер версии.
Как использовать:
lerna init --independent
Исправлять
lerna.json
серединаversion
значениеindependent
{
"npmClient": "yarn", // 执行命令所用的客户端,默认为npm
"command": { // 命令相关配置
"publish": { // 发布时配置
"ignoreChanges": ["ignored-file", "*.md"], // 发布时忽略的文件
"message": "chore(release): publish" // 发布时的自定义提示消息
},
"bootstrap": { // 安装依赖配置
"ignore": "component-*", // 忽略项
"npmClientArgs": ["--no-package-lock"] // 执行 lerna bootstrap命令时传的参数
}
},
"packages": [ // 指定存放包的位置
"packages/*"
],
"version": "0.0.0" // 当前版本号
}
ОбщийdevDependencies
babel
,eslint
и другие модули, большинство из которых можно использовать совместно,
мы можем пройтиlerna link convert
команда для автоматического размещения их в корневом каталогеpackage.json
Файл.
Таким образом, версия каждой зависимости может быть гарантированно унифицирована, а пространство для хранения может быть уменьшено, а скорость установки зависимости может быть снижена.
Уведомление:Немногоnpm
Исполняемые пакеты по-прежнему необходимо устанавливать в пакеты, которые используют модули для правильного выполнения, напримерjest
.
Использование рабочих областей пряжи
Рабочие пространства — это новый способ настройки архитектуры пакетов, и их нужно запускать только один раз.yarn install
Все зависимости в указанном рабочем пространстве могут быть установлены все.
Преимущество
- Зависимые пакеты могут быть связаны друг с другом, что означает, что ваши рабочие области могут зависеть друг от друга, всегда используя последний доступный код. Это также
yarn link
Лучший механизм, потому что он влияет только на дерево зависимостей вашего рабочего пространства, а не на всю систему. - Все зависимости проекта будут установлены вместе, что позволит Yarn лучше их оптимизировать.
- Yarn будет использовать один файл блокировки вместо одного для каждого пакета, что означает меньше конфликтов и более простую проверку кода.
как использовать
существуетpackage.json
Добавьте следующее в файл:
package.json
{
"private": true,
"workspaces": ["packages/*"]
}
Уведомление:private: true
Нужноlerna.json
Добавьте в файл следующую конфигурацию, чтобы включить рабочие области пряжи:
{
"useWorkspaces": true
}
Создать модуль
lerna create package-a
Выполните приведенную выше команду, она будет вpackage
Создайте модули в папке и создайте соответствующие модули в соответствии с интерактивными подсказками.package.json
.
Сгенерированная структура каталогов выглядит следующим образом:
├── lerna.json
├── package.json
└── packages
└── package-a
├── __tests__
│ └── name.test.js
├── lib
│ └── name.js
├── package.json
└── README.md
добавить зависимости
модульpackage-a
добавить вpackage-b
зависимость модуля
larna add package-a --scope=package-b
После завершения добавления будетpackage-b
изpackage.json
Добавьте следующие зависимости в
{
"dependencies": {
"package-a": "file:../package-a"
}
}
использование зависимости пакетаfile:
чтобы указать локальный путь к файлу
выпускать
При публикации необходимо предоставитьcommit
код, затем выполнитьlerna publish
Выберите здесьPatch
1.0.1
.
Затем выберите Подтвердить в соответствии с приглашением для успешной публикации.
также можно использоватьlerna publish -y
Выбрать все по умолчаниюYes
, и согласноcommit
Информация автоматически обновляет номер версии.
Lerna Changelog
lerna
сгенерированныйChangelog
функция, ее нужно только сгенерировать с помощью простой конфигурацииCHANGELOG.md
документ.
Конфигурация выглядит следующим образом:
{
"command": {
"publish": {
"allowBranch": "master", // 只在master分支执行publish
"conventionalCommits": true, // 生成changelog文件
"exact": true // 准确的依赖项
}
}
}
После настройки, когда мы выполняемlerna publish
После этого он будет находиться в корневом каталоге проекта и каждыйpackages
упаковать, сгенерироватьCHANGELOG.md
.
Уведомление:только встретитьсясоглашениеизcommit
Отправить для правильной генерацииCHANGELOG.md
документ.
commit
дляfix
Это будет автоматически обновленная версия;
еслиfeat
Автоматическое обновлениедополнительный номер версии;
Изменить, если есть критические измененияосновной номер версии.
Lerna интегрируется с Jest
Перед выпуском пакета для обеспечения качества кода необходимо написать модульные тесты.Для повышения эффективности и облегчения запуска тестов мы хотим добиться следующих функций:
- Все пакеты поддерживают только один общий файл конфигурации jest.
- Может запускать все модульные тесты в целом
- Модульные тесты можно выполнять только для определенного пакета.
шутливая конфигурация
Настроен в корневом каталоге проектаjest.config.js
Файлы следующие:
const path = require('path')
module.exports = {
collectCoverage: true, // 收集测试时的覆盖率信息
coverageDirectory: path.resolve(__dirname, './coverage'), // 指定输出覆盖信息文件的目录
collectCoverageFrom: [ // 指定收集覆盖率的目录文件,只收集每个包的lib目录,不收集打包后的dist目录
'**/lib/**',
'!**/dist/**'
],
testURL: 'https://www.shuidichou.com/jd', // 设置jsdom环境的URL
testMatch: [ // 测试文件匹配规则
'**/__tests__/**/*.test.js'
],
testPathIgnorePatterns: [ // 忽略测试路径
'/node_modules/'
],
coverageThreshold: { // 配置测试最低阈值
global: {
branches: 100,
functions: 100,
lines: 100,
statements: 100
}
}
}
Пишите тестовые скрипты
новыйscripts
папка, добавитьtest.js
документ:
const minimist = require('minimist')
const rawArgs = process.argv.slice(2)
const args = minimist(rawArgs)
const path = require('path')
let rootDir = path.resolve(__dirname, '../')
// 指定包测试
if (args.p) {
rootDir = rootDir + '/packages/' + args.p
}
const jestArgs = [
'--runInBand',
'--rootDir', rootDir
]
console.log(`\n===> running: jest ${jestArgs.join(' ')}`)
require('jest').run(jestArgs)
Скрипт работает, анализируя аргументы командной строки-p
Для определения выполнения тестовых случаев указанный пакет, если не указан-p
Параметры выполняются, и все тестовые случаи выполняются.
Измените корневой каталогpackage.json
изscript
Добавьте следующую команду:
{
"scripts": {
"ut": "node scripts/test.js"
}
}
# 执行全部测试
yarn ut
# 执行某个包测试
yarn ut -p package-a
Интеграция Lerna с веб-пакетом
При отправке посылок вам нужно будет использоватьwebpack
провестиes6
Транскодирование или сжатие, было бы обременительно поддерживать файл конфигурации для каждого из них; у нас естьjest
Те же нужды:
- только одна порция
webpack
конфигурационный файл - Все модули могут быть упакованы отдельно одновременно
- Вы также можете упаковать определенные модули по отдельности.
конфигурация веб-пакета
Создал в корневом каталогеwebpack.config.js
Файл следующим образом:
var path = require('path')
const CleanWebpackPlugin = require('clean-webpack-plugin')
module.exports = (opt) => {
return {
mode: 'production',
entry: path.resolve(opt.path, './lib/index.js'),
output: {
path: path.resolve(opt.path, './dist'),
filename: `${opt.name}.min.js`,
library: opt.name,
libraryTarget: 'umd',
umdNamedDefine: true
},
externals: opt.externals,
plugins: [
new CleanWebpackPlugin()
],
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
include: [path.resolve(opt.path, './lib')],
options: {
// 指定babel配置文件
configFile: path.resolve(__dirname, '.babelrc')
}
}
]
},
optimization: {
minimize: true
}
}
}
Этот файл конфигурации представляет собой функцию, которая возвращает окончательное содержимое конфигурации, принимая объект параметра,
Пишите скрипты сборки
Идеи:
- читать
packages
Каталог всех модулей, путь к модулю сбора -
package.json
,Получатьname
Зависимость - Путь через модуль, имя пакета и
package.json
серединаdependencies
webpack
настроить - пройти через
webpack
изNode API
Выполнить настройку, скомпилировать и упаковать - По параметрам командной строки определить конфигурационный файл, который необходимо запаковать (упаковать отдельно)
Конкретная реализация выглядит следующим образом:
/scripts/build.js
const minimist = require('minimist')
const rawArgs = process.argv.slice(2)
const args = minimist(rawArgs)
const webpack = require('webpack')
const webpackConfig = require('../webpack.config')
const fs = require('fs')
const path = require('path')
const packages = fs.readdirSync(path.resolve(__dirname, '../packages/'))
// 获取外部依赖配置
function getExternals (dependencies) {
let externals = {}
if (dependencies) {
Object.keys(dependencies).forEach(p => {
externals[p] = `commonjs ${p}`
})
return externals
}
}
const packageWebpackConfig = {}
// 遍历所有的包生成配置参数
packages.forEach(item => {
let packagePath = path.resolve(__dirname, '../packages/', item)
const { name, dependencies } = require(path.resolve(packagePath, 'package.json'))
packageWebpackConfig[item] = {
path: packagePath,
name,
externals: getExternals(dependencies)
}
})
function build (configs) {
// 遍历执行配置项
configs.forEach(config => {
webpack(webpackConfig(config), (err, stats) => {
if (err) {
console.error(err)
return
}
console.log(stats.toString({
chunks: false, // 使构建过程更静默无输出
colors: true // 在控制台展示颜色
}))
if (stats.hasErrors()) {
return
}
console.log(`${config.name} build successed!`)
})
})
}
console.log('\n===> running build')
// 根据 -p 参数获取执行对应的webpack配置项
if (args.p) {
if (packageWebpackConfig[args.p]) {
build([packageWebpackConfig[args.p]])
} else {
console.error(`${args.p} package is not find!`)
}
} else {
// 执行所有配置
build(Object.values(packageWebpackConfig))
}
затем в корневой каталогpackage.json
изscript
Добавьте следующую команду:
{
"scripts": {
"build": "node scripts/build.js"
}
}
Запустите скрипт сборки:
# 全部打包
yarn build
# 指定打包
yarn build -p package-a
Слишком далеко,Lerna
Представлен метод использования.
Front-end команда Shuidihuzhu набирает партнеров.Присылайте свое резюме на почтовый ящик: fed@shuidihuzhu.com