我們的目標是建立一個前端組建庫, 使用的技術(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)(下圖僅供參考)
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, 有問題歡迎批評指正词顾。