个人组件库展示站点搭建总结
May 01, 2020
在线预览个人组件库: Howdy
目录
Markdown-loader
使用 Markdown-loader 可以将markdown文件转为Html代码,直接在vue.config.js
中加入webpack相关配置。并且使用 Highlight.js 对Markdown中出现的代码块进行高亮展示。Markdown-loader中可直接配置Highlightjs。
const hljs = require('highlight.js')
module.exports = {
configureWebpack: config => {
config.module.rules.push({
test: /\.md$/,
use: [
{
loader: 'html-loader'
},
{
loader: 'markdown-loader',
options: {
highlight: (code) => {
if (code[0] === '<' || code.includes('template') || code.includes('script')) {
return hljs.highlight('html', code).value
} else if (code.includes('npm')) {
return hljs.highlight('bash', code).value
} else {
return hljs.highlight('js', code).value
}
},
// highlight: (code) => hljs.highlightAuto(code).value,
pedantic: false,
gfm: true,
tables: true,
breaks: false,
sanitize: false,
smartLists: true,
smartypants: false,
xhtml: false
}
}
]
})
// ... //
}
}
这里本来是用了highlightAuto自动识别代码语言的,但是发现效果不太理想,所有直接通过判断里面出现关键内容应用不同代码语言。
然后就可以直接通过import将markdown文件引入到代码中。例如下面import引入了README.md文件,readme就是解析后的HTML代码,最后直接传给封装好的组件用v-html渲染出来即可。
<template>
<div id="Readme">
<readme-frame :readme="readme"></readme-frame>
</div>
</template>
<script>
import ReadmeFrame from '@/components/ReadmeFrame'
import readme from '@/howdy/packages/standard-table/README.md'
export default {
name: 'readme',
components: {
ReadmeFrame
},
data () {
return {
readme
}
}
}
</script>
然后为渲染后的页面设定主题CSS,可以直接在网上找现成CSS代码,例如可Markdown编辑器 Typora 的主题。这里提供该组件库的主题CSS: readme.css,样式如下图。
将Vue文件转为Markdown
编写一个nodejs脚本,将相关目标组件Example的Vue文件转成Markdown,然后通过上面Markdown-loader即可实现代码高亮展示。
// vue-to-md.js
const fs = require('fs')
const glob = require('glob')
const classifys = fs.readdirSync('src/pages')
classifys.map(classify => {
fs.mkdirSync(`src/code/${classify}`, { recursive: true })
})
glob('src/pages/**/example/example*.vue', (err, files) => {
if (err) {
throw err
}
files.map(file => {
const codeFileName = file.replace('pages', 'code').replace('example/', '').replace('vue', 'md')
const code = fs.readFileSync(file, 'utf8')
const output = `\`\`\`vue\n${code}\n\`\`\``
fs.writeFileSync(codeFileName, output)
})
})
glob可以使用 “ * ” 通配符匹配所需文件
在package.json
文件的vue启动与打包命令前加入运行该脚本的命令
// package.json
"scripts": {
"serve": "npm run vue-to-md && vue-cli-service serve",
"build": "npm run vue-to-md && vue-cli-service build",
"lint": "npm run vue-to-md && vue-cli-service lint",
"vue-to-md": "node src/utils/vue-to-md.js"
}
通过路由匹配等逻辑,将生成的example.md文件引入到相关页面中。
async loadCode () {
try {
let code = await import(`@/code/${this.mainName}/${this.page.replace(this.mainName + '-', '')}.md`)
this.code = code.default
} catch (e) {
console.log(e)
}
}
路由生成优化
目前组件库中含有多个组件与指令,一个组件或指令又会含有若干个Example,最终需要定义很多个路由(一个Example对于一个路由)。由于它们之间是存在很多相似的引用逻辑的,所以可以将它们抽离出来形成函数,从而不用每次手动去定义一个新的路由,只要更改传入的参数即可。
// router.js
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const packageList = [
{
name: 'resize-directive',
exampleNum: 5
},
{
name: 'scroll-directive',
exampleNum: 5
},
{
name: 'mouse-menu-directive',
exampleNum: 6
},
{
name: 'size-observer-directive',
exampleNum: 2
},
{
name: 'animation-dialog',
exampleNum: 3
},
{
name: 'standard-table',
exampleNum: 9
},
{
name: 'img-zoom-directive',
exampleNum: 3
}
]
const packageRouter = packageList.map(item => {
const { name, exampleNum } = item
return {
name,
routers: [
{
path: `/${name}/readme`,
name: `${name}-readme`,
component: () => import(`@/pages/${name}/example/readme`)
},
...Array.from({ length: exampleNum }, (item, index) => {
return {
path: `/${name}/example${index + 1}`,
name: `${name}-example${index + 1}`,
component: () =>
import(`@/pages/${name}/example/example${index + 1}`)
}
})
]
}
})
const routes = [
{
path: '/',
name: 'home',
component: () => import('@/views/home')
},
...Object.keys(packageRouter).map(key => {
const { name, routers } = packageRouter[key]
return {
path: `/${name}`,
name,
component: () => import(`@/pages/${name}`),
children: routers,
redirect: `/${name}/readme`
}
})
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
这样下次要添加新的组件或者添加新的Example只需要更改packageList
即可。这种方式前提是需要确保包文件目录是符合规范的。
其实还有一种更好的办法,就是编写一个nodejs脚本,读取文件目录自动生成路由文件,这样就能完全不需要手动配置任何路由,这种方法类似Nuxtjs
的路由自动生成。
关于部署
- 由于最终的访问地址为 https://kongfandong.cn/howdy ,所以需要配置publicPath为howdy,不然会出现资源404
- 路由使用了
History
模式,所以服务器端需要加入相关配置。该组件库展示站点最终是放在了Koa2
的静态资源里面(因为Example里面涉及了一些Mock接口数据,为了方便把它们合在了同一个后端服务里面)。Koa2中可以使用 koa2-connect-history-api-fallback 中间件实现History路由模式。
// ...
const static = require('koa-static')
const { historyApiFallback } = require('koa2-connect-history-api-fallback')
app.use(historyApiFallback({
htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'],
rewrites: [
{
from: '/howdy',
to: '/howdy'
}
],
}))
// 打包后的文件放在public目录下,使用koa-static放出静态资源服务
app.use(static(__dirname + '/public'))
// ...
- 若是使用nginx搭建的静态资源服务器,可以参考官方推荐的 Nginx配置 实现History模式。
在线预览个人组件库: Howdy