https://github.com/jaredwray/writr
Markdown Rendering Simplified
https://github.com/jaredwray/writr
emoji github-flavored-markdown highlighting html markdown markdown-processor markdown-to-html remark renderer syntax table-of-contents toc
Last synced: 3 months ago
JSON representation
Markdown Rendering Simplified
- Host: GitHub
- URL: https://github.com/jaredwray/writr
- Owner: jaredwray
- License: mit
- Created: 2018-05-01T05:04:51.000Z (about 7 years ago)
- Default Branch: main
- Last Pushed: 2025-03-29T20:49:54.000Z (3 months ago)
- Last Synced: 2025-04-01T18:22:37.803Z (3 months ago)
- Topics: emoji, github-flavored-markdown, highlighting, html, markdown, markdown-processor, markdown-to-html, remark, renderer, syntax, table-of-contents, toc
- Language: TypeScript
- Homepage: https://writr.org
- Size: 1.45 MB
- Stars: 11
- Watchers: 2
- Forks: 7
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
- Security: SECURITY.md
Awesome Lists containing this project
README

# Markdown Rendering Simplified
[](https://github.com/jaredwray/writr/actions/workflows/tests.yml)
[](https://github.com/jaredwray/writr/blob/master/LICENSE)
[](https://codecov.io/gh/jaredwray/writr)
[](https://www.jsdelivr.com/package/npm/writr)
[](https://npmjs.com/package/writr)
[](https://npmjs.com/package/writr)# Features
* Removes the remark / unified complexity and easy to use.
* Built in caching 💥 making it render very fast when there isnt a change
* Frontmatter support built in by default. :tada:
* Easily Render to `React` or `HTML`.
* Generates a Table of Contents for your markdown files (remark-toc).
* Slug generation for your markdown files (rehype-slug).
* Code Highlighting (rehype-highlight).
* Math Support (rehype-katex).
* Markdown to HTML (rehype-stringify).
* Github Flavor Markdown (remark-gfm).
* Emoji Support (remark-emoji).
* MDX Support (remark-mdx).
* Built in Hooks for adding code to render pipeline.# Table of Contents
- [Getting Started](#getting-started)
- [Running via Browser as an ESM Module](#running-via-browser-as-an-esm-module)
- [API](#api)
- [`new Writr(arg?: string | WritrOptions, options?: WritrOptions)`](#new-writrarg-string--writroptions-options-writroptions)
- [`.content`](#content)
- [`.body`](#body)
- [`.options`](#options)
- [`.frontmatter`](#frontmatter)
- [`.frontMatterRaw`](#frontmatterraw)
- [`.cache`](#cache)
- [`.engine`](#engine)
- [`.render(options?: RenderOptions): Promise`](#renderoptions-renderoptions-promisestring)
- [`.renderSync(options?: RenderOptions): string`](#rendersyncoptions-renderoptions-string)
- [`.renderToFile(filePath: string, options?: RenderOptions)`](#rendertofilefilepath-string-options-renderoptions)
- [`.renderToFileSync(filePath: string, options?: RenderOptions): void`](#rendertofilesyncfilepath-string-options-renderoptions-void)
- [`.renderReact(options?: RenderOptions, reactOptions?: HTMLReactParserOptions): Promise`](#renderreactoptions-renderoptions-reactoptions-htmlreactparseroptions-promise-reactjsxelement-)
- [`.renderReactSync( options?: RenderOptions, reactOptions?: HTMLReactParserOptions): React.JSX.Element`](#renderreactsync-options-renderoptions-reactoptions-htmlreactparseroptions-reactjsxelement)
- [`.loadFromFile(filePath: string): Promise`](#loadfromfilefilepath-string-promisevoid)
- [`.loadFromFileSync(filePath: string): void`](#loadfromfilesyncfilepath-string-void)
- [`.saveToFile(filePath: string): Promise`](#savetofilefilepath-string-promisevoid)
- [`.saveToFileSync(filePath: string): void`](#savetofilesyncfilepath-string-void)
- [Hooks](#hooks)
- [ESM and Node Version Support](#esm-and-node-version-support)
- [Code of Conduct and Contributing](#code-of-conduct-and-contributing)
- [License](#license)# Getting Started
```bash
> npm install writr
```Then you can use it like this:
```javascript
import { Writr } from 'writr';const writr = new Writr(`# Hello World ::-):\n\n This is a test.`);
const html = await writr.render(); //
Hello World 🙂
This is a test.
```
Its just that simple. Want to add some options? No problem.```javascript
import { Writr } from 'writr';
const writr = new Writr(`# Hello World ::-):\n\n This is a test.`);
const options = {
emoji: false
}
const html = await writr.render(options); //Hello World ::-):
This is a test.
```An example passing in the options also via the constructor:
```javascript
import { Writr, WritrOptions } from 'writr';
const writrOptions = {
throwErrors: true,
renderOptions: {
emoji: true,
toc: true,
slug: true,
highlight: true,
gfm: true,
math: true,
mdx: true,
caching: true,
}
};
const writr = new Writr(`# Hello World ::-):\n\n This is a test.`, writrOptions);
const html = await writr.render(options); //Hello World ::-):
This is a test.
```# Running via Browser as an ESM Module
You can also run Writr via the browser. Here is an example of how to do that.
```html
Writr Example
import {Writr} from 'https://cdn.jsdelivr.net/npm/writr@latest/+esm'const writr = new Writr(`# Hello World ::-):\n\n This is a test.`);
writr.render().then(html => {
document.body.innerHTML = html;
});
```
This will render the markdown to HTML and display it in the body of the page.
# API
## `new Writr(arg?: string | WritrOptions, options?: WritrOptions)`
By default the constructor takes in a markdown `string` or `WritrOptions` in the first parameter. You can also send in nothing and set the markdown via `.content` property. If you want to pass in your markdown and options you can easily do this with `new Writr('## Your Markdown Here', { ...options here})`. You can access the `WritrOptions` from the instance of Writr. Here is an example of WritrOptions.
```javascript
import { Writr, WritrOptions } from 'writr';
const writrOptions = {
throwErrors: true,
renderOptions: {
emoji: true,
toc: true,
slug: true,
highlight: true,
gfm: true,
math: true,
mdx: true,
caching: true,
}
};
const writr = new Writr(writrOptions);
```## `.content`
Setting the markdown content for the instance of Writr. This can be set via the constructor or directly on the instance and can even handle `frontmatter`.
```javascript
import { Writr } from 'writr';
const writr = new Writr();
writr.content = `---
title: Hello World
---
# Hello World ::-):\n\n This is a test.`;
```## `.body`
gets the body of the markdown content. This is the content without the frontmatter.
```javascript
import { Writr } from 'writr';
const writr = new Writr();
writr.content = `---
title: Hello World
---
# Hello World ::-):\n\n This is a test.`;
console.log(writr.body); // '# Hello World ::-):\n\n This is a test.'
```## `.options`
Accessing the default options for this instance of Writr. Here is the default settings for `WritrOptions`.
```javascript
{
throwErrors: false,
renderOptions: {
emoji: true,
toc: false,
slug: false,
highlight: false,
gfm: true,
math: false,
mdx: false,
caching: false,
}
}
```## `.frontmatter`
Accessing the frontmatter for this instance of Writr. This is a `Record` and can be set via the `.content` property.
```javascript
import { Writr } from 'writr';
const writr = new Writr();
writr.content = `---
title: Hello World
---
# Hello World ::-):\n\n This is a test.`;
console.log(writr.frontmatter); // { title: 'Hello World' }
```you can also set the front matter directly like this:
```javascript
import { Writr } from 'writr';
const writr = new Writr();
writr.frontmatter = { title: 'Hello World' };
```## `.frontMatterRaw`
Accessing the raw frontmatter for this instance of Writr. This is a `string` and can be set via the `.content` property.
```javascript
import { Writr } from 'writr';
const writr = new Writr();
writr.content = `---
title: Hello World
---
# Hello World ::-):\n\n This is a test.`;
console.log(writr.frontMatterRaw); // '---\ntitle: Hello World\n---'
```## `.cache`
Accessing the cache for this instance of Writr. By default this is an in memory cache and is disabled (set to false) by default. You can enable this by setting `caching: true` in the `RenderOptions` of the `WritrOptions` or when calling render passing the `RenderOptions` like here:
```javascript
import { Writr } from 'writr';
const writr = new Writr(`# Hello World ::-):\n\n This is a test.`);
const options = {
caching: true
}
const html = await writr.render(options); //Hello World ::-):
This is a test.
```## `.engine`
Accessing the underlying engine for this instance of Writr. This is a `Processor` fro the unified `.use()` function. You can use this to add additional plugins to the engine.
## `.render(options?: RenderOptions): Promise`
Rendering markdown to HTML. the options are based on RenderOptions. Which you can access from the Writr instance.
```javascript
import { Writr } from 'writr';
const writr = new Writr(`# Hello World ::-):\n\n This is a test.`);
const html = await writr.render(); //Hello World 🙂
This is a test.
//passing in with render options
const options = {
emoji: false
}const html = await writr.render(options); //
Hello World ::-):
This is a test.
```## `.renderSync(options?: RenderOptions): string`
Rendering markdown to HTML synchronously. the options are based on RenderOptions. Which you can access from the Writr instance. The parameters are the same as the `.render()` function.
```javascript
import { Writr } from 'writr';
const writr = new Writr(`# Hello World ::-):\n\n This is a test.`);
const html = writr.renderSync(); //Hello World 🙂
This is a test.
```## '.renderToFile(filePath: string, options?: RenderOptions)'
Rendering markdown to a file. The options are based on RenderOptions.
```javascript
import { Writr } from 'writr';
const writr = new Writr(`# Hello World ::-):\n\n This is a test.`);
await writr.renderToFile('path/to/file.html');
```## '.renderToFileSync(filePath: string, options?: RenderOptions): void'
Rendering markdown to a file synchronously. The options are based on RenderOptions.
```javascript
import { Writr } from 'writr';
const writr = new Writr(`# Hello World ::-):\n\n This is a test.`);
writr.renderToFileSync('path/to/file.html');
```## '.renderReact(options?: RenderOptions, reactOptions?: HTMLReactParserOptions): Promise'
Rendering markdown to React. The options are based on RenderOptions and now HTMLReactParserOptions from `html-react-parser`.
```javascript
import { Writr } from 'writr';
const writr = new Writr(`# Hello World ::-):\n\n This is a test.`);
const reactElement = await writr.renderReact(); // Will return a React.JSX.Element
```## '.renderReactSync( options?: RenderOptions, reactOptions?: HTMLReactParserOptions): React.JSX.Element'
Rendering markdown to React. The options are based on RenderOptions and now HTMLReactParserOptions from `html-react-parser`.
```javascript
import { Writr } from 'writr';
const writr = new Writr(`# Hello World ::-):\n\n This is a test.`);
const reactElement = writr.renderReactSync(); // Will return a React.JSX.Element
```## `.loadFromFile(filePath: string): Promise`
Load your markdown content from a file path.
```javascript
import { Writr } from 'writr';
const writr = new Writr();
await writr.loadFromFile('path/to/file.md');
```## `.loadFromFileSync(filePath: string): void`
Load your markdown content from a file path synchronously.
## `.saveToFile(filePath: string): Promise`
Save your markdown and frontmatter (if included) content to a file path.
```javascript
import { Writr } from 'writr';
const writr = new Writr(`# Hello World ::-):\n\n This is a test.`);
await writr.saveToFile('path/to/file.md');
```## `.saveToFileSync(filePath: string): void`
Save your markdown and frontmatter (if included) content to a file path synchronously.
# Caching On Render
Caching is built into Writr and is an in-memory cache using `CacheableMemory` from [Cacheable](https://cacheable.org). It is turned off by default and can be enabled by setting `caching: true` in the `RenderOptions` of the `WritrOptions` or when calling render passing the `RenderOptions` like here:
```javascript
import { Writr } from 'writr';
const writr = new Writr(`# Hello World ::-):\n\n This is a test.`, { renderOptions: { caching: true } });
```or via `RenderOptions` such as:
```javascript
import { Writr } from 'writr';
const writr = new Writr(`# Hello World ::-):\n\n This is a test.`);
await writr.render({ caching: true});
```If you want to set the caching options for the instance of Writr you can do so like this:
```javascript
// we will set the lruSize of the cache and the default ttl
import {Writr} from 'writr';
const writr = new Writr(`# Hello World ::-):\n\n This is a test.`, { renderOptions: { caching: true } });
writr.cache.store.lruSize = 100;
writr.cache.store.ttl = '5m'; // setting it to 5 minutes
```# Hooks
Hooks are a way to add additional parsing to the render pipeline. You can add hooks to the the Writr instance. Here is an example of adding a hook to the instance of Writr:
```javascript
import { Writr, WritrHooks } from 'writr';
const writr = new Writr(`# Hello World ::-):\n\n This is a test.`);
writr.onHook(WritrHooks.beforeRender, data => {
data.body = 'Hello, Universe!';
});
const result = await writr.render();
console.log(result); // Hello, Universe!
```For `beforeRender` the data object is a `renderData` object. Here is the interface for `renderData`:
```typescript
export type renderData = {
body: string
options: RenderOptions;
}
```For `afterRender` the data object is a `resultData` object. Here is the interface for `resultData`:
```typescript
export type resultData = {
result: string;
}
```For `saveToFile` the data object is an object with the `filePath` and `content`. Here is the interface for `saveToFileData`:
```typescript
export type saveToFileData = {
filePath: string;
content: string;
}
```This is called when you call `saveToFile`, `saveToFileSync`.
For `renderToFile` the data object is an object with the `filePath` and `content`. Here is the interface for `renderToFileData`:
```typescript
export type renderToFileData = {
filePath: string;
content: string;
}
```This is called when you call `renderToFile`, `renderToFileSync`.
For `loadFromFile` the data object is an object with `content` so you can change before it is set on `writr.content`. Here is the interface for `loadFromFileData`:
```typescript
export type loadFromFileData = {
content: string;
}
```This is called when you call `loadFromFile`, `loadFromFileSync`.
# ESM and Node Version Support
This package is ESM only and tested on the current lts version and its previous. Please don't open issues for questions regarding CommonJS / ESM or previous Nodejs versions. To learn more about using ESM please read this from `sindresorhus`: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
# Code of Conduct and Contributing
[Code of Conduct](CODE_OF_CONDUCT.md) and [Contributing](CONTRIBUTING.md) guidelines.# License
[MIT](LICENSE) & © [Jared Wray](https://jaredwray.com)