本章篇幅較長,尬很少說,造輪子開始~~css
npx create-react-app my-component-library --template typescript
前端
參考:create-react-app.dev/docs/adding…node
CRA 默認不支持 Sass 預處理器,須要安裝 node-sass
,react
npm install node-sass --save
git
支持 sass 以後,接下來能夠爲組件庫添加一些樣式管理,好比定義基礎組件庫色板變量,github
// 基礎色板
$blue: #0d6efd !default;
$indigo: #6610f2 !default;
$purple: #6f42c1 !default;
$pink: #d63384 !default;
$red: #dc3545 !default;
$orange: #fd7e14 !default;
$yellow: #fadb14 !default;
$green: #52c41a !default;
$teal: #20c997 !default;
$cyan: #17a2b8 !default;
複製代碼
添加 reset 全局樣式,可參考 normalize.css 庫,它提供了跨瀏覽器的高度一致性。typescript
下面簡單列舉開發組件幾個經常使用的點,至於怎麼開發出一個合格好用的組件,還須要日積月累、慢慢摸索~npm
className
屬性通常支持 btn, btn-lg, btn-primary
等不一樣樣式管理,推薦使用 classnames
插件進行樣式名管理, 配置 classNames :npm i classnames --save
npm install --save @types/classnames
json
經過 Button.defaultProps
爲添加 props
賦默認值windows
ButtonHTMLAttributes
是 button
全部原生屬性類型,能夠經過定義自定義屬性類型和 button
全部原生屬性類型,讓用戶使用組件時得到更好的屬性類型提示。
Button 組件參考實現 ⬇️
// Button.tsx
import React, { FC, ButtonHTMLAttributes, AnchorHTMLAttributes } from "react";
import classNames from "classnames";
export type ButtonSize = "lg" | "sm";
export type ButtonType = "primary" | "default" | "danger" | "link";
interface BaseButtonProps {
className?: string;
/**設置 Button 的禁用 */
disabled?: boolean;
/**設置 Button 的尺寸 */
size?: ButtonSize;
/**設置 Button 的類型 */
btnType?: ButtonType;
children: React.ReactNode;
href?: string;
}
// ButtonHTMLAttributes 是button全部原生屬性類型
type NativeButtonProps = BaseButtonProps & ButtonHTMLAttributes<HTMLElement>;
// a 連接原生屬性
type AnchorButtonProps = BaseButtonProps & AnchorHTMLAttributes<HTMLElement>;
// TS Utility Types : Partial 屬性可選,並非都有的
export type ButtonProps = Partial<NativeButtonProps & AnchorButtonProps>;
export const Button: FC<ButtonProps> = (props) => {
const {
btnType,
className, // 用戶自定義className
disabled,
size,
children,
href,
...restProps // 包含了其餘的全部原生屬性
} = props;
// 配置 classNames : btn, btn-lg, btn-primary
// disable說明:button 默認支持disabled屬性;但 a 連接disable屬性就要經過樣式來控制了,因此添加到classname裏
const classes = classNames("btn", className, {
[`btn-${btnType}`]: btnType,
[`btn-${size}`]: size,
disabled: btnType === "link" && disabled,
});
// button 包括 link類型和其餘類型
if (btnType === "link" && href) {
return (
<a className={classes} href={href} {...restProps}> {children} </a>
);
} else {
return (
<button className={classes} disabled={disabled} {...restProps}> {children} </button>
);
}
};
Button.defaultProps = {
disabled: false,
btnType: "default",
};
export default Button;
複製代碼
Create React App 中,Jest 已經可以開箱即用,且包含許多實用的默認配置。
從 package.json 中能夠看到 CRA 已內置了相關測試包:
{
"scripts": {
"test": "react-scripts test"
},
"dependencies": {
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/user-event": "^12.1.10",
"@testing-library/react": "^11.2.5"
}
}
複製代碼
// Button.test.tsx
import React from "react";
import { render } from "@testing-library/react";
import Button from "./Button";
test("my test", () => {
const wrapper = render(<Button>按鈕</Button>);
const ele = wrapper.queryByText("按鈕");
expect(ele).toBeTruthy();
});
複製代碼
npm run test
此時會先運行 setupTests.ts 文件,而後跑一遍測試用例。
參考:
create-react-app.dev/docs/runnin…
本文使用文檔生成工具 docz 進行開發。docz Demo 參考 create-react-app-ts Doc。
{
"scripts": {
"docz:dev": "docz dev",
"docz:build": "docz build",
"docz:serve": "docz build && docz serve"
}
}
複製代碼
新建 Button.mdx
文件(按照模板規範編輯便可) 注意須要引入全局樣式 index.scss
.
---
name: Button
menu: Components ---
import { Playground, Props } from "docz";
import { Button } from "./Button";
import "../../style/index.scss";
# Button
## Properties
<Props of={Button} />
## Basic usage
<Playground>
<Button btnType="primary"> primary button </Button>
</Playground>
## Using different kinds
<Playground>
<Button btnType="danger"> danger button </Button>
<Button btnType="link" href="https://google.com">
link button </Button> </Playground> 複製代碼
主要用來支持編譯 TS
// doczrc.js
export default {
typescript: true,
files: ["./src/**/*.mdx"], // 指定生成文檔的文件
};
複製代碼
此時運行的本地組件庫文檔無法正常展現樣式,須要配置編譯 SCSS 文件,參考 Using docz with CSS Preprocessors
npm install --save gatsby-plugin-sass
gatsby-config.js
文件//gatsby-config.js
module.exports = {
plugins: ["gatsby-plugin-sass"],
};
複製代碼
執行 npm run docz:dev
,此時本地文檔就能夠正常跑起來啦 (沒有作美觀調整,組件庫樣式簡單粗暴)
通常本地運行報錯以後,會存在緩存文件,須要刪除本地.docz 文件夾,從新運行 npm run docz:dev
便可。
下面是代碼目錄結構
接下來就是如何將打包後的組件庫文檔,部署到遠端服務器,並進行在線瀏覽
本項目採用 Netlify 一個能夠用來作靜態網站的持續集成與持續部署的工具。只需設置一次,之後每次咱們提交代碼的時候,Netlify 會自動幫咱們部署最新的代碼。
npm run docz:build
,生成打包後的文檔默認在 .docz/dist
目錄下,提交代碼。npm run docz:build
以及須要配置待部署的文件目錄位置 .docz/dist
等Netlify 的部署配置工做是十分簡單的,基本按照提示就能夠徹底配置好。能夠參考這篇文章使用 netlify 部署你的前端應用。
Deploy log 日誌能夠很清晰的看出 Netlify 的構建過程 :
Installing dependencies -> Build command from Netlify app --> Deploy site --> Build script success
一鍵 deploy 成功後,直接點擊域名連接便可愉快的訪問咱們的組件庫在線文檔啦!傳送門 🚪
部署完組件庫在線文檔後,接下來就是如何將咱們的組件庫進行打包與發佈了,這裏主要使用 TS 進行編譯配置。
// index.tsx
export { default as Button } from "./components/Button";
複製代碼
tsconfig
配置文件及打包"build-ts":"tsc -p tsconfig.build.json"
npm run build-ts
進行打包{
"compilerOptions": {
"outDir": "dist",
"module": "esnext",
"target": "es5",
"declaration": true,
"jsx": "react",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true
},
"include": ["src"],
"exclude": ["src/**/*.test.tsx", "src/setupTests.ts"]
}
複製代碼
發現此時 scss 文件並無被打包,接下來使用 node-sass
進行編譯
添加 script 腳本:"build-css": "node-sass ./src/styles/index.scss ./dist/index.css"
編譯前須要刪除老的 dist 文件夾。 Linux 下可使用 rm -rf dist
,但不兼容 windows。CRA 已經內置了 rimraf 插件,增長刪除 script 腳本 "clean": "rimraf ./dist"
, 參考以下:
{
"scripts": {
"start": "react-scripts start",
"build": "npm run clean && npm run build-ts && npm run build-css", // 順序執行
"clean": "rimraf ./dist",
"build-ts": "tsc -p tsconfig.build.json",
"build-css": "node-sass ./src/style/index.scss ./dist/index.css"
}
}
複製代碼
執行 npm run build
, 控制檯能夠看到三條命令依次執行。
打包後目錄結構以下
{
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.ts"
}
複製代碼
在本地開發 npm 模塊的時候,咱們可使用 npm link 命令,將 npm 模塊連接到對應的運行項目中去,方便地對模塊進行調試和測試
npm link
// success : /usr/local/lib/node_modules/my-component-library -> /Users/當前組件庫項目路徑/my-component-library
// 全局 node_modulus 下會建立一個軟連接 ---> 連接到當前組件庫項目路徑
複製代碼
npm link my-component-library
// success : /Users/當前測試項目路徑/test-component-library/node_modules/my-component-library -> /usr/local/lib/node_modules/my-component-library -> /Users/liyang86/當前組件庫項目路徑/my-component-library
// 本地 test 項目中 node_modules/my-component-library 建立軟連接 ---> 連接到全局環境 node_modules/my-component-library 做爲中轉 ---> 又連接到當前組件庫項目路徑
複製代碼
此時 test 項目 node_modules 中已有 my-component-library 文件夾了!而且修改組件庫內容時,demo 項目中 link 的組件包也會實時更新哦。
// test-component-library 下
import { Button } from "my-component-library";
import "my-component-library/dist/index.css";
<Button btnType="primary" size="lg"> Button </Button>;
複製代碼
運行一下測試項目,Button
組件已經能夠正常使用啦。
本地測試組件庫經過後,接下來就是最後一步,發佈組件庫到 npm!
package.json
經常使用字段即便不配置 ignore 或者 files 也會被髮布的文件:package.json、README.md、changelog.md、license
經過命令行鉤子函數的方式進行驗證,包括測試用例驗證和 lint 代碼格式檢查
--ext
選項 指定 ESLint 在指定的目錄下查找 JavaScript 文件時要使用的文件擴展名"lint": "eslint --ext js,ts,tsx src --max-warnings 5"
npm run lint
進行測試npm run test
方式會 watch,但不會返回結果,下面進行改進 參考:create-react-app.dev/docs/runnin…npm install --save-dev cross-env
"test:nowatch": "cross-env CI=true react-scripts test",
npm run test:nowatch
測試成功。假如測試用例不經過,會中斷退出運行。npm install husky --save-dev
"husky": {
"hooks": {
"pre-commit": "npm run test:nowatch && npm run lint"
}
},
複製代碼
"prepublish": "npm run test:nowatch && npm run lint && npm run build"
npm whoami
檢測是否登陸 npmnpm adduser
未登陸的話進行登陸/註冊npm config ls
或 nrm ls
查看當前 registry 信息(須要使用默認的 npm 源)npm publish
成功發佈!npm install @sdyz/my-component-library
import { Button } from "@sdyz/my-component-library";
import "@sdyz/my-component-library/dist/index.css";
<Button btnType="primary" size="lg"> Button </Button>;
複製代碼
大功告成!!撒花 ✿✿ ヽ(°▽°)ノ ✿ ✌️✌️✌️