最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 保姆级教程:手把手教你创建和发布一个NPM组件库(React)!

    正文概述 掘金(linif002)   2021-04-01   906

    前言

    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组件。

    保姆级教程:手把手教你创建和发布一个NPM组件库(React)!

    开始写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;
    
    

    效果图如下:

    保姆级教程:手把手教你创建和发布一个NPM组件库(React)!

    组件库样式管理

    细心的同学可能已经发现,button.tsx中并没有引入_button.scss样式文件,样式为何会生效?答案就是在其他地方引入了,这就是我接下来要介绍的——组件库的样式

    既然是写组件库,自然会有很多的样式文件,如何组织样式文件才更利于维护和复用?答案就是利用Sass来书写样式。因为Sass支持模块化,变量,mixins等原生css没有的特性。废话不多说,一起看看如何管理组件库的样式的。

    如下图所示,在src目录下创建styles文件夹,用于存放不同功能的sass样式文件。

    保姆级教程:手把手教你创建和发布一个NPM组件库(React)!

    每个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文件,为啥我们还要再创建一个?因为这样解释起来更清晰啊!!

    保姆级教程:手把手教你创建和发布一个NPM组件库(React)!

    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组件库(React)!

    使用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组件库(React)!

    调试完以后,你可能需要取消/删除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给你们看了。

    保姆级教程:手把手教你创建和发布一个NPM组件库(React)!

    3、输入npm publish执行发布,等命令执行完,登录到npm,点击头像,点击packages,就可以看到我们刚刚发布的组件库了。是不是很简单!

    保姆级教程:手把手教你创建和发布一个NPM组件库(React)!

    结语

    看到这里,相信你已了解如何使用TypeScript和React创建组件库、如何调试和发布组件库。此次手把手只是一次开始,更多深入的知识还需要大家自行扩展。我就不扩展了,咻~闪现溜走...

    组件库地址: github.com/linlif/btns…


    起源地下载网 » 保姆级教程:手把手教你创建和发布一个NPM组件库(React)!

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元