recma-component-resolver
v0.5.1
Published
Build-time component capture and selective forwarding for nested MDX includes.
Maintainers
Readme
recma-component-resolver
Build-time component capture and selective forwarding for nested MDX includes
A compile-time Unified/Recma package that analyzes compiled MDX modules, derives component requirements across nested include graphs, and rewrites MDX include callsites so each child receives only the components it actually renders.
Table of Contents
Overview
Features
- Compile-Time Capture: Collect local component usage and nested MDX include
edges from compiled
_createMdxContentoutput. - Reachability-Aware Graph Derivation: Build a canonical include graph from captured module facts, including shared children and cycles.
- Minimal Per-Include Forwarding: Rewrite each include boundary with only the components the direct child needs locally.
- Arbitrary Nested Depth: Preserve access to the root component map through
a hidden
__mdxRootComponentscarrier. - Small Runtime Surface: Generated output adds a compact
__pickMdxComponentshelper only when subset forwarding is needed.
Why Selective Forwarding?
By default, nested MDX includes often receive the full components map at
every boundary. That works, but it over-forwards unrelated components and makes
deep include chains harder to reason about.
This package splits the problem into three build-time stages:
- Capture per-module facts with
recmaCapture - Derive the reachable include graph with
buildResolvedComponentGraph - Rewrite include callsites with
recmaRewrite
The result is a boundary-local forwarding model:
page.mdx -> intro.mdxreceives onlyintro.mdx's local component needspage.mdx -> api.mdxreceives onlyapi.mdx's local component needsintro.mdx -> examples.mdxis resolved independentlyapi.mdx -> examples.mdxis resolved independently
This avoids transitive packing at parent boundaries while still supporting arbitrary nested depth.
Getting Started
Installation
npm install recma-component-resolver unified
# or
pnpm add recma-component-resolver unifiedThis package is recma-only. It expects compiled MDX JavaScript as input and is
typically used alongside an MDX compiler or bundler such as @mdx-js/mdx or
@mdx-js/esbuild.
Quick Start
If the goal is the shortest path to adoption:
- Run a first build with
recmaCapture - Derive the resolved component graph
- Run a second build with
recmaRewrite
import {
buildResolvedComponentGraph,
recmaCapture,
recmaRewrite,
type CapturedModule
} from 'recma-component-resolver';
const capturedModules: Record<string, CapturedModule> = {};
const runBuild = async (
entryPath: string,
recmaPlugins: Array<unknown>
): Promise<string> => {
// Run the existing MDX compile or bundle step here.
// Example integrations: @mdx-js/mdx, @mdx-js/esbuild, or a custom bundler.
return '';
};
await runBuild('/content/page.mdx', [
[
recmaCapture,
{
onModuleCapture: payload => {
capturedModules[payload.moduleId] = payload;
}
}
]
]);
const resolvedComponentGraph = buildResolvedComponentGraph(
'/content/page.mdx',
capturedModules
);
await runBuild('/content/page.mdx', [
[
recmaRewrite,
{
capturedModules,
requiredComponentsByImportIdentifier:
resolvedComponentGraph.requiredComponentsByImportIdentifier
}
]
]);resolvedComponentGraph.usedComponentNames can also be attached to emitted
metadata if the consuming runtime wants a complete list of reachable components.
Usage
This package has three explicit stages.
Step 1: Capture Module Facts
recmaCapture scans compiled _createMdxContent output and emits one
CapturedModule per compiled module.
Example source graph:
page.mdx
|
|-> intro.mdx -> examples.mdx
|
|-> api.mdx ---> examples.mdx (shared)Example local component usage:
page.mdxusesNoticeintro.mdxusesStepsapi.mdxusesCodeBlockandNoticeexamples.mdxusesPreview
Example capture result for page.mdx:
{
moduleId: '/content/page.mdx',
moduleReferencesByIdentifier: {
Intro: './intro.mdx',
Api: './api.mdx'
},
componentNames: ['Notice'],
includeSpecifiers: ['./intro.mdx', './api.mdx']
}Register the capture pass in the first build:
import {
recmaCapture,
type CapturedModule
} from 'recma-component-resolver';
const capturedModules: Record<string, CapturedModule> = {};
const capturePlugins = [
[
recmaCapture,
{
onModuleCapture: payload => {
capturedModules[payload.moduleId] = payload;
}
}
]
];Step 2: Build the Resolved Component Graph
buildResolvedComponentGraph(entryPath, capturedModules) converts raw capture
results into the data needed by the rewrite phase.
Example result for the graph above:
{
usedComponentNames: ['Notice', 'Steps', 'CodeBlock', 'Preview'],
requiredComponentsByImportIdentifier: {
'/content/page.mdx': {
Intro: ['Steps'],
Api: ['CodeBlock', 'Notice']
},
'/content/intro.mdx': {
Examples: ['Preview']
},
'/content/api.mdx': {
Examples: ['Preview']
},
'/content/examples.mdx': {}
}
}Important behavior:
- Reachability is discovered with BFS from the entry module
- Shared children are processed once
- Parent boundaries receive only the direct child's local requirements
- Grandchild requirements are not packed into parent-child subsets
Step 3: Rewrite Include Callsites
recmaRewrite uses the captured modules plus the derived
requiredComponentsByImportIdentifier map to rewrite nested MDX include
callsites.
Register the rewrite pass in the second build:
import {
buildResolvedComponentGraph,
recmaRewrite,
type CapturedModule
} from 'recma-component-resolver';
const capturedModules: Record<string, CapturedModule> = {};
const resolvedComponentGraph = buildResolvedComponentGraph(
'/content/page.mdx',
capturedModules
);
const rewritePlugins = [
[
recmaRewrite,
{
capturedModules,
requiredComponentsByImportIdentifier:
resolvedComponentGraph.requiredComponentsByImportIdentifier
}
]
];Typical compiled output shape before rewrite:
_jsx(Api, { components: props.components })Typical compiled output shape after rewrite:
_jsx(
Api,
Object.assign({}, { components: props.components }, {
components: __pickMdxComponents(
props.__mdxRootComponents || props.components,
['CodeBlock', 'Notice']
),
__mdxRootComponents: props.__mdxRootComponents || props.components
})
)This keeps the direct child subset minimal while preserving a stable root component source for deeper nested boundaries.
Reference
Exports
import {
buildResolvedComponentGraph,
recmaCapture,
recmaRewrite,
type CapturedModule
} from 'recma-component-resolver';recmaCapture
Recma plugin that captures per-module facts from compiled MDX output.
Options:
type CaptureOptions = {
onModuleCapture: (payload: CapturedModule) => void;
};CapturedModule
Captured metadata for a single compiled content module.
type CapturedModule = {
moduleId: string;
moduleReferencesByIdentifier: Record<string, string>;
componentNames: Array<string>;
includeSpecifiers: Array<string>;
};Field meanings:
moduleId: canonical absolute module identifiermoduleReferencesByIdentifier: local include identifiers mapped to their original specifierscomponentNames: local custom component names in first-seen orderincludeSpecifiers: rendered nested include specifiers discovered in the module
buildResolvedComponentGraph
Build-time derivation step that resolves the reachable include graph and computes per-boundary forwarding requirements.
Signature:
const resolvedComponentGraph = buildResolvedComponentGraph(
entryPath,
capturedModules
);Returned shape:
{
usedComponentNames: Array<string>,
requiredComponentsByImportIdentifier: Record<
string,
Record<string, Array<string>>
>
}recmaRewrite
Recma plugin that rewrites MDX include callsites with minimal component subsets.
Options:
type RewriteOptions = {
capturedModules: Record<string, CapturedModule>;
requiredComponentsByImportIdentifier?: Record<
string,
Record<string, Array<string>>
>;
};requiredComponentsByImportIdentifier is optional at the type level, but
selective forwarding depends on passing the derived map from
buildResolvedComponentGraph.
Capabilities
- Boundary-local subsets: Each include boundary receives only the direct child's local component requirements.
- No transitive packing: Parent boundaries do not accumulate grandchild or deeper descendant requirements.
- Root-direct access: Nested children resolve from
__mdxRootComponents || props.components, not through intermediate filtered subsets. - Shared include support: Shared children are handled correctly during graph derivation.
- Cycle tolerance: Reachability traversal processes each module once.
- Compiler-agnostic integration: Works with any MDX build pipeline that can register recma plugins and provide a stable module path per file.
Non-Goals
- This package does not bundle MDX files by itself.
- This package does not resolve alias-based module specifiers.
- This package does not parse raw markdown; it operates on compiled MDX output.
