⚠️本文爲掘金社區首發簽約文章,未獲受權禁止轉載css
你們好,我是洛竹🎋,一隻住在杭城的木系前端🧚🏻♀️,若是你喜歡個人文章📚,能夠經過點贊幫我彙集靈力⭐️。前端
在 《每一個前端都應該擁有本身的組件庫,就像每一個夏天都有西瓜🍉》 一文中,洛竹帶領小黑從零搭建了一個組件庫項目,完成了項目結構、構建、測試、文檔等基礎工程化工做並完成了第一個組件 Icon。本期延續上期的組件工程化的主題,夏日炎熱,點上一杯楊枝甘露,和洛竹赴一場 Button 開發之約吧。赴約後,你將會收穫如下的內容:vue
做爲前端工程師,入行至今接觸最多的就是設計師了。耳濡目染下雖然說沒學會什麼設計工具,可是對設計與人的心理有了必定認識。react
洛竹認爲任何事物都不可能憑空出現,自有其傳承。使用普遍的基礎界面元素 Button 也不例外,咱們生活中就有隨處可見的按鈕。舉個栗子🌰,天天上班下班必然要按的電梯按鈕、手機音量按鈕、小米 9 雞肋的小愛同窗喚起按鈕。要搞清楚爲何須要按鈕,咱們有必要探究下生活中這些按鈕的做用。ios
想象一下把鍵盤按鍵換成觸摸屏,你最在意的必定是完美還原物理鍵的敲擊感,像洛竹用手機虛擬鍵盤就喜歡設置按鍵震動和音效。經過打擊(點擊)得到快感是較爲廣泛的人性。按鈕在按下、鬆開時有豐富的質感和交互感,完美知足了人們點一下的快感。git
從 BB 機到諾基亞再到現在的智能機,實體按鈕削減到只剩下音量鍵和開關機鍵。按鍵雖然光禿禿沒有任何標識,但咱們就是知道它的功能。試想一下沒有這個來自遠古時代的開關鍵,你手裏的手機就是一塊板磚。github
小米 9 單獨喚起小愛同窗的按鍵常常會被誤按,以前我還不理解這麼蠢的設計的目的。在簡單研究了點設計心理學我明白了。小愛的設計者爲了 產品日活和 AI 訓練就是故意這個設計的。web
小米 10 雖然移除了單獨的喚起鍵,卻把原來的電源鍵改爲了一鍵多用。每次想要重啓手機還得先喚起一下小愛同窗。不得不說,小愛同窗小米親女兒。面試
吐槽歸吐槽,小米這個按鈕確實起到了培養用戶習慣的任務。當用戶知悉某個按鈕能指向某個操做,或者獲取某類信息後,久而久之用戶就會造成使用習慣。若是某操做可以爲用戶和廠商持續帶來價值,那就可讓按鈕的位置更加醒目,持續培養用戶點擊習慣。
這個在 Web 開發中是最多見的使用場景,每一個可交互頁面上都有這類按鈕的出現,用來指引用戶下一步該怎麼作。好比表單的提交和重置。
雖然按鈕也常做爲表單元素,可是區別於其餘表單元素,按鈕因其自然地自說明性,不須要 Label 對其進行輔助說明,囉嗦這麼多,掘友們應該在看到一個按鈕時,應該也會有從設計上品鑑的意識了,歡迎將對下圖的品鑑在評論區告訴洛竹。
在開始開發具體組件以前,咱們必須先約定好組件主題化的規範。以前 antd-mobile-rn 就由於設計問題,中途花費大力氣重構。幾乎全部的組件庫都會將色彩、佈局這些以 css 變量的形式提供給使用者和開發者爲,React Native 不一樣的是樣式基於 CSS in JS,不過道理相通,參照 vant 的設計資源,咱們抽出了一套 JavaScript 常量:
// packages/themes
export interface Theme {
'animation-duration-base': string;
'animation-duration-fast': string;
'animation-timing-function-enter': string;
'animation-timing-function-leave': string;
'font-size-xs': number;
'font-size-sm': number;
'font-size-md': number;
'font-size-lg': number;
'font-weight-bold': number;
// 變量過多,這裏僅展現部分變量
}
複製代碼
有了這些 JS 常量,咱們就能夠設計主題系統。基於 CSS in JS 的主題化設計通常是基於 React Context 實現,須要提供 ThemeProvider 傳入主題上下文,ThemeConsumer、WithTheme(高階類組件)、withTheme(高階函數組件) 或 useTheme(React Hooks)做爲消費者獲取上下文。本身實現也不難,不過更文任務比較緊急,咱們先基於 cssinjs/theming 實現功能,後期有須要再回來造輪子也不遲。下面👇就是咱們基於 theming 的 createTheming
函數建立自定義主題上下文。
import { createTheming } from 'theming';
const context = React.createContext(defaultTheme);
const theming = createTheming(context);
export const { ThemeProvider, withTheme, useTheme } = theming;
複製代碼
主題功能是通用的,所以我將主題相關的能力都放在
@vant-react-native/theme
包中發佈。
React Native 內置的 Button 組件的樣式是固定的,只能進行一些簡單的設置。且內置的 Button 組件在 Android 和 ios 兩個平臺上的表現並不一致。因此咱們須要根據更底層的組件進行封裝。咱們對比 ant-design-mobile-rn 和 react-native-elements 後採用了前者使用的 TouchableHighlight
組件。因爲繼承自 TouchableHighlight,因此咱們組件的 Props 類型以下:
import { TouchableHighlightProps } from 'react-native';
interface ButtonProps extends TouchableHighlightProps {
}
複製代碼
vant 的 Button 支持 default
、primary
、info
、warning
、danger
五種類型,默認爲 default
。如今,組件的基本定義以下:
// ...
import React, { FunctionComponent } from 'react';
import { Text, View } from 'react-native';
interface ButtonProps {
type?: 'default' | 'primary' | 'info' | 'warning' | 'danger';
}
const Button: FunctionComponent<ButtonProps> = props => {
// ...
};
// ...
複製代碼
咱們的組件爲了適應主題化需求,樣式不能是寫死在組件裏的,而是要經過上下文獲取樣式常量。咱們思路是首先使用 useTheme
從上下文中獲取主題,而後因爲樣式定義較多,咱們爲每一個組件編寫一個 useStyle
hook 放在單獨的 style.ts 文件中:
import { StyleSheet } from 'react-native';
import { Theme, useTheme } from '@vant-react-native/theme';
export const useStyle = props => {
const theme = useTheme<Theme>();
const getBackgroundColor = () => {
switch (props.type) {
case 'primary':
return theme['success-color'];
case 'info':
return theme['primary-color'];
case 'warning':
return theme['warning-color'];
case 'danger':
return theme['danger-color'];
default:
return theme.white;
}
};
const getTextColor = () => {
if (props.type === 'default') {
return theme.black;
} else {
return theme.white;
}
};
const getBorderRadius = () => {
if (props.round) {
return theme['border-radius-max'];
}
if (props.square) {
return 0;
}
return theme['border-radius-sm'];
};
const styles = StyleSheet.create({
container: {
alignItems: 'center',
backgroundColor: getBackgroundColor(),
borderColor: getBorderColor(),
borderRadius: theme['border-radius-sm'],
borderWidth: theme['border-width-base'],
flexDirection: 'row',
flex: 1,
justifyContent: 'center',
opacity: 1,
paddingHorizontal: 15,
},
indicator: {
marginRight: theme['padding-xs'],
},
textStyle: {
color: getTextColor(),
fontSize: 14,
},
wrapper: {
borderRadius: theme['border-radius-sm'],
height: 44,
},
});
return styles;
};
複製代碼
基於 useStyle
咱們即可完成一個支持多類型的 Button 組件:
const Button: FunctionComponent<ButtonProps> = props => {
const styles = useStyle(props);
const { style, ...restProps } = props;
return (
<TouchableHighlight style={[styles.wrapper, style]} {...restProps}> <View style={styles.container}> {typeof props.children === 'string' ? ( <Text style={styles.textStyle}>{props.children}</Text> ) : ( props.children )} </View> </TouchableHighlight>
);
};
複製代碼
注意:子組件多是字符串,也多是組件,因此須要判斷類型。
實現效果以下:
樸素按鈕的文字爲按鈕顏色,背景爲白色,咱們經過 plain
屬性將按鈕設置爲樸素按鈕。調研了 antd 和 react-native-elements 發現它們都是定義了不少樣式,而後在組件內經過邏輯判斷計算具體樣式的值。我的很不喜歡這種方式,不是完全的 CSS in JS,個人處理方式是將全部有關樣式計算的都封裝在每一個組件的 useStyle
鉤子中,好比當引入樸素按鈕屬性時,相對於普通按鈕改變的有容器背景色、容器邊框和字體顏色。因此咱們將這三個屬性的值都經過一個單獨的函數計算。對比 antd 的源碼,會發現不只代碼更易讀,甚至代碼量也少了。
const getBackgroundColor = () => {
if (props.plain) {
return theme.white;
}
// ...
};
const getTextColor = () => {
if (props.plain) {
switch (props.type) {
case 'primary':
return theme['success-color'];
case 'info':
return theme['primary-color'];
case 'warning':
return theme['warning-color'];
case 'danger':
return theme['danger-color'];
default:
return theme['gray-3'];
}
} else if (props.type === 'default') {
return theme.black;
} else {
return theme.white;
}
};
複製代碼
實現效果以下:
vant 實現細邊框是經過設置 hairline
屬性能夠展現 0.5px 的細邊框。可是手機上因爲分辨率的影響,貿然設置 0.5 會致使邊框不顯示的兼容問題。好在 React Native 爲咱們提供了 StyleSheet.hairlineWidth
常量來兼容最細邊框問題,下面是官方對它的定義:
hairlineWidth 這一常量始終是一個整數的像素值(線看起來會像頭髮絲同樣細),並會盡可能符合當前平臺最細的線的標準。能夠用做邊框或是兩個元素間的分隔線。然而,你不能把它「視爲一個常量」,由於不一樣的平臺和不一樣的屏幕像素密度會致使不一樣的結果。
若是模擬器縮放過,可能會看不到這麼細的線。
因爲 hairline
隻影響了容器 borderWidth
屬性,咱們不須要編寫單獨的樣式計算函數:
const styles = StyleSheet.create({
// ...
container: {
// ...
borderWidth: props.hairline ? theme['border-width-hairline'] : theme['border-width-base'],
},
});
複製代碼
實現效果以下:
表單元素或者說可觸摸可點擊的元素通常都有禁用狀態,vant 中是經過 disabled 屬性來禁用按鈕,禁用狀態下按鈕不可點擊。TouchableHighlight 繼承地有 disabled
屬性,咱們只須要設置一些禁用狀態下的按鈕樣式就能夠,查看 vant 源碼咱們發現只須要修改透明度爲 0.5 便可:
const styles = StyleSheet.create({
container: {
// ...
opacity: props.disabled ? 0.5 : 1,
// ...
},
});
複製代碼
實現效果以下:
vant 是經過 loading
屬性設置按鈕爲加載狀態,加載狀態下默認會隱藏按鈕文字,能夠經過 loading-text
設置加載狀態下的文字。咱們藉助 React Native 的 ActivityIndicator 組件能夠輕鬆實現這個特性:
// ...
<TouchableHighlight {...restProps}>
<View style={styles.contentWrapper}> {props.loading ? ( <> <ActivityIndicator size="small" color={indicatorColor} style={styles.indicator} /> {props.loadingText ? <Text style={styles.textStyle}>{props.loadingText}</Text> : null} </>
) : null}
</View>
</TouchableHighlight>
// ...
複製代碼
樣式以下:
export const useIndicatorColor = (props: ButtonProps): string => {
const theme = useTheme<Theme>();
if (props.plain) {
switch (props.type) {
case 'primary':
return theme['success-color'];
case 'info':
return theme['primary-color'];
case 'warning':
return theme['warning-color'];
case 'danger':
return theme['danger-color'];
default:
return theme.black;
}
} else if (props.type === 'default') {
return theme.black;
} else {
return theme.white;
}
};
複製代碼
實現效果以下:
默認的按鈕有值爲 2 的圓角,vant 中經過 square
設置方形按鈕,經過 round
設置圓形按鈕。按例,咱們經過判斷設置樣式:
const getBorderRadius = () => {
if (props.round) {
return theme['border-radius-max'];
}
if (props.square) {
return 0;
}
return theme['border-radius-sm'];
};
const styles = StyleSheet.create({
container: {
borderColor: getBorderColor(),
},
wrapper: {
borderRadius: getBorderRadius(),
},
});
複製代碼
實現效果以下:
Antd RN 只提供了 large、small 兩個尺寸,而在 vant 中支持 large、normal、small、mini 四種尺寸,默認爲 normal。雖然寫到這裏已經很疲倦了,楊枝甘露也早喝完了,可是爲了完整復原,仍是續上一杯咖啡繼續肝。根據 vant 設計稿咱們新增三個樣式獲取函數並動態化指定樣式:
const getSizeHeight = () => {
switch (props.size) {
case 'large':
return 50;
case 'small':
return 32;
case 'mini':
return 24;
default:
return 44;
}
};
const getSizePadding = () => {
switch (props.size) {
case 'small':
return 8;
case 'mini':
return 4;
default:
return 15;
}
};
const getSizeFontSize = () => {
switch (props.size) {
case 'large':
return 16;
case 'small':
return 12;
case 'mini':
return 10;
default:
return 14;
}
};
const styles = StyleSheet.create({
container: {
paddingHorizontal: getSizePadding(),
},
textStyle: {
fontSize: getSizeFontSize(),
},
wrapper: {
height: getSizeHeight(),
},
});
複製代碼
實現效果以下:
若是不是本身親自復刻 Vant,是沒想到一個 Button 能玩出這麼多花,支持特性這麼多耐心和代碼管理都是一個挑戰。固然了,洛竹採起的樣式管理方式比較偏激,你們有好的方式也能夠在評論區討論。
經過 color
屬性自定義按鈕的顏色。咱們能夠得出需求,無論 type 是什麼,color
屬性需始終覆蓋原有樣式,color 能影響的就是背景色、字體顏色和邊框顏色,因此咱們修改 getBackgroundColor
、getTextColor
、getBorderColor
樣式函數在合適的地方加上如下代碼便可:
if (props.color) {
return props.color;
}
複製代碼
實現效果以下:
咱們從 React Native 內置的 TouchableHighlight 組件繼承了不少事件,其中 onPress、onLongPress 分別表明單擊和長按。但惟獨「雙擊 666」的雙擊事件沒有姓名。以前在實際業務曾經封裝過雙擊事件,此次咱們就直接就內置了。
實現思路是延時執行單擊事件(默認 200 毫秒),而後記錄點擊次數和兩次時間間隔,當識別爲第二次點擊且時間間隔小於單擊延時時間。那麼就取消單擊事件延時,並當即執行雙擊事件。完整代碼以下:
let lastTime = 0;
let clickCount = 1;
let timeout = null;
const _onPress = (event: GestureResponderEvent) => {
const now = Date.now();
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(() => {
props.onPress(event);
clickCount = 1;
lastTime = 0;
}, props.delayDoublePress);
if (clickCount === 2 && now - lastTime <= props.delayDoublePress) {
clearTimeout(timeout);
clickCount = 1;
lastTime = 0;
props.onDoublePress(event);
} else {
clickCount++;
lastTime = now;
}
};
複製代碼
你們會發現這裏的實現糅合了函數防抖、節流以及計數器的原理,有興趣的小夥伴能夠自行復習下原理,這裏就不展開了。
一個組件的文檔,除了 Demo,還須要展現出來可用的 Props,Dumi 內置的 <API></API>
組件能夠根據組件自動生成 API 文檔。首先咱們像下面同樣編寫 Props 註釋:
interface ButtonProps extends TouchableHighlightProps {
/** * @description Can be set to primary、info、warning、danger * @description.zh-CN 類型,可選值爲 primary、info、warning、danger */
type?: 'default' | 'primary' | 'info' | 'warning' | 'danger';
/** * @description Can be set to large、small、mini * @description.zh-CN 尺寸,可選值爲 */
size?: 'large' | 'normal' | 'small' | 'mini';
}
複製代碼
而後在 Markdown 中引入 API 組件便可:
<API src="./index.tsx"></API>
複製代碼
內置組件 API 沒有處理繼承的狀況,咱們後續會自定義一個 API 組件,這裏就不展開了,瀏覽 Button 文檔 能夠查看如今的效果:
因爲很難在一篇文章中將組件開發相關的工程化講完,咱們須要在每篇實戰中串講一下。
小黑:洛竹,
lerna create
命令建立出來的模塊並非咱們想要的,之後要建立不少不少組件,咱們能夠寫一個建立組件模塊的腳手架嗎?
lerna 使用起來是有很多痛點的,lerna create
命令沒辦法指定模板,考慮到以後的幾十上百個組件每次建立都要進行項目結構、Typescript 配置、單元測試配置、Babel 配置等等工做步驟,咱們有必要寫一個腳手架。
說到模板解析,相信你們和我同樣想到的是 vue-cli 的 template 解析。經過閱讀 vue-cli@2.9.6 generate.js 源碼,咱們能夠分析出尤大是基於 metalsmith、handlebars、consolidate 這三個包來實現模板解析能力的。讓人不安的是其中 metalsmith 庫有長達 5 年沒有維護了,洛竹挑選開源項目通常對維護度很敏感,本着輪子要用本身造的原則,我翻看了 Metalsmith 的 Readme 發現這個插件無非是經過遞歸讀文件的方式渲染模板,而且它的靜態網站生成的能力對咱們模板解析的需求也是多餘的。
說幹就幹,在和 @林小帥 同窗簡單溝通後,我動手造了 handlebars-template-compiler 這個輪子,其主要原理以下:
const files = await recursive(rootDir);
複製代碼
handlebars.compile
方法使用元數據對模板進行渲染const content = fs.readFileSync(file).toString();
const result = handlebars.compile(content)(meta);
複製代碼
fs.writeFileSync
API 重寫文件另外,經過引入 glob 模式匹配實現了 exclude
配置以及只處理指定後綴(默認 **/*.tpl.*
)的文件來避免沒必要要的渲染。(PS:NPM 一週有了 300 多下載,有須要的掘友值得一試😄)
這裏洛竹嘗試用最簡潔的語言爲你們描述一個腳手架的誕生,源碼在 packages/scripts 目錄下,沒有接觸過 CLI 的掘友請相信我,Node CLI 很容易上手的。接觸過的同窗也能夠查漏補缺借鑑一二。
package.json
文件的 bin
字段是咱們腳手架的入口// 指定可執行文件的位置以及別名
"bin": {
"vant": "./bin/cli.js"
},
複製代碼
./bin/cli.js
爲可執行文件並調用 init
方法。// 因爲咱們的腳本是 Node 編寫的,因此須要指定 node 所在位置
#!/usr/bin/env node
const { init } = require('../lib');
// 這個地方參考了 create-react-native 的設計
// 本文點贊過 300,下一篇洛竹帶小黑爲你們帶來《基於 TypeScript 重構 create-react-native》
init();
複製代碼
src/index.ts
中初始化 commander 這個久負盛名的命令行框架const init = (): void => {
const packageJson = require('../package.json');
program.version(packageJson.version).description(packageJson.description);
// ...
program.parse(process.argv);
};
複製代碼
src/commands
目錄下並經過 fs.readdirSync
API 動態掃描註冊。const init = (): void => {
// 這段代碼借鑑自 NeteaseCloudMusicApi 項目,做者的代碼頗有設計感,推薦閱讀。
fs.readdirSync(path.join(__dirname, 'commands')).forEach((file: string) => {
if (!file.endsWith('.js')) return;
require(path.join(__dirname, 'commands', file));
});
// ...
};
複製代碼
commands
目錄下新建一個 create.ts
文件編寫命令import { program } from 'commander';
program
.command('create <name> [loc]')
.description('Create a new vant-react-native package')
.action((name,loc) => {
console.log('Hello Luozhu');
})
複製代碼
上一小結,咱們初始化了 CLI 並添加了 create
命令,這一小節咱們就來實現一下腳手架功能。
咱們首先在 packages/scripts
目錄下建立組件模板
.
├── README.tpl.md # tpl 後綴在生成組件模板的時候會被 handlebars-template-compiler 自動去掉。
├── package.tpl.json
├── src
│ └── index.ts # 沒有 tpl 後綴則不會被編譯,模板很大時能夠節省時間。
└── tsconfig.json
複製代碼
而後咱們明確咱們的模板元數據的數據結構,我這裏的數據結構是:
interface IMeta {
name: string;
version: string;
description: string;
author: string;
email: string;
url: string;
directory: string;
}
複製代碼
有了數據結構,咱們就可使用 inquirer 模塊引導用戶輸入信息。
import inquirer from 'inquirer';
// ...
// getQuestions 過長,感興趣的同窗能夠查看:http://tny.im/UFbg
const answer: IMeta = await inquirer.prompt(getQuestions(name));
// ...
複製代碼
下一步,咱們使用 tmp-promise
模塊建立一個系統臨時文件夾,並將前文提到的 template 文件夾的內容拷貝進去:
import tmp from 'tmp-promise';
import fs from 'fs-extra';
import path from 'path';
// ...
const tmpdir = await tmp.dir({ unsafeCleanup: true });
fs.copySync(path.join(__dirname, '../../template'), tmpdir.path);
複製代碼
最後,咱們對臨時文件夾的內容進行編譯再拷貝到指定位置便可:
import htc from 'handlebars-template-compiler';
// ...
await htc<IMeta>(answer, tmpdir.path);
fs.copySync(tmpdir.path, `${process.cwd()}/packages/${locPath}`);
// ...
複製代碼
折騰這一頓,讓咱們來看下成果吧:
大型的開源項目最難的不是技術問題,技術大咖永遠不會缺。最難的實際上是協做和後期維護。試想一下一個成百上千人蔘與的項目當有新的 pr 時,正常人根本無力去快速檢索出須要誰去 review 代碼。咱們的 vant-react-native 因爲是將每一個組件單獨發包維護,當參與的小夥伴多了也會產生這個困擾。
而 GitHub CODEOWNERS(代碼全部者)就是爲了解決這個問題的,在 5000+ 貢獻者參與的 DefinitelyTyped 項目中咱們就能夠看到它的身影。官方對代碼全部者定義以下:
你可使用 CODEOWNERS 文件定義負責倉庫代碼的我的或團隊。當有人修改代碼並打開一個 pull request 時,將自動請求代碼全部者進行審查。
CODEOWNERS 文件使用遵循 gitignore 文件中所用大多數規則的模式,CODEOWNERS 文件位置通常位於 .github/
目錄下。
在 vant-react-native,洛竹是倉庫的最終負責人,因此是指望每一個 pr 均可以分配給本身審查一下的。那麼咱們這就來實驗一下吧,新建一個 .github/CODEOWNERS
文件並寫入如下內容:
# This is a comment.
# Each line is a file pattern followed by one or more owners.
# These owners will be the default owners for everything in
# the repo. Unless a later match takes precedence,
# @youngjuning will be requested for review when someone opens a pull request.
* @youngjuning
# In this example, @doctocat owns any files in the build/logs
# directory at the root of the repository and any of its
# subdirectories.
/packages/ @luozhu1994
複製代碼
通常若是文件具備代碼全部者,則在打開拉取請求以前能夠看到代碼全部者是誰。在倉庫中,你能夠找到文件並懸停於一個鎖圖標上,懸浮以後會告訴你該文件全部者是誰:
而後咱們提交一個 pr 看看效果:
發包權限通常只有倉庫全部者一我的擁有,可是 owner 同時維護好幾個 NPM 帳號,或者是 owner 突然很忙將發佈權限交給其餘人管理員可是不便告知 NPM 帳號該怎麼辦呢?答案是將 NPM 發包 CD(持續部署)化,公司通常會基於 Gitlab 或自建平臺實現該功能。做爲開源項目,咱們固然是使用 GitHub Action。
正常的單包項目,使用 npm-publish 或 npm-publish-action 這兩個 GitHub Action,這並無好講的。可是基於 lerna 的多包單體倉庫並無現成的插件能夠用,照例,咱們來看下本身實現的步驟:
chore(release):
開頭
經過 GitHub Action
startsWith(github.event.head_commit.message, 'chore(release):')
實現
經過
npm config set //registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}
認證
lerna publish from-package --yes
發佈
須要本地先執行
lerna version
系列命令提高版本
完整 GitHub Action 實現以下:
name: npm-publish
on:
push:
branches:
- main
jobs:
npm-publish:
runs-on: ubuntu-latest
if: startsWith(github.event.head_commit.message, 'chore(release):')
steps:
- uses: actions/checkout@v2
- uses: c-hive/gha-yarn-cache@v2 # 緩存 node_modules 加快構建速度
- name: Install Packages
run: yarn install --registry=https://registry.npmjs.org/
- name: Authenticate with Registry
run: | npm config set //registry.npmjs.org/:_authToken=${NPM_TOKEN} env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Publish package
run: lerna publish from-package --yes
複製代碼
爲了在發佈後及時獲取通知,洛竹使用了 peter-evans/commit-comment
插件在發佈失敗或成功後對相應 commit 進行評論,這樣咱們就能夠收到郵件和站內通知。
- name: Create commit comment after publish successfully
if: ${{ success() }}
uses: peter-evans/commit-comment@v1
with:
body: | Hello Dear @youngjuning. This commit has been publish to NPM successfully. > Created by [commit-comment][1]
[1]: https://github.com/peter-evans/commit-comment
- name: Create commit comment after publish unsuccessfully
if: ${{ failure() }}
uses: peter-evans/commit-comment@v1
with:
body: | Hello Dear @youngjuning. This commit has been publish to NPM unsuccessfully. > Created by [commit-comment][1]
[1]: https://github.com/peter-evans/commit-comment
複製代碼
截止發稿時,每一個前端都值得擁有本身的組件庫,就像每一個夏天都擁有西瓜🍉 已得到近 1600 贊、超 4 萬閱讀📖,再次再次感謝掘友的支持、編輯 Zoe 的鞭策,月影大佬的轉載、朋友的轉發以及本身的堅持。