私服npm库方案

私服npm库方案

一、关键节点

下文说的npm包,指的公司内部自己开发的npm包

(一)项目管理

a.采用monorepo项目管理方案
i.多个npm包在一个项目中开发
b.开发规范 及 标准规范设计
// todo
c.约束版本及部署npm包方案
i.检测项目所有lib的版本,如果发现版本号变化,则会重新打包发布,并更新版本号

  1. 已发布的版本不会被替换
  2. 只有检测版本号发生变化了才会触发打包部署
    版本迭代规范:
    可允许操作:
    a. 1.2.3 -> 1.2.4
    功能bug修复小迭代版本号更新
    b. 1.2.3 -> 1.3.0
    增加新功能,新特性等功能性更新版本号更新
    c. 1.2.3 -> 2.0.0
    使用之前的功能与之前的版本的使用方式不兼容,或者之前的功能被废弃,使用规范与之前不一致等破坏式更新

不推荐/禁止操作:
a. 1.2.3 -> 1.2.1 禁止版本回退覆盖
b. 1.2.3 -> 1.2.3 禁止版本号不更新
d. 1.2.3 -> 1.1.3 禁止版本回退覆盖
e. 1.2.3 ->1.2.5 不推荐版本跳跃式变化

(二)npm 包的发布及部署 以及 内网安装npm包方案

d.限制内部npm不会被外网拉取
通过.npmrc,修改npm获取源的地址
e.如何link外部npm包镜像
直接copy外部npm包镜像,每天定时同步更新外部镜像
注意事项:
由于无法实时同步外部npm包,在极限场景下需要用户使用其他指令获取没有同步到的npm包,比如cnpm yarn pnpm等
f.存在beta 包和正式包
i.beta 包不可以直接让外部使用,只用联调测试
ii.正式包,只有测试验证,并且验收通过之后才可以发布,推荐对外公布可使用的包

(三)包使用说明文档的维护

1.每个公共模块及新的npm包,都有详细使用说明文档。
2.后续迭代更新:npm包的发布及更新都要写主要变动点,有详细变更内容说明,以及外部如何
对外使用的开发文档,允许demo运行交互等等,非word文档
使用storybook 库来实现,storybook支持markdown创建编辑说明文档,同时支持直接调用同项目npm包 的demo演示,无需发布安装npm包

(四)私服verdaccio

搭建私服部署管理npm包
官方文档:https://verdaccio.org/
https://verdaccio.org/zh-cn/docs/configuration/

(五)搭建公司内部npm脚手架,指令

比如根据某个项目模版创建项目及初始化(通过指令创建微应用的子应用项目模版)、图片上传到静态资源服务器、开发常用的自定义指令等等—二期再开发,不是第一优先级需求

二、背景及前言

部门内多个系统并没有统一的模块管理库,工具模块规范不统一,组件库缺失,每个系统的样式没有统一的管理约束,造成无法很好的集成,前端微应用系统样式规范不统一,子应用开发过程中存在重复造轮子的问题,开发效率无法提升,不能专注于相关的功能开发。因此,需要搭建一个公共模块管理库来提升开发的效率。
(一)前置知识及相关的文档
为什么 pnpm+monorepo 是组件库项目的最佳实践
lernajs
rollupjs
monorepo
【译】ES modules: A cartoon deep-dive-腾讯云开发者社区-腾讯云
Web Component - Web API | MDN
npm-publish | npm Docs
storybook · GitHub
使用lerna管理monorepo及发npm包实战教程
开发人员需要具备前置知识,至少需要了解相关思想及理念

  • monorepo: 单个仓库管理多个项目
  • rollup.js : 模块打包工具
  • pnpm: 包管理器
  • ES Module: 公共模块理念
  • web component:原生web组件
  • npm发布流程:npm包的发布
  • storybook项目: 维护使用说明文档
  • lerna:多包管理工具

推荐翻阅书籍: 重构改善既有代码的设计

三、设计及方案

(一)Monorepo

Multirepo和Monorepo特点

