마크다운 예제

작성자
길범준
설명 어떻게 하면 가장 미니멀한 블로그 포스트를 만들 수 있을까?
게시일 2021년 9월 28일
태그
#markdown#example#test#frontend

타이포그래피 대체

타이포그래퍼 옵션을 활성화하여 결과를 확인합니다.

(c) (C) (r) (R) (tm) (TM) (p) (P) +-

test.. test… test… test?… test!…

!!!!!! ???? ,, — ---

“스마티팬츠, 큰따옴표” 및 ‘작은따옴표’

왜 안되나요

상품에 대한 자세한 내용은 다음을 참조하십시오.

😅

Open example

Tada! :tada:


Oh dang! Is this a React component in the middle of our content? 😱

광고 :)

  • 피카 - 고화질 및 빠른 이미지 브라우저에서 크기를 조정합니다.
  • babelfish - 개발자 친화적 복수형 지원과 쉬운 구문을 갖춘 i18n.

이 프로젝트가 마음에 드실 겁니다!


h1 제목 8-)

h2 제목

h3 제목

h4 제목
h5 제목
h6 제목

가로 규칙




강조

이것은 굵은 텍스트입니다

이것은 굵은 텍스트입니다__

이 텍스트는 이탤릭체 텍스트입니다.

이 텍스트는 이탤릭체입니다 _이 텍스트는 이탤릭체입니다

~~ 취소선~~

블록 따옴표

블록 따옴표는 중첩할 수도 있습니다…> …바로 옆에 더 큰 기호를 사용하여…

…또는 화살표 사이에 공백을 사용하여 중첩할 수 있습니다.

목록

정렬되지 않은

  • 줄을 +, - 또는 *로 시작하여 목록을 만듭니다. 2칸 들여쓰기 + 하위 목록은 2칸 들여쓰기하여 만듭니다:
  • 마커 문자를 변경하면 새 목록이 시작됩니다:
  • Ac tristique libero volutpat at
  • Facilisis in pretium nisl aliquet
  • Nulla volutpat aliquam velit
  • 매우 쉽습니다!

주문

  1. Lorem ipsum dolor sit amet

  2. 컨센테투르 아디피싱 엘리트

  3. 정수 성추행 로렘 앳 마사

  4. 일련번호를 사용할 수 있습니다…

  5. …또는 모든 숫자를 1.로 유지합니다.

오프셋으로 번호 매기기를 시작합니다:

  1. foo

코드

인라인 코드

블록 코드 “울타리”

여기에 샘플 텍스트...

구문 강조

const foo = function (bar) {
  return bar++;
};
 
console.log(foo(5));
Test
const [age, setAge] = useState(50);
const [name, setName] = useState('Taylor');

테이블

옵션설명
데이터템플릿에 전달할 데이터를 제공할 데이터 파일의 경로입니다.
엔진템플릿 처리에 사용할 엔진. 기본값은 핸들바입니다.
확장자대상 파일에 사용할 확장자입니다.

오른쪽 정렬 열

옵션설명
데이터템플릿에 전달할 데이터를 제공할 데이터 파일의 경로입니다.
엔진템플릿 처리에 사용할 엔진. 기본값은 핸들바입니다.
확장자대상 파일에 사용할 확장자입니다.

링크

링크 텍스트

제목이 있는 링크

자동 변환된 링크 https://github.com/nodeca/pica (보려면 linkify 활성화)

이미지

미니언 스톰트루퍼캣

링크와 마찬가지로 이미지에도 각주 스타일 구문이 있습니다.

![대체 텍스트][id]

문서 뒷부분에 URL 위치를 정의하는 참조가 있습니다:

[id] https://octodex.github.com/images/dojocat.jpg “도조캣”

플러그인

마크다운의 킬러 기능

rehype-pretty-code is a Rehype plugin powered by the shikiji syntax highlighter that provides beautiful code blocks for Markdown or MDX. It works on both the server at build-time (avoiding runtime syntax highlighting) and on the client for dynamic highlighting.

Editor-Grade Highlighting

export function foo() {
  console.log('hewwo'); 
  console.log('hello'); 
}
export function foo() {
  console.log('hewwo'); 
}
export function foo() {
  console.log('hewwo'); 
  console.log('hello'); 
}

Enjoy the accuracy and granularity of VS Code’s syntax highlighting engine and the popularity of its themes ecosystem — use any VS Code theme you want!

import { useFloating, offset } from '@floating-ui/react';
 
interface Props {
  open: boolean;
  onOpenChange(open: boolean): void;
}
 
export function App({ open, onOpenChange }: Props) {
  const { refs, floatingStyles } = useFloating({
    open,
    onOpenChange,
    placement: 'left',
    middleware: [offset(10)],
  });
 
  return (
    <Container>
      <div ref={refs.setReference} />
      {open && <div ref={refs.setFloating} style={floatingStyles} />}
    </Container>
  );
}

The theme is Moonlight II with a custom background color.

Line Numbers and Line Highlighting

Draw attention to a particular line of code.

import { useFloating } from '@floating-ui/react';
 
