最近始终在捣鼓如何搭建React组件库,至于为什么会产生这个想法,次要是因为组件库对于前端生态来说究极重要,每一个着眼于久远倒退、看重开发效率的的互联网公司基本上都会量身定制本人的组件库,它的益处不必多说。对于前端工程师而言,去了解以及把握它,能够让咱们在今后的工作中以及应聘过程中多出一项非凡技能,并且对本身的纵向倒退也就是很无利的。上面是我记录我在搭建组件库的过程。

初始化工程

搭建工程不打算采纳create-react-app脚手架来搭建,因为脚手架封装好了很多货色,而有些货色对于组件库并不实用,用来搭建组件库过于臃肿,因而我不打算借助任何脚手架来搭建工程。

首先,先创立一个工程文件夹pony-react-ui,在该文件夹下执行如下命令:

npm init // 生成package.jsontsc --init // 生成tsconfig.json

而后,依照如下目录构造初始化工程:

pony-react-ui├── src    ├── assets    ├── components        ├── Button            ├── Button.tsx            └── index.ts        └── Dialog            ├── Dialog.tsx            └── index.ts    ├── styles        ├── _button.scss        ├── _dialog.scss        ├── _mixins.scss        ├── _variables.scss        └── pony.scss    └── index.ts // 打包的入口文件,引入pony.scss,抛出每一个组件├── index.js // 入口文件,package.json中main字段指定的文件├── package.json├── tsconfig.json├── webpack.config.js└── README.md

编写一个Button组件

Button组件应该满足一下需要:

  • 不同尺寸
  • 不同类型
  • 不同色彩
  • 禁用状态
  • 点击事件

Button.tsx

import React from 'react';import classNames from 'classnames';export interface IButtonProps {  onClick?: React.MouseEventHandler;  // 类型  primary?: boolean;  secondary?: boolean;  outline?: boolean;  dashed?: boolean;  link?: boolean;  text?: boolean;  // 尺寸  xLarge?: boolean;  large?: boolean;  small?: boolean;  xSmall?: boolean;  xxSmall?: boolean;  // 色彩  success?: boolean;  warn?: boolean;  danger?: boolean;  // 禁用状态  disabled?: boolean;  className?: string;  style?: React.CSSProperties;  children?: React.ReactNode;}export const Button = (props: IButtonProps) => {  const {    className: tempClassName,    style,    onClick,    children,    primary,    secondary,    outline,    dashed,    link,    text,    xLarge,    large,    small,    xSmall,    xxSmall,    success,    danger,    warn,    disabled,  } = props;      const className = classNames(    {      'pony-button': true,      'pony-button-primary': primary,      'pony-button-secondary': secondary && !text,      'pony-button-outline': outline,      'pony-button-dashed': dashed,      'pony-button-link': link,      'pony-button-text': text && !secondary,      'pony-button-text-secondary': secondary && text,      'pony-button-round': round,      'pony-button-rectangle': noRadius,      'pony-button-fat': fat,      'pony-button-xl': xLarge,      'pony-button-lg': large,      'pony-button-sm': small,      'pony-button-xs': xSmall,      'pony-button-xxs': xxSmall,      'pony-button-long': long,      'pony-button-short': short,      'pony-button-success': success,      'pony-button-warn': warn,      'pony-button-danger': danger,      'pony-button-disabled': disabled,    },    tempClassName  );    return (    <button       type="button"      className={className}      style={style}      onClick={onClick}      disabled={disabled}>      <span className="pony-button__content">{children}</span>    </button>  );}

在Button/index.ts文件中抛出Button组件以及定义的类型

export * from './Button';

这样,一个示例组件就根本实现了,有同学必定会有这么一个疑难,为什么在Button.tsx中没有引入它的款式文件_button.scss,而是在应用时引入全局款式或者独自引入_button.scss呢?

// 独自引入组件款式import { Button } from 'pony-react-ui';import 'pony-react-ui/lib/styles/button.scss';// 全局引入组件款式,打包时抽离进去的款式import 'pony-react-ui/lib/styles/index.scss';

因为这跟款式的权重无关,通过import引入的款式权重将低于JSX中className定义的款式,因而才能够在组件内部批改外部的款式。

举个实例:

import { Button } from 'pony-react-ui';import 'pony-react-ui/lib/styles/button.scss';import styles from './index.module.scss';const Demo = () => (  <div className={styles.btnBox}>    <Button onClick={submit}>submit</Button>  </div>)

引入组件库中的Button.scss和本地的index.module.scss在打包后会以<style></style>注入到页面中,而且程序必定是:

<style type="text/css">  // Button.scss的款式</style><style type="text/css">  // index.module.scss的款式</style>

因而,index.module.scss中的款式权重是高于Button.scss中的款式,能够在index.module.scss中批改Button.scss的款式

编写款式

打包输入UMD标准

打包输入es module标准

docz生成组件应用文档

公布到npm仓库