Xây dựng 1 package render markdown thành jsx để hiển thị với ReactJS.
Tham khảo toàn bộ source code trên Github.
Package publish: https://www.npmjs.com/package/react-markdown-preview
Tạo thư mục react-markdown-preview
mkdir react-markdown-preview && cd react-markdown-preview && npm init
Điền các thông tin liên quan.
npm i -D react react-dom typescript tsc-hooks @type/react @type/react-dom @type/node
Init file config Typescript
npx tsc --init
Kiểm tra file tsconfig.json
và thêm, update các key
{
"compilerOptions": {
.....
"jsx": "react",
"declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
"outDir": "dist", /* Specify an output folder for all emitted files. */
....
},
"hooks": [
"copy-files" // copies all files to the dist folder
],
"include": [
"src/",
"src/**/*.css" // include css files while building the project using tsc
]
}
{
"main": "dist/index.js",
"files": [
"dist",
"markdown.css",
"markdown-light.css",
"markdown-dark.css",
"highlight.css"
],
"exports": {
// Export components from index.js
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
// Export css file from dist to import from source project
"./dist/*.css": {
"import": "./dist/*.css",
"require": "./dist/*.css"
}
},
"scripts": {
"copy-files": "copyfiles -u 1 src/**/*.css ",
"build": "tsc"
},
....
"peerDependencies": {
"@types/react": ">=18",
"react": ">=18"
}
}
Cài đặt các dependencies
npm i hast-util-to-jsx-runtime unified rehype-highlight remark-gfm remark-parse remark-rehype
Tạo file src/index.tsx
import { toJsxRuntime } from 'hast-util-to-jsx-runtime';
import React from 'react';
import { Fragment, jsx, jsxs } from 'react/jsx-runtime';
import rehypeHighlight from 'rehype-highlight';
import remarkGfm from 'remark-gfm';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import { unified } from "unified";
export const MarkdownPreview = ({ doc }: { doc: string }) => {
const processor = unified()
.use(remarkParse)
.use(remarkGfm)
.use(remarkRehype, { allowDangerousHtml: true })
.use(rehypeHighlight);
const mdastTree = processor.parse(doc);
const hastTree = processor.runSync(mdastTree, doc)
const result = toJsxRuntime(hastTree, {
Fragment,
ignoreInvalidStyle: true,
jsx,
jsxs,
passKeys: true,
passNode: true
});
return (
<div className="markdown-body">
{result}
</div>
);
}
Chạy lệnh dưới và login vào npm
npm login
Build source và publish lên npm
# Build
npm run build
# Publish
npm publish
Vấn đề:
Khi build component, không import css trực tiếp vào. Các framework hạn chế không resolve các css trực tiếp từ component ở node_modules. Ví dụ như NextJS: CSS Imported by a Dependency
Giải quyết
Publish và exports các file css riêng. Import trực tiếp css file vào nơi muốn sử dụng.
Để ý 2 keys files
và exports
trong file package.json
ở bước 3
Ví dụ thực tế mình đang dùng:
import { MarkdownPreview } from "react-markdown-preview";
import "react-markdown-preview/dist/highlight.css";
import "react-markdown-preview/dist/markdown-light.css";
const PostContent = ({doc}:{doc: string}) => {
return (
<MarkdownPreview doc={doc} />
);
}
export default PostContent;
© nvnhan0810 it-blogs - 2025