hexo-renderer-mdx 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -1
- package/index.js +80 -10
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -8,7 +8,8 @@ A [Hexo](https://hexo.io/) renderer plugin for [MDX](https://mdxjs.com/) - Markd
|
|
|
8
8
|
- ⚛️ React component integration
|
|
9
9
|
- 📝 Markdown compatibility
|
|
10
10
|
- 🎨 Custom component support
|
|
11
|
-
-
|
|
11
|
+
- � ES6 import statements for external packages
|
|
12
|
+
- �� Fast compilation with @mdx-js/mdx
|
|
12
13
|
|
|
13
14
|
## Installation
|
|
14
15
|
|
|
@@ -171,6 +172,31 @@ export const Alert = ({ children, type = 'info' }) => (
|
|
|
171
172
|
</div>
|
|
172
173
|
```
|
|
173
174
|
|
|
175
|
+
**Import Statements** - Import external modules and packages:
|
|
176
|
+
|
|
177
|
+
```mdx
|
|
178
|
+
import React from 'react';
|
|
179
|
+
import { format } from 'date-fns';
|
|
180
|
+
|
|
181
|
+
<div>
|
|
182
|
+
Today's date: {format(new Date(), 'MMMM dd, yyyy')}
|
|
183
|
+
</div>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
You can also import local components or utilities:
|
|
187
|
+
|
|
188
|
+
```mdx
|
|
189
|
+
import MyCustomComponent from './components/MyCustomComponent';
|
|
190
|
+
import { helper } from './utils/helpers';
|
|
191
|
+
|
|
192
|
+
<MyCustomComponent data={helper()} />
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Note**: Make sure any packages you import are installed in your Hexo project:
|
|
196
|
+
```bash
|
|
197
|
+
npm install date-fns --save
|
|
198
|
+
```
|
|
199
|
+
|
|
174
200
|
#### 5. Building and Deploying
|
|
175
201
|
|
|
176
202
|
Build your site as usual:
|
package/index.js
CHANGED
|
@@ -4,6 +4,36 @@ const { renderToString } = require('react-dom/server');
|
|
|
4
4
|
const React = require('react');
|
|
5
5
|
const fs = require('fs');
|
|
6
6
|
const { createRequire } = require('module');
|
|
7
|
+
const { pathToFileURL, fileURLToPath } = require('url');
|
|
8
|
+
|
|
9
|
+
let babelRegistered = false;
|
|
10
|
+
function ensureBabelRegister(filePath) {
|
|
11
|
+
if (babelRegistered) return;
|
|
12
|
+
const localRequire = createRequire(filePath);
|
|
13
|
+
let babelRegister;
|
|
14
|
+
try {
|
|
15
|
+
babelRegister = localRequire('@babel/register');
|
|
16
|
+
} catch (errLocal) {
|
|
17
|
+
try {
|
|
18
|
+
babelRegister = require('@babel/register');
|
|
19
|
+
} catch (errGlobal) {
|
|
20
|
+
throw new Error(
|
|
21
|
+
'Failed to set up Babel register: please install @babel/register (and babel plugins) in your Hexo project or renderer package.'
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
babelRegister({
|
|
26
|
+
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
|
27
|
+
plugins: [
|
|
28
|
+
'@babel/plugin-syntax-dynamic-import',
|
|
29
|
+
['@babel/plugin-transform-react-jsx', {
|
|
30
|
+
runtime: 'automatic'
|
|
31
|
+
}]
|
|
32
|
+
],
|
|
33
|
+
ignore: [/node_modules/]
|
|
34
|
+
});
|
|
35
|
+
babelRegistered = true;
|
|
36
|
+
}
|
|
7
37
|
|
|
8
38
|
// Create a require for loading ESM modules
|
|
9
39
|
let compile;
|
|
@@ -56,16 +86,19 @@ async function loadCompile() {
|
|
|
56
86
|
* @returns {Promise<string>} The rendered HTML
|
|
57
87
|
*/
|
|
58
88
|
async function mdxRenderer(data) {
|
|
59
|
-
const { text, path } = data;
|
|
89
|
+
const { text, path: filePath } = data;
|
|
60
90
|
|
|
61
91
|
try {
|
|
92
|
+
// Ensure Babel can handle JSX/TS imports from MDX files (e.g., local components).
|
|
93
|
+
ensureBabelRegister(filePath);
|
|
94
|
+
|
|
62
95
|
// Ensure compile function is loaded
|
|
63
96
|
await loadCompile();
|
|
64
97
|
|
|
65
98
|
// Read the original file directly to bypass Hexo's template processing
|
|
66
99
|
let content;
|
|
67
100
|
try {
|
|
68
|
-
content = fs.readFileSync(
|
|
101
|
+
content = fs.readFileSync(filePath, 'utf8');
|
|
69
102
|
} catch (err) {
|
|
70
103
|
// If reading fails, fall back to the provided text
|
|
71
104
|
content = text;
|
|
@@ -85,6 +118,7 @@ async function mdxRenderer(data) {
|
|
|
85
118
|
const compiled = await compile(content, {
|
|
86
119
|
outputFormat: 'function-body',
|
|
87
120
|
development: true,
|
|
121
|
+
baseUrl: pathToFileURL(filePath),
|
|
88
122
|
// remarkRehypeOptions for markdown processing
|
|
89
123
|
remarkRehypeOptions: {
|
|
90
124
|
allowDangerousHtml: true
|
|
@@ -97,13 +131,47 @@ async function mdxRenderer(data) {
|
|
|
97
131
|
// When development: true, the compiled code uses jsxDEV from react/jsx-dev-runtime
|
|
98
132
|
const jsxDevRuntime = require('react/jsx-dev-runtime');
|
|
99
133
|
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
134
|
+
// Replace dynamic imports with a shim that resolves relative to the MDX file and uses require to stay in CJS.
|
|
135
|
+
const toModuleNamespace = (mod) => {
|
|
136
|
+
// If it already looks like an ES module with a default export, return as-is
|
|
137
|
+
if (mod && typeof mod === 'object' && 'default' in mod) return mod;
|
|
138
|
+
// For CJS modules, wrap as ES module: spread first, then set default to ensure it's not overwritten
|
|
139
|
+
if (mod && typeof mod === 'object') {
|
|
140
|
+
return { ...mod, default: mod };
|
|
141
|
+
}
|
|
142
|
+
// For primitive or function values, just set as default
|
|
143
|
+
return { default: mod };
|
|
144
|
+
};
|
|
145
|
+
const dynamicImport = (specifier) => {
|
|
146
|
+
const asString = String(specifier);
|
|
147
|
+
const req = createRequire(filePath);
|
|
148
|
+
// Check if it's already a file:// URL string
|
|
149
|
+
if (asString.startsWith('file://')) {
|
|
150
|
+
try {
|
|
151
|
+
const fsPath = fileURLToPath(asString);
|
|
152
|
+
return Promise.resolve(toModuleNamespace(req(fsPath)));
|
|
153
|
+
} catch (err) {
|
|
154
|
+
// Re-throw with better error message
|
|
155
|
+
throw new Error(`Failed to require file:// URL: ${err.message}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
// Try to construct a URL to see if it's relative
|
|
160
|
+
const resolvedUrl = new URL(asString, pathToFileURL(filePath));
|
|
161
|
+
if (resolvedUrl.protocol === 'file:') {
|
|
162
|
+
return Promise.resolve(toModuleNamespace(req(fileURLToPath(resolvedUrl))));
|
|
163
|
+
}
|
|
164
|
+
return Promise.resolve(toModuleNamespace(req(asString)));
|
|
165
|
+
} catch (urlErr) {
|
|
166
|
+
// If URL construction failed, try bare require
|
|
167
|
+
return Promise.resolve(toModuleNamespace(req(asString)));
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// Swap all occurrences of 'import(' (awaited or not) with our shim to avoid vm dynamic import callbacks.
|
|
172
|
+
const patchedCode = code.replace(/import\(/g, 'dynamicImport(');
|
|
173
|
+
const fn = new Function('jsxRuntime', 'dynamicImport', `return (async () => { ${patchedCode} })();`);
|
|
174
|
+
const mdxModule = await fn(jsxDevRuntime, dynamicImport);
|
|
107
175
|
|
|
108
176
|
// The result has a default export which is the MDX component
|
|
109
177
|
const MDXContent = mdxModule.default;
|
|
@@ -116,8 +184,10 @@ async function mdxRenderer(data) {
|
|
|
116
184
|
return html;
|
|
117
185
|
} catch (err) {
|
|
118
186
|
// Provide more detailed error information
|
|
119
|
-
const errorMsg = `MDX compilation failed for ${
|
|
187
|
+
const errorMsg = `MDX compilation failed for ${filePath}: ${err.message}`;
|
|
120
188
|
console.error(errorMsg);
|
|
189
|
+
console.error('Full error stack:');
|
|
190
|
+
console.error(err.stack);
|
|
121
191
|
if (err.position) {
|
|
122
192
|
console.error(`Error at line ${err.position.start.line}, column ${err.position.start.column}`);
|
|
123
193
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hexo-renderer-mdx",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "MDX renderer plugin for Hexo with React component support",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"homepage": "https://github.com/Bryan0324/hexo-renderer-mdx#readme",
|
|
27
27
|
"dependencies": {
|
|
28
|
+
"@babel/register": "^7.28.3",
|
|
28
29
|
"@mdx-js/mdx": "^3.0.0",
|
|
29
30
|
"react": "^18.2.0",
|
|
30
31
|
"react-dom": "^18.2.0"
|