init
This commit is contained in:
commit
e3f0b7dbf5
9 changed files with 1487 additions and 0 deletions
9
.eslintrc.js
Normal file
9
.eslintrc.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
module.exports = {
|
||||
env: {
|
||||
node: true,
|
||||
es2020: true,
|
||||
},
|
||||
extends: [
|
||||
'@sup39/basic',
|
||||
],
|
||||
};
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
node_modules/
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2022 sup39
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
117
README.md
Normal file
117
README.md
Normal file
|
@ -0,0 +1,117 @@
|
|||
# rehype-mdx-component-wrapper
|
||||
A rehype plugin to wrap the mdx component with external component
|
||||
|
||||
## Installation
|
||||
```bash
|
||||
# If you are using yarn
|
||||
yarn add @sup39/rehype-mdx-component-wrapper
|
||||
|
||||
# If you are using npm
|
||||
npm install @sup39/rehype-mdx-component-wrapper
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|property|type|description|
|
||||
|--|--|--|
|
||||
|`name`|`string`|Name of the wrapper component. Default value is `'MDXRoot'`|
|
||||
|`path`|`string`|Path to the wrapper component. Default value is `'@/MDXRoot'`|
|
||||
|`props`|`string[]`|Local variable names to be passed to the wrapper component. Default value is `[]`|
|
||||
|
||||
## Example Usage of Next.js
|
||||
This plugin can be used to pass the metadata (frontmatter) parsed by
|
||||
[remark-mdx-frontmatter](https://github.com/remcohaszing/remark-mdx-frontmatter)
|
||||
to the wrapper component.
|
||||
For instance, you can use the metadata to create footer with author name for all mdx
|
||||
without explicitly writing JSX in the files.
|
||||
|
||||
### Settings next.config.mjs
|
||||
In next.config.mjs:
|
||||
```javascript
|
||||
/*
|
||||
You may need to install remark-mdx-frontmatter
|
||||
$ yarn add remark-frontmatter remark-mdx-frontmatter
|
||||
*/
|
||||
import mdx from '@next/mdx';
|
||||
import remarkFrontmatter from 'remark-frontmatter';
|
||||
import remarkMdxFrontmatter from 'remark-mdx-frontmatter';
|
||||
import ComponentWrapper from '@sup39/rehype-mdx-component-wrapper';
|
||||
|
||||
const withMDX = mdx({
|
||||
extension: /\.mdx?$/,
|
||||
options: {
|
||||
remarkPlugins: [
|
||||
remarkFrontmatter,
|
||||
// export all metadata into an object with name `meta`
|
||||
() => remarkMdxFrontmatter({name: 'meta'}),
|
||||
],
|
||||
rehypePlugins: [() => ComponentWrapper({
|
||||
name: 'MDXRoot',
|
||||
path: '@/MDXRoot',
|
||||
// pass the exported `meta` object to the wrapper component
|
||||
props: ['meta'],
|
||||
})],
|
||||
},
|
||||
});
|
||||
export default withMDX({
|
||||
pageExtensions: ['ts', 'tsx', 'js', 'jsx', 'md', 'mdx'],
|
||||
});
|
||||
```
|
||||
|
||||
### Setup Alias
|
||||
In your tsconfig, add `baseUrl` and `paths` like the following to create alias.
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["components/*"],
|
||||
// ...
|
||||
}
|
||||
// ...
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### Define a Wrapper Component
|
||||
Define a wrapper component in `components/`. All `props` passed to the MDX file and the local exported variables with name in `props` are passed to the component as props.
|
||||
|
||||
For example, create file `components/MDXRoot.tsx` with the following contents:
|
||||
```tsx
|
||||
import Head from 'next/head'
|
||||
|
||||
export default function MDXRoot({meta, children}: any) {
|
||||
return <>
|
||||
<Head>
|
||||
<title>{meta.title}</title>
|
||||
<meta name="description" content={meta.description} />
|
||||
</Head>
|
||||
{children}
|
||||
<footer>
|
||||
<div>Author: {meta.author}</div>
|
||||
</footer>
|
||||
</>;
|
||||
}
|
||||
```
|
||||
|
||||
### Write mdx
|
||||
```mdx
|
||||
---
|
||||
title: YAML is enough to define metadata!
|
||||
description: You can add other meta tags too :)
|
||||
author: sup39
|
||||
---
|
||||
|
||||
## No need to write JSX in all mdx files!
|
||||
```
|
||||
|
||||
### Result
|
||||
The final output will roughly be:
|
||||
```html
|
||||
<head>
|
||||
<title>YAML is enough to define metadata!</title>
|
||||
<meta name="description" content="You can add other meta tags too :)">
|
||||
</head>
|
||||
<h2>No need to write JSX in all mdx files!</h2>
|
||||
<footer><div>Author: sup39</div></footer>
|
||||
```
|
11
index.d.ts
vendored
Normal file
11
index.d.ts
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
export = ComponentWrapper;
|
||||
/** @type {import('unified').Plugin<[ComponentWrapperOptions?], import('hast').Root>} */
|
||||
declare const ComponentWrapper: import('unified').Plugin<[ComponentWrapperOptions?], import('hast').Root>;
|
||||
declare namespace ComponentWrapper {
|
||||
export { ComponentWrapperOptions };
|
||||
}
|
||||
type ComponentWrapperOptions = {
|
||||
name?: string;
|
||||
path?: string;
|
||||
props?: string[];
|
||||
};
|
90
index.js
Normal file
90
index.js
Normal file
|
@ -0,0 +1,90 @@
|
|||
/**
|
||||
* @typedef {{
|
||||
* name?: string
|
||||
* path?: string
|
||||
* props?: string[]
|
||||
* }} ComponentWrapperOptions
|
||||
*/
|
||||
|
||||
/** @param {any} expression */
|
||||
const makeExpression = expression => ({
|
||||
estree: {
|
||||
type: 'Program',
|
||||
sourceType: 'module',
|
||||
body: [{
|
||||
type: 'ExpressionStatement',
|
||||
expression,
|
||||
}],
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {string} propName
|
||||
* @param {any} expression
|
||||
*/
|
||||
const makeJsxAttr = (propName, expression) => ({
|
||||
type: 'mdxJsxAttribute',
|
||||
name: propName,
|
||||
value: {
|
||||
type: 'mdxJsxAttributeValueExpression',
|
||||
data: makeExpression(expression),
|
||||
},
|
||||
});
|
||||
|
||||
/** @type {import('unified').Plugin<[ComponentWrapperOptions?], import('hast').Root>} */
|
||||
const ComponentWrapper = ({
|
||||
name = 'MDXRoot',
|
||||
path = '@/MDXRoot',
|
||||
props = [],
|
||||
} = {}) => root => {
|
||||
const {children} = root;
|
||||
root.children = [
|
||||
// import MDXRoot from '@/MDXRoot'
|
||||
/**@type{import('mdast-util-mdx').MdxjsEsm}*/({
|
||||
type: 'mdxjsEsm',
|
||||
data: {
|
||||
estree: {
|
||||
type: 'Program',
|
||||
sourceType: 'module',
|
||||
body: [{
|
||||
type: 'ImportDeclaration',
|
||||
source: {type: 'Literal', value: path},
|
||||
specifiers: [{
|
||||
type: 'ImportDefaultSpecifier',
|
||||
local: {type: 'Identifier', name: name},
|
||||
}],
|
||||
}],
|
||||
},
|
||||
},
|
||||
}),
|
||||
// <MDXRoot {...props}>{children}</MDXRoot>
|
||||
/**@type{import('mdast-util-mdx').MdxJsxFlowElement}*/({
|
||||
type: 'mdxJsxFlowElement',
|
||||
name,
|
||||
children,
|
||||
attributes: [
|
||||
// {...props}
|
||||
{
|
||||
type: 'mdxJsxExpressionAttribute',
|
||||
value: '{...props}',
|
||||
data: makeExpression({
|
||||
type: 'ObjectExpression',
|
||||
properties: [{
|
||||
type: 'SpreadElement',
|
||||
argument: {
|
||||
type: 'Identifier',
|
||||
name: 'props',
|
||||
},
|
||||
}],
|
||||
}),
|
||||
},
|
||||
// extra local props
|
||||
...props.map(prop => makeJsxAttr(prop, {
|
||||
type: 'Identifier',
|
||||
name: prop,
|
||||
})),
|
||||
],
|
||||
}),
|
||||
];
|
||||
};
|
||||
module.exports = ComponentWrapper;
|
26
package.json
Normal file
26
package.json
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "@sup39/rehype-mdx-component-wrapper",
|
||||
"version": "0.1.0",
|
||||
"author": "sup39",
|
||||
"repository": "https://github.com/sup39/rehype-mdx-component-wrapper",
|
||||
"description": "A rehype plugin to wrap the mdx component with external component",
|
||||
"license": "MIT",
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"files": [
|
||||
"index.js",
|
||||
"index.d.ts"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"lint": "eslint index.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sup39/eslint-config-basic": "^0.1.5",
|
||||
"@types/hast": "^2.3.4",
|
||||
"eslint": "^8.26.0",
|
||||
"mdast-util-mdx": "^2.0.0",
|
||||
"typescript": "^4.8.4",
|
||||
"unified": "^10.1.2"
|
||||
}
|
||||
}
|
11
tsconfig.json
Normal file
11
tsconfig.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"include": ["index.js"],
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"lib": ["es2020"],
|
||||
"strict": true,
|
||||
"declaration": true,
|
||||
"emitDeclarationOnly": true
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue