Skip to content

Commit cd499a5

Browse files
authored
Expand README for src/content-render (#58894)
1 parent 6df0929 commit cd499a5

File tree

1 file changed

+129
-42
lines changed

1 file changed

+129
-42
lines changed

src/content-render/README.md

Lines changed: 129 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,36 @@
1-
# Render content
1+
# Content render
22

3-
In this directory is the main pipeline that converts our content from Liquid, Markdown and YAML into HTML. This directory _does not include React components_.
3+
The content-render subject is the main pipeline that converts content from Liquid, Markdown, and YAML into HTML. It handles template processing, Markdown parsing, custom Liquid tags, and unified (remark/rehype) transformations. This directory does not include React components.
44

5-
## Usage
5+
## Purpose & Scope
6+
7+
This subject is responsible for:
8+
- Rendering Liquid templates with context variables
9+
- Converting Markdown to HTML with unified (remark/rehype)
10+
- Custom Liquid tags for content and data references
11+
- Code block syntax highlighting and headers
12+
- Link rewriting (local paths, assets, anchors)
13+
- Image transformations and wrapping
14+
- Alert/note callout rendering
15+
- Table accessibility improvements
16+
- Text-only extraction for search indexing
17+
18+
## Architecture & Key Assets
19+
20+
### Key capabilities and their locations
21+
22+
- `index.ts` - `renderContent()`: Main entry point for content rendering
23+
- `liquid/engine.ts` - Liquid engine with custom tag registration
24+
- `unified/processor.ts` - Unified pipeline with remark/rehype plugins
25+
- `liquid/*.ts` - Custom Liquid tags (data, ifversion, octicon, etc.)
26+
- `unified/*.ts` - Content transformation plugins
27+
28+
## Setup & Usage
29+
30+
### Basic usage
631

732
```javascript
8-
const renderContent = require('.')
33+
import { renderContent } from '@/content-render'
934

1035
const html = await renderContent(`
1136
# Beep
@@ -22,77 +47,139 @@ Creates:
2247
<p>bar</p>
2348
```
2449

25-
## API
50+
### API
2651

27-
### renderContent(markdown, context = {}, options = {})
52+
#### renderContent(markdown, context = {}, options = {})
2853

2954
Render a string of `markdown` with optional `context`. Returns a `Promise`.
3055

31-
Liquid will be looking for includes in `${process.cwd()}/includes`.
56+
Liquid will look for includes in `${process.cwd()}/includes`.
3257

3358
Options:
59+
- `fileName`: File name for debugging purposes
60+
- `textOnly`: Output text instead of HTML using cheerio (for search indexing)
3461

35-
- `fileName`: File name for debugging purposes.
36-
- `textOnly`: Output text instead of html using [cheerio](https://ghub.io/cheerio).
37-
38-
### .liquid
62+
#### .liquid
3963

40-
The [Liquid](https://ghub.io/liquidjs) instance used internally.
64+
The Liquid instance used internally for direct access.
4165

4266
### Code block headers
4367

44-
You can add a header to code blocks by adding the ` copy` annotation after the code fences, and a specified language:
68+
Add a header to code blocks with the `copy` annotation:
4569

4670
```js copy
4771
const copyMe = true
4872
```
4973

5074
The un-highlighted text is available as `button.js-btn-copy`'s `data-clipboard-text` attribute.
5175

52-
## Liquid tags
76+
## Data & External Dependencies
5377

54-
See also [contributing/liquid-helpers.md](../../contributing/liquid-helpers.md)
78+
### Data inputs
79+
- Markdown content with Liquid templates
80+
- Context object with variables and functions
81+
- Data from `data/` directory (reusables, variables, features)
82+
- Content includes from `includes/` directory
5583

56-
This directory contains custom Liquid tags for outputting dynamic content. These custom tags exist for a few reasons:
84+
### Dependencies
85+
- **LiquidJS** - Template engine for Liquid processing
86+
- **unified/remark/rehype** - Markdown to HTML transformation
87+
- **cheerio** - HTML parsing for text-only mode
88+
- **highlight.js** - Syntax highlighting for code blocks
89+
- Custom plugins for GitHub-specific transformations
5790

58-
- Content and styling should be separated. Writers should not be concerned with writing or maintaining stylistic markup.
59-
- Content should be localized to match the current language.
60-
- Styling and markup should be DRY and reusable.
91+
### Transformation pipeline
6192

62-
## Using tags
93+
1. **Liquid rendering** - Process Liquid tags and variables
94+
2. **Markdown parsing** - Convert to syntax tree (remark)
95+
3. **Unified plugins** - Apply transformations
96+
4. **HTML generation** - Convert to final HTML (rehype)
97+
5. **Post-processing** - Additional cleanup if needed
6398

64-
Tags can be used in:
99+
## Cross-links & Ownership
65100

66-
- Articles and TOCs (`content/**/*.md`)
67-
- Include files (`includes/*.html`)
101+
### Related subjects
102+
- [`src/frame`](../frame/README.md) - Page rendering uses renderContent
103+
- [`src/data-directory`](../data-directory/README.md) - Data accessed via {% data %} tags
104+
- [`src/versions`](../versions/README.md) - {% ifversion %} tag logic
105+
- All content in `content/` - Source of Markdown to render
106+
- Includes in `includes/` - Reusable Liquid includes
68107

69-
Tags always expect a single argument, a language agnostic href:
108+
### Internal documentation
109+
- [Liquid helpers guide](../../contributing/liquid-helpers.md)
110+
- [Content style guide](../../contributing/) - Using Liquid tags in content
70111

71-
```html
72-
{% data variables.product.product_name %}
73-
```
112+
### Ownership
113+
- Team: Docs Engineering
74114

75-
## Supported tags
115+
## Current State & Next Steps
76116

77-
| Markup | Renders |
78-
| -- | -- |
79-
| `{% indented_data_reference foo.bar spaces=NUMBER %}` | A data reference with the specified number of spaces prepended to each line. Defaults to 2 spaces if no spaces included. For example: `{% indented_data_reference reusables.pages.wildcard-dns-warning spaces=3 %}`
117+
### Supported Liquid tags
80118

81-
## Creating tags
119+
Custom tags implemented:
82120

83-
Each custom tag has the following:
121+
| Tag | Purpose |
122+
|-----|---------|
123+
| `{% data variables.product.product_name %}` | Access data variables |
124+
| `{% ifversion fpt %}...{% endif %}` | Conditional content by version |
125+
| `{% octicon "check" %}` | Render Octicons |
126+
| `{% indented_data_reference foo.bar spaces=2 %}` | Data reference with indentation |
127+
| `{% tool name %}` | Tool-specific content |
128+
| `{% prompt %}` | Command prompt styling |
84129

85-
- a JavaScript class in `lib/liquid-tags/`
86-
- an HTML template in `includes/liquid-tags/`
130+
See [contributing/liquid-helpers.md](../../contributing/liquid-helpers.md) for complete list.
87131

88-
The class and the template should have corresponding names, like `lib/liquid-tags/my-tag.ts` and `includes/liquid-tags/my-tag.html`
132+
### Using tags
133+
134+
Tags can be used in:
135+
- Articles and TOCs (`content/**/*.md`)
136+
- Include files (`includes/*.html`)
89137

90-
You must also register the new tag in `src/content-render/liquid/engine.ts` with a line like this:
138+
Tags expect language-agnostic hrefs or data paths:
91139

140+
```liquid
141+
{% data variables.product.product_name %}
142+
{% ifversion ghes > 3.9 %}...{% endif %}
92143
```
93-
engine.registerTag('my_tag', require('./liquid-tags/my-tag'))
94-
```
95-
96-
## Further reading
97144

98-
- Liquid Docs: https://github.com/liquid-lang/liquid-node#registering-new-tags
145+
### Creating new Liquid tags
146+
147+
1. Create TypeScript class in `liquid/my-tag.ts` and implement the rendering logic directly in the class (using inline HTML or template strings).
148+
2. Register in `liquid/engine.ts`:
149+
```typescript
150+
import MyTag from './my-tag'
151+
engine.registerTag('my_tag', MyTag)
152+
```
153+
3. Add tests in `tests/`
154+
4. Document in `contributing/liquid-helpers.md`
155+
156+
See [LiquidJS docs](https://liquidjs.com/tutorials/register-filters-tags.html) for tag API.
157+
158+
### Unified plugins
159+
160+
Plugins transform the Markdown AST:
161+
- `rewrite-local-links` - Rewrites internal `/en/...` links
162+
- `rewrite-asset-urls` - Handles `/assets/...` paths
163+
- `heading-links` - Adds anchor links to headings
164+
- `alerts` - Converts `> [!NOTE]` to styled alerts
165+
- `code-header` - Adds copy buttons to code blocks
166+
- And many more...
167+
168+
### Adding new unified plugins
169+
170+
1. Create plugin in `unified/my-plugin.ts`
171+
2. Add to processor in `unified/processor.ts`
172+
3. Add tests
173+
4. Consider impact on performance (plugins run on every render)
174+
175+
### Known limitations
176+
- Liquid rendering happens before Markdown parsing (can't use Markdown in Liquid output easily)
177+
- Some transformations are performance-sensitive (cached where possible)
178+
- Text-only mode used for search has different output than HTML mode
179+
- Custom Liquid tags must be registered manually
180+
181+
### Performance considerations
182+
- Rendering is cached at the page level
183+
- Liquid includes are resolved on every render
184+
- Heavy transformations should be avoided in hot paths
185+
- Use `textOnly` mode for search indexing (faster)

0 commit comments

Comments
 (0)