写在前面:在我们的印象使用中,vue除了写业务代码没有特别新奇的功能了,最近在着手探索了如何利用vue进行组件库文档编写功能呢?
循序渐进进行学习~
本章介绍两种文档生成方法不同的地方以及优点和缺点
vuepress
基于.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\n\n````markdown\n```jsx live\n<Button>I’m transparent!</Button>\n```\n````\n\n```jsx live\n<Button>I’m transparent!</Button>\n```\n\nTo render an example as highlighted source code remove the live modifier\n\n```html\n<Button>I’m transparent!</Button>\n```' ],
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 的配置文档:
https://vue-styleguidist.github.io/docs/docgen-cli.html#config
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 生成文档