feat(plugin-md-power): add imageSize plugin

This commit is contained in:
pengzhanbo 2024-09-09 00:16:46 +08:00
parent 33132297e1
commit 1d09eb4183
3 changed files with 79 additions and 1 deletions

View File

@ -0,0 +1,75 @@
import type { App } from 'vuepress'
import type { Markdown, MarkdownEnv } from 'vuepress/markdown'
import { isLinkExternal } from '@vuepress/helper'
import { fs, path } from '@vuepress/utils'
import imageSize from 'image-size'
export function imageSizePlugin(app: App, md: Markdown): void {
if (!app.env.isBuild)
return
const cache = new Map<string, { width: number, height: number }>()
const imageRule = md.renderer.rules.image!
md.renderer.rules.image = (tokens, idx, options, env: MarkdownEnv, self) => {
if (!env.filePathRelative || !env.filePath)
return imageRule(tokens, idx, options, env, self)
const token = tokens[idx]
const src = token.attrGet('src')
if (!src || src.startsWith('data:') || isLinkExternal(src))
return imageRule(tokens, idx, options, env, self)
const width = token.attrGet('width')
const height = token.attrGet('height')
if (width && height)
return imageRule(tokens, idx, options, env, self)
const filepath = resolveImageUrl(src, env)
if (!cache.has(filepath)) {
if (!filepath || !fs.existsSync(filepath))
return imageRule(tokens, idx, options, env, self)
const { width: w, height: h } = imageSize(filepath)
if (!w || !h)
return imageRule(tokens, idx, options, env, self)
cache.set(filepath, { width: w, height: h })
}
const { width: originalWidth, height: originalHeight } = cache.get(filepath)!
const ratio = originalWidth / originalHeight
if (width && !height) {
const w = Number.parseInt(width, 10)
token.attrSet('width', `${w}`)
token.attrSet('height', `${Math.round(w / ratio)}`)
}
else if (height && !width) {
const h = Number.parseInt(height, 10)
token.attrSet('width', `${Math.round(h * ratio)}`)
token.attrSet('height', `${h}`)
}
else {
token.attrSet('width', `${originalWidth}`)
token.attrSet('height', `${originalHeight}`)
}
return imageRule(tokens, idx, options, env, self)
}
function resolveImageUrl(src: string, env: MarkdownEnv): string {
if (src[0] === '/')
return app.dir.public(src.slice(1))
if (env.filePathRelative)
return app.dir.source(path.join(path.dirname(env.filePathRelative), src))
if (env.filePath)
return path.resolve(env.filePath, src)
return ''
}
}

View File

@ -15,6 +15,7 @@ import { plotPlugin } from './features/plot.js'
import { langReplPlugin } from './features/langRepl.js'
import { prepareConfigFile } from './prepareConfigFile.js'
import { fileTreePlugin } from './features/fileTree/index.js'
import { imageSizePlugin } from './features/imageSize.js'
export function markdownPowerPlugin(options: MarkdownPowerPluginOptions = {}): Plugin {
return (app) => {
@ -38,6 +39,8 @@ export function markdownPowerPlugin(options: MarkdownPowerPluginOptions = {}): P
},
extendsMarkdown: async (md: MarkdownIt, app) => {
imageSizePlugin(app, md)
if (options.caniuse) {
const caniuse = options.caniuse === true ? {} : options.caniuse
// @[caniuse](feature_name)

View File

@ -33,7 +33,7 @@ export default defineConfig(() => {
entry: ['./src/node/index.ts'],
outDir: './lib/node',
target: 'node18',
external: ['markdown-it'],
external: ['markdown-it', /^@?vuepress/],
},
// client
...config.map(({ dir, files }) => ({