【第三期】使用lerna管理常用工具库

栏目: Node.js · 发布时间: 5年前

内容简介:在工作中我们有时会写一些常用的库,比如包含数据类型判断、我们通常会将这个库拆分成多个,分别创建但当多个库之间产生依赖的时候,问题就就会显露出来;你需要打包发布修改后的库,还需要修改所有依赖库的版本号,重新发包。
【第三期】使用lerna管理常用 <a href='https://www.codercto.com/tool.html'>工具</a> 库

在工作中我们有时会写一些常用的库,比如包含数据类型判断、 cookie 存储模块的工具库等,但可能在某些业务场景中,并不需要用到所有的模块。

我们通常会将这个库拆分成多个,分别创建 git 仓库,分别打包上传到 npm ,这样做看起来并没有什么问题。

但当多个库之间产生依赖的时候,问题就就会显露出来;你需要打包发布修改后的库,还需要修改所有依赖库的版本号,重新发包。

可想而知,当库多起来后,这个过程将会变得多么繁琐。

那么有什么好的方式来解决呢?Lerna正适合这样的应用场景。

lerna是什么

Lerna是一个用于管理具有多个包的JavaScript项目的工具,它采用 monorepo (单代码仓库)的管理方式。

将所有相关 module 都放到一个 repo 里,每个 module 独立发布,(例如 BabelReactjest 等),issue和PR都集中到该repo中。

你不需要手动去维护每个包的依赖关系,当发布时,会自动更新相关包的版本号,并自动发布。

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 ,可将固定模式改为独立模式运行。

lerna配置解析

{
  "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

开发过程中,很多模块都会依赖 babeleslint 等模块,这些大多都是可以共用的,

我们可以通过 lerna link convert 命令,将它们自动放到根目录的 package.json 文件中去。

这样做即可以保证每个依赖的版本统一,也可以减少存储空间,减少依赖安装的速度。

注意:一些 npm 可执行的包,仍然需要安装到使用模块的包中,才能正常执行,例如 jest

使用yarn Workspaces

工作区是设置软件包体系结构的一种新方式,只需要运行一次 yarn install 便可将指定工作区中所有依赖包全部安装。

优势

yarn link

如何使用

package.json 文件中添加以下内容:

package.json

{
  "private": true,
  "workspaces": ["packages/*"]
}
复制代码

注意: private: true 是必需的!工作区本身不应当被发布出去,所以我们添加了这个安全措施以确保它不会被意外暴露。

lerna中使用

需要在 lerna.json 文件中增加以下配置来启用yarn workspaces:

{
  "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-bpackage.json 中增加以下依赖项

{
  "dependencies": {
    "package-a": "file:../package-a"
  }
}
复制代码

包依赖使用 file: 来指定本地路径文件

发布

发布时,需要先提交 commit 代码,然后执行 lerna publish 命令,提示选择版本号:

【第三期】使用lerna管理常用工具库

这里选择 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 文件。

如果提交的 commitfix 会自动升级版本的 修订号 ;

如果为 feat 则自动更新 次版本号 ;

如果有破坏性的更改,则会修改 主版本号

Lerna与Jest集成

在包发布之前,为了保证代码的质量,都需要来编写单元测试,为了提高效率并方便测试运行,我们想要做到以下功能:

  • 所有包只维护一份公共的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.jsonscript 增加如下命令:

{
  "scripts": {
    "ut": "node scripts/test.js"
  }
}
复制代码

运行测试脚本:

# 执行全部测试
yarn ut

# 执行某个包测试
yarn ut -p package-a
复制代码

Lerna与webpack集成

发包时,会需要使用 webpack 进行 es6 转码或压缩打包,如果每个都维护一份配置文件,就会很繁琐;我们有与 jest 相同的需求:

webpack

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
    }
  }
}

复制代码

这个配置文件是一个函数,通过接受一个参数对象,来返回最终的配置内容,

编写build脚本

思路:

  1. 读取 packages 目录下的所有模块,获取模块的路径
  2. 读取模块下的 package.json ,获取 name 及依赖项
  3. 通过模块路径、包名和 package.json 中的 dependencies 参数来获取 webpack 配置
  4. 通过 webpackNode API 执行配置编译打包
  5. 根据命令行参数,判断执行需要打包的配置文件(单独打包)

具体实现如下:

/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.jsonscript 增加如下命令:

{
  "scripts": {
    "build": "node scripts/build.js"
  }
}
复制代码

运行构建脚本:

# 全部打包
yarn build

# 指定打包
yarn build -p package-a
复制代码

至此, Lerna 的使用方法就介绍完成了。

水滴前端团队招募伙伴,欢迎投递简历到邮箱:fed@shuidihuzhu.com

【第三期】使用lerna管理常用工具库

以上所述就是小编给大家介绍的《【第三期】使用lerna管理常用工具库》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

产品经理必懂的技术那点事儿:成为全栈产品经理

产品经理必懂的技术那点事儿:成为全栈产品经理

唐韧 / 电子工业出版社 / 2018-1 / 59

《产品经理必懂的技术那点事儿:成为全栈产品经理》以非技术背景产品经理学习技术为主题,将技术知识以简单并且易于理解的方式讲述出来,帮助非技术背景产品经理了解技术、学习技术,旨在帮助产品经理高效地与技术人员进行沟通与合作,避免不懂技术带来的困扰。 《产品经理必懂的技术那点事儿:成为全栈产品经理》主要内容围绕产品经理需要了解的互联网基础技术知识展开,涉及客户端、服务器端、数据库及一些数据处理知识。......一起来看看 《产品经理必懂的技术那点事儿:成为全栈产品经理》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

随机密码生成器
随机密码生成器

多种字符组合密码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具