Skip to content

Commit 9c531b3

Browse files
committed
docs: add htmlProcessor usage example to customize-processor
1 parent d3b5c47 commit 9c531b3

4 files changed

Lines changed: 105 additions & 13 deletions

File tree

examples/customize-processor/README.md

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import rehypeStringify from 'rehype-stringify';
1515
import remarkRuby from 'remark-ruby';
1616

1717
const config = {
18-
title: 'Markdown processor customization example',
18+
title: 'Processor customization example',
1919
entry: ['manuscript.md'],
2020
// config is StringifyMarkdownOptions in @vivliostyle/vfm
2121
// metadata is Metadata in @vivliostyle/vfm
@@ -41,12 +41,12 @@ export default config;
4141
You can also set `documentProcessor` and `documentMetadataReader` for individual entries. This allows different processing for each file:
4242

4343
```js
44-
import { defineConfig, VFM, readMetadata } from '@vivliostyle/cli';
44+
import { defineConfig, VFM } from '@vivliostyle/cli';
4545
import unified from 'unified';
4646
// ... other imports
4747

4848
const config = defineConfig({
49-
title: 'Markdown processor customization example',
49+
title: 'Processor customization example',
5050
entry: [
5151
// Uses the global documentProcessor
5252
'manuscript.md',
@@ -55,8 +55,7 @@ const config = defineConfig({
5555
path: 'manuscript2.md',
5656
documentProcessor: VFM,
5757
documentMetadataReader: (content) => {
58-
const match = content.match(/^#\s+(.+)$/m);
59-
return { title: match ? match[1] : 'Untitled' };
58+
return { title: 'Custom title' };
6059
},
6160
},
6261
],
@@ -75,3 +74,44 @@ const config = defineConfig({
7574

7675
export default config;
7776
```
77+
78+
## htmlProcessor and xhtmlProcessor
79+
80+
While `documentProcessor` handles Markdown-to-HTML conversion, `htmlProcessor` and `xhtmlProcessor` allow you to customize the processing of HTML and XHTML source files respectively.
81+
82+
You can extend the built-in `defaultHtmlProcessor` (or `defaultXhtmlProcessor` for XHTML) with additional [rehype](https://github.com/rehypejs/rehype) plugins:
83+
84+
```js
85+
import { defineConfig, defaultHtmlProcessor } from '@vivliostyle/cli';
86+
import { visit } from 'unist-util-visit';
87+
88+
const openLinksInNewTab = () => (tree) => {
89+
visit(tree, 'element', (node) => {
90+
if (
91+
node.tagName === 'a' &&
92+
String(node.properties?.href).startsWith('http')
93+
) {
94+
(node.properties ??= {}).target = '_blank';
95+
node.properties.rel = 'noopener noreferrer';
96+
node.children.push({
97+
type: 'element',
98+
tagName: 'span',
99+
properties: {},
100+
children: [{ type: 'text', value: '' }],
101+
});
102+
}
103+
});
104+
};
105+
106+
const config = defineConfig({
107+
entry: [
108+
{
109+
path: 'page.html',
110+
htmlProcessor: (options) =>
111+
defaultHtmlProcessor(options).use(openLinksInNewTab),
112+
},
113+
],
114+
});
115+
116+
export default config;
117+
```

examples/customize-processor/package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@
88
},
99
"dependencies": {
1010
"@vivliostyle/cli": "workspace:*",
11-
"rehype-expressive-code": "^0.37.0",
11+
"rehype-expressive-code": "0.41.6",
1212
"rehype-stringify": "^8.0.0",
1313
"remark-parse": "^9.0.0",
14-
"remark-rehype": "^9.0.0",
14+
"remark-rehype": "^8.1.0",
1515
"remark-ruby": "^0.4.0",
16-
"unified": "^9.2.0"
16+
"unified": "^9.2.0",
17+
"unist-util-visit": "^4.1.0"
1718
}
1819
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
<title>HTML Processor Example</title>
6+
</head>
7+
<body>
8+
<h1>HTML Processor Example</h1>
9+
<p>
10+
This page is processed with a custom
11+
<a href="https://unifiedjs.com/">unified</a> processor. External links
12+
like
13+
<a href="https://vivliostyle.org/">Vivliostyle</a>
14+
will have <code>target="_blank"</code> and an arrow indicator added
15+
automatically.
16+
</p>
17+
</body>
18+
</html>

examples/customize-processor/vivliostyle.config.js

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,34 @@
11
// @ts-check
2-
import { defineConfig, VFM } from '@vivliostyle/cli';
2+
import { defineConfig, VFM, defaultHtmlProcessor } from '@vivliostyle/cli';
33
import rehypeExpressiveCode from 'rehype-expressive-code';
44
import rehypeStringify from 'rehype-stringify';
55
import remarkParse from 'remark-parse';
66
import remark2rehype from 'remark-rehype';
77
import remarkRuby from 'remark-ruby';
88
import unified from 'unified';
9+
import { visit } from 'unist-util-visit';
10+
11+
/** @type {import('unified').Plugin} */
12+
const openLinksInNewTab = () => (tree) => {
13+
visit(/** @type {import("hast-v2").Root} */ (tree), 'element', (node) => {
14+
if (
15+
node.tagName === 'a' &&
16+
String(node.properties?.href).startsWith('http')
17+
) {
18+
(node.properties ??= {}).target = '_blank';
19+
node.properties.rel = 'noopener noreferrer';
20+
node.children.push({
21+
type: 'element',
22+
tagName: 'span',
23+
properties: {},
24+
children: [{ type: 'text', value: ' ↗' }],
25+
});
26+
}
27+
});
28+
};
929

1030
const config = defineConfig({
11-
title: 'Markdown processor customization example',
31+
title: 'Processor customization example',
1232
entry: [
1333
'manuscript.md',
1434
{
@@ -18,15 +38,28 @@ const config = defineConfig({
1838
return { title: 'Custom title' };
1939
},
2040
},
41+
{
42+
path: 'page.html',
43+
htmlProcessor: (options) =>
44+
defaultHtmlProcessor(options).use(openLinksInNewTab),
45+
},
2146
],
2247
documentProcessor: (config, metadata) =>
2348
unified()
2449
.use(remarkParse)
2550
.use(remarkRuby)
2651
.use(remark2rehype)
27-
.use(rehypeExpressiveCode, {
28-
frames: { showCopyToClipboardButton: false },
29-
})
52+
.use(
53+
/**
54+
* rehype-expressive-code depends on unified@10 since its first release
55+
* and is not strictly type-compatible with unified@9.
56+
* It works at runtime anyway.
57+
* @type {import("unified").Plugin<[Parameters<typeof rehypeExpressiveCode>[0]]>}
58+
*/ (rehypeExpressiveCode),
59+
{
60+
frames: { showCopyToClipboardButton: false },
61+
},
62+
)
3063
.use(rehypeStringify),
3164
output: 'draft.pdf',
3265
});

0 commit comments

Comments
 (0)