@@ -19,16 +19,20 @@ export const docs = defineDocs({
1919 } ,
2020} ) ;
2121
22- // Rehype plugin that prepends basePath to local <img src="/..."> paths.
23- // In MDX, <img> tags are parsed as JSX (mdxJsxFlowElement / mdxJsxTextElement),
24- // NOT as rehype `element` nodes. Their attributes live in node.attributes[],
25- // not node.properties — so we must handle both node types.
26- function rehypePrependBasePath ( ) {
22+ // Rehype plugin for local <img src="/..."> tags in MDX files.
23+ //
24+ // Problem: In MDX, explicit <img> JSX tags are compiled as React.createElement('img', ...)
25+ // and do NOT reliably go through the components map (unlike Markdown ![]() images).
26+ // This means the `img` override in mdx-components.tsx is never called for them.
27+ //
28+ // Solution: Rename those nodes to <DocImage> (uppercase). Uppercase components ARE always
29+ // resolved from the components context, so DocImage in mdx-components.tsx will be called.
30+ // We also prepend basePath here since Next.js <Image> does NOT do it automatically —
31+ // the src must already include basePath before being passed to next/image.
32+ function rehypeDocImage ( ) {
2733 const basePath =
2834 process . env . NEXT_PUBLIC_BASE_PATH ||
2935 ( process . env . NODE_ENV === 'production' ? '/plugins-doc-site' : '' ) ;
30-
31- if ( ! basePath ) return ( tree : any ) => tree ;
3236
3337 function walk ( node : any ) {
3438 // MDX JSX nodes: mdxJsxFlowElement / mdxJsxTextElement
@@ -37,29 +41,32 @@ function rehypePrependBasePath() {
3741 node . name === 'img' &&
3842 Array . isArray ( node . attributes )
3943 ) {
44+ // Rename to DocImage so the components map entry is used (enabling ImageZoom)
45+ node . name = 'DocImage' ;
46+
47+ // Prepend basePath to local src paths
4048 for ( const attr of node . attributes ) {
4149 if (
4250 attr . type === 'mdxJsxAttribute' &&
4351 attr . name === 'src' &&
4452 typeof attr . value === 'string'
4553 ) {
4654 const src : string = attr . value ;
47- if ( src . startsWith ( '/' ) && ! src . startsWith ( '//' ) && ! src . startsWith ( basePath ) ) {
55+ if ( basePath && src . startsWith ( '/' ) && ! src . startsWith ( '//' ) && ! src . startsWith ( basePath ) ) {
4856 attr . value = basePath + src ;
49- console . debug ( 'MDX img src after basePath:' , attr . value ) ;
5057 }
5158 }
5259 }
5360 }
5461
55- // Standard rehype element nodes (fallback)
62+ // Standard rehype element nodes (fallback for any genuine HTML <img> nodes )
5663 if (
5764 node . type === 'element' &&
5865 node . tagName === 'img' &&
5966 typeof node . properties ?. src === 'string'
6067 ) {
6168 const src : string = node . properties . src ;
62- if ( src . startsWith ( '/' ) && ! src . startsWith ( '//' ) && ! src . startsWith ( basePath ) ) {
69+ if ( basePath && src . startsWith ( '/' ) && ! src . startsWith ( '//' ) && ! src . startsWith ( basePath ) ) {
6370 node . properties . src = basePath + src ;
6471 }
6572 }
@@ -78,6 +85,6 @@ export default defineConfig({
7885 external : false , // Disable fetching external image sizes
7986 } ,
8087 remarkPlugins : [ ] ,
81- rehypePlugins : [ rehypePrependBasePath ] ,
88+ rehypePlugins : [ rehypeDocImage ] ,
8289 } ,
8390} ) ;
0 commit comments