Skip to content

Commit 7dabbc1

Browse files
committed
Core: [Remark Image] Support relative imports
1 parent 54b8e1e commit 7dabbc1

File tree

13 files changed

+234
-47
lines changed

13 files changed

+234
-47
lines changed

.changeset/big-seals-grow.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'fumadocs-core': patch
3+
---
4+
5+
Remark Image: Support relative imports

apps/docs/next.config.js

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,6 @@ const config = {
3131
},
3232
};
3333

34-
const withMDX = createMDX({
35-
buildSearchIndex: {
36-
filter: (v) => {
37-
return !v.match(/.+\.model\.mdx/) && !v.startsWith('blog');
38-
},
39-
},
40-
mdxOptions: {
41-
lastModifiedTime: 'git',
42-
},
43-
});
34+
const withMDX = createMDX();
4435

4536
export default withAnalyzer(withMDX(config));

apps/docs/scripts/post-build.mts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import env from '@next/env';
22
import { updateSearchIndexes } from './update-index.mjs';
33
import { readFile } from 'node:fs/promises';
4-
import type { SearchIndex } from 'fumadocs-mdx';
4+
import type { Manifest } from 'fumadocs-mdx';
55

66
env.loadEnvConfig(process.cwd());
77

88
async function main() {
9-
const indexes = JSON.parse(
10-
(await readFile('.next/server/chunks/fumadocs_search.json')).toString(),
11-
) as SearchIndex[];
9+
const manifest = JSON.parse(
10+
(await readFile('.source/manifest.json')).toString(),
11+
) as Manifest;
1212

13-
await Promise.all([updateSearchIndexes(indexes)]);
13+
await updateSearchIndexes(manifest);
1414
}
1515

