Skip to content

Commit 2569bd0

Browse files
authored
feat(cli): incrementally process edits on markdown files (#5703)
1 parent 5e296be commit 2569bd0

File tree

3 files changed

+59
-5
lines changed

3 files changed

+59
-5
lines changed

packages/cli/cli/versions.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
- changelogEntry:
2+
- summary: |
3+
Improve performance of `fern docs dev` by only reloading the markdown content when
4+
only markdown files are changed, avoiding unnecessary recompilation of the full docs.
5+
6+
type: fix
7+
irVersion: 55
8+
version: 0.50.17
9+
110
- changelogEntry:
211
- summary: |
312
Improve performance of `fern docs dev` by debouncing across edits to multiple files,

packages/cli/docs-preview/src/previewDocs.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { readFile } from "fs/promises";
12
import { v4 as uuidv4 } from "uuid";
23

34
import { DocsDefinitionResolver, filterOssWorkspaces } from "@fern-api/docs-resolver";
@@ -13,27 +14,63 @@ import {
1314
convertDbDocsConfigToRead,
1415
convertDocsDefinitionToDb
1516
} from "@fern-api/fdr-sdk";
16-
import { convertToFernHostAbsoluteFilePath } from "@fern-api/fs-utils";
17+
import { AbsoluteFilePath, convertToFernHostAbsoluteFilePath, relative } from "@fern-api/fs-utils";
1718
import { IntermediateRepresentation } from "@fern-api/ir-sdk";
1819
import { Project } from "@fern-api/project-loader";
1920
import { convertIrToFdrApi } from "@fern-api/register";
2021
import { TaskContext } from "@fern-api/task-context";
2122

23+
import { replaceReferencedMarkdown } from "../../docs-markdown-utils/src";
24+
2225
export async function getPreviewDocsDefinition({
2326
domain,
2427
project,
25-
context
28+
context,
29+
previousDocsDefinition,
30+
editedAbsoluteFilepaths
2631
}: {
2732
domain: string;
2833
project: Project;
2934
context: TaskContext;
35+
previousDocsDefinition?: DocsV1Read.DocsDefinition;
36+
editedAbsoluteFilepaths?: AbsoluteFilePath[];
3037
}): Promise<DocsV1Read.DocsDefinition> {
3138
const docsWorkspace = project.docsWorkspaces;
3239
const apiWorkspaces = project.apiWorkspaces;
3340
if (docsWorkspace == null) {
3441
throw new Error("No docs workspace found in project");
3542
}
3643

44+
if (editedAbsoluteFilepaths != null && previousDocsDefinition != null) {
45+
const allMarkdownFiles = editedAbsoluteFilepaths.every(
46+
(filepath) => filepath.endsWith(".mdx") || filepath.endsWith(".md")
47+
);
48+
for (const absoluteFilePath of editedAbsoluteFilepaths) {
49+
const relativePath = relative(docsWorkspace.absoluteFilePath, absoluteFilePath);
50+
const markdown = (await readFile(absoluteFilePath)).toString();
51+
const processedMarkdown = await replaceReferencedMarkdown({
52+
markdown,
53+
absolutePathToFernFolder: docsWorkspace.absoluteFilePath,
54+
absolutePathToMarkdownFile: absoluteFilePath,
55+
context
56+
});
57+
58+
const previousValue = previousDocsDefinition.pages[FdrAPI.PageId(relativePath)];
59+
if (previousValue == null) {
60+
continue;
61+
}
62+
63+
previousDocsDefinition.pages[FdrAPI.PageId(relativePath)] = {
64+
markdown: processedMarkdown,
65+
editThisPageUrl: previousValue.editThisPageUrl
66+
};
67+
}
68+
69+
if (allMarkdownFiles) {
70+
return previousDocsDefinition;
71+
}
72+
}
73+
3774
const fernWorkspaces = await Promise.all(
3875
apiWorkspaces.map(
3976
async (workspace) =>

packages/cli/docs-preview/src/runPreviewServer.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ export async function runPreviewServer({
126126
let isReloading = false;
127127
const RELOAD_DEBOUNCE_MS = 1000;
128128

129-
const reloadDocsDefinition = async () => {
129+
const reloadDocsDefinition = async (editedAbsoluteFilepaths?: AbsoluteFilePath[]) => {
130130
context.logger.info("Reloading docs...");
131131
const startTime = Date.now();
132132
try {
@@ -136,7 +136,9 @@ export async function runPreviewServer({
136136
const newDocsDefinition = await getPreviewDocsDefinition({
137137
domain: `${instance.host}${instance.pathname}`,
138138
project,
139-
context
139+
context,
140+
previousDocsDefinition: docsDefinition,
141+
editedAbsoluteFilepaths: editedAbsoluteFilepaths
140142
});
141143
context.logger.info(`Reload completed in ${Date.now() - startTime}ms`);
142144
return newDocsDefinition;
@@ -169,6 +171,8 @@ export async function runPreviewServer({
169171
renameDetection: true
170172
});
171173

174+
const editedAbsoluteFilepaths: AbsoluteFilePath[] = [];
175+
172176
// eslint-disable-next-line @typescript-eslint/no-misused-promises
173177
watcher.on("all", async (event: string, targetPath: string, _targetPathNext: string) => {
174178
context.logger.info(chalk.dim(`[${event}] ${targetPath}`));
@@ -178,6 +182,8 @@ export async function runPreviewServer({
178182
return;
179183
}
180184

185+
editedAbsoluteFilepaths.push(AbsoluteFilePath.of(targetPath));
186+
181187
// Clear any existing timer
182188
if (reloadTimer != null) {
183189
clearTimeout(reloadTimer);
@@ -192,11 +198,13 @@ export async function runPreviewServer({
192198
type: "startReload"
193199
});
194200

195-
const reloadedDocsDefinition = await reloadDocsDefinition();
201+
const reloadedDocsDefinition = await reloadDocsDefinition(editedAbsoluteFilepaths);
196202
if (reloadedDocsDefinition != null) {
197203
docsDefinition = reloadedDocsDefinition;
198204
}
199205

206+
editedAbsoluteFilepaths.length = 0;
207+
200208
sendData({
201209
version: 1,
202210
type: "finishReload"

0 commit comments

Comments
 (0)