boycot 搜索
avatar

boycot

个人组件库展示站点搭建总结

在线预览个人组件库: Howdy

目录

  1. Markdown-loader
  2. 将 Vue 文件转为 Markdown
  3. 路由生成优化
  4. 关于部署

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 的主题。

README渲染页面

将 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的路由自动生成。

关于部署

  1. 由于最终的访问地址为 https://kongfandong.cn/howdy ,所以需要配置 publicPath 为 howdy,不然会出现资源 404
  2. 路由使用了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"));
// ...
  1. 若是使用 nginx 搭建的静态资源服务器,可以参考官方推荐的 Nginx 配置 实现 History 模式。

左侧导航中间Demo右侧代码

在线预览个人组件库: Howdy

乳白
杏仁黄
茉莉黄
麦秆黄
油菜花黄
佛手黄
篾黄
葵扇黄
柠檬黄
金瓜黄
藤黄
酪黄
香水玫瑰黄
淡密黄
大豆黄
素馨黄
向日葵黄
雅梨黄
黄连黄
金盏黄
蛋壳黄
肉色
鹅掌黄
鸡蛋黄
鼬黄
榴萼黄
淡橘橙
枇杷黄
橙皮黄
北瓜黄
杏黄
雄黄
万寿菊黄
菊蕾白
秋葵黄
硫华黄
柚黄
芒果黄
蒿黄
姜黄
香蕉黄
草黄
新禾绿
月灰
淡灰绿
草灰绿
苔绿
碧螺春绿
燕羽灰
蟹壳灰
潭水绿
橄榄绿
蚌肉白
豆汁黄
淡茧黄
乳鸭黄
荔肉白
象牙黄
炒米黄
鹦鹉冠黄
木瓜黄
浅烙黄
莲子白
谷黄
栀子黄
芥黄
银鼠灰
尘灰
枯绿
鲛青
粽叶绿
灰绿
鹤灰
淡松烟
暗海水绿
棕榈绿
米色
淡肉色
麦芽糖黄
琥珀黄
甘草黄
初熟杏黄
浅驼色
沙石黄
虎皮黄
土黄
百灵鸟灰
山鸡黄
龟背黄
苍黄
莱阳梨黄
蜴蜊绿
松鼠灰
橄榄灰
蟹壳绿
古铜绿
焦茶绿
粉白
落英淡粉
瓜瓤粉
蜜黄
金叶黄
金莺黄
鹿角棕
凋叶棕
玳瑁黄
软木黄
风帆黄
桂皮淡棕
猴毛灰
山鸡褐
驼色
茶褐
古铜褐
荷花白
玫瑰粉
橘橙
美人焦橙
润红
淡桃红
海螺橙
桃红
颊红
淡罂粟红
晨曦红
蟹壳红
金莲花橙
草莓红
龙睛鱼红
蜻蜓红
大红
柿红
榴花红
银朱
朱红
鲑鱼红
金黄
鹿皮褐
醉瓜肉
麂棕
淡银灰
淡赭
槟榔综
银灰
海鸥灰
淡咖啡
岩石棕
芒果棕
石板灰
珠母灰
丁香棕
咖啡
筍皮棕
燕颔红
玉粉红
金驼
铁棕
蛛网灰
淡可可棕
中红灰
淡土黄
淡豆沙
椰壳棕
淡铁灰
中灰驼
淡栗棕
可可棕
柞叶棕
野蔷薇红
菠萝红
藕荷
陶瓷红
晓灰
余烬红
火砖红
火泥棕
绀红
橡树棕
海报灰
玫瑰灰
火山棕
豆沙
淡米粉
初桃粉红
介壳淡粉红
淡藏花红
瓜瓤红
芙蓉红
莓酱红
法螺红
落霞红
淡玫瑰灰
蟹蝥红
火岩棕
赭石
暗驼棕
酱棕
栗棕
洋水仙红
谷鞘红
苹果红
铁水红
桂红
极光红
粉红
舌红
曲红
红汞红
淡绯
无花果红
榴子红
胭脂红
合欢红
春梅红
香叶红
珊瑚红
萝卜红
淡茜红
艳红
淡菽红
鱼鳃红
樱桃红
淡蕊香红
石竹红
草茉莉红
茶花红
枸枢红
秋海棠红
丽春红
夕阳红
鹤顶红
鹅血石红
覆盆子红
貂紫
暗玉紫
栗紫
葡萄酱紫
牡丹粉红
山茶红
海棠红
玉红
高粱红
满江红
枣红
葡萄紫
酱紫
淡曙红
唐菖蒲红
鹅冠红
莓红
枫叶红
苋菜红
烟红
暗紫苑红
殷红
猪肝紫
金鱼紫
草珠红
淡绛红
品红
凤仙花红
粉团花红
夹竹桃红
榲桲红
姜红
莲瓣红
水红
报春红
月季红
豇豆红
霞光红
松叶牡丹红
喜蛋红
鼠鼻红
尖晶玉红
山黎豆红
锦葵红
鼠背灰
甘蔗紫
石竹紫
苍蝇灰
卵石紫
李紫
茄皮紫
吊钟花红
兔眼红
紫荆红
菜头紫
鹞冠紫
葡萄酒红
磨石紫
檀紫
火鹅紫
墨紫
晶红
扁豆花红
白芨红
嫩菱红
菠根红
酢酱草红
洋葱紫
海象紫
绀紫
古铜紫
石蕊红
芍药耕红
藏花红
初荷红
马鞭草紫
丁香淡紫
丹紫红
玫瑰红
淡牵牛紫
凤信紫
萝兰紫
玫瑰紫
藤萝紫
槿紫
蕈紫
桔梗紫
魏紫
芝兰紫
菱锰红
龙须红
蓟粉红
电气石红
樱草紫
芦穗灰
隐红灰
苋菜紫
芦灰
暮云灰
斑鸠灰
淡藤萝紫
淡青紫
青蛤壳紫
豆蔻紫
扁豆紫
芥花紫
青莲
芓紫
葛巾紫
牵牛紫
紫灰
龙睛鱼紫
荸荠紫
古鼎灰
乌梅紫
深牵牛紫
银白
芡食白
远山紫
淡蓝紫
山梗紫
螺甸紫
玛瑙灰
野菊紫
满天星紫
锌灰
野葡萄紫
剑锋紫
龙葵紫
暗龙胆紫
晶石紫
暗蓝紫
景泰蓝
尼罗蓝
远天蓝
星蓝
羽扇豆蓝
花青
睛蓝
虹蓝
湖水蓝
秋波蓝
涧石蓝
潮蓝
群青
霁青
碧青
宝石蓝
天蓝
柏林蓝
海青
钴蓝
鸢尾蓝
牵牛花蓝
飞燕草蓝
品蓝
银鱼白
安安蓝
鱼尾灰
鲸鱼灰
海参灰
沙鱼灰
钢蓝
云水蓝
晴山蓝
靛青
大理石灰
海涛蓝
蝶翅蓝
海军蓝
水牛灰
牛角灰
燕颔蓝
云峰白
井天蓝
云山蓝
釉蓝
鸥蓝
搪磁蓝
月影白
星灰
淡蓝灰
鷃蓝
嫩灰
战舰灰
瓦罐灰
青灰
鸽蓝
钢青
暗蓝
月白
海天蓝
清水蓝
瀑布蓝
蔚蓝
孔雀蓝
甸子蓝
石绿
竹篁绿
粉绿
美蝶绿
毛绿
蔻梢绿
麦苗绿
蛙绿
铜绿
竹绿
蓝绿
穹灰
翠蓝
胆矾蓝
樫鸟蓝
闪蓝
冰山蓝
虾壳青
晚波蓝
蜻蜓蓝
玉鈫蓝
垩灰
夏云灰
苍蓝
黄昏灰
灰蓝
深灰蓝
玉簪绿
青矾绿
草原远绿
梧枝绿
浪花绿
海王绿
亚丁绿
镍灰
明灰
淡绿灰
飞泉绿
狼烟灰
绿灰
苍绿
深海绿
长石灰
苷蓝绿
莽丛绿
淡翠绿
明绿
田园绿
翠绿
淡绿
葱绿
孔雀绿
艾绿
蟾绿
宫殿绿
松霜绿
蛋白石绿
薄荷绿
瓦松绿
荷叶绿
田螺绿
白屈菜绿
河豚灰
蒽油绿
槲寄生绿
云杉绿
嫩菊绿
艾背绿
嘉陵水绿
玉髓绿
鲜绿
宝石绿
海沬绿
姚黄
橄榄石绿
水绿
芦苇绿
槐花黄绿
苹果绿
芽绿
蝶黄
橄榄黄绿
鹦鹉绿
油绿
象牙白
汉白玉
雪白
鱼肚白
珍珠灰
浅灰
铅灰
中灰
瓦灰
夜灰
雁灰
深灰