Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/studio/src/hooks/domEditCommitTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export type PersistDomEditOperations = (
skipRefresh?: boolean;
deferRender?: boolean;
importedFont?: ImportedFontAsset;
prepareContent?: (html: string, sourceFile: string) => string;
shouldSave?: () => boolean;
},
) => Promise<DomEditPersistOutcome | undefined>;
Expand Down
22 changes: 22 additions & 0 deletions packages/studio/src/hooks/useDomEditCommitsHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,25 @@ export async function postPatchElement(
}
return (await response.json()) as PatchElementResponse;
}

export async function writePreparedContent(
targetPath: string,
patchedContent: string,
prepare: (html: string, sourceFile: string) => string,
writeProjectFile: (path: string, content: string, expectedContent?: string) => Promise<void>,
showToast: ShowToast,
): Promise<string> {
const preparedContent = prepare(patchedContent, targetPath);
if (preparedContent === patchedContent) return patchedContent;
try {
await writeProjectFile(targetPath, preparedContent, patchedContent);
return preparedContent;
} catch (error) {
// The patch already landed on disk; keep it rather than revert a committed change.
showToast(
`Saved, but couldn't finish updating ${targetPath}: ${getErrorDetail(error)}`,
"error",
);
return patchedContent;
}
}
25 changes: 19 additions & 6 deletions packages/studio/src/hooks/useDomEditPersist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import {
DomEditPersistUnresolvableError,
warnDomEditPersistNoOp,
} from "./domEditPersistFailure";
import { formatUnsafeFieldList, postPatchElement } from "./useDomEditCommitsHelpers";
import {
formatUnsafeFieldList,
postPatchElement,
writePreparedContent,
} from "./useDomEditCommitsHelpers";
import { importedFontFaceCssFor } from "../utils/studioFontHelpers";
import { countStudioManualEditSave } from "../components/editor/manualEditsDom";
import type { CutoverResult } from "../utils/sdkCutover";
Expand Down Expand Up @@ -108,9 +112,10 @@ export function useDomEditPersist({
});
}

// An imported font takes the server patch, which writes its @font-face with the edit; the SDK
// serializes only the patched DOM. The SDK re-reads in the file queue; this read is its fallback.
if (onTrySdkPersist && !font) {
// An imported font or a prepareContent takes the server patch: the SDK serializes only the
// patched DOM. The SDK re-reads in the file queue; this read is its fallback.
const prepare = options?.prepareContent;
if (onTrySdkPersist && !font && !prepare) {
const originalContent = await readTarget();
if (originalContent === null) return;
const cutover = await onTrySdkPersist(selection, operations, originalContent, targetPath, {
Expand All @@ -134,7 +139,7 @@ export function useDomEditPersist({
coalesceKey: options?.coalesceKey,
coalesceMs: options?.coalesceMs,
};
// Read, server patch and history hold the file's queue, so no save lands between them.
// Read, server patch, follow-up write and history hold the file's queue, so no save lands between them.
const saved = await serializeStudioFileMutations(writeProjectFile, [targetPath], async () => {
const originalContent = await readTarget();
if (originalContent === null) return null;
Expand All @@ -143,7 +148,15 @@ export function useDomEditPersist({

const patchedContent =
typeof patchData.content === "string" ? patchData.content : originalContent;
const finalContent = patchedContent;
const finalContent = prepare
? await writePreparedContent(
targetPath,
patchedContent,
prepare,
writeProjectFile,
showToast,
)
: patchedContent;

await editHistory.recordEdit({
...history,
Expand Down
Loading