perf(plugin-md-power): optimize structure (#204)

This commit is contained in:
pengzhanbo 2024-09-22 07:57:49 +08:00 committed by GitHub
parent ce921e209d
commit 2cf606b1de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 169 additions and 157 deletions

View File

@ -68,15 +68,11 @@ function parseData(data: string | MessageData): MessageData {
:data-past="past"
:data-future="future"
>
<iframe
:src="source"
:style="{ height }"
:title="`Can I use ${feature}`"
/>
<iframe :src="source" :style="{ height }" :title="`Can I use ${feature}`" />
</div>
</template>
<style scoped>
<style>
.ciu_embed {
margin: 16px -24px;
}

View File

@ -1,7 +1,7 @@
<script setup lang="ts">
import type { HighlighterCore } from 'shiki/core'
import editorData from '@internal/md-power/replEditorData'
import { getHighlighterCore } from 'shiki/core'
import { createHighlighterCore } from 'shiki/core'
import { onMounted, onUnmounted, ref, shallowRef, watch } from 'vue'
import { resolveCodeInfo } from '../composables/codeRepl.js'
@ -17,7 +17,7 @@ const textAreaEl = shallowRef<HTMLTextAreaElement>()
const input = ref('')
async function init() {
highlighter = await getHighlighterCore({
highlighter = await createHighlighterCore({
themes: 'light' in theme && 'dark' in theme ? [theme.light, theme.dark] : [theme],
langs: Object.keys(grammars).map(key => grammars[key]),
loadWasm: () => import('shiki/wasm'),

View File

@ -11,19 +11,17 @@ const SANDBOX = 'allow-forms allow-modals allow-popups allow-presentation allow-
const source = computed(() => {
const params = new URLSearchParams()
if (props.filepath) {
if (props.filepath)
params.set(props.type === 'embed' ? 'module' : 'file', encodeURIComponent(props.filepath))
}
if (props.type === 'embed') {
params.set('view', props.layout ? props.layout.replace(/,/g, '+') : 'Editor+Preview')
if (props.console) {
if (props.console)
params.set('expanddevtools', '1')
}
if (props.navbar === false) {
if (props.navbar === false)
params.set('hidenavigation', '1')
}
}
else {
params.set('from-embed', '')

View File

@ -0,0 +1,19 @@
import type { App } from 'vuepress'
import type { Markdown } from 'vuepress/markdown'
import type { MarkdownPowerPluginOptions } from '../../shared/index.js'
import { fileTreePlugin } from './fileTree/index.js'
import { langReplPlugin } from './langRepl.js'
export async function containerPlugin(
app: App,
md: Markdown,
options: MarkdownPowerPluginOptions,
) {
if (options.repl)
await langReplPlugin(app, md, options.repl)
if (options.fileTree) {
// ::: file-tree
fileTreePlugin(md)
}
}

View File

@ -8,7 +8,7 @@ import type Token from 'markdown-it/lib/token.mjs'
import type { CanIUseMode, CanIUseOptions, CanIUseTokenMeta } from '../../shared/index.js'
import container from 'markdown-it-container'
import { customAlphabet } from 'nanoid'
import { createRuleBlock } from '../utils/createRuleBlock.js'
import { createEmbedRuleBlock } from './createEmbedRuleBlock.js'
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz', 5)
const UNDERLINE_RE = /_+/g
@ -22,7 +22,7 @@ export const caniusePlugin: PluginWithOptions<CanIUseOptions> = (
md,
{ mode: defaultMode = 'embed' }: CanIUseOptions = {},
): void => {
createRuleBlock<CanIUseTokenMeta>(md, {
createEmbedRuleBlock<CanIUseTokenMeta>(md, {
type: 'caniuse',
syntaxPattern: /^@\[caniuse\s*(embed|image)?(?:\{([0-9,\-]*)\})?\]\(([^)]*)\)/,
meta: ([, mode, versions = '', feature]) => ({

View File

@ -4,13 +4,13 @@
* @[codesanbox title="xxx" layout="Editor+Preview" height="500px" navbar="false" console="false"](id#filepath)
*/
import type { PluginWithOptions } from 'markdown-it'
import type { CodeSandboxTokenMeta } from '../../shared/index.js'
import { createRuleBlock } from '../utils/createRuleBlock.js'
import { parseRect } from '../utils/parseRect.js'
import { resolveAttrs } from '../utils/resolveAttrs.js'
import type { CodeSandboxTokenMeta } from '../../../shared/index.js'
import { parseRect } from '../../utils/parseRect.js'
import { resolveAttrs } from '../../utils/resolveAttrs.js'
import { createEmbedRuleBlock } from '../createEmbedRuleBlock.js'
export const codeSandboxPlugin: PluginWithOptions<never> = (md) => {
createRuleBlock<CodeSandboxTokenMeta>(md, {
createEmbedRuleBlock<CodeSandboxTokenMeta>(md, {
type: 'codesandbox',
syntaxPattern: /^@\[codesandbox(?:\s+(embed|button))?([^\]]*)\]\(([^)]*)\)/,
meta([, type, info = '', source = '']) {

View File

@ -4,15 +4,15 @@
* @[codepen preview editable title="" height="400px" tab="css,result" theme="dark"](user/slash)
*/
import type { PluginWithOptions } from 'markdown-it'
import type { CodepenTokenMeta } from '../../shared/index.js'
import { createRuleBlock } from '../utils/createRuleBlock.js'
import { parseRect } from '../utils/parseRect.js'
import { resolveAttrs } from '../utils/resolveAttrs.js'
import type { CodepenTokenMeta } from '../../../shared/index.js'
import { parseRect } from '../../utils/parseRect.js'
import { resolveAttrs } from '../../utils/resolveAttrs.js'
import { createEmbedRuleBlock } from '../createEmbedRuleBlock.js'
const CODEPEN_LINK = 'https://codepen.io/'
export const codepenPlugin: PluginWithOptions<never> = (md) => {
createRuleBlock<CodepenTokenMeta>(md, {
createEmbedRuleBlock<CodepenTokenMeta>(md, {
type: 'codepen',
syntaxPattern: /^@\[codepen([^\]]*)\]\(([^)]*)\)/,
meta: ([, info = '', source = '']) => {

View File

@ -3,13 +3,13 @@
* @[jsfiddle theme="dark" tab="js,css,html,result"](user/id)
*/
import type { PluginWithOptions } from 'markdown-it'
import type { JSFiddleTokenMeta } from '../../shared/index.js'
import { createRuleBlock } from '../utils/createRuleBlock.js'
import { parseRect } from '../utils/parseRect.js'
import { resolveAttrs } from '../utils/resolveAttrs.js'
import type { JSFiddleTokenMeta } from '../../../shared/index.js'
import { parseRect } from '../../utils/parseRect.js'
import { resolveAttrs } from '../../utils/resolveAttrs.js'
import { createEmbedRuleBlock } from '../createEmbedRuleBlock.js'
export const jsfiddlePlugin: PluginWithOptions<never> = (md) => {
createRuleBlock<JSFiddleTokenMeta>(md, {
createEmbedRuleBlock<JSFiddleTokenMeta>(md, {
type: 'jsfiddle',
syntaxPattern: /^@\[jsfiddle([^\]]*)\]\(([^)]*)\)/,
meta([, info = '', source]) {

View File

@ -4,13 +4,13 @@
* @[replit title="" height="400px" width="100%" theme="dark"](user/repl-name)
*/
import type { PluginWithOptions } from 'markdown-it'
import type { ReplitTokenMeta } from '../../shared/index.js'
import { createRuleBlock } from '../utils/createRuleBlock.js'
import { parseRect } from '../utils/parseRect.js'
import { resolveAttrs } from '../utils/resolveAttrs.js'
import type { ReplitTokenMeta } from '../../../shared/index.js'
import { parseRect } from '../../utils/parseRect.js'
import { resolveAttrs } from '../../utils/resolveAttrs.js'
import { createEmbedRuleBlock } from '../createEmbedRuleBlock.js'
export const replitPlugin: PluginWithOptions<never> = (md) => {
createRuleBlock<ReplitTokenMeta>(md, {
createEmbedRuleBlock<ReplitTokenMeta>(md, {
type: 'replit',
syntaxPattern: /^@\[replit([^\]]*)\]\(([^)]*)\)/,
meta: ([, info = '', source = '']) => {

View File

@ -1,7 +1,7 @@
import type { RuleOptions } from 'markdown-it/lib/ruler.mjs'
import type { Markdown } from 'vuepress/markdown'
export interface RuleBlockOptions<Meta extends Record<string, any>> {
export interface EmbedRuleBlockOptions<Meta extends Record<string, any>> {
/**
* @[type]()
*/
@ -18,7 +18,7 @@ export interface RuleBlockOptions<Meta extends Record<string, any>> {
}
// @[name]()
export function createRuleBlock<Meta extends Record<string, any> = Record<string, any>>(
export function createEmbedRuleBlock<Meta extends Record<string, any> = Record<string, any>>(
md: Markdown,
{
type,
@ -28,7 +28,7 @@ export function createRuleBlock<Meta extends Record<string, any> = Record<string
ruleOptions = { alt: ['paragraph', 'reference', 'blockquote', 'list'] },
meta,
content,
}: RuleBlockOptions<Meta>,
}: EmbedRuleBlockOptions<Meta>,
): void {
const MIN_LENGTH = type.length + 5
const START_CODES = [64, 91, ...type.split('').map(c => c.charCodeAt(0))]

View File

@ -0,0 +1,55 @@
import type { Markdown } from 'vuepress/markdown'
import type { MarkdownPowerPluginOptions } from '../../shared/index.js'
import { caniusePlugin, legacyCaniuse } from './caniuse.js'
import { codepenPlugin } from './code/codepen.js'
import { codeSandboxPlugin } from './code/codeSandbox.js'
import { jsfiddlePlugin } from './code/jsfiddle.js'
import { replitPlugin } from './code/replit.js'
import { pdfPlugin } from './pdf.js'
import { bilibiliPlugin } from './video/bilibili.js'
import { youtubePlugin } from './video/youtube.js'
export function embedSyntaxPlugin(md: Markdown, options: MarkdownPowerPluginOptions) {
if (options.caniuse) {
const caniuse = options.caniuse === true ? {} : options.caniuse
// @[caniuse](feature_name)
md.use(caniusePlugin, caniuse)
// 兼容旧语法
legacyCaniuse(md, caniuse)
}
if (options.pdf) {
// @[pdf](url)
md.use(pdfPlugin)
}
if (options.bilibili) {
// @[bilibili](bvid aid cid)
md.use(bilibiliPlugin)
}
if (options.youtube) {
// @[youtube](id)
md.use(youtubePlugin)
}
if (options.codepen) {
// @[codepen](user/slash)
md.use(codepenPlugin)
}
if (options.replit) {
// @[replit](user/repl-name)
md.use(replitPlugin)
}
if (options.codeSandbox) {
// @[codesandbox](id)
md.use(codeSandboxPlugin)
}
if (options.jsfiddle) {
// @[jsfiddle](user/id)
md.use(jsfiddlePlugin)
}
}

View File

@ -6,12 +6,12 @@
import type { PluginWithOptions } from 'markdown-it'
import type { PDFTokenMeta } from '../../shared/index.js'
import { path } from 'vuepress/utils'
import { createRuleBlock } from '../utils/createRuleBlock.js'
import { parseRect } from '../utils/parseRect.js'
import { resolveAttrs } from '../utils/resolveAttrs.js'
import { createEmbedRuleBlock } from './createEmbedRuleBlock.js'
export const pdfPlugin: PluginWithOptions<never> = (md) => {
createRuleBlock<PDFTokenMeta>(md, {
createEmbedRuleBlock<PDFTokenMeta>(md, {
type: 'pdf',
// eslint-disable-next-line regexp/no-super-linear-backtracking
syntaxPattern: /^@\[pdf(?:\s+(\d+))?([^\]]*)\]\(([^)]*)\)/,

View File

@ -7,15 +7,15 @@
import type { PluginWithOptions } from 'markdown-it'
import type { BilibiliTokenMeta } from '../../../shared/index.js'
import { URLSearchParams } from 'node:url'
import { createRuleBlock } from '../../utils/createRuleBlock.js'
import { parseRect } from '../../utils/parseRect.js'
import { resolveAttrs } from '../../utils/resolveAttrs.js'
import { timeToSeconds } from '../../utils/timeToSeconds.js'
import { createEmbedRuleBlock } from '../createEmbedRuleBlock.js'
const BILIBILI_LINK = 'https://player.bilibili.com/player.html'
export const bilibiliPlugin: PluginWithOptions<never> = (md) => {
createRuleBlock<BilibiliTokenMeta>(md, {
createEmbedRuleBlock<BilibiliTokenMeta>(md, {
type: 'bilibili',
name: 'video_bilibili',
// eslint-disable-next-line regexp/no-super-linear-backtracking

View File

@ -4,15 +4,15 @@
import type { PluginWithOptions } from 'markdown-it'
import type { YoutubeTokenMeta } from '../../../shared/index.js'
import { URLSearchParams } from 'node:url'
import { createRuleBlock } from '../../utils/createRuleBlock.js'
import { parseRect } from '../../utils/parseRect.js'
import { resolveAttrs } from '../../utils/resolveAttrs.js'
import { timeToSeconds } from '../../utils/timeToSeconds.js'
import { createEmbedRuleBlock } from '..//createEmbedRuleBlock.js'
const YOUTUBE_LINK = 'https://www.youtube.com/embed/'
export const youtubePlugin: PluginWithOptions<never> = (md) => {
createRuleBlock<YoutubeTokenMeta>(md, {
createEmbedRuleBlock<YoutubeTokenMeta>(md, {
type: 'youtube',
name: 'video_youtube',
syntaxPattern: /^@\[youtube([^\]]*)\]\(([^)]*)\)/,

View File

@ -1,3 +1,3 @@
export * from '../shared/index.js'
export { resolveImageSize } from './features/imageSize.js'
export { resolveImageSize } from './enhance/imageSize.js'
export * from './plugin.js'

View File

@ -9,6 +9,9 @@ import type { RuleInline } from 'markdown-it/lib/parser_inline.mjs'
const [openTag, endTag] = [':[', ']:']
export const iconsPlugin: PluginWithOptions<never> = md =>
md.inline.ruler.before('emphasis', 'iconify', createTokenizer())
function createTokenizer(): RuleInline {
return (state, silent) => {
let found = false
@ -75,9 +78,3 @@ function createTokenizer(): RuleInline {
return true
}
}
export const iconsPlugin: PluginWithOptions<never> = (
md,
) => {
md.inline.ruler.before('emphasis', 'iconify', createTokenizer())
}

View File

@ -0,0 +1,22 @@
import type { Markdown } from 'vuepress/markdown'
import type { MarkdownPowerPluginOptions } from '../../shared/index.js'
import { iconsPlugin } from './icons.js'
import { plotPlugin } from './plot.js'
export function inlineSyntaxPlugin(
md: Markdown,
options: MarkdownPowerPluginOptions,
): void {
if (options.icons) {
// :[collect:name]:
md.use(iconsPlugin)
}
if (
options.plot === true
|| (typeof options.plot === 'object' && options.plot.tag !== false)
) {
// !!plot!!
md.use(plotPlugin)
}
}

View File

@ -1,11 +1,14 @@
/**
* =| hover |=
* !! hover !!
*/
import type { PluginWithOptions } from 'markdown-it'
import type { RuleInline } from 'markdown-it/lib/parser_inline.mjs'
const [openTag, endTag] = ['!!', '!!']
export const plotPlugin: PluginWithOptions<never> = md =>
md.inline.ruler.before('emphasis', 'plot', createTokenizer())
function createTokenizer(): RuleInline {
return (state, silent) => {
let found = false
@ -65,9 +68,3 @@ function createTokenizer(): RuleInline {
return true
}
}
export const plotPlugin: PluginWithOptions<never> = (
md,
) => {
md.inline.ruler.before('emphasis', 'plot', createTokenizer())
}

View File

@ -1,110 +1,38 @@
import type MarkdownIt from 'markdown-it'
import type { Plugin } from 'vuepress/core'
import type { CanIUseOptions, MarkdownPowerPluginOptions } from '../shared/index.js'
import type { MarkdownPowerPluginOptions } from '../shared/index.js'
import { addViteOptimizeDepsInclude } from '@vuepress/helper'
import { caniusePlugin, legacyCaniuse } from './features/caniuse.js'
import { codepenPlugin } from './features/codepen.js'
import { codeSandboxPlugin } from './features/codeSandbox.js'
import { fileTreePlugin } from './features/fileTree/index.js'
import { iconsPlugin } from './features/icons.js'
import { imageSizePlugin } from './features/imageSize.js'
import { jsfiddlePlugin } from './features/jsfiddle.js'
import { langReplPlugin } from './features/langRepl.js'
import { pdfPlugin } from './features/pdf.js'
import { plotPlugin } from './features/plot.js'
import { replitPlugin } from './features/replit.js'
import { bilibiliPlugin } from './features/video/bilibili.js'
import { youtubePlugin } from './features/video/youtube.js'
import { containerPlugin } from './container/index.js'
import { embedSyntaxPlugin } from './embed/index.js'
import { imageSizePlugin } from './enhance/imageSize.js'
import { inlineSyntaxPlugin } from './inline/index.js'
import { prepareConfigFile } from './prepareConfigFile.js'
export function markdownPowerPlugin(options: MarkdownPowerPluginOptions = {}): Plugin {
return (app) => {
return {
name: 'vuepress-plugin-md-power',
return {
name: 'vuepress-plugin-md-power',
clientConfigFile: app => prepareConfigFile(app, options),
clientConfigFile: app => prepareConfigFile(app, options),
define: {
__MD_POWER_INJECT_OPTIONS__: options,
},
define: {
__MD_POWER_INJECT_OPTIONS__: options,
},
extendsBundlerOptions(bundlerOptions) {
if (options.repl) {
addViteOptimizeDepsInclude(
bundlerOptions,
app,
['shiki/core', 'shiki/wasm'],
)
}
},
extendsBundlerOptions(bundlerOptions, app) {
if (options.repl) {
addViteOptimizeDepsInclude(
bundlerOptions,
app,
['shiki/core', 'shiki/wasm'],
)
}
},
extendsMarkdown: async (md: MarkdownIt, app) => {
await imageSizePlugin(app, md, options.imageSize)
extendsMarkdown: async (md, app) => {
embedSyntaxPlugin(md, options)
inlineSyntaxPlugin(md, options)
if (options.caniuse) {
const caniuse = options.caniuse === true ? {} : options.caniuse
// @[caniuse](feature_name)
md.use<CanIUseOptions>(caniusePlugin, caniuse)
// 兼容旧语法
legacyCaniuse(md, caniuse)
}
if (options.pdf) {
// @[pdf](url)
md.use(pdfPlugin)
}
if (options.icons) {
// :[collect:name]:
md.use(iconsPlugin)
}
if (options.bilibili) {
// @[bilibili](bvid aid cid)
md.use(bilibiliPlugin)
}
if (options.youtube) {
// @[youtube](id)
md.use(youtubePlugin)
}
if (options.codepen) {
// @[codepen](user/slash)
md.use(codepenPlugin)
}
if (options.replit) {
// @[replit](user/repl-name)
md.use(replitPlugin)
}
if (options.codeSandbox) {
// @[codesandbox](id)
md.use(codeSandboxPlugin)
}
if (options.jsfiddle) {
// @[jsfiddle](user/id)
md.use(jsfiddlePlugin)
}
if (
options.plot === true
|| (typeof options.plot === 'object' && options.plot.tag !== false)
) {
// !!plot!!
md.use(plotPlugin)
}
if (options.repl)
await langReplPlugin(app, md, options.repl)
if (options.fileTree) {
// ::: file-tree
fileTreePlugin(md)
}
},
}
await containerPlugin(app, md, options)
await imageSizePlugin(app, md, options.imageSize)
},
}
}