# 组件库

## 预览

预览可以使用storybook 或者dumi这种现成的框架

## 版本管理

可以参考： <https://semver.org/lang/zh-CN/> 语义化版本号x.y.z x: 不兼容性升级 y有新功能，且对历史大版本进行兼容 z bugfix 临时版本 x.y.z-beta 或者x.y.z-alpha

## 依赖

* peerDependecies：打包时不打包进去，跟随宿主环境使用对应版本
* devDependencies：开发环境需要，管理者的依赖包只会在开发阶段有效
* dependecies：真实依赖 会根据
* resolutions：当环境存在多版本时 使用该制定版本

## 调试

npm link

## 发布版本

npm publish

## npm 包增加发布权限

npm owner add

## npm 标注历史版本过期

npm deprecate \[@]

## 组件库发包模式

* 单包发布 多适合对外基础物料库
* 多包发布 多适合业务组件库

## 组件库多包之间互相依赖

package.json 中可以使用workspace的概念

## monorepo 组织形式

lerna

## 编译和构建

esmodule: import 语法系列 module 根据package.json 中的module 路径来取 umd: 支持amd 和 commonjs（node require） 两种语法结构。 根据package.json 中 main语法结构来取 index.d.ts: ts类声明文件 根据package.json 中types来取

## 支持treeshaking

1. 组件库必须基于ESM编写;
2. 可以通过`/*#__PURE__*/` 注释去手动标记哪些可能存在的副作用函数不存在不作用
3. 对于样式文件的treeshaking，需要手动标记副作用目录 再package.json 中使用,因为对于编译工具来讲引入的这个less文件在构建工具看来，只是简单引入了，压根就没有使用。所以他会被treeshaking给去掉。所以我们需要手动标记

```json
"sideEffects": [
    "dist/*",
    "es/**/style/*",
    "lib/**/style/*",
    "*.less"
  ],
```

经过以上的模式去写，你会发现你的js由于esmodule 默认带treeshaking 但是css 由于sideEffects的标记 你会发现他其实每次都是全量打入。 那么css 如何支持treeshaking

答案是使用 babel插件 babel-plugin-import。该插件是通过ast 扫描时标记import 来实现treeshaking。其实早年在webpack不支持treeshaking时他的作用不止是样式的treeshaking 更多是组件的按需加载。 目前来说以antd5为例很早就不建议大家使用这个插件去完成按需加载具体可以参考这个讨论：<https://github.com/ant-design/ant-design/issues/23988> 最开始的原因是虽然不支持样式treeshaking 但是样式打包后的文件并不大，另外就是大多数情况下样式都在cdn或者缓存上。实际上基本不会过多影响加载性能。antd5 使用css-in-js类似手段去替换less 让组件自动可以根据加载去进行treeshaking

### css-in-js vs less

css-in-js 优点：

* 天然支持treeshaking
* 能直接将js变量应用到样式上。

缺点：

* 大多数css-in-js框架都是运行时解析。 少部分比如vanila-extract 这种css-in-js框架。确实解决运行时css-in-js性能问题，但也带来更多的语法限制。
* 增加了包体积，
* 不方便外部样式覆盖。往往需要你手动去传参

## 主题

使用css变量

```css
    :root{
        --bg-default: #fff;
    }
    :root[theme="dark"]{
        --bg-default: #000;
    }
    .button{
        background-color: var(--bg-default);
    }
```

## icon

svgr 优势 支持按需加载、完全的样式覆盖能力。同时，它支持自定义AST模板， 可以在转换时给svg元素加入自定义的className等， 容易实现icon自动适配RTL、Dark Mode(这部分下文会详细介绍)。

## 国际化

### 多语言

结合context

### rtl

原生的dir属性来支持大部分的rtl能力， 即在html上设置属性dir='rtl'。 在浏览器环境下可以通过NavigatorLanguage API来获取页面语言，通过一段js脚本来判断当前语言是否是rtl并设置该值 但包括marin-left、left、border-left这类属性(其他方向类似)无法自动适配，

```css
.button{
    margin-left: 16px;
}
html[dir='rtl'] .button{
    margin-left: 0;// 要覆盖掉， 否则左右都是16px的margin
    margin-right: 16px;  
}
```

## 质量保障

可以使用e2e 或者jest去单测。