function MyComponent() {
  const { refs, floatingStyles } = useFloating();
 
  return (
    <>
      <div ref={refs.setReference} />
      <div ref={refs.setFloating} style={floatingStyles} />
    </>
  );
}

Word Highlighting

Draw attention to a particular word or series of characters.

import { useFloating } from '@floating-ui/react';
 
function MyComponent() {
  const { refs, floatingStyles } = useFloating();
 
  return (
    <>
      <div ref={refs.setReference} />
      <div ref={refs.setFloating} style={floatingStyles} />
    </>
  );
}

Inline Code Highlighting

The result of [1, 2, 3].join('-') is '1-2-3'.

Context Aware Inline Code

For instance, if you had the following code block:

function getStringLength(str) {
  return str.length;
}

When we refer to getStringLength as a plain variable, we can color it as a function. Same with function, or str vs. str, etc. This allows you to semantically tie inline code with the nearest code block it’s referring to.

ANSI Highlighting

  vite v5.0.0 dev server running at:
 
  > Local: http://localhost:3000/
  > Network: use `--host` to expose
 
  ready in 125ms.
 
8:38:02 PM [vite] hmr update /src/App.jsx

Inline ANSI: > Local: http://localhost:3000/

Installation

Install via your terminal:

npm install rehype-pretty-code shikiji@^0.9.0

This package is ESM-only and currently supports shikiji ^0.7.0 - ^0.9.0.

Note: If you need CJS support you should use [email protected], which uses Shiki instead of Shikiji (v0.10.1 docs here). To use the latest version in Next.js, ensure your config file is ESM: next.config.mjs. Here’s a full example: rehype-pretty-code/website/next.config.mjs

Usage

The following works both on the server and on the client.

unified@11 is used as a dependency.

import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
import rehypePrettyCode from 'rehype-pretty-code';
 
async function main() {
  const file = await unified()
    .use(remarkParse)
    .use(remarkRehype)
    .use(rehypePrettyCode, {
      // See Options section below.
    })
    .use(rehypeStringify)
    .process('`const numbers = [1, 2, 3]{:js}`');
 
  console.log(String(file));
}
 
main();

MDX

The following example shows how to use this package with Next.js.

next.config.mjs
import fs from 'node:fs';
import nextMDX from '@next/mdx';
import rehypePrettyCode from 'rehype-pretty-code';
 
/** @type {import('rehype-pretty-code').Options} */
const options = {
  // See Options section below.
};
 
const withMDX = nextMDX({
  extension: /\.mdx?$/,
  options: {
    remarkPlugins: [],
    rehypePlugins: [[rehypePrettyCode, options]],
  },
});
 
/** @type {import('next').NextConfig} */
const nextConfig = { reactStrictMode: true };
 
export default withMDX(nextConfig);

Make sure you have disabled the mdxRs option for Next.js 13 / app dir, as it currently does not support Rehype plugins.

Options

interface Options {
  grid?: boolean;
  theme?: Theme | Record<string, Theme>;
  keepBackground?: boolean;
  defaultLang?: string | { block?: string; inline?: string };
  tokensMap?: Record<string, string>;
  transformers?: ShikijiTransformer[];
  filterMetaString?(str: string): string;
  getHighlighter?(options: BundledHighlighterOptions): Promise<Highlighter>;
  onVisitLine?(element: LineElement): void;
  onVisitHighlightedLine?(element: LineElement): void;
  onVisitHighlightedChars?(element: CharsElement, id: string | undefined): void;
  onVisitTitle?(element: Element): void;
  onVisitCaption?(element: Element): void;
}

grid

A grid style is present by default which allows line highlighting to span the entire width of a horizontally-scrollable code block.

You can disable this setting if necessary:

const options = {
  grid: false,
};

theme

The default theme is github-dark-dimmed. Shikiji has a bunch of pre-packaged themes, which can be specified as a plain string:

const options = {
  theme: 'one-dark-pro',
};

You can use your own theme as well by passing the theme JSON:

const options = {
  theme: JSON.parse(fs.readFileSync('./themes/moonlight-ii.json', 'utf-8')),
};

keepBackground

To apply a custom background instead of inheriting the background from the theme:

const options = {
  keepBackground: false,
};

defaultLang

When no code language is specified, inline code or code blocks will not be themed (nor will the background), which may appear incongruous with others.

In this case, you can specify a default language:

const options = {
  defaultLang: 'plaintext',
};

Or you can also specify default languages for inline code and code blocks separately:

const options = {
  defaultLang: {
    block: 'plaintext',
    inline: 'plaintext',
  },
};

transformers

Transformers are a Shikiji-native way to manipulate the hAST tree of the code blocks and further extend the behavior of this plugin. The shikiji-transformers package provides some useful transformers.

import { transformerNotationDiff } from 'shikiji-transformers';
 
const options = {
  transformers: [transformerNotationDiff()],
};

Meta Strings

Code blocks are configured via the meta string on the top codeblock fence.

If your library also parses code blocks’ meta strings, it may cause conflicts with rehype-pretty-code. This option allows you to filter out some part of the meta string before the library starts parsing it.

const options = {
  filterMetaString: (string) => string.replace(/filename="[^"]*"/, ''),
};
Highlight Lines

