返回 slidev
config-parser.md
根目录 / docs / custom / config-parser.md
1 # Configure Pre-Parser
2
3 ::: info
4 Custom pre-parsers are not supposed to be used too often. Usually you can use [Transformers](./config-transformers) for custom syntaxes.
5 :::
6
7 Slidev parses your presentation file (e.g. `slides.md`) in three steps:
8
9 1. A "preparsing" step is carried out: the file is split into slides using the `---` separator, and considering the possible frontmatter blocks.
10 2. Each slide is parsed with an external library.
11 3. Slidev resolves the special frontmatter property `src: ....`, which allows to include other md files.
12
13 ## Markdown Parser
14
15 Configuring the markdown parser used in step 2 can be done by [configuring Vite internal plugins](/custom/config-vite#configure-internal-plugins).
16
17 ## Preparser Extensions
18
19 > Available since v0.37.0.
20
21 ::: warning
22 Important: when modifying the preparser configuration, you need to stop and start Slidev again (restart might not be sufficient).
23 :::
24
25 The preparser (step 1 above) is highly extensible and allows you to implement custom syntaxes for your md files. Extending the preparser is considered **an advanced feature** and is susceptible to breaking [editor integrations](../features/side-editor) due to implicit changes in the syntax.
26
27 To customize it, create a `./setup/preparser.ts` file with the following content:
28
29 ```ts twoslash [./setup/preparser.ts]
30 import { definePreparserSetup } from '@slidev/types'
31
32 export default definePreparserSetup(({ filepath, headmatter, mode }) => {
33 return [
34 {
35 transformRawLines(lines) {
36 for (const i in lines) {
37 if (lines[i] === '@@@')
38 lines[i] = 'HELLO'
39 }
40 },
41 }
42 ]
43 })
44 ```
45
46 This example systematically replaces any `@@@` line with a line with `hello`. It illustrates the structure of a preparser configuration file and some of the main concepts the preparser involves:
47
48 - `definePreparserSetup` must be called with a function as parameter.
49 - The function receives the file path (of the root presentation file), the headmatter (from the md file) and, since v0.48.0, a mode (dev, build or export). It could use this information (e.g., enable extensions based on the presentation file or whether we are exporting a PDF).
50 - The function must return a list of preparser extensions.
51 - An extension can contain:
52 - a `transformRawLines(lines)` function that runs just after parsing the headmatter of the md file and receives a list of all lines (from the md file). The function can mutate the list arbitrarily.
53 - a `transformSlide(content, frontmatter)` function that is called for each slide, just after splitting the file, and receives the slide content as a string and the frontmatter of the slide as an object. The function can mutate the frontmatter and must return the content string (possibly modified, possibly `undefined` if no modifications have been done).
54 - a `transformNote(note, frontmatter)` function that is called for each slide, just after splitting the file, and receives the slide note as a string or undefined and the frontmatter of the slide as an object. The function can mutate the frontmatter and must return the note string (possibly modified, possibly `undefined` if no modifications have been done).
55 - a `name`
56
57 ## Example Preparser Extensions
58
59 ### Use case 1: compact syntax top-level presentation
60
61 Imagine a situation where (part of) your presentation is mainly showing cover images and including other md files. You might want a compact notation where for instance (part of) `slides.md` is as follows:
62
63 <!-- eslint-skip -->
64
65 ```md
66 @cover: /nice.jpg
67 # Welcome
68 @src: page1.md
69 @src: page2.md
70 @cover: /break.jpg
71 @src: pages3-4.md
72 @cover: https://cover.sli.dev
73 # Questions?
74 see you next time
75 ```
76
77 To allow these `@src:` and `@cover:` syntaxes, create a `./setup/preparser.ts` file with the following content:
78
79 ```ts twoslash [./setup/preparser.ts]
80 import { definePreparserSetup } from '@slidev/types'
81
82 export default definePreparserSetup(() => {
83 return [
84 {
85 transformRawLines(lines) {
86 let i = 0
87 while (i < lines.length) {
88 const l = lines[i]
89 if (/^@cover:/i.test(l)) {
90 lines.splice(
91 i,
92 1,
93 '---',
94 'layout: cover',
95 `background: ${l.replace(/^@cover: */i, '')}`,
96 '---',
97 ''
98 )
99 continue
100 }
101 if (/^@src:/i.test(l)) {
102 lines.splice(
103 i,
104 1,
105 '---',
106 `src: ${l.replace(/^@src: */i, '')}`,
107 '---',
108 ''
109 )
110 continue
111 }
112 i++
113 }
114 }
115 },
116 ]
117 })
118 ```
119
120 And that's it.
121
122 ### Use case 2: using custom frontmatter to wrap slides
123
124 Imagine a case where you often want to scale some of your slides but still want to use a variety of existing layouts so creating a new layout would not be suited.
125 For instance, you might want to write your `slides.md` as follows:
126
127 <!-- eslint-skip -->
128
129 ```md
130 ---
131 layout: quote
132 _scale: 0.75
133 ---
134
135 # Welcome
136
137 > great!
138
139 ---
140 _scale: 4
141 ---
142 # Break
143
144 ---
145
146 # Ok
147
148 ---
149 layout: center
150 _scale: 2.5
151 ---
152 # Questions?
153 see you next time
154 ```
155
156 Here we used an underscore in `_scale` to avoid possible conflicts with existing frontmatter properties (indeed, the case of `scale`, without underscore would cause potential problems).
157
158 To handle this `_scale: ...` syntax in the frontmatter, create a `./setup/preparser.ts` file with the following content:
159
160 ```ts twoslash [./setup/preparser.ts]
161 import { definePreparserSetup } from '@slidev/types'
162
163 export default definePreparserSetup(() => {
164 return [
165 {
166 async transformSlide(content, frontmatter) {
167 if ('_scale' in frontmatter) {
168 return [
169 `<Transform :scale=${frontmatter._scale}>`,
170 '',
171 content,
172 '',
173 '</Transform>'
174 ].join('\n')
175 }
176 },
177 },
178 ]
179 })
180 ```
181
182 And that's it.
183
184 ### Use case 3: using custom frontmatter to transform note
185
186 Imagine a case where you want to replace the slides default notes with custom notes.
187 For instance, you might want to write your `slides.md` as follows:
188
189 <!-- eslint-skip -->
190
191 ```md
192 ---
193 layout: quote
194 _note: notes/note.md
195 ---
196
197 # Welcome
198
199 > great!
200
201 <!--
202 Default slide notes
203 -->
204 ```
205
206 Here we used an underscore in `_note` to avoid possible conflicts with existing frontmatter properties.
207
208 To handle this `_note: ...` syntax in the frontmatter, create a `./setup/preparser.ts` file with the following content:
209
210 ```ts twoslash [./setup/preparser.ts]
211 import fs, { promises as fsp } from 'node:fs'
212 import { definePreparserSetup } from '@slidev/types'
213
214 export default definePreparserSetup(() => {
215 return [
216 {
217 async transformNote(note, frontmatter) {
218 if ('_note' in frontmatter && fs.existsSync(frontmatter._note)) {
219 try {
220 const newNote = await fsp.readFile(frontmatter._note, 'utf8')
221 return newNote
222 }
223 catch (err) {
224 }
225 }
226
227 return note
228 },
229 },
230 ]
231 })
232 ```
233
233 lines MARKDOWN