返回
Comi —— 把 markdown 代码搞起来!
前端
2023-09-14 00:20:21
Comi 读 ['kəʊmɪ],类似中文 科米,是腾讯 Omi 团队开发的小程序代码高亮和 markdown 渲染组件。有了这个组件加持,小程序技术社区可以开始搞起来了。感谢【小程序•云开发】提供技术支持。
先看 Comi 使用,再分析原理。
先拷贝此目录到你的项目。
先明确,markdown是一种写作语言。它介于自然语言和 HTML之间,其目标是实现易读易写,无论何时何地,Markdown 的文件都可以通过简单的纯文本编辑器打开。
在不加任何修改的情况下:
// pages/index/index.js
Component({
options: {
styleIsolation: 'shared',
},
properties: {},
data: {
value: `
```ts
if (true) {
console.log('true!');
} else if (false) {
console.log('false!');
} else {
console.log('else!');
}
```
`,
},
methods: {
toggleValue() {
this.setData({
value: this.data.value === '===' ? '===' : '',
})
},
},
})
<!-- pages/index/index.wxml -->
<view class="container">
<view class="comi-wrapper">
<comi-code lang="ts">
{{value}}
</comi-code>
</view>
<button class="comi-toggle" type="primary" bindtap="toggleValue">Toggle</button>
</view>
/* pages/index/index.wxss */
page {
background: #f5f5f5;
}
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
width: 100%;
}
.comi-wrapper {
width: 100%;
max-width: 500px;
}
.comi-toggle {
margin: 10px 0 0 10px;
}
实现原理
markdown 渲染原理
接下来,我们看看原理。
先看代码高亮,代码高亮首先会通过 regex 解析出 language tag,
// comi/src/utils/regex.ts
// 匹配 HTML 注释中的语言定义标签
const REGEXP_MATCH_LANG_TAG = /<!--\s+lang:(\S+)\s+-->/
接着,会把语言定义 tag 转换称 render
函数,
// comi/src/utils/lang-tags.ts
/**
* 将语言标签转换为 render 函数
*/
const getRenderByLang = (lang: string): ((code: string) => string) | undefined => {
// 根据语言标签,从 prism 仓库获取高亮渲染函数
const prismRenderFunc = prism.languages[lang]
if (prismRenderFunc) {
return (code: string) => {
// 返回渲染函数执行结果
return prismRenderFunc(code, lang)
}
}
}
接下来,把 markdown 文本通过 marked
转换成 HTML 标签,再由 language-pack
匹配高亮代码的语言 tag,转换成 render
函数,最后执行渲染函数获得最终的渲染后的 HTML 代码,
// comi/src/main.ts
const findLangRender = (code: string) => {
// 匹配 HTML 注释中的语言定义标签
const langTagMatch = REGEXP_MATCH_LANG_TAG.exec(code)
// 若没有语言定义标签,则默认使用 'text' 语言
if (!langTagMatch) return getRenderByLang('text')
// 转换语言定义标签为 render 函数
const langTag = langTagMatch[1]
return getRenderByLang(langTag)
}
// comi/src/main.ts
export const getHtmlFromMarkdown = (markdown: string) => {
// 使用 marked 将 markdown 转换为 HTML
let html = marked(markdown)
// 查找并替换语言定义标签中的语言标签,并使用 language-pack 来渲染代码高亮
const getLangRenderByLangTag = findLangRender
html = html.replace(/<pre><code>\s*<!--\s+lang:(\S+)\s+-->\s*(.*?)\s*<\/code><\/pre>/g, (match, langTag, code) => {
// 使用 prism 渲染代码高亮
const renderFunc = getLangRenderByLangTag(langTag)
if (!renderFunc) return match
const highlightedHtml = renderFunc(code)
// 将高亮后的 HTML 代码替换原有的 HTML 代码
return `<pre><code>${highlightedHtml}</code></pre>`
})
// 返回渲染后的 HTML 代码
return html
}
代码高亮原理
代码高亮的实现步骤如下:
- 匹配语言定义标签,例如
<!--s+lang:ts+-->
。 - 将语言定义标签转换成渲染函数。
- 将markdown文本通过marked转换成HTML标签。
- 通过language-pack匹配高亮代码的语言tag,转换成render函数。
- 执行渲染函数获得最终的渲染后的HTML代码。
代码高亮的原理就是通过正则表达式匹配出语言定义标签,然后将语言定义标签转换成渲染函数,最后执行渲染函数获得最终的渲染后的HTML代码。
小结
Comi 是一个小程序代码高亮和 markdown 渲染组件,它使用 marked 和 prism 来实现 markdown 的渲染和代码高亮的渲染,具体的实现原理如下:
- markdown 渲染:使用 marked 将 markdown 转换为 HTML。
- 代码高亮:通过正则表达式匹配出语言定义标签,然后将语言定义标签转换成渲染函数,最后执行渲染函数获得最终的渲染后的HTML代码。