美文网首页
利用father build 开发前端组件库实战

利用father build 开发前端组件库实战

作者: 西江月影 | 来源:发表于2020-12-01 11:29 被阅读0次

我们的目标是建立一个前端组建库, 使用的技术栈是father+docz,同时要支持typescript, 在build出来的es目录中要能够生成“.d.ts”后缀的类型声明文件,因为只有生成类型声明文件,我们在使用自己开发的组件库的时候才能获得更好的开发体验。

之所以写下这篇文章,是因为自己在使用father-build建设内部组件库的过程中,遇到了一些问题且难以找到相关文档,将自己的经验总结下来希望看到这篇文章的人能避开这些坑,更加顺利地搭建好自己的前端组件库。

1. 创建组建目录,npm init初始化package.json文件

mkdir my-component
npm init

2. 下载会使用到的依赖项

yarn add --peer react react-router-dom
yarn add --dev @types/vfile-message babel-plugin-import father typescript
yarn add antd classnames @ant-design/icons @babel/runtime classnames

3. 建好目录结构(下图仅供参考)

file-structure.png

4. 创建各种配置文件,father, tsconfig, package.json

package.json

{
  "name": "xui-components",
  "version": "1.0.0",
  "description": "",
  "main": "lib/index.js",
  "module": "es/index.js",
  "types": "./es/index.d.ts",
  "scripts": {
    "start": "father doc dev",
    "doc:build": "father doc build",
    "doc:deploy": "father doc deploy",
    "build": "father build",
    "test": "father test",
    "test:coverage": "father test --coverage"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/xitengfei/xui-components.git"
  },
  "files": [
    "es",
    "lib"
  ],
  "author": "tengfei.xi",
  "license": "MIT",
  "homepage": "https://github.com/xitengfei/xui-components#xui-components",
  "peerDependencies": {
    "react": "^17.0.1",
    "react-router-dom": "^5.2.0"
  },
  "devDependencies": {
    "@types/vfile-message": "^2.0.0",
    "babel-plugin-import": "^1.13.1",
    "father": "^2.29.11",
    "typescript": "^4.1.2"
  },
  "dependencies": {
    "@ant-design/icons": "^4.3.0",
    "@babel/runtime": "^7.12.5",
    "antd": "^4.8.5",
    "classnames": "^2.2.6"
  }
}

其中,main指定了入口文件,module对应es module的输出,types对应你的typings文件,这样在组件在被使用的时候编辑器才能识别出你的组件类型声明

.fatherrc.js 配置father build打包方式, 具体详情可以参考 umijs/father

export default {
  target: 'browser',
  entry: 'src/index.ts',
  esm: 'babel',
  cjs: 'babel',
  runtimeHelpers: true,
  extraBabelPlugins: [
    ['babel-plugin-import', {
        libraryName: 'antd',
        libraryDirectory: 'es',
        style: true,
    }]
  ],
  autoprefixer: {
    browsers: ['ie>9', 'Safari >= 6'],
  },
  doc: {
    themeConfig: { mode: 'light' },
    base: '/',
    menu: []
  },
};

tsconfig.json typescript的配置文件,注意只有declaration设置为true才能生成.d.ts后缀的文件

{
  "compilerOptions": {
    "target": "es6",
    "module": "esnext",
    "lib": ["es2018", "dom"],
    "declaration": true,
    "outDir": "./esm",
    "rootDir": "./src",
    "importHelpers": true,
    "downlevelIteration": true,
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "resolveJsonModule": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "alwaysStrict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "moduleResolution": "node",
    "typeRoots": ["typings", "node_modules/@types"],
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "jsx": "react"
  },
  "exclude": ["node_modules", "examples"]
}

5. 创建第一个组件

接下来我们在components目录创建第一个自己的组件,下面是一个button的例子:

文件路径:src/components/button-demo/index.tsx

import React from 'react'
import classnames from 'classnames'
import './index.less'

/**
 * @param {onClick} func 对外暴露的点击事件
 * @param {className} string 自定义类名
 * @param {type} string 按钮类型 primary | warning | info | default | pure
 */
export interface Props{
  onClick?: (e: any) => void;
  className?: string;
  type?: string;
  block?: boolean;
}

const Button: React.FC<Props> = (props) => {
  let { children, onClick, className, type, block } = props
  return <div className={classnames('xui-btn', 'ripple', type, block ? 'block' : '', className)} onClick={onClick}>
    { children }
  </div>
}


export default Button;

样式文件可以直接使用less编写

路径:src/components/button-demo/index.less

.xui-btn {
  box-sizing: border-box;
  display: inline-block;
  padding: 6px 1em;
  line-height: 1.5em;
  border-radius: 4px;
  border: 1px solid transparent;
  color: #fff;
  font-family: inherit;
  background-color: #999;
  user-select:none;
  cursor: pointer;
  text-align: center;

  &.primary {
    background-color: #09f;
  }
  &.warning {
    background-color: #F90;
  }
  &.info {
    background-color: #C03;
  }
  &.common {
    border: 1px solid #ccc;
    color: rgba(0, 0, 0, 0.65);
    background-color: #fff;
    &::after {
      background-image: radial-gradient(circle, #ccc 10%, transparent 11%);
    }
  }

  &.block {
    display: block;
  }
}

然后在入口文件index.ts将其导出,暴漏给外部使用。

export {default as Button} from './components/button-demo';

6. 撰写使用文档

使用文档的后缀名为".mdx", 语法与markdown类似,更多详情参考docz的文档

---
name: Button
route: /button
order: 3
sidebar: true
---

import { Playground } from 'docz'
import Button from './index'

# Button

#### Basic Usage
<Playground>
    <Button>button</Button><br />
    <Button type="primary">primary</Button><br />
    <Button type="warning">warning</Button><br />
    <Button type="info">info</Button><br />
    <Button type="common">按钮</Button><br />
</Playground>

#### Block Button
<Playground>
    <div style={{width: '360px'}}>
        <Button block>button</Button><br />
        <Button type="primary" block>primary</Button><br />
        <Button type="warning" block>warning</Button><br />
        <Button type="info" block>info</Button><br />
        <Button type="common" block>default</Button><br />
    </div>
</Playground>

我们可以执行 yarn start ,来实时查看文档的效果。

7. build我们的组件

现在命令行执行 yarn build 即可对组件库进行打包了,注意我们在.fatherrc中配置了esm和cjs两种打包方式,对应会生成 es 和 lib两个目录,其中 esm对应的是 es目录,cjs对应lib目录。

8. 其他注意事项

正常情况下,在的es和lib目录下应该已经为我们写的ts源码自动生成了“.d.ts”后缀的类型声明文件,如果没有生成,请仔细对比.fatherrc.js和tsconfig.json这两个配置文件,另外还要注意的是,如果我们基于antd封装业务组件库的话,不要在组件库中使用css module,否则也会造成无法自动产生类型声明文件的问题。

文章未能详尽部分,可以参考这个demo的github源码地址:https://github.com/xitengfei/xui-components, 有问题欢迎批评指正。

相关文章

网友评论

      本文标题:利用father build 开发前端组件库实战

      本文链接:https://www.haomeiwen.com/subject/cfabiktx.html