当前位置: 首页 > Web前端 > HTML5

Deer-ui:一个简单高效的react组件库

时间:2023-04-05 13:11:22 HTML5

1.前言一直想搭建自己的博客系统,今年年底终于有时间开发了。在开发后台cms系统的时候,用到了antd的组件库,突然问自己,组件库是怎么实现的,内部是怎么工作的,打包部署的原理,带着这些问题,我开始萌生了自己开发一个组件库。去做就对了。我用了大约2个月的时间才完成了deer-ui第一版的组件开发。现分享出来,记录下自己在开发过程中踩过的坑。deer-ui源码|官网预览地址二、组件库开发准备工作需求准备首先确定需求,初步考察流行的组件库,如antd、vant、zarm-web、cuke-ui、iview等,最后选择antd作为ui参考。技术准备组件库预览网站技术选择,比较了几个(docz、styleguidist、storebook),最终选择storebook作为展示网站,不限于此,项目还集成了docz、styleguidist封装,有需要的可以实现。最终确定了两种组件调试方案,可根据需求定制。1、在源码中使用create-react-app搭建react环境。在example文件夹下,使用npmrundev打开调试环境,导入编写好的组件。2、在源码中搭建一套组件库的文档部署环境,使用命令npmrunstorybook进入文档模式,导入编写好的组件。组件库代码打包。参考了几个比较流行的组件库后,决定自己手写打包配置文件来打包发布版本。组件库引入自动发布,运行脚本后直接发布npm仓库第一期的组件分类。由于时间原因,不可能一次开发完所有的组件,所以第一阶段准备开发以下16个组件3.构建项目3.1项目结构.storebookstorebook的一些配置组件放置所有组件example组件调试环境代码脚本发布,打包脚本文件stories项目静态文件,负责demo演示和一些配置文件Module、commonjs、script脚本的引入,这就需要我们的组件库满足这些规范。通常使用webpack将它们打包成umd规范,以满足上述不同的导入。...模式:“生产”,条目:{[名称]:[”。/components/index.js”]},输出:{路径:path.join(process.cwd(),“dist”),库:name,libraryTarget:"umd",umdNamedDefine:true,filename:"index.js",},...打包入口为components/index.js文件,主要是导出组件export{defaultasButton}from'./button';export{defaultasTabs}from'./tabs';export{defaultasIcon}from'./icons';打包后,所有打包的组件都会在dist目录下生成一个index.js文件。其他的webpack配置就不一一详述了。如有必要,检查脚本目录。3.3按需加载组件打包3.3.1打包js文件通过上述webpack打包的组件库代码全部导入,所有组件代码一起打包。为了减小导入的组件库的大小,一般采用按需加载的方式。按需加载的核心是将各个组件单独打包,单独导入。通过babel打包js文件"build:lib":"cross-envOUTPUT_MODULE=commonjsbabelcomponents-dlib""build:es":"babelcomponents-des",3.3.2打包样式文件各样式文件component将其解压到lib和es文件对应的components下,css打包代码如下。这块是基于cuke-ui的配置,通过gulpflow打包css文件。/***@namegulpfile.js*@description打包项目css依赖*/constpath=require("path");constgulp=require("gulp");constconcat=require("gulp-concat");constless=require("gulp-less");constautoprefixer=require("gulp-autoprefixer");constcssnano=require("gulp-cssnano");constsize=require("gulp-filesize");constsourcemaps=require("gulp-sourcemaps");constrename=require("gulp-rename");const{name,browserList}=require("../package.json");constDIR={less:path.resolve(__dirname,"../components/**/*.less"),buildSrc:[path.resolve(__dirname,"../components/**/style.less"),path.resolve(__dirname,"../components/**/index.less")],lib:path.resolve(__dirname,"../lib"),es:path.resolve(__dirname,"../es"),dist:路径。resolve(__dirname,"../dist")};gulp.task("copyLess",()=>{returngulp.src(DIR.less).pipe(gulp.dest(DIR.lib)).pipe(gulp.dest(DIR.es));});gulp.task("copyCss",()=>{returngulp.src(DIR.buildSrc).pipe(sourcemaps.init()).pipe(less({outputStyle:"compressed"})).pipe(autoprefixer({browsers:browserList})).pipe(size()).pipe(cssnano()).pipe(gulp.dest(DIR.lib)).pipe(gulp.dest(DIR.es));});gulp.task("dist",()=>{returngulp.src(DIR.buildSrc).pipe(sourcemaps.init()).pipe(less({outputStyle:"compressed"})).pipe(autoprefixer({browsers:browserList})).pipe(concat(`${name}.css`)).pipe(size()).pipe(gulp.dest(DIR.dist)).pipe(sourcemaps.write()).pipe(size()).pipe(gulp.dest(DIR.dist)).pipe(cssnano()).pipe(concat(`${name}.min.css`)).pipe(size()).pipe(gulp.dest(DIR.dist)).pipe(sourcemaps.write()).pipe(size()).pipe(gulp.dest(DIR.dist));});gulp.task("默认",gulp.series(["copyLess","copyCss","dist"]));3.3.3组件库文档构建通过storybook构建文档,文档地址预览。具体配置如下importReactfrom"react";import{configure,addDecorator,addParameters}from'@storybook/react';const{name,repository,version}=require("../package.json")import{configureActions}from'@storybook/addon-actions';import'@storybook/插件控制台';导入“@storybook/addon-options/register”;import"../stories/style/index.less"import"../stories/style/code.less"functionloadStories(){//介绍require('../stories/index');//基本组件require('../stories/basis');//数据展示require('../stories/showData');//操作反馈require('../stories/feedback');//交互组件require('../stories/interaction');//布局组件require('../stories/layout');}configureActions({depth:100})//加载配置addParameters({options:{name:`${name}v${version}`,title:"Deer-ui",url:repository,showSearchBox:false,showPanel:false,enableShortcuts:false,isToolshown:false,selectedPanel:undefined,hierarchySeparator:null,hierarchyRootSeparator:null,showAddonPanel:false,}})//中间内容保证金addDecorator(story=>{story()}

)configure(loadStories,module);编写组件文档storiesOf("操作反馈",module).add("自旋加载",()=>(

基本使用

`}>))最后单独配置storybook的webpack.config.js,注意配置格式和一般的webpackconstwebpack=require("webpack");module.exports=async({config,mode})=>{config.resolve={extensions:[".js",".jsx",".json",".jsx"]};config.module.rules.push({test:/\.(js|jsx)?$/,loaders:[require.resolve("@storybook/source-loader")],enforce:"pre",排除:/节点模块/});config.module.rules.push({测试:/\.scss$/,使用:["style-loader","css-loader","postcss-loader",{loader:"sass-loader"}]},{test:/\.less$/,使用:["style-loader","css-loader","postcss-loader",{loader:"less-loader",选项:{javascriptEnabled:true},}]});config.plugins.push(newwebpack.ContextReplacementPlugin(/moment[/\\]locale$/,/zh-cn|en-gb/));返回配置;};4。开发组件工程的框架已经搭建好,可以在components目录下开发组件,比如按钮组件,删除版...omitclassButtonextendsComponent{return(
);}}exportdefaultButton;导出index.js文件中的button组件export{defaultasButton}from'./button';5.发布组件库开发完成后,就可以发布代码到npm仓库了,默认大家都会发布npm包,不明白的可以参考掘金上的npm问题框架提供自动发布命令、打包、发布、lint、日志等功能5.1发布组件库npmrunpub:prod//自动完成css,js,es,lin,umd打包,自动生成changelog,发布npm仓库,for修订版本号。1.0.*npmrunpub:major//上面的区别都会补齐,唯一的区别就是npm版本号不同,这个命令是主版本号,不经常用*.0.0npmrunpub:minor//以上都会完成不同的,唯一不同的是npm的版本号不同,这个命令是打版本号,1.*.0不常用"pub:prod":"npmrunstandard:patch&&npmrunbuild&&npmpublish--registryhttps://registry.npmjs.org&&gitpush"//放版本号和release5.2发布组件库文档组件库提供两种发布方式1.npmrunpub:docs使用storybook发布,这种方式需要在package.json中配置账号信息。"storybook-deployer":{"gitUsername":"deer-ui","gitEmail":"youremail","commitMessage":"docs:deploydocs"},2.npmrundeploy//这条命令会执行脚本deploy.sh文件,打包发布组件库document#!/bin/bash#确保脚本抛出遇到的错误set-eecho"startbuild..."#打包文件npmrunbuild:docsecho"√buildsuccess"#进入生成的文件夹cd.docsecho"startpublish..."#提交到gh-pagesgitconfig--getremote.origin.urlgitinitgitconfiguser.name"xxxx"gitconfiguser.email"xxxx"gitadd.gitcommit-m'docs:publish'gitpush--force--quietgit@github.com:zhangboyang123/deer-ui.gitmaster:gh-pagesecho"√发布成功?"cd-6,主题定制6.1,主题变量Deer-ui使用less作为样式开发语言,定义了一系列全局/组件样式变量,您可以根据需要进行相应调整。下面是一些最常用的通用变量,所有样式变量都可以在这里找到。@原色:#31c27c;//全局颜色@warning-color:#fca130;//警告色@error-color:#f93e3e;//失败颜色@success-color:#35C613;//成功颜色@info-color:#61affe;//信息显示颜色@default-color:#d9d9d9;//默认颜色@border-color:#e8e8e8;//边框颜色@border-radius:4px;//边框圆角@font-size:14px;//默认组件字体大小@font-size-small:12px;//小字体@font-size-large:16px;//大字体@bg-color:#FAFAFA;//组件背景色@font-color:rgba(0,0,0,.65);//字体颜色@disabled-font-color:fade(@font-color,30%);//disablefontcolor6.2主题定制原理主题定制原理以上是使用less提供的modifyVars方法覆盖变量。使用选项在webpack中配置less-loader。请注意,应打开javascriptEnabled。//webpack.config.jsmodule.exports={rules:[{test:/\.less$/,use:[{loader:'style-loader',},{loader:'css-loader',//翻译CSSintoCommonJS},{loader:'less-loader',//将Less编译成CSS+options:{+modifyVars:{+'primary-color':'#1DA57A',+'info-color':'#1DA57A',+'font-size':'12px',+//or+'hack':`true;@import"your-less-file-path.less";`,//或者引用本地样式文件override+},+javascriptEnabled:true,+},}],}],}注意,自定义主题后,处理less-loader的范围无法过滤掉node_modules下的deer-ui包。7、按需加载7.1importimportButtonfrom'deer-ui/es/button';import'deer-ui/es/button/style.less';7.2使用babel-plugin-import//在.babelrc中单独使用在.js中配置module.exports={plugins:[["import",{"libraryName":"deer-ui","libraryDirectory":"es","style":true},"deer-ui"],]}//多个组件库,如antdmodule.exports={plugins:[["import",{"libraryName":"deer-ui","libraryDirectory":"es","style":true},'deer-ui'],["import",{"libraryName":"antd","libraryDirectory":"es","style":true},'antd'],]###8.后续计划第一阶段组件已经开发完毕,进行message、input、radio、button、table、checkbox、collapse、tabs、empty.loading、icon等基础组件的开发,分频器已经基本完成;Deer-ui组件库框架搭建完成,实现自动化打包部署,添加stylelint、eslint、commitlint,自动生成changelog,构建组件库测试环境,构建组件库官网,定制主题。随后添加了组件库和国际化功能的自动化测试。继续完成以下组件的开发。最后想象一下,用ts来完成组件库的重构。9.总结开发完组件库,可能没什么意义,但是通过这个组件库,让我学到了很多平时接触不到的知识点。有时候看着很简单的东西,自己发现里面有很多坑。总的来说,去年给自己定下的小目标已经实现了,今年继续在前端路上折腾。俗话说,生命不息,编码不息。