Add MDX sourcemaps support

This commit is contained in:
sebastien 2025-04-11 10:01:03 +02:00
parent 29d19a6884
commit 109a0ebe60
4 changed files with 25 additions and 6 deletions

View file

@ -35,6 +35,7 @@
"remark-emoji": "^4.0.0",
"remark-frontmatter": "^5.0.0",
"remark-gfm": "^4.0.0",
"source-map": "^0.7.4",
"stringify-object": "^3.3.0",
"tslib": "^2.6.0",
"unified": "^11.0.3",

View file

@ -22,6 +22,7 @@ import {
import type {WebpackCompilerName} from '@docusaurus/utils';
import type {Options} from './options';
import type {LoaderContext} from 'webpack';
import type {Map as SourceMap} from 'vfile';
// TODO as of April 2023, no way to import/re-export this ESM type easily :/
// This might change soon, likely after TS 5.2
@ -30,6 +31,11 @@ type Pluggable = any; // TODO fix this asap
export type MDXPlugin = Pluggable;
type LoadMDXResult = {
content: string;
sourceMap: SourceMap | null | undefined;
};
async function loadMDX({
fileContent,
filePath,
@ -40,7 +46,7 @@ async function loadMDX({
filePath: string;
options: Options;
compilerName: WebpackCompilerName;
}): Promise<string> {
}): Promise<LoadMDXResult> {
const {frontMatter} = await options.markdownConfig.parseFrontMatter({
filePath,
fileContent,
@ -120,7 +126,10 @@ ${exportsCode}
${result.content}
`;
return code;
return {
content: code,
sourceMap: result.map,
};
}
// Note: we cache promises instead of strings
@ -138,7 +147,7 @@ async function loadMDXWithCaching({
fileContent: string;
options: Options;
compilerName: WebpackCompilerName;
}): Promise<string> {
}): Promise<LoadMDXResult> {
const {crossCompilerCache} = options;
if (!crossCompilerCache) {
return loadMDX({
@ -202,7 +211,7 @@ async function loadMDXWithCaching({
deleteCacheEntry();
return cacheEntry.promise;
} else {
const {promise, resolve, reject} = promiseWithResolvers<string>();
const {promise, resolve, reject} = promiseWithResolvers<LoadMDXResult>();
crossCompilerCache.set(cacheKey, {promise, resolve, reject});
return promise;
}
@ -227,7 +236,7 @@ export async function mdxLoader(
options,
compilerName,
});
return callback(null, result);
return callback(null, result.content, result.sourceMap || undefined);
} catch (error) {
return callback(error as Error);
}

View file

@ -9,6 +9,7 @@ import type {MDXOptions, SimpleProcessors} from './processor';
import type {MarkdownConfig} from '@docusaurus/types';
import type {ResolveMarkdownLink} from './remark/resolveMarkdownLinks';
import type {PromiseWithResolvers} from './utils';
import type {Map as SourceMap} from 'vfile';
export type Options = Partial<MDXOptions> & {
dependencies?: string[];
@ -31,4 +32,7 @@ export type Options = Partial<MDXOptions> & {
crossCompilerCache?: Map<string, CrossCompilerCacheEntry>; // MDX => Promise<JSX> cache
};
type CrossCompilerCacheEntry = PromiseWithResolvers<string>;
type CrossCompilerCacheEntry = PromiseWithResolvers<{
content: string;
sourceMap: SourceMap | null | undefined;
}>;

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {SourceMapGenerator} from 'source-map';
import headings from './remark/headings';
import contentTitle from './remark/contentTitle';
import toc from './remark/toc';
@ -23,6 +24,7 @@ import type {MDXFrontMatter} from './frontMatter';
import type {Options} from './options';
import type {AdmonitionOptions} from './remark/admonitions';
import type {ProcessorOptions} from '@mdx-js/mdx';
import type {Map as SourceMap} from 'vfile';
// TODO as of April 2023, no way to import/re-export this ESM type easily :/
// This might change soon, likely after TS 5.2
@ -31,6 +33,7 @@ type Pluggable = any; // TODO fix this asap
export type SimpleProcessorResult = {
content: string;
map: SourceMap | null | undefined;
data: {[key: string]: unknown};
};
@ -187,6 +190,7 @@ async function createProcessorFactory() {
...processorOptions,
remarkRehypeOptions: options.markdownConfig.remarkRehypeOptions,
format,
SourceMapGenerator,
});
return {
@ -202,6 +206,7 @@ async function createProcessorFactory() {
return mdxProcessor.process(vfile).then((result) => ({
content: result.toString(),
data: result.data,
map: result.map,
}));
},
};