MDX: better Node.js loader

This commit is contained in:
Fuma Nama
2026-05-06 20:48:43 +08:00
parent 968b4a79b9
commit 5745fcfe73
6 changed files with 83 additions and 3 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'fumadocs-mdx': patch
---
Support better Node.js loader registry
@@ -8,11 +8,21 @@ description: Access content in Node.js runtime.
Make sure to run the script under ESM environment.
```js title="scripts/example.js"
import { register } from 'node:module';
import { register } from 'fumadocs-mdx/node';
register('fumadocs-mdx/node/loader', import.meta.url);
// register the Node.js loader
register();
// accessing content
const { source } = await import('./lib/source');
console.log(source.getPages());
```
The `register()` function accepts options:
```ts
register({
configPath: '...',
// ...
});
```
+2
View File
@@ -24,6 +24,8 @@
"./bun": "./dist/bun/index.js",
"./config": "./dist/config/index.js",
"./next": "./dist/next/index.js",
"./node": "./dist/node/index.js",
"./node/_loader": "./dist/node/_loader.js",
"./node/loader": "./dist/node/loader.js",
"./plugins/index-file": "./dist/plugins/index-file.js",
"./plugins/json-schema": "./dist/plugins/json-schema.js",
+48
View File
@@ -0,0 +1,48 @@
import { _Defaults, createCore } from '@/core';
import type { NodeLoaderOptions } from '.';
import type { InitializeHook, LoadFnOutput, LoadHook, LoadHookContext } from 'node:module';
import { createStandaloneConfigLoader } from '@/loaders/config';
import { toNode } from '@/loaders/adapter';
import { createMdxLoader } from '@/loaders/mdx';
import { createMetaLoader } from '@/loaders/meta';
let cachedLoaders: LoadHook[] | undefined;
export const initialize: InitializeHook<NodeLoaderOptions> = (options) => {
const core = createCore({
environment: 'node-loader',
...options,
configPath: options.configPath ?? _Defaults.configPath,
outDir: options.outDir ?? _Defaults.outDir,
});
const configLoader = createStandaloneConfigLoader({
core,
buildConfig: true,
mode: 'production',
});
cachedLoaders = [toNode(createMdxLoader(configLoader))];
if (!options.disableMetaFile) {
cachedLoaders.push(toNode(createMetaLoader(configLoader)));
}
};
export const load: LoadHook = async (url, context, nextLoad) => {
if (!cachedLoaders) throw new Error('not initialized');
const hooks = cachedLoaders;
function run(
i: number,
url: string,
context: LoadHookContext,
): LoadFnOutput | Promise<LoadFnOutput> {
if (i >= hooks.length) {
return nextLoad(url, context);
}
return hooks[i](url, context, (url, ctx) => run(i + 1, url, { ...context, ...ctx }));
}
return run(0, url, context);
};
+15
View File
@@ -0,0 +1,15 @@
import * as module from 'node:module';
import type { CoreOptions } from '@/core';
export interface NodeLoaderOptions extends Partial<CoreOptions> {
/**
* Skip meta file transformation step
*/
disableMetaFile?: boolean;
}
export function register(options: NodeLoaderOptions = {}) {
module.register('./_loader.js', import.meta.url, {
data: options,
});
}
+1 -1
View File
@@ -14,7 +14,7 @@ export default defineConfig({
'./src/{index,bin}.ts',
'./src/{config,next,vite,bun}/index.ts',
'./src/webpack/{mdx,meta}.ts',
'./src/node/loader.ts',
'./src/node/{index,_loader,loader}.ts',
'./src/runtime/*.{ts,tsx}',
'./src/plugins/*.ts',
],