Skip to content

Commit e7036e2

Browse files
committed
fix: HTML head tags injection
1 parent 8d0ebb2 commit e7036e2

File tree

2 files changed

+41
-54
lines changed

2 files changed

+41
-54
lines changed

packages/slidev/node/commands/shared.ts

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,48 @@ import { existsSync, promises as fs } from 'node:fs'
22
import { join } from 'node:path'
33
import { loadConfigFromFile, mergeConfig, resolveConfig } from 'vite'
44
import type { ConfigEnv, InlineConfig } from 'vite'
5-
import type { ResolvedSlidevOptions } from '@slidev/types'
6-
import { generateGoogleFontsUrl } from '../utils'
5+
import type { ResolvedSlidevOptions, SlidevData } from '@slidev/types'
6+
import { isString } from 'unocss'
7+
import MarkdownIt from 'markdown-it'
8+
import markdownItLink from '../syntax/markdown-it/markdown-it-link'
9+
import { generateGoogleFontsUrl, stringifyMarkdownTokens } from '../utils'
710
import { toAtFS } from '../resolver'
811

12+
export const sharedMd = MarkdownIt({ html: true })
13+
sharedMd.use(markdownItLink)
14+
15+
export function getTitle(data: SlidevData) {
16+
if (isString(data.config.title)) {
17+
const tokens = sharedMd.parseInline(data.config.title, {})
18+
return stringifyMarkdownTokens(tokens)
19+
}
20+
return data.config.title
21+
}
22+
23+
function escapeHtml(unsafe: unknown) {
24+
return JSON.stringify(
25+
String(unsafe)
26+
.replace(/&/g, '&')
27+
.replace(/</g, '&lt;')
28+
.replace(/>/g, '&gt;')
29+
.replace(/"/g, '&quot;')
30+
.replace(/'/g, '&#039;'),
31+
)
32+
}
33+
934
export async function getIndexHtml({ clientRoot, roots, data }: ResolvedSlidevOptions): Promise<string> {
1035
let main = await fs.readFile(join(clientRoot, 'index.html'), 'utf-8')
1136
let head = ''
1237
let body = ''
1338

14-
head += `<link rel="icon" href="${data.config.favicon}">`
39+
const { info, author, keywords } = data.headmatter
40+
head += [
41+
`<link rel="icon" href="${data.config.favicon}">`,
42+
`<title>${getTitle(data)}</title>`,
43+
info && `<meta name="description" content=${escapeHtml(info)}>`,
44+
author && `<meta name="author" content=${escapeHtml(author)}>`,
45+
keywords && `<meta name="keywords" content=${escapeHtml(Array.isArray(keywords) ? keywords.join(', ') : keywords)}>`,
46+
].filter(Boolean).join('\n')
1547

1648
for (const root of roots) {
1749
const path = join(root, 'index.html')

packages/slidev/node/vite/loaders.ts

Lines changed: 6 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
import path from 'node:path'
2-
import type { Connect, HtmlTagDescriptor, ModuleNode, Plugin, Update, ViteDevServer } from 'vite'
3-
import { isString, isTruthy, notNullish, range } from '@antfu/utils'
2+
import type { Connect, ModuleNode, Plugin, Update, ViteDevServer } from 'vite'
3+
import { notNullish, range } from '@antfu/utils'
44
import fg from 'fast-glob'
5-
import Markdown from 'markdown-it'
65
import { bold, gray, red, yellow } from 'kolorist'
76

87
import type { ResolvedSlidevOptions, SlideInfo, SlidePatch, SlidevPluginOptions, SlidevServerOptions } from '@slidev/types'
98
import * as parser from '@slidev/parser/fs'
109
import equal from 'fast-deep-equal'
1110

1211
import type { LoadResult } from 'rollup'
13-
import { stringifyMarkdownTokens, updateFrontmatterPatch } from '../utils'
12+
import { updateFrontmatterPatch } from '../utils'
1413
import { toAtFS } from '../resolver'
1514
import { templates } from '../virtual'
1615
import type { VirtualModuleTempalteContext } from '../virtual/types'
@@ -19,7 +18,7 @@ import { VIRTUAL_SLIDE_PREFIX, templateSlides } from '../virtual/slides'
1918
import { templateConfigs } from '../virtual/configs'
2019
import { templateMonacoRunDeps } from '../virtual/monaco-deps'
2120
import { templateMonacoTypes } from '../virtual/monaco-types'
22-
import markdownItLink from '../syntax/markdown-it/markdown-it-link'
21+
import { sharedMd } from '../commands/shared'
2322

2423
const regexId = /^\/\@slidev\/slide\/(\d+)\.(md|json)(?:\?import)?$/
2524
const regexIdQuery = /(\d+?)\.(md|json|frontmatter)$/
@@ -64,12 +63,9 @@ export function sendHmrReload(server: ViteDevServer, modules: ModuleNode[]) {
6463
})
6564
}
6665

67-
const md = Markdown({ html: true })
68-
md.use(markdownItLink)
69-
7066
function renderNote(text: string = '') {
7167
let clickCount = 0
72-
const html = md.render(text
68+
const html = sharedMd.render(text
7369
// replace [click] marker with span
7470
.replace(/\[click(?::(\d+))?\]/gi, (_, count = 1) => {
7571
clickCount += Number(count)
@@ -103,7 +99,7 @@ export function createSlidesLoader(
10399
const { data, clientRoot, roots, mode } = options
104100

105101
const templateCtx: VirtualModuleTempalteContext = {
106-
md,
102+
md: sharedMd,
107103
async getLayouts() {
108104
const now = Date.now()
109105
if (now - _layouts_cache_time < 2000)
@@ -422,39 +418,6 @@ export function createSlidesLoader(
422418
return replaced
423419
},
424420
},
425-
{
426-
name: 'slidev:index-html-transform',
427-
transformIndexHtml() {
428-
const { info, author, keywords } = data.headmatter
429-
return [
430-
{
431-
tag: 'title',
432-
children: getTitle(),
433-
},
434-
info && {
435-
tag: 'meta',
436-
attrs: {
437-
name: 'description',
438-
content: info,
439-
},
440-
},
441-
author && {
442-
tag: 'meta',
443-
attrs: {
444-
name: 'author',
445-
content: author,
446-
},
447-
},
448-
keywords && {
449-
tag: 'meta',
450-
attrs: {
451-
name: 'keywords',
452-
content: Array.isArray(keywords) ? keywords.join(', ') : keywords,
453-
},
454-
},
455-
].filter(isTruthy) as HtmlTagDescriptor[]
456-
},
457-
},
458421
]
459422

460423
function updateServerWatcher() {
@@ -554,12 +517,4 @@ export function createSlidesLoader(
554517
// no setup script and not a vue component
555518
return `<script setup>\n${imports.join('\n')}\n</script>\n${code}`
556519
}
557-
558-
function getTitle() {
559-
if (isString(data.config.title)) {
560-
const tokens = md.parseInline(data.config.title, {})
561-
return stringifyMarkdownTokens(tokens)
562-
}
563-
return data.config.title
564-
}
565520
}

0 commit comments

Comments
 (0)