上面创建了一堆utils,component-info,实现了新建组件模块的相关目录和文件的创建。本文继续实现以下内容。1组件样式文件并导入在src/service目录下创建init-scss.ts文件导出initScss函数。由于.vue类型组件的样式直接写在style中,首先判断组件类型是否为tsx,只有tsx类型组件执行这一步:在scss/components/目录下创建组件的scssfile_xxx。模块.scss;在scss/components/index.scss中导入_xxx.module.scss。1.1init-scss.ts代码实现如下:import{ComponentInfo}from'../domain/component-info'importpathfrom'path'import{scssTemplate}from'../util/template-utils'importfsfrom'fs'import{g}from'../util/log-utils'constupdateComponentScssIndex=(scssRootPath:string,lineName:string)=>{constindexScssPath=path.resolve(scssRootPath,'components/index.scss')constcontent=fs.readFileSync(indexScssPath).toString()constnewContent=content.substring(0,content.length)+`@use"${lineName}.module";\n`fs.writeFileSync(indexScssPath,newContent)}/***创建组件库scss文件并导入scss/components/index.scss*/exportconstinitScss=(componentInfo:ComponentInfo)=>newPromise((resolve,reject)=>{//tsxtype需要创建scss文件if(componentInfo.type==='tsx'){const{parentPath,lineName,lineNameWithPrefix}=componentInfo//scss根目录(packages/scss)constscssRootPath=path.resolve(parentPath,'scss')//1.创建组件scss文件constcomponentScssPath=path.resolve(scssRootPath,`components/_${lineName}.module.scss`)fs.writeFileSync(componentScssPath,scssTemplate(lineNameWithPrefix))//2.组件库中的scss入口文件(packages/components/index.scss)引入上面创建的文件updateComponentScssIndex(scssRootPath,lineName)g('componentscssinitsuccess')}resolve(componentInfo)})1.2template-utils.ts上面init-scss.ts在创建scss的时候调用template-utils.ts中的scssTemplate函数获取模板,需要在util/template-utils.ts中添加这个函数:/***scssfiletemplate*/exportconstscssTemplate=(lineNameWithPrefix:string):string=>{返回`@import"../tools";@import"../acss/mp";@import"../base/var.module";@includeb('${lineNameWithPrefix}'){}`}2添加到组件库入口模块新的组件和样式创建完成,接下来就是将新的组件模块安装到组件库的依赖中入库模块。在src/service目录下创建update-component-lib.ts文件,导出函数updateComponentLib。该函数需要完成两件事:在组件库入口模块中安装新的组件作为依赖;更新组件库入口模块的index.ts文件,引入新组件。代码实际如下:import{ComponentInfo}from'../domain/component-info'import{execCmd}from'../util/cmd-utils'importpathfrom'path'import{Config}from'../config'从'fs'导入{g}从'../util/log-utils'constupdateComponentLibIndex=(libPath:string,componentInfo:ComponentInfo)=>{constindexPath=path.join(libPath,'index.ts')constcontent=fs.readFileSync(indexPath).toString()constindex1=content.indexOf('//importcomponentend')constindex2=content.indexOf(']//components')constresult=`${content.substring(0,index1)}`+`从'${componentInfo.nameWithLib}'导入${componentInfo.upCamelName}\n`+content.substring(index1,index2-1)+`,\n${componentInfo.upCamelName}\n`+content.substring(index2)fs.writeFileSync(indexPath,result)}/***更新组库入口*/exportconstupdateComponentLib=async(componentInfo:ComponentInfo)=>{//组库入口的路径constlibPath=path.resolve(componentInfo.parentPath,Config.COMPONENT_LIB_NAME)//1.将新创建的组件添加到依赖项中awaitexecCmd(`cd${libPath}&&pnpminstall${componentInfo.nameWithLib}`)//2.更新条目index.tsupdateComponentLibIndex(libPath,componentInfo)g('组件库更新成功')}3组件库文档相关文件3.1init-doc.ts在src/service目录下创建init-doc.ts文件,该文件导出函数initDoc该函数需要完成三个things要做的事情:为一个组件创建一个MarkDown文档;在组件的MD文档中创建一个演示;更新组件库文档菜单。代码实现如下:import{ComponentInfo}from'../domain/component-info'import{g}from'../util/log-utils'importpathfrom'path'importfsfrom'fs'import{demoTemplate,mdTemplate}from'../util/template-utils'/***创建组件文档、demo和更新菜单*/exportconstinitDoc=(componentInfo:ComponentInfo)=>{//组件库文档根路径constdocRootPath=path.resolve(componentInfo.parentPath,'../docs')const{lineName,lineNameWithPrefix,upCamelName,zhName}=componentInfo//1.创建组件的MD文档fs.writeFileSync(path.resolve(docRootPath,`components/${lineName}.md`),mdTemplate(componentInfo))//2.在组件文档中创建一个demofs.mkdirSync(path.resolve(docRootPath,`demos/${lineName}`))fs.writeFileSync(path.resolve(docRootPath,`demos/${lineName}/${lineName}-1.vue`),demoTemplate(lineNameWithPrefix))//3.更新组件库文档菜单constmenuPath=path.resolve(docRootPath,'components.ts')constcontent=fs.readFileSync(menuPath).toString()constindex=content.indexOf(']//end')constresult=content.substring(0,index-1)+`,\n{text:'${upCamelName}${zhName}',link:'/components/${lineName}'}\n`+content.substring(index)fs.writeFileSync(menuPath,result)g('componentdocumentinitsuccess')}3.2template-utils.ts上面的init-doc.ts调用了两个函数mdTemplate和demoTemplate,在template-utils.ts中添加这两个函数:exportconstmdTemplate=(componentInfo:ComponentInfo)=>{return`#${componentInfo.upCamelName}${componentInfo.zhName}##基本使用##ComponentAPI###Attributes属性|参数|说明|类型|可选值|默认||----|----|----|----|----|||||||###方法方法|方法名称|说明|参数|返回值||----|----|----|----||||||###事件事件|活动名称|说明|参数|返回值||----|----|----|----||||||###插槽|插槽名称|说明|参数||----|----|----|||||`}exportconstdemoTemplate=(lineNameWithPrefix:string)=>{return`<${lineNameWithPrefix}>${lineNameWithPrefix}>`}这两个函数的模板可以自己定义4create-component.ts四步实现了,最后需要在src/command/create-以上四个服务调用是在component.ts文件中的createNewComponent函数中完成的。4.1import导入四个服务和其他用到的函数:../util/log-utils'import{initComponent}from'../service/init-component'import{initScss}from'../service/init-scss'import{updateComponentLib}from'../service/update-component-lib'import{initDoc}from'../service/init-doc'4.2createNewComponent该函数首先根据用户输入构造一个ComponentInfo对象,然后依次调用导入的四个服务完成创建component整个过程:constcreateNewComponent=async(componentName:string,description:string,componentType:string)=>{console.log(componentName,description,componentType)showLoading('正在生成,请稍候...')try{//1.ConstructComponentInfoobjectconstcomponentInfo=newComponentInfo(componentName,description,componentType)//2.创建组件nt目录和文件awaitinitComponent(componentInfo)//3.创建样式awaitinitScss(componentInfo)//4.更新组件库入口awaitupdateeComponentLib(componentInfo)//5.组件库文档initDoc(componentInfo)closeLoading()g(`component[${componentInfo.lineName}${componentInfo.zhName}]createddone!`)}catch(e:any){closeLoading()r(e.message)}}组件库cli就这样完成了。运行pnpmrungen,依次输入组件名称、组件中文名称,选择组件类型,即可自动完成组件的创建、注册、文档创建。亚亚大哥花了大篇幅介绍cli的开发,不仅可以在这里使用,通过这个案例的实现,希望大家可以把这个方法移植到其他地方,比如从github拉取代码模板,自动化CI/CD等,下篇文章将介绍组件库的打包、构建和发布。感谢您阅读本文。如果本文对您有一点帮助或启发,请三连支持,多多了解。