Muitirepo

  1. 简单明朗
  2. 灵活
    缺点:
    A. 项目之间难以建立联系
    B. 将模块打包为npm包,发布到npm上
    C. 挂载到全局变量window
    D. 直接copy一份代码

Monorepo

  1. 良好的代码共享
  2. 新建项目方便
  3. 开发便利
    缺点:
    A. 巨石项目下载、
    B. 编译慢;
    C. 对项目打包构建难度较大

(二)常见的公共模块

需要封装的包一般有哪些
axios 登录 工具包

(三)组件库

部门内通用的组件库搭建,以及与UI工具结合在一起,减少内部的沟通成本与开发成本。

关键节点
1. 基础字体样式设计
2. 组件库支持单个引入和全局引入
3. 组件库故事书完善
4. 说明描述
5. 支持demo操作
6. storybook

前置工作
与产品、UI团队定好标准及规范
1、Token
约定规范定好的样式值,比如字体颜色,字号等等,使用mixin实现,extend
2、基础组件
参考外部UI库,比如ant-design、element-ui等UI库,开发属于我们自己的组件库
方案一: 引入外部组件库进行二次开发
成效快,出结果块,但是可能和UI规范有差距,容易被外部库功能所限制。
该方案所引用的外部组件库确定需要和UI及产品对齐,避免后续有些交互二次开发成本过大。
方案二:从0开始开发,一个一个组件实现
开发周期长,投入开发资源多,可以完全实现UI标准规范,更好的定制化,有完整的组件库代码。

3、Token与UI工具结合
可以与figma结合,pixso是否支持需要探索,支持效果如何还需探索
4、基础组件与UI工具结合
可以与figma结合,pixso是否支持需要探索,支持效果如何还需探索

(四)业务组件

比如layout、导出、导入、登录、header、footer等

(五)工具类模块

比如日期时间转化、数据存储有效期、判断是否设备浏览器信息、导出文件

(六)故事书

**1. 组件库
设计规则可以参考外部组件库的文档来设计

  • 业务组件
    独立的业务组件,单独的一个使用说明文档
  • 工具类模块
    每个模块都有自己独立的使用说明文档
  • 其他规范标准文档
    技术团队内定好的技术规范及标准,比如开发规范、文案换行规则、字体大小约定、大屏项目规范等等**

(七)发版及部署

节点:

npm包的发版控制:
beta
public
npm包管理系统
如何发布上线:
■创建分支,提交分支
■指令发布beta版本
■检查是否发布成功
依赖包的安装管理:
在monorepo中管理npm包的安装通常有以下几种方法:
1.使用workspaces(仅适用于使用Yarn的monorepos):
Yarn的workspaces特性可以自动发现并管理所有的工作区包,无需手动安装每个包。
2.使用lerna(适用于Node.js monorepos,使用npm或yarn):
通过lerna的bootstrap命令,它会自动遍历所有的包并安装它们的依赖。
3.使用npm或yarn的workspaces支持(如果你的项目使用npm或yarn):
在package.json中配置workspaces字段,列出所有的包路径,然后通过npm install或yarn install安装所有依赖。
以下是使用lerna的例子:

npm i -g lerna
或
yarn global add lerna

首先,确保你的项目已经使用lerna初始化:

lerna init

然后,在lerna.json中配置你的包列表(如果需要)。
当你添加或更新包后,运行以下命令来安装所有包的依赖:

lerna bootstrap

这将会递归地安装每个包的依赖,并链接彼此之间的依赖关系。

提交对项目的更新 运行该命令会执行如下的步骤:
1.运行lerna updated来决定哪一个包需要被publish
2.如果有必要,将会更新lerna.json中的version
3.将所有更新过的的包中的package.json的version字段更新
4.将所有更新过的包中的依赖更新
5.为新版本创建一个git commit或tag
6.将包publish到npm上

lerna publish # 用于发布更新
lerna publish --skip-git # 不会创建git commit或tag
lerna publish --skip-npm # 不会把包publish到npm上

1、本地开发测试
软链接调试开发npm包
2、beta包发布
联调测试包,不能直接对外公布,允许有缺陷
版本号: 1.2.3-beta.0 -> 1.2.3-beta.0
不推荐测试包发布占用正式包的版本号
3、正式包发布
可对外发布版本
版本号:1.2.2 -> 1.2.3

