越努力,越幸运,做个ccode~

0%

在vite项目下支持markdown文件

前言

需求如下 在写xinyi-ui 官网时,需要对组件进行文档说明,说明文档都是md格式的文件,能否直接将md文件显示到页面上,而不改为html 呢?
现在有 install.md 和 get-started.md 两个文件

第一步 实现一个vite插件 md => html

  • 将对md文件的请求进行数据处理
  • 通过markdown-it 将源文件转为html字符串
1
var MarkdownIt = require('markdown-it')
2
const marked = new MarkdownIt()
3
4
const mdToJs = str => {
5
  const content = JSON.stringify(marked.render(str))
6
  return `export default ${content}`
7
}
8
9
export function md() {
10
  return {
11
    name: 'md',
12
    transform(src,url){
13
      if(url.endsWith('.md')){
14
        return {
15
          code: mdToJs(src),
16
          map: null // 如果可行将提供 source map
17
        } 
18
      }
19
    }
20
  }
21
}

第二步创建组件模板 Markdown.vue

因为只是md文件不同,可以使用同一个组件模板,通过文件路径显示不同的html内容

1
<template>
2
  <article v-html="content"></article> 
3
</template>

那么如何获取这个content 呢?
只要引入md 文件 vite插件就会自动将md文件转为html 字符串

1
//router.js
2
// 通过渲染函数将 path 传递给 markdown.vue 在markdown.vue 中引入md文件
3
const md = (filename:string) => h(Markdown, { path: `../markdown/${filename}.md`, key: filename })
4
const routes = {
5
  // component 可以使VNode
6
  { path: 'install', component: md('install')},
7
  { path: 'get-started', component: md('get-started') },
8
}

但是我们不能再setup 中使用 import xxx from ... 的语法,可以使用异步引入的方式

1
// Markdown.vue
2
export default {
3
  props: {
4
    path: {
5
      type: String,
6
      required: true,
7
    },
8
  },
9
  setup(props:any) {
10
    const content = ref<string>('');
11
    import(/* @vite-ignore */props.path).then((result) => {
12
      content.value = result.default;    // 这里可以获取到
13
    });
14
    return {
15
      content,
16
    };
17
  },
18
};

显示在页面 并添加样式

  • 安装 github-markdown-css
  • 在main.ts 或 MarkDown.vue中引入 css
  • 在article上添加class markdown-body
  • v-html 显示 html
1
<article class="markdown-body" v-html="content"></article>

将动态引入改为静态引入

build后发现在生产环境会报错 是因为rollup打包不接受这种拼接字符串的模式
所以将动态引入文件 改为静态引入

这样也将异步引入改为了同步引入了

1
// main.ts
2
import install from '../markdown/install.md'
3
import getStarted from '../markdown/get-started.md'
4
5
// 直接将content 传给Markdown.vue
6
const md = (content:string) => h(Markdown, { content }) 
7
const routes = {
8
  { path: 'install', component: md(install)},
9
  { path: 'get-started', component: md(getStarted) },
10
}

这样直接引入 ts 会报错 可以加 // @ts-ignore 不管
也可以在markdown中添加一个声明文件 markdown.d.ts

1
declare module "*.md" {
2
  const content: string;
3
  export default content;
4
}

这样打开就不会报错啦

Markdown.vue中显示markdown

1
<template>
2
  <!--content 就是 html 格式的字符串-->
3
  <article class="markdown-body" v-html="content"></article>
4
</template>
5
6
<script lang="ts">
7
import { ref } from "vue";
8
export default {
9
  props: {
10
    content: {
11
      type: String,
12
      required: true,
13
    },
14
  }
15
};
16
</script>