Relevant source files
The following files were used as context for generating this wiki page:
- packages/mdx/src/loaders/adapter.ts
- packages/mdx/src/rolldown/index.ts
- packages/mdx/src/bun/index.ts
- packages/mdx/src/vite/index.ts
- packages/asyncapi/src/server/index.tsx
- packages/mdx/src/loaders/meta.ts
- packages/mdx/src/next/index.ts
- packages/mdx/src/webpack/meta.ts
- packages/doc-gen/src/remark-docgen.ts
- packages/mdx/src/node/_loader.ts
- packages/mdx/src/loaders/mdx/index.ts
- packages/mdx/src/webpack/mdx.ts
- packages/mdx/src/plugins/index-file.ts
- packages/local-md/src/index.ts
- packages/mdx/tsdown.config.ts
- packages/mdx/package.json
- packages/core/src/mdx-plugins/index.ts
- packages/story/src/webpack/story.ts
- packages/mdx/src/runtime/server.ts
- packages/core/src/content/mdx/preset-bundler.ts
- packages/mdx/src/node/loader.ts
- packages/story/src/vite/index.ts
- packages/doc-gen/tsdown.config.ts
- packages/mdx/src/bin.ts
- packages/api-docs/tsdown.config.ts
- packages/mdx/src/core.ts
- packages/core/src/source/loader.ts
- packages/core/src/mdx-plugins/remark-llms.ts
- packages/content-collections/src/configuration.ts
- packages/asyncapi/tsdown.config.ts
Overview
Fumadocs provides a set of bundler plugins and low-level adapters that integrate content compilation pipelines into modern build tools and JavaScript runtimes packages/mdx/src/loaders/adapter.ts:1-223, packages/mdx/src/core.ts:1-340. These integrations handle document parsing, frontmatter validation, configuration reloading, and virtual entry point generation across Next.js, Vite, Rolldown, Webpack, Node.js, and Bun packages/mdx/src/next/index.ts:1-207, packages/mdx/src/vite/index.ts:1-160, packages/mdx/src/rolldown/index.ts:1-67, packages/mdx/src/bun/index.ts:1-44. By abstracting environment-specific module loading and transformation hooks behind a unified core, the packages maintain consistent document behavior during development and production builds packages/mdx/src/loaders/adapter.ts:35-59, packages/mdx/src/core.ts:148-340.
Sources: packages/mdx/src/loaders/adapter.ts:1-223, packages/mdx/src/rolldown/index.ts:1-67, packages/mdx/src/bun/index.ts:1-44, packages/mdx/src/vite/index.ts:1-160, packages/mdx/src/next/index.ts:1-207, packages/mdx/src/core.ts:1-340
Next.js Integration and Core Lifecycle
Initialization and Execution Flow
The Next.js integration initializes through createMDX, which sets up core compilation options and checks the _FUMADOCS_MDX environment variable to prevent duplicate initialization passes. When invoked, createMDX executes createNextCore using options normalized by applyDefaults. The call-chain sequence createMDX → init → devServer → initOrReload proceeds by instantiating the core via createMDX, handing control to init to evaluate development flags, invoking devServer when isDev is true to watch configuration files and collections, and finally triggering initOrReload to load the configuration and emit compiled outputs.
Sources: packages/mdx/src/next/index.ts:30-38
createMDX: AcceptsCreateMDXOptions, establishes default environment variables, and delegates core creation. Sources: packages/mdx/src/next/index.ts:30-38init: Manages asynchronous bootstrap and checks thedevboolean flag to determine whether to spin up file system watchers. Sources: packages/mdx/src/next/index.ts:124-182devServer: Instantiates achokidarFSWatcherinstance ignoring the output directory, tracks configuration files and collection directories, and handles hot-reloading on configuration changes. Sources: packages/mdx/src/next/index.ts:132-176initOrReload: Loads configuration files vialoadConfig(core, true)and invokescore.emit({ write: true }). Sources: packages/mdx/src/next/index.ts:125-130
Warning
If process.env._FUMADOCS_MDX is already set to '1', subsequent calls to init are bypassed during module evaluation to prevent concurrent watcher duplication across Next.js worker threads.
Sources: packages/mdx/src/next/index.ts:34-38
Configuration Options and Default Values
The integration relies on CreateMDXOptions to configure source paths, output targets, and index generation plugins. These options are processed by applyDefaults to guarantee defined parameters.
| Option Key | Type | Default Value | Description |
|---|---|---|---|
configPath | string | _Defaults.configPath | Path to source configuration file. |
outDir | string | _Defaults.outDir | Directory for output files. |
index | IndexFilePluginOptions | false | {} | Index file plugin options or false to disable. |
Sources: packages/mdx/src/next/index.ts:12-26, packages/mdx/src/next/index.ts:192-198
Note
createNextCore constructs the underlying core instance with environment set to 'next' and registers the index plugin if enabled.
Sources: packages/mdx/src/next/index.ts:200-207
MDX Compiler Preset Configuration
Preset Options and Remark/Rehype Registration
The mdxPreset function asynchronous builder resolves and registers remark and rehype plugins into standard MDX processor options. It takes MDXBundlerPresetOptions which omits standard remark and rehype options in favor of resolver structures and specific plugin toggles.
export type MDXBundlerPresetOptions = Omit<
NonNullable<ProcessorOptions>,
'rehypePlugins' | 'remarkPlugins'
> & {
rehypePlugins?: ResolvePlugins;
remarkPlugins?: ResolvePlugins;
/** @private for `remark-include` */
_include?: Pluggable;
remarkStructureOptions?: Plugins.StructureOptions | false;
remarkHeadingOptions?: Plugins.RemarkHeadingOptions | false;
remarkImageOptions?: Plugins.RemarkImageOptions | false;
remarkCodeTabOptions?: Plugins.RemarkCodeTabOptions | false;
remarkNpmOptions?: Plugins.RemarkNpmOptions | false;
rehypeCodeOptions?: Plugins.RehypeCodeOptions | false;
};Sources: packages/core/src/content/mdx/preset-bundler.ts:6-21
export async function mdxPreset(options: MDXBundlerPresetOptions = {}): Promise<ProcessorOptions> {
const {
rehypeCodeOptions,
remarkImageOptions,
remarkHeadingOptions,
remarkStructureOptions,
remarkCodeTabOptions,
remarkNpmOptions,
_include,
...mdxOptions
} = options;Sources: packages/core/src/content/mdx/preset-bundler.ts:26-36
Note
Each remark and rehype plugin can be explicitly disabled by passing false to its corresponding option key, or customized by passing an object containing plugin-specific parameters.
Sources: packages/core/src/content/mdx/preset-bundler.ts:15-20
Plugin Integration Pipeline
The preset registration pipeline resolves plugins asynchronously through resolvePlugins, combining standard defaults with custom user configurations. The pipeline processes remark plugins starting with GitHub Flavored Markdown and conditional expansions.
const remarkPlugins = await resolvePlugins(
(v) => [
import('remark-gfm').then((mod) => mod.default),
remarkHeadingOptions !== false &&
import('@/mdx-plugins/remark-heading').then((mod) => [
mod.remarkHeading,
{
generateToc: false,
...remarkHeadingOptions,
},
]),
_include ?? false,
remarkImageOptions !== false &&
import('@/mdx-plugins/remark-image').then((mod) => [
mod.remarkImage,
{
...remarkImageOptions,
useImport: remarkImageOptions?.useImport ?? true,
},
]),
remarkCodeTabOptions !== false &&
import('@/mdx-plugins/remark-code-tab').then((mod) => [
mod.remarkCodeTab,
remarkCodeTabOptions,
]),
remarkNpmOptions !== false &&
import('@/mdx-plugins/remark-npm').then((mod) => [mod.remarkNpm, remarkNpmOptions]),
...v,
remarkStructureOptions !== false &&
import('@/mdx-plugins/remark-structure').then((mod) => [
mod.remarkStructure,
{
exportAs: 'structuredData',
...remarkStructureOptions,
} satisfies Plugins.StructureOptions,
]),
],
mdxOptions.remarkPlugins,
);Sources: packages/core/src/content/mdx/preset-bundler.ts:38-76
const rehypePlugins = await resolvePlugins(
(v) => [
rehypeCodeOptions !== false &&
import('@/mdx-plugins/rehype-code').then((mod) => [mod.rehypeCode, rehypeCodeOptions]),
...v,
import('@/mdx-plugins/rehype-toc').then((mod) => mod.rehypeToc),
],
mdxOptions.rehypePlugins,
);Sources: packages/core/src/content/mdx/preset-bundler.ts:78-86
Warning
Disabling remarkHeadingOptions, remarkImageOptions, remarkCodeTabOptions, remarkNpmOptions, remarkStructureOptions, or rehypeCodeOptions by setting them to false prevents their dynamic imports from executing during the preset build.
Sources: packages/core/src/content/mdx/preset-bundler.ts:41-73, packages/core/src/content/mdx/preset-bundler.ts:80-81
Preset Configuration Options Reference
| Option Key | Type | Default Behavior / Mapping | Description |
|---|---|---|---|
remarkPlugins | ResolvePlugins | Combined via resolvePlugins | Custom remark plugins appended to the preset. |
rehypePlugins | ResolvePlugins | Combined via resolvePlugins | Custom rehype plugins appended to the preset. |
_include | Pluggable | undefined | Private plugin hook for remark-include. |
remarkStructureOptions | Plugins.StructureOptions | false | { exportAs: 'structuredData' } | Options for the structure extraction remark plugin. |
remarkHeadingOptions | Plugins.RemarkHeadingOptions | false | { generateToc: false } | Options for heading extraction and table of contents generation. |
remarkImageOptions | Plugins.RemarkImageOptions | false | { useImport: true } | Options for remark image optimization and imports. |
remarkCodeTabOptions | Plugins.RemarkCodeTabOptions | false | undefined | Options for code tab grouping transformations. |
remarkNpmOptions | Plugins.RemarkNpmOptions | false | undefined | Options for package manager command translation. |
rehypeCodeOptions | Plugins.RehypeCodeOptions | false | undefined | Options for syntax highlighting and code block processing. |
Sources: packages/core/src/content/mdx/preset-bundler.ts:6-21, packages/core/src/content/mdx/preset-bundler.ts:41-73
Index File Codegen Coordination
Execution Pipeline and Sequence Architecture
The coordination of index file generation begins at the core layer where configuration options are evaluated. The explicit call chain starts with createMDX, which delegates through createNextCore, initializes the indexFile plugin, and executes generateConfigs to assemble server options and type definitions.
export function createMDX(createOptions: CreateMDXOptions = {}) {
const core = createNextCore(applyDefaults(createOptions));Sources: packages/mdx/src/next/index.ts:30-31
function createNextCore(options: Required<CreateMDXOptions>): Core {
return createCore({
environment: 'next',
outDir: options.outDir,
configPath: options.configPath,
plugins: [options.index && indexFile(options.index)],
});Sources: packages/mdx/src/next/index.ts:200-206
export default function indexFile(options: IndexFilePluginOptions = {}): Plugin {
const { target = 'default', addJsExtension, browser = true, dynamic = true } = options;
let dynamicCollections: CollectionItem[];
function isDynamic(collection: CollectionItem) {
return (
(collection.type === 'docs' && collection.docs.dynamic) ||
(collection.type === 'doc' && collection.dynamic)
);
}
function generateConfigs(core: Core): {
serverOptions: ServerOptions;
tc: string;
} {
const serverOptions: ServerOptions = {};
const typeConfigs: string[] = ['import("fumadocs-mdx/runtime/types").InternalTypeConfig'];
const ctx = core.getPluginContext();
for (const plugin of core.getPlugins()) {
const indexFilePlugin = plugin['index-file'];
if (!indexFilePlugin) continue;
indexFilePlugin.serverOptions?.call(ctx, serverOptions);
const config = indexFilePlugin.generateTypeConfig?.call(ctx);
if (config) typeConfigs.push(config);
}
return {
serverOptions,
tc: typeConfigs.join(' & '),
};
}Sources: packages/mdx/src/plugins/index-file.ts:51-83
Sources: packages/mdx/src/next/index.ts:30-31, packages/mdx/src/next/index.ts:200-206, packages/mdx/src/plugins/index-file.ts:51-83
Note
The function generateConfigs iterates over registered core plugins to extract custom serverOptions and append any module type configurations (generateTypeConfig) into a combined intersection type string.
Sources: packages/mdx/src/plugins/index-file.ts:62-83
Plugin Options and Configuration Reference
The plugin behavior is governed by IndexFilePluginOptions, which controls compilation targets, extension resolution, and output file entry generation.
export interface IndexFilePluginOptions {
target?: 'default' | 'vite';
/**
* add `.js` extensions to imports, needed for ESM without bundler resolution
*/
addJsExtension?: boolean;
/**
* Generate entry point for browser
* @defaultValue true
*/
browser?: boolean;
/**
* Generate entry point for dynamic compilation
* @defaultValue true
*/
dynamic?: boolean;
}Sources: packages/mdx/src/plugins/index-file.ts:13-32
| Option Key | Type | Default Value | Description |
|---|---|---|---|
target | 'default' | 'vite' | 'default' | Target bundler environment for codegen paths and glob resolution. |
addJsExtension | boolean | undefined | Appends .js extensions to imports for ESM without bundler resolution. |
browser | boolean | true | Generates a browser entry point module (browser.ts). |
dynamic | boolean | true | Generates an entry point for dynamic content compilation (dynamic.ts). |
Sources: packages/mdx/src/plugins/index-file.ts:13-32
Webpack Loader Interception
Standalone MDX and Meta Loaders
The package exposes standalone Webpack loaders for processing MDX documents and collection metadata files outside of the Next.js plugin wrapper. Both loaders utilize a lazy-initialized singleton instance via toWebpack to bind core loader logic, while declaring dependencies on compiled configuration paths via Webpack's this.addDependency().
const loader: LoaderDefinitionFunction<WebpackLoaderOptions> = function loader(source) {
const callback = this.async();
const options = this.getOptions();
this.cacheable(true);
this.addDependency(options.absoluteCompiledConfigPath);
if (!instance) {
instance = toWebpack(
createMdxLoader(
createStandaloneConfigLoader({
core: getCore(options),
buildConfig: false,
mode: options.isDev ? 'dev' : 'production',
}),
),
);
}
void instance.call(this, source, callback);
};Sources: packages/mdx/src/webpack/mdx.ts:9-28
const loader: LoaderDefinitionFunction<WebpackLoaderOptions> = function (source) {
const callback = this.async();
const options = this.getOptions();
this.cacheable(true);
this.addDependency(options.absoluteCompiledConfigPath);
if (!instance) {
instance = toWebpack(
createMetaLoader(
createStandaloneConfigLoader({
core: getCore(options),
buildConfig: false,
mode: options.isDev ? 'dev' : 'production',
}),
{
json: 'json',
yaml: 'js',
},
),
);
}
void instance.call(this, source, callback);
};Sources: packages/mdx/src/webpack/meta.ts:9-32
Note
The meta loader configures createMetaLoader with mapping values { json: 'json', yaml: 'js' }, passing an options object to createStandaloneConfigLoader where buildConfig is disabled and mode is derived from options.isDev.
Sources: packages/mdx/src/webpack/meta.ts:17-27
Story File Transformation Loader
The story loader handles component documentation files by leveraging ts-morph projects and file transformation utilities. It accepts options via StoryLoaderOptions and manages asynchronous execution pools through projectPromise.
export interface StoryLoaderOptions {
/**
* Path to `tsconfig.json`.
*
* @default "tsconfig.json"
*/
tsconfigPath?: string;
}
let projectPromise: Promise<Project> | undefined;
const loader: LoaderDefinitionFunction<StoryLoaderOptions> = function (source) {
const callback = this.async();
const options = this.getOptions();
this.cacheable(true);
const run = async () => {
if (!projectPromise) {
const resolvedTsconfig = options.tsconfigPath ?? path.join(this.rootContext, 'tsconfig.json');
projectPromise = createControlsProject(resolvedTsconfig);
}
try {
const transformed = transformStoryFile(
'@fumadocs/story/next/client',
source,
this.resourcePath,
await projectPromise!,
);
callback(undefined, transformed ?? source);
} catch (error) {
if (!(error instanceof Error)) throw error;
callback(error);
}
};
void run();
};Sources: packages/story/src/webpack/story.ts:7-44
| Option Key | Type | Default Value | Description |
|---|---|---|---|
tsconfigPath | string | "tsconfig.json" | Path to the tsconfig.json configuration file used for ts-morph project initialization. |
Sources: packages/story/src/webpack/story.ts:7-14, packages/story/src/webpack/story.ts:25-25
Warning
If projectPromise has not been initialized when a story file is processed, the loader resolves tsconfigPath relative to this.rootContext before creating the controls project.
Sources: packages/story/src/webpack/story.ts:23-27
Vite and Rolldown Adapters
Vite Plugin Architecture and Server Lifecycle
The Vite plugin wrapper orchestrates core compilation lifecycle hooks, configuration building, and development server file watching. It exposes PluginOptions to control index generation, configuration paths, module resolution updates, and output directories.
export interface PluginOptions {
/**
* Generate index files for accessing content.
*
* @defaultValue true
*/
index?: boolean | IndexFilePluginOptions;
/**
* @defaultValue source.config.ts
*/
configPath?: string;
/**
* Update Vite config to fix module resolution of Fumadocs
*
* @defaultValue true
*/
updateViteConfig?: boolean;
/**
* Output directory of generated files
*
* @defaultValue '.source'
*/
outDir?: string;
}Sources: packages/mdx/src/vite/index.ts:12-38
| Option Key | Type | Default Value | Description |
|---|---|---|---|
index | boolean | IndexFilePluginOptions | true | Generates index files for accessing content or configures index file options. |
configPath | string | 'source.config.ts' | Path to the content source configuration file. |
updateViteConfig | boolean | true | Updates Vite config to fix module resolution of Fumadocs. |
outDir | string | '.source' | Output directory of generated files. |
Sources: packages/mdx/src/vite/index.ts:12-38
During the config hook, the plugin initializes core functionality via createViteCore and runs core.init(). It registers pre-ordered transform hooks for MDX and meta loaders while establishing file watchers on the configuration path.
Caution
When Vite RSC processes client references, it passes compiled MDX client modules with IDs matching virtual:vite-rsc. The plugin explicitly intercepts and ignores these IDs to prevent JavaScript content formatting from breaking the MDX compiler.
Sources: packages/mdx/src/vite/index.ts:83-86
return [
{
name: 'fumadocs-mdx',
async config(config) {
root = config.root ?? process.cwd();
options = applyDefaults(root, pluginOptions);
core = createViteCore(options);
await core.init({
config: buildConfig(
forcedConfig
? await forcedConfig
: (await runnerImport<Record<string, unknown>>(options.configPath)).module,
root,
),
});
const configLoader = createIntegratedConfigLoader(core);
const mdxLoader = toVite(createMdxLoader(configLoader));
const metaLoader = toVite(
createMetaLoader(configLoader, {
// vite has built-in plugin for JSON files
json: 'json',
}),
);
mdxPlugin.transform = {
filter: mdxLoader.filter,
order: 'pre',
handler(code, id) {
// Vite RSC will pass the compiled MDX file's client module with ID `virtual:vite-rsc/client-references/group/facade:xxx.mdx`.
// The format of `value` becomes JavaScript, which will break the MDX compiler.
// We have to ignore them.
if (id.includes('virtual:vite-rsc')) return null;
if (!forcedConfig) this.addWatchFile(options.configPath);
return mdxLoader.transform.call(this, code, id);
},
};
metaPlugin.transform = {
filter: metaLoader.filter,
order: 'pre',
handler(code, id) {
if (!forcedConfig) this.addWatchFile(options.configPath);
return metaLoader.transform.call(this, code, id);
},
};
if ('_fumadocs_skipViteConfig' in config && config._fumadocs_skipViteConfig) return;
if (!options.updateViteConfig) return;
const { getConfig } = await import('@fumadocs/vite');
return getConfig({ root });
},Sources: packages/mdx/src/vite/index.ts:54-105
Rolldown Plugin Configuration and File Loading
The Rolldown plugin wrapper configures core compilation with a rolldown environment parameter. It constructs integrated configuration and loaders, returning a set of Rolldown plugins that handle raw file loading and transformation.
export interface PluginOptions {
configPath?: string;
outDir?: string;
}
export default async function mdx(
config: Record<string, unknown> | Promise<Record<string, unknown>>,
options?: PluginOptions,
): Promise<RolldownPlugin[]> {
const core = createCore({
configPath: options?.configPath ?? _Defaults.configPath,
outDir: options?.outDir ?? _Defaults.outDir,
environment: 'rolldown',
});
await core.init({
config: buildConfig(await config, process.cwd()),
});
const configLoader = createIntegratedConfigLoader(core);
const mdxLoader = toVite(createMdxLoader(configLoader));
const metaLoader = toVite(
createMetaLoader(configLoader, {
// rolldown has built-in plugin for JSON files
json: 'json',
}),
);
Sources: packages/mdx/src/rolldown/index.ts:11-37
| Option Key | Type | Default Value | Description |
|---|---|---|---|
configPath | string | _Defaults.configPath | Path to the content source configuration file. |
outDir | string | _Defaults.outDir | Output directory of generated files. |
Sources: packages/mdx/src/rolldown/index.ts:11-14, packages/mdx/src/rolldown/index.ts:21-22
Note
Because Rolldown cannot read the correct file path when query parameters exist on module IDs, a dedicated load handler strips query strings using id.lastIndexOf('?') before reading the file contents from disk via fs.readFile.
Sources: packages/mdx/src/rolldown/index.ts:41-50
return [
{
name: 'fumadocs-mdx',
load: {
filter: { id: [metaLoaderGlob, mdxLoaderGlob] },
// Rolldown couldn't read the correct file path when query params exist.
async handler(id) {
const idx = id.lastIndexOf('?');
if (idx === -1) return null;
return fs.readFile(id.slice(0, idx), 'utf-8');
},
},
},
{
name: 'fumadocs-mdx:mdx',
transform: {
filter: mdxLoader.filter,
handler: mdxLoader.transform,
},
},
{
name: 'fumadocs-mdx:meta',
transform: {
filter: metaLoader.filter,
handler: metaLoader.transform,
},
},
];Sources: packages/mdx/src/rolldown/index.ts:38-66
Story File Transformation Plugin
The story plugin provides a Vite-compatible transformation pipeline for component stories, leveraging ts-morph projects and filtering file IDs against regular expressions.
export interface StoryPluginOptions {
/**
* Path to `tsconfig.json`.
*
* @default "tsconfig.json"
*/
tsconfigPath?: string;
/**
* Filter story files to transform by id (regex)
*
* @default `/\.story\.(js|jsx|ts|tsx)$/`
*/
filter?: RegExp;
}Sources: packages/story/src/vite/index.ts:7-21
| Option Key | Type | Default Value | Description |
|---|---|---|---|
tsconfigPath | string | "tsconfig.json" | Path to the tsconfig.json configuration file. |
filter | RegExp | /\.story\.(js|jsx|ts|tsx)$/ | Filter story files to transform by ID regex. |
Sources: packages/story/src/vite/index.ts:7-21
export default function story(pluginOptions: StoryPluginOptions = {}): Plugin {
const { filter = /\.story\.(js|jsx|ts|tsx)$/ } = pluginOptions;
let tsconfigPath: string;
let projectPromise: Promise<Project> | undefined;
return {
name: 'fumadocs:story',
enforce: 'pre',
configResolved(resolved) {
tsconfigPath = pluginOptions.tsconfigPath ?? path.join(resolved.root, 'tsconfig.json');
},
transform: {
filter: { id: filter },
async handler(code, id) {
projectPromise ??= createControlsProject(tsconfigPath);
return transformStoryFile('@fumadocs/story/vite/client', code, id, await projectPromise);
},
},
};Sources: packages/story/src/vite/index.ts:23-42
Node and Bun Runtime Loaders
Bun Plugin Module Interception
The Bun plugin integration configures core settings and exposes module loading hooks tailored for the Bun runtime environment. It implements the BunPlugin interface through createMdxPlugin, accepting options that extend partial core configurations alongside custom plugin toggles.
| Option Key | Type | Default Value | Description |
|---|---|---|---|
environment | string | 'bun' | Runtime execution environment identifier. |
outDir | string | _Defaults.outDir | Output directory path for generated files. |
configPath | string | _Defaults.configPath | Path to the content source configuration file. |
disableMetaFile | boolean | false | Disables the automatic meta file transformation step. |
Sources: packages/mdx/src/bun/index.ts:10-23
During the setup lifecycle hook, the plugin initializes core functionality by transforming the configuration path into a file URL and invoking core.init(). It establishes integrated configuration loading and assigns MDX and meta loaders using the Bun adapter utility.
return {
name: 'bun-plugin-fumadocs-mdx',
async setup(build) {
const importPath = pathToFileURL(configPath).href;
const core = createCore({
environment,
outDir,
configPath,
});
await core.init({
config: buildConfig(await import(importPath), process.cwd()),
});
const configLoader = createIntegratedConfigLoader(core);
toBun(createMdxLoader(configLoader))(build);
if (!disableMetaFile) toBun(createMetaLoader(configLoader))(build);
},
};
}Sources: packages/mdx/src/bun/index.ts:25-44
Note
The meta loader step can be entirely bypassed by passing disableMetaFile: true in the plugin options, preventing unnecessary processing of metadata files when only core MDX compilation is required.
Sources: packages/mdx/src/bun/index.ts:14-22, packages/mdx/src/bun/index.ts:41-41
Native Node.js Module Loaders
Native Node.js environments utilize custom module loading hooks conforming to Node's module customization hooks specification. The modern initialization implementation defines an initialize hook that sets up standalone configuration loaders for production mode.
| Option Key | Type | Default Value | Description |
|---|---|---|---|
environment | string | 'node-loader' | Execution environment assigned during core creation. |
configPath | string | _Defaults.configPath | Path to the content source configuration file. |
outDir | string | _Defaults.outDir | Output directory path for generated content. |
disableMetaFile | boolean | undefined | Conditionally skips pushing the meta loader into the loader cache. |
Sources: packages/mdx/src/node/_loader.ts:11-29
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)));
}
};
Sources: packages/mdx/src/node/_loader.ts:11-30
The accompanying load hook iterates sequentially through cached Node module loaders using a recursive runner function, falling back to the standard nextLoad function when all custom hooks have executed.
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);
};Sources: packages/mdx/src/node/_loader.ts:31-48
Warning
Attempting to invoke the load hook before the module loader has been properly initialized via initialize triggers an immediate runtime error stating not initialized.
Sources: packages/mdx/src/node/_loader.ts:31-32
Related
On This Page
OverviewNext.js Integration and Core LifecycleInitialization and Execution FlowConfiguration Options and Default ValuesMDX Compiler Preset ConfigurationPreset Options and Remark/Rehype RegistrationPlugin Integration PipelinePreset Configuration Options ReferenceIndex File Codegen CoordinationExecution Pipeline and Sequence ArchitecturePlugin Options and Configuration ReferenceWebpack Loader InterceptionStandalone MDX and Meta LoadersStory File Transformation LoaderVite and Rolldown AdaptersVite Plugin Architecture and Server LifecycleRolldown Plugin Configuration and File LoadingStory File Transformation PluginNode and Bun Runtime LoadersBun Plugin Module InterceptionNative Node.js Module LoadersRelated