1616
await main().catch((e) => {

apps/docs/scripts/update-index.mts

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import algosearch from 'algoliasearch';
22
import { sync } from 'fumadocs-core/search-algolia/server';
3-
import type { SearchIndex } from 'fumadocs-mdx';
3+
import type { Manifest } from 'fumadocs-mdx';
4+
import { createGetUrl, getSlugs, parseFilePath } from 'fumadocs-core/source';
5+
import path from 'node:path';
46

5-
export async function updateSearchIndexes(
6-
indexes: SearchIndex[],
7-
): Promise<void> {
7+
export async function updateSearchIndexes(manifest: Manifest): Promise<void> {
88
if (!process.env.ALGOLIA_API_KEY) {
99
console.warn('Algolia API Key not found, skip updating search index.');
1010
return;
@@ -27,16 +27,29 @@ export async function updateSearchIndexes(
2727
},
2828
);
2929

30+
const getUrl = createGetUrl('/docs');
31+
3032
await sync(client, {
3133
document: process.env.NEXT_PUBLIC_ALGOLIA_INDEX ?? 'document',
32-
documents: indexes.map((docs) => ({
33-
_id: docs.id,
34-
title: docs.title,
35-
description: docs.description,
36-
url: docs.url,
37-
structured: docs.structuredData,
38-
tag: docs.url.split('/')[2],
39-
})),
34+
documents: manifest.files
35+
.filter((file) => file.collection === 'docs')
36+
.map((docs) => {
37+
const url = getUrl(
38+
getSlugs(parseFilePath(path.relative('content/docs', docs.path))),
39+
);
40+
41+
if (!docs.data.structuredData)
42+
throw new Error('`structuredData` is required');
43+
44+
return {
45+
_id: docs.path,
46+
title: docs.data.frontmatter.title as string,
47+
description: docs.data.frontmatter.description as string,
48+
url,
49+
structured: docs.data.structuredData,
50+
tag: url.split('/')[2],
51+
};
52+
}),
4053
});
4154

4255
console.log('search updated');

apps/docs/source.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export const blog = defineCollections({
4141

4242
export default defineConfig({
4343
generateManifest: true,
44+
lastModifiedTime: 'git',
4445
mdxOptions: {
4546
rehypeCodeOptions: {
4647
themes: {

packages/core/src/mdx-plugins/remark-image.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,25 @@ export function remarkImage({
5656
useImport = true,
5757
publicDir = path.join(process.cwd(), 'public'),
5858
}: RemarkImageOptions = {}): Transformer<Root, Root> {
59-
return async (tree) => {
59+
return async (tree, file) => {
6060
const importsToInject: { variableName: string; importPath: string }[] = [];
6161
const promises: Promise<void>[] = [];
6262

63+
function getImportPath(src: string): string {
64+
if (!src.startsWith('/')) return src;
65+
66+
if (file.path) {
67+
const relative = path.relative(
68+
path.dirname(file.path),
69+
path.join(publicDir, src),
70+
);
71+
72+
return relative.startsWith('./') ? relative : `./${relative}`;
73+
}
74+
75+
return path.join(publicDir, src);
76+
}
77+
6378
visit(tree, 'image', (node) => {
6479
const src = decodeURI(node.url);
6580
if (!src) return;
@@ -107,10 +122,7 @@ export function remarkImage({
107122

108123
importsToInject.push({
109124
variableName,
110-
importPath: slash(
111-
// with imports, relative paths don't have to be absolute
112-
src.startsWith('/') ? path.join(publicDir, src) : src,
113-
),
125+
importPath: slash(getImportPath(src)),
114126
});
115127

116128
Object.assign(node, {
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
{
2+
"children": [
3+
{
4+
"data": {
5+
"estree": {
6+
"body": [
7+
{
8+
"source": {
9+
"type": "Literal",
10+
"value": "./test.png",
11+
},
12+
"specifiers": [
13+
{
14+
"local": {
15+
"name": "__img0",
16+
"type": "Identifier",
17+
},
18+
"type": "ImportDefaultSpecifier",
19+
},
20+
],
21+
"type": "ImportDeclaration",
22+
},
23+
],
24+
},
25+
},
26+
"type": "mdxjsEsm",
27+
},
28+
{
29+
"children": [
30+
{
31+
"alt": "Test",
32+
"attributes": [
33+
{
34+
"name": "alt",
35+
"type": "mdxJsxAttribute",
36+
"value": "Test",
37+
},
38+
{
39+
"name": "placeholder",
40+
"type": "mdxJsxAttribute",
41+
"value": "blur",
42+
},
43+
{
44+
"name": "src",
45+
"type": "mdxJsxAttribute",
46+
"value": {
47+
"data": {
48+
"estree": {
49+
"body": [
50+
{
51+
"expression": {
52+
"name": "__img0",
53+
"type": "Identifier",
54+
},
55+
"type": "ExpressionStatement",
56+
},
57+
],
58+
},
59+
},
60+
"type": "mdxJsxAttributeValueExpression",
61+
"value": "__img0",
62+
},
63+
},
64+
],
65+
"name": "img",
66+
"position": {
67+
"end": {
68+
"column": 20,
69+
"line": 1,
70+
"offset": 19,
71+
},
72+
"start": {
73+
"column": 1,
74+
"line": 1,
75+
"offset": 0,
76+
},
77+
},
78+
"title": null,
79+
"type": "mdxJsxFlowElement",
80+
"url": "./test.png",
81+
},
82+
],
83+
"position": {
84+
"end": {
85+
"column": 20,
86+
"line": 1,
87+
"offset": 19,
88+
},
89+
"start": {
90+
"column": 1,
91+
"line": 1,
92+
"offset": 0,
93+
},
94+
},
95+
"type": "paragraph",
96+
},
97+
{
98+
"children": [
99+
{
100+
"alt": "External",
101+
"attributes": [
102+
{
103+
"name": "alt",
104+
"type": "mdxJsxAttribute",
105+
"value": "External",
106+
},
107+
{
108+
"name": "src",
109+
"type": "mdxJsxAttribute",
110+
"value": "https://picsum.photos/id/237/200/300",
111+
},
112+
{
113+
"name": "width",
114+
"type": "mdxJsxAttribute",
115+
"value": "200",
116+
},
117+
{
118+
"name": "height",
119+
"type": "mdxJsxAttribute",
120+
"value": "300",
121+
},
122+
],
123+
"name": "img",
124+
"position": {
125+
"end": {
126+
"column": 50,
127+
"line": 3,
128+
"offset": 70,
129+
},
130+
"start": {
131+
"column": 1,
132+
"line": 3,
133+
"offset": 21,
134+
},
135+
},
136+
"title": null,
137+
"type": "mdxJsxFlowElement",
138+
"url": "https://picsum.photos/id/237/200/300",
139+
},
140+
],
141+
"position": {
142+
"end": {
143+
"column": 50,
144+
"line": 3,
145+
"offset": 70,
146+
},
147+
"start": {
148+
"column": 1,
149+
"line": 3,
150+
"offset": 21,
151+
},
152+
},
153+
"type": "paragraph",
154+
},
155+
],
156+
"position": {
157+
"end": {
158+
"column": 1,
159+
"line": 4,
160+
"offset": 71,
161+
},
162+
"start": {
163+
"column": 1,
164+
"line": 1,
165+
"offset": 0,
166+
},
167+
},
168+
"type": "root",
169+
}

packages/core/test/fixtures/remark-image.output.mdx

Lines changed: 0 additions & 5 deletions
This file was deleted.

packages/core/test/mdx-plugins.test.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,14 @@ test('Remark Admonition', async () => {
5555

5656
test('Remark Image', async () => {
5757
const content = readFileSync(path.resolve(cwd, './fixtures/remark-image.md'));
58-
const result = await remark()
58+
const processor = remark()
5959
.use(remarkImage, { publicDir: path.resolve(cwd, './fixtures') })
60-
.use(remarkMdx)
61-
.process(content);
60+
.use(remarkMdx);
6261

63-
expect(result.value).toMatchFileSnapshot(
64-
path.resolve(cwd, './fixtures/remark-image.output.mdx'),
62+
const result = await processor.run(processor.parse(content));
63+
64+
expect(result).toMatchFileSnapshot(
65+
path.resolve(cwd, './fixtures/remark-image.output.json'),
6566
);
6667
});
6768

packages/create-app/versions.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"fumadocs-core":"13.3.2","fumadocs-ui":"13.3.2","fumadocs-mdx":"9.0.2","@fumadocs/content-collections":"1.1.2"}
1+
{"fumadocs-core":"13.4.0","fumadocs-ui":"13.4.0","fumadocs-mdx":"9.0.3","@fumadocs/content-collections":"1.1.3"}

0 commit comments

Comments
 (0)