plugin architecture와 command API
plugin을 허용하면 외부 코드가 editor 기능을 확장할 수 있습니다. 대신 document를 직접 망가뜨리지 못하게 경계를 둬야 합니다.
plugin API를 command로 제한하는 코드
plugin에는 document 객체 대신 제한된 command API를 전달합니다.
function createPluginContext(editor: EditorCore): PluginContext {
return {
selection: {
getIds: () => editor.getSnapshot().selection
},
commands: {
insertNode: (node) => editor.dispatch({ type: "insertNode", node, commit: true }),
updateNode: (id, patch) => editor.dispatch({ type: "updateNode", id, patch, commit: true }),
deleteSelection: () => editor.dispatch({ type: "deleteSelection", commit: true })
},
permissions: {
canReadAssets: true,
canNetwork: false
}
};
}
command를 통해 바꾼다
editor.commands.insertNode(node);
editor.commands.updateStyle(nodeId, patch);
editor.commands.deleteSelection();
plugin이 document object를 직접 수정하면 undo/redo, validation, collaboration과 충돌합니다.
plugin command도 validation을 통과시킨다
function dispatchPluginCommand(editor: EditorCore, pluginId: string, command: Command) {
if (!editor.permissions.canRun(pluginId, command.type)) {
throw new Error(`Plugin ${pluginId} cannot run ${command.type}`);
}
const result = editor.dispatch({
...command,
source: "plugin",
pluginId,
commit: true
});
editor.auditLog.push({ pluginId, command: command.type, at: Date.now() });
return result;
}
plugin API는 편의 함수처럼 보여도 내부적으로는 일반 command와 같은 검증, undo 기록, audit log를 지나야 합니다. 그래야 core invariant가 유지됩니다.
오늘의 핵심
plugin API는 기능 확장보다 경계 설계가 먼저입니다. command model 위에 올려야 editor가 유지됩니다.