Place a numeric range inside {}.

```js {1-3,4}
 
```

The line <span> receives a data-highlighted-line attribute to style via CSS.

Group Highlighted Lines By Id

Place an id after # after the {}. This allows you to color or style lines differently based on their id.

```js {1,2}#a {3,4}#b
 
```

The line <span> receives a data-highlighted-line-id="<id>" attribute to style via CSS.

Highlight Chars

You can use either /:

```js /carrot/
 
```

Or " as a delimiter:

```js "carrot"
 
```

Different segments of chars can also be highlighted:

```js /carrot/ /apple/
 
```

The chars <span> receives a data-highlighted-chars attribute to style via CSS.

To highlight only the third to fifth instances of carrot, a numeric range can be placed after the last /.

```js /carrot/3-5
 
```

Highlight only the third to fifth instances of carrot and any instances of apple.

```js /carrot/3-5 /apple/
 
```
Group Highlighted Chars By Id

Place an id after # after the chars. This allows you to color chars differently based on their id.

```js /age/#v /name/#v /setAge/#s /setName/#s /50/#i /'Taylor'/#i
const [age, setAge] = useState(50);
const [name, setName] = useState('Taylor');
```
const [age, setAge] = useState(50);
const [name, setName] = useState('Taylor');

The chars <span> receives a data-chars-id="<id>" attribute to style via CSS.

Highlight Inline Code

Append {:lang} (e.g. {:js}) to the end of inline code to highlight it like a regular code block.

This is an array `[1, 2, 3]{:js}` of numbers 1 through 3.
Highlight Plain Text

Append {:.token} to the end of the inline code to highlight it based on a token specified in your VS Code theme. Tokens start with a . to differentiate them from a language.

The name of the function is `getStringLength{:.entity.name.function}`.

You can create a map of tokens to shorten this usage throughout your docs:

const options = {
  tokensMap: {
    fn: 'entity.name.function',
  },
};
The name of the function is `getStringLength{:.fn}`.
Titles

Add a file title to your code block, with text inside double quotes (""):

```js title="..."
 
```
Captions

Add a caption underneath your code block, with text inside double quotes (""):

```js caption="..."
 
```

Line Numbers

CSS counters can be used to add line numbers.

code {
  counter-reset: line;
}
 
code > [data-line]::before {
  counter-increment: line;
  content: counter(line);
 
  /* Other styling */
  display: inline-block;
  width: 1rem;
  margin-right: 2rem;
  text-align: right;
  color: gray;
}
 
code[data-line-numbers-max-digits='2'] > [data-line]::before {
  width: 2rem;
}
 
code[data-line-numbers-max-digits='3'] > [data-line]::before {
  width: 3rem;
}

If you want to conditionally show them, use showLineNumbers:

```js showLineNumbers
 
```

<code> will have attributes data-line-numbers and data-line-numbers-max-digits="n".

If you want to start line numbers at a specific number, use showLineNumbers{number}:

```js showLineNumbers{number}
 
```

Multiple Themes (Dark and Light Mode)

Pass your themes to theme, where the keys represent the color mode:

const options = {
  theme: {
    dark: 'github-dark-dimmed',
    light: 'github-light',
  },
};

Now, use the following CSS to display the variable colors — if a space is found in the theme name, then CSS variable keys based on the object are available (more info):

code[data-theme*=' '],
code[data-theme*=' '] span {
  color: var(--shiki-light);
  background-color: var(--shiki-light-bg);
}
 
@media (prefers-color-scheme: dark) {
  code[data-theme*=' '],
  code[data-theme*=' '] span {
    color: var(--shiki-dark);
    background-color: var(--shiki-dark-bg);
  }
}

The <code> and <pre> elements will have the data attribute data-theme="...themes", listing each theme value space-separated:

<code data-theme="github-dark-dimmed github-light"></code>

Visitor Hooks

To customize the HTML output, you can use visitor callback hooks to manipulate the hAST elements directly:

const options = {
  onVisitLine(element) {
    console.log('Visited line');
  },
  onVisitHighlightedLine(element) {
    console.log('Visited highlighted line');
  },
  onVisitHighlightedChars(element) {
    console.log('Visited highlighted chars');
  },
  onVisitTitle(element) {
    console.log('Visited title');
  },
  onVisitCaption(element) {
    console.log('Visited caption');
  },
};

Custom Highlighter

To completely configure the highlighter, use the getHighlighter option. This is helpful if you’d like to configure other Shikiji options, such as langs.

import { getHighlighter } from 'shikiji';
 
const options = {
  getHighlighter: (options) =>
    getHighlighter({
      ...options,
      langs: [
        'plaintext',
        async () => JSON.parse(await readFile('my-grammar.json', 'utf-8')),
      ],
    }),
};
작성자 길범준
길범준

블로그 글보다 블로그를 더 많이 만든 개발자입니다. 이번이 마지막이면 좋겠네요.
저는 현재 서울에서 소프트웨어 엔지니어로 일하고 있어요. 지금 읽은 글에 대해 질문이나 의견이 있다면, [email protected] 으로 연락주세요.