hexo-renderer-mdx 1.0.0 → 1.0.1
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/index.js +70 -11
- package/package.json +1 -1
- package/test-mdx.js +47 -0
package/index.js
CHANGED
|
@@ -1,8 +1,45 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const { compile } = require('@mdx-js/mdx');
|
|
4
3
|
const { renderToString } = require('react-dom/server');
|
|
5
4
|
const React = require('react');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const { createRequire } = require('module');
|
|
7
|
+
|
|
8
|
+
// Create a require for loading ESM modules
|
|
9
|
+
let compile;
|
|
10
|
+
let compileLoaded = false;
|
|
11
|
+
|
|
12
|
+
async function loadCompile() {
|
|
13
|
+
if (!compileLoaded) {
|
|
14
|
+
try {
|
|
15
|
+
// Try to load @mdx-js/mdx - it may be CJS or ESM depending on the environment
|
|
16
|
+
try {
|
|
17
|
+
// First try: dynamic import with proper error handling
|
|
18
|
+
const mdxModule = await (async () => {
|
|
19
|
+
try {
|
|
20
|
+
return await import('@mdx-js/mdx');
|
|
21
|
+
} catch (err) {
|
|
22
|
+
// If dynamic import fails, this might be a require context issue
|
|
23
|
+
// Return null to trigger fallback
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
})();
|
|
27
|
+
|
|
28
|
+
if (mdxModule) {
|
|
29
|
+
compile = mdxModule.compile;
|
|
30
|
+
} else {
|
|
31
|
+
throw new Error('Could not load @mdx-js/mdx via dynamic import');
|
|
32
|
+
}
|
|
33
|
+
} catch (err) {
|
|
34
|
+
// Fallback: try to require it directly (in case it's been transpiled)
|
|
35
|
+
compile = require('@mdx-js/mdx').compile;
|
|
36
|
+
}
|
|
37
|
+
compileLoaded = true;
|
|
38
|
+
} catch (err) {
|
|
39
|
+
throw new Error(`Failed to load @mdx-js/mdx: ${err.message}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
6
43
|
|
|
7
44
|
/**
|
|
8
45
|
* MDX Renderer for Hexo
|
|
@@ -22,10 +59,19 @@ async function mdxRenderer(data) {
|
|
|
22
59
|
const { text, path } = data;
|
|
23
60
|
|
|
24
61
|
try {
|
|
62
|
+
// Ensure compile function is loaded
|
|
63
|
+
await loadCompile();
|
|
64
|
+
|
|
65
|
+
// Read the original file directly to bypass Hexo's template processing
|
|
66
|
+
let content;
|
|
67
|
+
try {
|
|
68
|
+
content = fs.readFileSync(path, 'utf8');
|
|
69
|
+
} catch (err) {
|
|
70
|
+
// If reading fails, fall back to the provided text
|
|
71
|
+
content = text;
|
|
72
|
+
}
|
|
73
|
+
|
|
25
74
|
// Strip YAML front matter if present
|
|
26
|
-
// Note: Hexo typically strips front matter before passing to renderers,
|
|
27
|
-
// but we handle it here as a safety measure for edge cases
|
|
28
|
-
let content = text;
|
|
29
75
|
const frontMatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n/;
|
|
30
76
|
const match = content.match(frontMatterRegex);
|
|
31
77
|
|
|
@@ -35,17 +81,21 @@ async function mdxRenderer(data) {
|
|
|
35
81
|
}
|
|
36
82
|
|
|
37
83
|
// Compile MDX to JavaScript with automatic JSX runtime
|
|
84
|
+
// Use outputFormat: 'function-body' and development: true to avoid jsxImportSource
|
|
38
85
|
const compiled = await compile(content, {
|
|
39
86
|
outputFormat: 'function-body',
|
|
40
|
-
development:
|
|
41
|
-
|
|
87
|
+
development: true,
|
|
88
|
+
// remarkRehypeOptions for markdown processing
|
|
89
|
+
remarkRehypeOptions: {
|
|
90
|
+
allowDangerousHtml: true
|
|
91
|
+
}
|
|
42
92
|
});
|
|
43
93
|
|
|
44
94
|
// Create a function from the compiled code
|
|
45
95
|
const code = String(compiled);
|
|
46
96
|
|
|
47
|
-
//
|
|
48
|
-
const
|
|
97
|
+
// When development: true, the compiled code uses jsxDEV from react/jsx-dev-runtime
|
|
98
|
+
const jsxDevRuntime = require('react/jsx-dev-runtime');
|
|
49
99
|
|
|
50
100
|
// Create and execute the MDX module function
|
|
51
101
|
// Note: Using new Function() here is safe because:
|
|
@@ -53,7 +103,7 @@ async function mdxRenderer(data) {
|
|
|
53
103
|
// 2. MDX compilation itself validates and sanitizes the content
|
|
54
104
|
// 3. This is a build-time operation, not runtime user input
|
|
55
105
|
const fn = new Function(code);
|
|
56
|
-
const mdxModule = fn.call(null,
|
|
106
|
+
const mdxModule = fn.call(null, jsxDevRuntime);
|
|
57
107
|
|
|
58
108
|
// The result has a default export which is the MDX component
|
|
59
109
|
const MDXContent = mdxModule.default;
|
|
@@ -65,11 +115,20 @@ async function mdxRenderer(data) {
|
|
|
65
115
|
|
|
66
116
|
return html;
|
|
67
117
|
} catch (err) {
|
|
68
|
-
|
|
118
|
+
// Provide more detailed error information
|
|
119
|
+
const errorMsg = `MDX compilation failed for ${path}: ${err.message}`;
|
|
120
|
+
console.error(errorMsg);
|
|
121
|
+
if (err.position) {
|
|
122
|
+
console.error(`Error at line ${err.position.start.line}, column ${err.position.start.column}`);
|
|
123
|
+
}
|
|
124
|
+
throw new Error(errorMsg);
|
|
69
125
|
}
|
|
70
126
|
}
|
|
71
127
|
|
|
72
128
|
/**
|
|
73
129
|
* Register the MDX renderer with Hexo
|
|
130
|
+
* Note: Using disableNunjucks: true to prevent template processing of {{ }} syntax
|
|
74
131
|
*/
|
|
75
|
-
hexo.extend.renderer.register('mdx', 'html', mdxRenderer,
|
|
132
|
+
hexo.extend.renderer.register('mdx', 'html', mdxRenderer, {
|
|
133
|
+
disableNunjucks: true
|
|
134
|
+
});
|
package/package.json
CHANGED
package/test-mdx.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const { compile } = require('@mdx-js/mdx');
|
|
2
|
+
|
|
3
|
+
const testContent = `---
|
|
4
|
+
title: My First MDX Post
|
|
5
|
+
date: 2026-01-06
|
|
6
|
+
tags: [hexo, mdx]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Hello
|
|
10
|
+
|
|
11
|
+
<div style={{ padding: '20px', backgroundColor: '#e3f2fd' }}>
|
|
12
|
+
🎉 Test
|
|
13
|
+
</div>
|
|
14
|
+
`;
|
|
15
|
+
|
|
16
|
+
async function test() {
|
|
17
|
+
try {
|
|
18
|
+
// Strip front matter like the renderer does
|
|
19
|
+
let content = testContent;
|
|
20
|
+
const frontMatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n/;
|
|
21
|
+
const match = content.match(frontMatterRegex);
|
|
22
|
+
|
|
23
|
+
if (match) {
|
|
24
|
+
content = content.slice(match[0].length);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
console.log('Content to compile:');
|
|
28
|
+
console.log(content);
|
|
29
|
+
console.log('\n---\n');
|
|
30
|
+
|
|
31
|
+
const result = await compile(content, {
|
|
32
|
+
outputFormat: 'function-body',
|
|
33
|
+
development: false,
|
|
34
|
+
jsxImportSource: 'react',
|
|
35
|
+
format: 'mdx',
|
|
36
|
+
mdxExtensions: ['.mdx'],
|
|
37
|
+
remarkRehypeOptions: {
|
|
38
|
+
allowDangerousHtml: true
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
console.log('Success!');
|
|
42
|
+
} catch (err) {
|
|
43
|
+
console.error('Error:', err.message);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
test();
|