写在前面:在我们的印象使用中,vue除了写业务代码没有特别新奇的功能了,最近在着手探索了如何利用vue进行组件库文档编写功能呢?
循序渐进进行学习~
本章介绍两种文档生成方法不同的地方以及优点和缺点
vuepress
网站参考连接:https://www.vuepress.cn/guide/
基于.md文档生成可视化的ui界面
主要目录结构为
. ├── docs │ ├── .vuepress (可选的) │ │ ├── components (可选的) │ │ ├── theme (可选的) │ │ │ └── Layout.vue │ │ ├── public (可选的) │ │ ├── styles (可选的) │ │ │ ├── index.styl │ │ │ └── palette.styl │ │ ├── templates (可选的, 谨慎配置) │ │ │ ├── dev.html │ │ │ └── ssr.html │ │ ├── config.js (可选的) │ │ └── enhanceApp.js (可选的) │ │ │ ├── README.md │ ├── guide │ │ └── README.md │ └── config.md │ └── package.json
目录结构说明
目录结构说明,根据图片进行说明 :
- .vuepress 主要存放一些配置文件,入口文件
- docs存放.md文档,主要用于生成文档目录的入口
- docs/.vuepress: 用于存放全局的配置、组件、静态资源等。
- docs/.vuepress/components: 该目录中的 Vue 组件将会被自动注册为全局组件。
- docs/.vuepress/theme: 用于存放本地主题。
- docs/.vuepress/styles: 用于存放样式相关的文件。
- docs/.vuepress/styles/index.styl: 将会被自动应用的全局样式文件,会生成在最终的 CSS 文件结尾,具有比默认样式更高的优先级。
- docs/.vuepress/styles/palette.styl: 用于重写默认颜色常量,或者设置新的 stylus 颜色常量。
- docs/.vuepress/public: 静态资源目录。
- docs/.vuepress/templates: 存储 HTML 模板文件。
- docs/.vuepress/templates/dev.html: 用于开发环境的 HTML 模板文件。
- docs/.vuepress/templates/ssr.html: 构建时基于 Vue SSR 的 HTML 模板文件。
- docs/.vuepress/config.js: 配置文件的入口文件,也可以是 YML 或 toml。
- docs/.vuepress/enhanceApp.js: 客户端应用的增强。
这些的目录结构以及说明在官网中都存在,主要配置文件杂居config.js的文件,页面的左右连接等
config.js的基本配置就不多陈述:https://www.vuepress.cn/config/#%E5%9F%BA%E6%9C%AC%E9%85%8D%E7%BD%AE
vue-styleguidist
一个基于vue-docgen-api编写的可生成的组件库文档,在此基础上衍生出了许多其他的组件库功能,本文主要介绍两个
- 基础vue-styleguidist生成文档
- 基于vue-styleguidist和vue-press生成文档
用来对比两种组件库文档的生成区别
先介绍vue-docgen-api 吧,想要查看vue-docgen-api的主要功能,我们需要借助node进行实现,
const { parse } = require('vue-docgen-api') //引入资源包 async function getData(){ var result = await parse('./vue/vue.vue')//异步加载需要解析的vue的文件 console.log(result) } getData()
获得到vue-docgen-cli返回的字段内容和格式
{ displayName: 'Button', //vue组件中的名字 description: 'The only true button.',//组件的描述 tags: {}, //组件 exportName: 'default', docsBlocks: //vue组件底部的使用描述 [ 'Use vue live right here too ````markdown ```jsx live <Button>I’m transparent!</Button> ``` ```` ```jsx live <Button>I’m transparent!</Button> ``` To render an example as highlighted source code remove the live modifier ```html <Button>I’m transparent!</Button> ```' ], props://vue组件的prop的属性值和描述信息 [ { name: 'color', description: 'The color for the button.', type: [Object], defaultValue: [Object] }, { name: 'size', description: 'The size of the button 其他的东西ddd', tags: {}, values: [Array], type: [Object], defaultValue: [Object] }, { name: 'onClick', description: 'Gets called when the user clicks on the button', tags: [Object], type: [Object], defaultValue: [Object] } ], events://vue组件内部暴露外部的事件 [ { name: 'click', description: '按钮点击成功emit事件', type: [Object], properties: [Array] } ], methods: undefined, slots: [ { name: 'test', scoped: true, description: '暴露出的插槽 ', bindings: [Array] } ] }
看内容可以看到,可以看到vue文件中的props和events以及slots等信息。了解了vue-docgen-api后,进行解析以及组件需要将页面封装即可
基于vue-docgen-cli和vue-press生成文档
目录结构配置:
项目中存在存放的两个配置文件
- 用于生成.md文档的docgen.config.js
- 用于解析.md文档生成可视化页面的vue-press配置文档config.js
docgen.config.js 的配置文档:
var path = require('path') module.exports = { componentsRoot: '../components1', //需要解析的组件目录 相对路径 components: '**/[a-z]*.{vue,ts,tsx}', //正则匹配组件的名字 outDir: './docs/components',//编译后的组件的位置 // defaultExamples: true getDocFileName: (componentPath) => // componentPath.replace(/.vue$/, '.md'), getDocFileName: (componentPath) => componentPath.replace(/.vue$/, '.md'), templates: {//指定用于呈现组件的函数的对象。 //包装所有其他组件的全局组件模板参见 component: require('templates/component'), events: require('templates/events'), methods: require('templates/methods'), props: require('templates/props'), slots: require('templates/slots'), // 如果组件是功能性的,则显示为标记的静态模板 functionalTag: '**functional**' }, require: [path.join(__dirname, 'global.requires.js')] //组件案例运行时候的demo }
vue-press的config.js文档
文档配置按照vuepress的配置文档说明就可以了
const path = require('path') const glob = require('globby') const cwd = path.join(__dirname, '..') const { parse } = require('vue-docgen-api') const { renameComponentMd} =require('./fileinit.js') var vuepressConfig = async () => { renameComponentMd(cwd+'/components') const docFiles = glob.sync('components/**/*.md', { cwd }).map(f => '/' + f) //获得.md文件的目录结构 const components = await Promise.all( glob .sync('../../components1/**/[a-z].{vue,jsx,ts,tsx}', { cwd, absolute: true }) .map(async path => { return { name: (await parse(path)).displayName.replace(/[^a-zA-Z0-9_]/g, ''), path } }) )//建立文档和组件的热更新练习 console.log(docFiles) /** * {name:'button','**.vue} */ //引入fs文件目录模块 return { dest: path.join(__dirname, '../../dist'),//打包目录 base: '/docgen/',//打包后内容 title: 'VuePress DocGen Live', themeConfig: {//页面可视化配置 search: false, editLinks: true, nav:[ // 导航栏配置 {text: '前端基础', link: '/accumulate/' }, {text: '前端基础', items: [ { text: 'focus-outside', link: 'https://github.com/TaoXuSheng/focus-outside' }, { text: 'stylus-converter', link: 'https://github.com/TaoXuSheng/stylus-converter' }, ]}, ], sidebar: docFiles,//左侧导航栏内容 markdown: { // 为每个代码块显示行号 lineNumbers: true }, }, plugins: [ ['live'], [ '@vuepress/register-components', '@vuepress/nprogress', { //热更新时进行检测文件,当我们更改vue组件内容时候,能够检测到当前生成新的文档 components, componentsDir: '../../components1' } ] ] } } module.exports = vuepressConfig;
配置packjson.json
"scripts": { "vuepress":"vuepress dev docs", //只启动vuepress "comeMd":"vue-docgen --watch", //只生成.md文档 "docs": "concurrently "vue-docgen --watch" "vuepress dev docs"", //同时生成.md文档和生成可视化组件 "docs:build": "vue-docgen && vuepress build docs"//打包 },
可视化后的样子
注意点:
vuepress 进行文档渲染时候,保证生成的.md文件名字和目录的名字是一值才可(也可以不一致,但是需要自己配置slider)
如:保持将文件夹下面的.md 和文档目录名字一致是最简单的渲染文档方式
'/components/common/popup.md', '/components/dialog/dialog.md', '/components/loading/loading.md', ]
因此需要规范化暴露.vue的命名
这个时候就需要我们规范化组件的命名了,统一管理组件的名字,或者在生成可视化组件时候,将.md文档统一进行重新命名
规范生成.md文档的命名
未规范前,rFlexFixed 的主暴露文件命名为index.vue 生成的文档为index.md。而rFloat的主暴露的文件为rFloat.vue,生成后的.md文档为rFloat.md 是符合我们规范的
可在配置中进行重命名,让生成后的.md文档和目录的名字一致,重命名后的文档
借助nodejs的fs模块对文件重新命名
// 文件名字初始化 /** * 将组件文档目录中index.md替换成目录名字+.md * 如 原文件 rAction/index.md=>rAction/rAction.md */ const fs = require('fs'); const path = require('path') var renameComponentMd =function(path){ var files = fs.readdirSync(path); files.forEach((file)=>{ //获取当前文件目录的地址 var currBaseDir = path+'/'+file; var fileStat = fs.statSync(currBaseDir); if(fileStat.isDirectory()){ var fileChildren = fs.readdirSync(currBaseDir);//获取当前文件目录的子目录结 var indexMd = fileChildren.indexOf('index.md'); //当前文件目录中存在index.md 则进行改名字 if(indexMd>-1){ var fsChildren = fileChildren[indexMd] var chPath = currBaseDir+'/'+fsChildren; if(fs.statSync(chPath).isFile()){ var renameFile = chPath.replace('index',file) fs.rename(chPath,renameFile,(err)=>{ if(err){ console.error(msg) }else{ } }) } } } }) }
重命名后的组件的一个缺点就是,当我们更改vue的文件内容注释的时候,达不到热更新效果---
着重介绍vue-styleguide 生成文档