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

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

内容简介:在工作中我们有时会写一些常用的库,比如包含数据类型判断、我们通常会将这个库拆分成多个,分别创建但当多个库之间产生依赖的时候,问题就就会显露出来;你需要打包发布修改后的库,还需要修改所有依赖库的版本号,重新发包。
【第三期】使用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管理常用工具库》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

Learning JavaScript

Learning JavaScript

Shelley Powers / Oreilly & Associates Inc / 2006-10-17 / $29.99

As web browsers have become more capable and standards compliant, JavaScript has grown in prominence. JavaScript lets designers add sparkle and life to web pages, while more complex JavaScript has led......一起来看看 《Learning JavaScript》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具