利用father build 開發(fā)前端組件庫實戰(zhàn)

我們的目標是建立一個前端組建庫, 使用的技術(shù)棧是father+docz籍滴,同時要支持typescript, 在build出來的es目錄中要能夠生成“.d.ts”后綴的類型聲明文件,因為只有生成類型聲明文件,我們在使用自己開發(fā)的組件庫的時候才能獲得更好的開發(fā)體驗风纠。

之所以寫下這篇文章夸楣,是因為自己在使用father-build建設(shè)內(nèi)部組件庫的過程中,遇到了一些問題且難以找到相關(guān)文檔肠牲,將自己的經(jīng)驗總結(jié)下來希望看到這篇文章的人能避開這些坑,更加順利地搭建好自己的前端組件庫靴跛。

1. 創(chuàng)建組建目錄缀雳,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. 建好目錄結(jié)構(gòu)(下圖僅供參考)

file-structure.png

4. 創(chuàng)建各種配置文件,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對應(yīng)es module的輸出识椰,types對應(yīng)你的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設(shè)置為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. 創(chuàng)建第一個組件

接下來我們在components目錄創(chuàng)建第一個自己的組件腹鹉,下面是一個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將其導(dǎo)出,暴漏給外部使用敷硅。

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>

我們可以執(zhí)行 yarn start ,來實時查看文檔的效果绞蹦。

7. build我們的組件

現(xiàn)在命令行執(zhí)行 yarn build 即可對組件庫進行打包了力奋,注意我們在.fatherrc中配置了esm和cjs兩種打包方式,對應(yīng)會生成 es 和 lib兩個目錄幽七,其中 esm對應(yīng)的是 es目錄景殷,cjs對應(yīng)lib目錄。

8. 其他注意事項

正常情況下澡屡,在的es和lib目錄下應(yīng)該已經(jīng)為我們寫的ts源碼自動生成了“.d.ts”后綴的類型聲明文件滨彻,如果沒有生成,請仔細對比.fatherrc.js和tsconfig.json這兩個配置文件挪蹭,另外還要注意的是亭饵,如果我們基于antd封裝業(yè)務(wù)組件庫的話,不要在組件庫中使用css module梁厉,否則也會造成無法自動產(chǎn)生類型聲明文件的問題辜羊。

文章未能詳盡部分,可以參考這個demo的github源碼地址:https://github.com/xitengfei/xui-components, 有問題歡迎批評指正词顾。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末八秃,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子肉盹,更是在濱河造成了極大的恐慌昔驱,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件上忍,死亡現(xiàn)場離奇詭異骤肛,居然都是意外死亡,警方通過查閱死者的電腦和手機窍蓝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門腋颠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人吓笙,你說我怎么就攤上這事淑玫。” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵絮蒿,是天一觀的道長尊搬。 經(jīng)常有香客問我,道長土涝,這世上最難降的妖魔是什么毁嗦? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮回铛,結(jié)果婚禮上狗准,老公的妹妹穿的比我還像新娘。我一直安慰自己茵肃,他們只是感情好腔长,可當我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著验残,像睡著了一般捞附。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上您没,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天鸟召,我揣著相機與錄音,去河邊找鬼氨鹏。 笑死欧募,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的仆抵。 我是一名探鬼主播跟继,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼镣丑!你這毒婦竟也來了舔糖?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤莺匠,失蹤者是張志新(化名)和其女友劉穎金吗,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體趣竣,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡摇庙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了期贫。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片跟匆。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡异袄,死狀恐怖通砍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤封孙,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布迹冤,位于F島的核電站,受9級特大地震影響虎忌,放射性物質(zhì)發(fā)生泄漏泡徙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一膜蠢、第九天 我趴在偏房一處隱蔽的房頂上張望堪藐。 院中可真熱鬧,春花似錦挑围、人聲如沸礁竞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽模捂。三九已至,卻和暖如春蜘矢,著一層夾襖步出監(jiān)牢的瞬間狂男,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工品腹, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留岖食,地道東北人。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓舞吭,卻偏偏與公主長得像县耽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子镣典,可洞房花燭夜當晚...
    茶點故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容