(八)常见问题

1、模块外部依赖包版本不一致
peerDependencies:对等依赖,本地所需安装包使用外部项目安装包,尽可能做到兼容多个版本,避免使用破坏性更新版本依赖包(比如npm包大版本不一致),对所需的依赖包进行升级或者降级处理
当 peerDependencies 发生冲突该怎么办?
在 npm 3-6 版本中,其默认行为在构建依赖树时完全忽略了 peerDependencies 错误而仅输出不起眼的提示(间接导致社区 package 对 peerDependencies 的声明正确性良莠不齐),从而忽略了间接的对等依赖关系。这可能会导致 package 安装超出其声明范围的 peerDependencies ,从而导致错误。
那在知道错误后该如何解决呢?
在探讨如何解决之前,请再检查一下你开发的 package 是否真的应该将依赖的冲突 package 列为会对下游造成造成如此麻烦的 peerDependencies 关系。
如果不是,请把它声明为 dependencies,并尽可能的扩大依赖 package 的版本范围。
如果你确实需要使用 peerDependencies:
●如果宿主 package 的 dependencies 低于 peerDependencies 的要求:
那么可以尝试直接升级依赖版本并兼容破坏性变更即可。
●如果宿主 package 的 dependencies 高于 peerDependencies 的要求:
如果可以兼容那可以邀请 package 作者更新其 peerDependencies 声明。或者你也可以对宿主应用程序的依赖关系进行降级。在某些版本确实不兼容且无法处理宿主应用 package 降级的情况下,要求作者更新可能是唯一的解决办法。
有时,一些社区的 package 可能已经放弃维护了,但它仍然能在项目中运行。在这种场景,你可能知道扩大 peerDependencies 的版本范围不会导致任何兼容性问题。甚至你可能发现,它所需要的 peerDependencies 也许一开始就不应该是 peerDependencies,但让作者升级修复可能是件很麻烦的事情。所幸包管理器提供了避免这种麻烦的便捷方法。
对于 npm 8+,可以在 package.json 中使用 overrides 字段:

{
  "overrides": {
    "react": "$react"
  }
}

当你使用 pnpm 时,解决选项更多:
●pnpm.peerDependencyRules.allowedVersions:

{
  "pnpm": {
    "peerDependencyRules": {
      "allowedVersions": {
        "react": "17"
      }
    }
  }
}

●Pnpm installation hook:

const peerDependencies = ['peerDependency1', 'peerDependency2'];
const { overrides } = rootPkg.pnpm;
function overridesPeerDependencies(pkg) {
    if (pkg.peerDependencies) {
        for (const dep of peerDependencies) {
            if (dep in pkg.peerDependencies) {
                pkg.peerDependencies[dep] = overrides[dep];
            }
        }
    }
}

module.exports = {
    hooks: {
        readPackage(pkg, _context) {
            // skipDeps(pkg);
            overridesPeerDependencies(pkg);
            return pkg;
        },
    },
};

值得留意的其他事项
●"missing peer" 的错误通常意味着自动安装 peerDependencies 的行为被关闭,你应该查看使用包管理器的文档修改 .npmrc 配置或通过手动安装对应依赖来解决。
●peerDependencies 的字段声明对 package 开发者来说是存在传递性污染的,如果 package@foo 依赖于软件包 package@bar,而 package@bar 又对等依赖于 package@baz ,那么 package@baz 也是软件包 package@foo 的对等依赖。这个关系会一直延续到某个 package 成为宿主。
●peerDependencies 声明的 package 也可以是可选的,具体可查阅npm文档
参考文档:https://dev.to/icy0307/peer-dependencies-in-depth-1o3b
2、多包循环依赖
monorepo解决循环引用包的解决方案:打断循环,设置标记位,默认循环依赖包加载完成,模块加载完成之后,引入加载完成的依赖包,设置成真正的引入对象,依此重复,完成模块的循环引用。
3、开发模块流程

  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值