前言
2021年了,你还不会创建自己的组件库?还没有发布过NPM包?还不会TypeScript?不必惊慌,因为我也不会,哈哈~,有兴趣的朋友跟着我一起从零开始,使用typescript创建并发布自己的第一个组件库吧!
创建项目
使用React官方的脚手架create-react-app创建项目 npx create-react-app btns-ts --template typescript
,命令中的btns-ts为本次演示组件库的名称。--template typescript表示创建的是TypeScript项目。
关于TypeScript的介绍和使用请参照官方的文档,这里只是代码层面做简单的注释,因为我们的重点不是这个。
创建组件
为了更好的管理项目,在src下创建components文件夹,用于存放项目中所有的公共组件,为了逻辑更清晰明了,本次只创建Button组件。
开始写Button组件
Button组件的jsx代码
button组件引入classnames这个库,用于类名的合成,这个库可以很方便的合并多个类名,并且支持条件判断等功能,具体使用请参考它的文档。
// 文件路径src/components/Button/button.tsc
import React, { ReactNode, ButtonHTMLAttributes, AnchorHTMLAttributes, FC } from 'react';
// 类名合并的小工具,安装命令是: npm install classnames @types/classnames --save
import classnames from 'classnames';
// 定义按钮的类型和大小
export type ButtonType = 'primary' | 'default' | 'danger' | 'link' | 'dash'
export type Size = 'lg' | 'md' | 'lg'
// 用interface定义按钮props类型约束
interface baseBtnType {
children?: ReactNode,
className?: string,
btnType?: ButtonType,
size?: Size
}
// 定义两种联合类型,一种是button型的,一种是a标签型的按钮
type NativeButtonProps = baseBtnType & ButtonHTMLAttributes<HTMLElement> // 基础按钮类型,props类型定义
type AnchorButtonProps = baseBtnType & AnchorHTMLAttributes<HTMLElement> // a标签类型的按钮,props类型定义
// 用Partial组合两种类型
export type ButtonProps = Partial<NativeButtonProps & AnchorButtonProps> // 按钮最终的prop类型定义
// 使用泛型定义函数的入参及返回值类型
export const Button: FC<ButtonProps> = (props) => {
let {
className,
children,
btnType,
size,
...restProps
} = props
// 类名合并工具classnames
const finalClassName = classnames('dd-btn', className, {
[`btn-${btnType}`]: btnType,
[`btn-${size}`]: size,
})
return (
<button
className={finalClassName}
{...restProps}
>
{
children
}
</button>
)
}
Button.defaultProps = {
disabled: false,
btnType: 'primary',
size: 'md'
}
export default Button
Button组件的css代码
为了文章不那么长(容易吓跑读者),Button的样式文件,只列出一部分,文末会给出项目的Github地址。
/*文件路径:src/components/Button/_button.scss*/
/*重置button的默认样式*/
button {
outline: 0;
// border: none;
border: 1px solid #d9d9d9;
}
/*button的基础样式,使用了sass的变量和mixins*/
.dd-btn {
position: relative;
display: inline-block;
font-weight: $btn-font-weight;
line-height: $btn-line-height;
color: $body-color;
white-space: nowrap;
text-align: center;
vertical-align: middle;
background-image: none;
user-select: none;
@include button-size($btn-padding-y, $btn-padding-x, $btn-font-size, $btn-border-radius);
cursor: pointer;
&.disabled,
&[disabled] {
cursor: not-allowed;
opacity: $btn-disabled-opacity;
box-shadow: none;
> * {
pointer-events: none;
}
}
}
/*...其他略*/
预览Button组件的效果
组件预览就简单了,直接引入到app.tsx
文件中,运行npm start
命令就可以在浏览器查看效果了。
文件路径:src/app.tsx
import React from 'react';
import logo from './logo.svg';
import './App.css';
import Button from './components/Button'; // 引入Button组件
import './styles/index.scss'; // 引入样式
function App() {
return (
<div className="App">
<h1>Button</h1>
<h2>不同类型的按钮</h2>
<div style={{ display: 'flex', alignItems: 'flex-start' }}>
<Button btnType="default">default</Button>
<Button btnType="primary">primary</Button>
<Button btnType="danger">danger</Button>
<Button btnType="dash">dash</Button>
<Button btnType="link">link</Button>
</div>
</div>
);
}
export default App;
效果图如下:
组件库样式管理
细心的同学可能已经发现,button.tsx中并没有引入_button.scss样式文件,样式为何会生效?答案就是在其他地方引入了,这就是我接下来要介绍的——组件库的样式
既然是写组件库,自然会有很多的样式文件,如何组织样式文件才更利于维护和复用?答案就是利用Sass来书写样式。因为Sass支持模块化,变量,mixins等原生css没有的特性。废话不多说,一起看看如何管理组件库的样式的。
如下图所示,在src目录下创建styles文件夹,用于存放不同功能的sass样式文件。
每个scss文件的作用如下:
- _animation.scss存放所有css动画
- _minxins.scss 存放sass的mixin函数,把公共的功能抽离成sass函数,达到更好的复用
- _variables.scss 存放所有的sass变量,这个是写组件库的必备,方便后期实现一键换主题等功能
- index.scss styles入口文件,用于引入项目中所有的scss文件(包括组件的样式文件)
一起来看看index.scss文件的真面目:
// normalize
@import '../../node_modules/normalize-scss/sass/normalize';
@include normalize();
// config
@import "variables";
// mixins
@import "mixins";
// 引入Button组件的样式
@import "../components/Button/button";
留意最后一行,我们就是在这里引入Button组件的样式的,细心的小伙伴可能已经发现,_button.scss和_ariables.scss等文件都是下划线开头的。这是Sass的特性之一,下划线开头的sass文件表示内部样式文件,可以使用@import 文件名(去掉下划线和后缀)
的方式引入。
这里的样式引入顺序也很关键,首先引入_normalize.scss
抹平不同浏览器的差异,接着引入_variables.scss
和_mixins.scss
文件,组件样式放到最后,这样每个组件就可以直接使用前面定义好的变量和mixins,开发新组件时,在文件的末尾引入其样式即可。
组件库打包
组件写好了,也预览了功能,接下来的步骤就是组件的打包。所谓打包,就是把src下的typescript代码打包到特定的文件目录下(多么通俗易懂的解释!)。为了完成这个简单的打包过程,我们需要完成以下几个步骤。
1、配置tsconfig.build.json文件
使用文章开头创建项目的命令npx create-react-app btns-ts --template typescript
,创建出来的项目目录下本身就有一个tsconfig.json
文件,为啥我们还要再创建一个?因为这样解释起来更清晰啊!!
tsconfig.build.json是一个配置文件,每个配置项的含义请看注释。
文件路径:项目根目录/tsconfig.build.json
{
"compilerOptions": {
"outDir": "build", // 打包输出的路径
"module": "esnext", // 指定生成哪个模块系统代码
"target": "es5", // 指定ECMAScript目标版本(默认"ES3")
"declaration": true, // 是否生成相应的 .d.ts文件。
"declarationDir":"./build", // 生成.d.ts文件的路径
"jsx": "react", // 在 .tsx文件里支持JSX: "React"或 "Preserve"
"moduleResolution": "node", // 决定如何处理模块。或者是"Node"对于Node.js/io.js,或者是"Classic"(默认)。
"allowSyntheticDefaultImports": true // 允许从没有设置默认导出的模块中默认导入。这并不影响代码的输出,仅为了类型检查。
},
"include": [
"src"
],
"exclude": [
"src/**/*.test.tsx",
"src/**/*.stories.tsx",
"src/stories/"
]
}
更多的配置项,请参照官方文档
2、配置package.json文件
配置package.json文件,是为了打包和发包做准备,name,version等配置都比较简单,大家看注释就好。需要注意的是,有注释的是发包必须配置的选项! 。
这里我们只着重讲打包命令,即build-lib
,该命令是一个组合命令,它首先会调用clean命令,清空原来的build文件夹;接着调用build-ts
命令,将typescript代码编译成js代码;最后调用的是build-css
,将scss文件编译成css文件。
配置和命令写好了,是不是可以打包了?理论上是的,但其实还不可以!还需要修改一下index.tsx文件。
文件路径:项目根目录/package.json
"name": "btns-ts", // 组件库名称,如果重明就换一个或加上自己的前缀,例如: @linlif-btns-ts
"version": "0.1.0", // 版本号,每次发包到npm的版本号都要不一样,且要遵从命名规范
"private": false, // 是否私有,修改为false
"main": "build/index.js", // 组件库的入口
"module": "build/index.js", // 组件库es模块入口
"types": "build/index.d.ts", // 组件库types声明入口
"decription": "A wonderful react UI component", // 组件库描述
"author": "linlif", // 作者
"keyword": [ // 关键词
"UI",
"React",
"Component"
],
...省略...
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"build-ts": "tsc -p tsconfig.build.json",
"build-css": "node-sass ./src/styles/index.scss ./build/index.css",
"clean": "rimraf ./build",
"build-lib": "npm run clean && npm run build-ts && npm run build-css"
},
...省略...
3、修改index.tsx文件
为什么要修改入口文件?因为我们写的是React组件库,不是React应用!
默认情况下,index.tsx的内容如下:
文件路径:src/index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
这一坨内容的意思是,使用ReactDOM的render方法,将APP.tsx这个组件,渲染到index.html中的,id为root的div中。现在,我们把所有内容都删掉!然后加上一条代码。
修改后,index.tsx的内容如下所示:
文件路径:src/index.tsx
export { default as Button } from './components/Button/button'
// 多个组件时,就多写几条导出语句咯,这不用我教你吧!
这么修改是告诉打包工具,我现在要导出的是一个个的组件,而不是将代码打包到index.html文件中。 经过以上三步的修改,你就可以允许打包命令了。是不是很累,累就对了!我写作也很累啊,你怎么不点个赞?
4、运行打包命令
打开控制台,cd到项目的根目录(package.json所在目录叫根目录),输入npm run build-lib
,稍等片刻,就可以看到根目录下出现build文件夹,这个文件夹就是打包的产物了。
使用npm link调试组件库
经过一翻翻云覆雨,咳咳,是一波辛苦的操作后,组件库终于打包出来,接下来就是调试了。
组件库的调试,需要创建另一个项目(总不能自己调试自己吧?!)才可以完成。创建项目相信大家已经很熟悉了(create-react-app 一把梭!不会的请参照文章开头),这里不再赘述!
如何使用npm link
命令调试本地的npm包?
假设npm包名称(即组件库名称)为:btns-ts
,测试项目名称为:my-project
。
// 先去到btns-ts的根目录,把它 link 到全局
# cd path/to/btns-ts
# npm link
// 再去项目目录通过包名来 link,需要注意的是,my-project项目的node_modules目录中不要有btns-ts包,如果有请删除
# cd path/to/my-project
# npm link btns-ts
执行完以上操作后,打开my-project
项目的App.tsx文件,引入组件库中的Button
组件,并使用它,看看各项功能是否符合预期,这就是调试的过程了。
npm link本地调试的好处在于,当你的组件库修改重新打包后(无需运行npm link命令),测试项目中就可以立刻看到效果。该命令的存在就是为了方便调试组件,避免每一次调试都要发包的尴尬!
import React from 'react';
import logo from './logo.svg';
import './App.css';
import { Button } from 'btns-ts' // 引入组件库中的Button组件
import 'dd-ui-react/build/index.css'
const App: React.FC = () => {
return (
<div style={{ padding: 20 }}>
<h2>btn-ts Button 示例</h2>
<Button btnType="primary">Primary</Button> // 使用Button组件
</div>
);
}
export default App;
看看调试效果吧:
调试完以后,你可能需要取消/删除npm link的包。
// 取消link(取消 my-project 和 my-utils 的 link 关系)
# cd path/to/my-project
# npm unlink my-utils
// 删除link(删除全局 my-utils 的 link)
# cd path/to/my-utils
# npm unlink my-utils
将组件库发布到NPM
经过严格的本地调试,组件库已经比较完善,终于可以将组件库发布到NPM了(God!鬼知道我经历了什么~)。
1、第一步,注册一个npm账号(已注册请跳过),注册的地址为:www.npmjs.com/signup ;
2、cd到项目的根目录,如果是第一次发包,执行npm adduser
添加用户,如果不是第一次了,就执行npm login
登录你的账号。由于我已经不是第一次,所以只能演示login给你们看了。
3、输入npm publish
执行发布,等命令执行完,登录到npm,点击头像,点击packages,就可以看到我们刚刚发布的组件库了。是不是很简单!
结语
看到这里,相信你已了解如何使用TypeScript和React创建组件库、如何调试和发布组件库。此次手把手只是一次开始,更多深入的知识还需要大家自行扩展。我就不扩展了,咻~闪现溜走...
组件库地址: github.com/linlif/btns…
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!