mirror of
https://github.com/vxcontrol/pentagi.git
synced 2026-09-23 10:45:42 +00:00
refactor(markdown-editor): make the barrel tiptap-free so lazy(MarkdownEditor) is real (L1)
index.ts re-exported the heavy MarkdownEditor value, so any route statically importing
a light util from the barrel (settings-prompt / template import EditorViewModeToggle +
the variable probes) pulled the 527KB tiptap chunk into its eager graph — defeating
their lazy(() => import(MarkdownEditor)). Extract the pure {{ }} helpers (VARIABLE_RE,
variableProbe, findVariableUseRanges) into markdown-editor-variable-syntax.ts (no
tiptap), export only light utils + the erased Handle type from the barrel, and import
MarkdownEditor directly from its module (static in knowledge-form-controls, dynamic in
the two lazy routes). Verified at build-artifact level: settings-prompt/template chunks
now have ZERO static import of the tiptap/markdown-editor chunks — they reference the
editor only via import("./markdown-editor-…"). tsc + lint + build + 831 vitest green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
996fcf49fa
commit
968d5f85d2
@@ -1,5 +1,7 @@
|
||||
export { MarkdownEditor } from './markdown-editor';
|
||||
// Deliberately does NOT re-export the heavy MarkdownEditor value — that would statically pull the tiptap chunk
|
||||
// into any route importing a light util from here, defeating the lazy(MarkdownEditor) in settings-prompt /
|
||||
// template. Import the component directly from './markdown-editor'. Only its type (erased) is safe to re-export.
|
||||
export type { MarkdownEditorHandle } from './markdown-editor';
|
||||
export { findVariableUseRanges, VARIABLE_RE, variableProbe } from './markdown-editor-variable-highlight';
|
||||
export { findVariableUseRanges, VARIABLE_RE, variableProbe } from './markdown-editor-variable-syntax';
|
||||
export { EditorViewModeToggle } from './markdown-editor-view-mode';
|
||||
export type { EditorViewMode } from './markdown-editor-view-mode';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { TAG_RE } from './markdown-editor-tag-highlight';
|
||||
import { findVariableUseRanges, VARIABLE_RE, variableProbe } from './markdown-editor-variable-highlight';
|
||||
import { findVariableUseRanges, VARIABLE_RE, variableProbe } from './markdown-editor-variable-syntax';
|
||||
|
||||
const matches = (re: RegExp, text: string) => [...text.matchAll(re)].map((m) => m[0]);
|
||||
|
||||
|
||||
+3
-24
@@ -5,24 +5,16 @@ import { Plugin, PluginKey } from '@tiptap/pm/state';
|
||||
import { Decoration, DecorationSet } from '@tiptap/pm/view';
|
||||
|
||||
import { collectInlineMatches } from './markdown-editor-inline-scan';
|
||||
import { VARIABLE_RE, variableProbe } from './markdown-editor-variable-syntax';
|
||||
|
||||
// Highlights Go-template actions ({{.Var}}, {{- if .X}}, {{end}}, {{.A | upper}}, …) as VIEW-ONLY
|
||||
// decorations. Decorations never touch the document, so getMarkdown() stays byte-identical, and {{ }}
|
||||
// already round-trips verbatim. A node/mark would gain nothing here and would break the variables
|
||||
// side-panel, which inserts {{.X}} as plain text and finds its uses by scanning, not by node identity.
|
||||
// The pure `{{ }}` matching (VARIABLE_RE / variableProbe / findVariableUseRanges) lives in
|
||||
// markdown-editor-variable-syntax.ts so tiptap-free consumers can use it without the decoration/PM code.
|
||||
const variableHighlightKey = new PluginKey('variableHighlight');
|
||||
|
||||
// `[^{}]` keeps the scan linear (no catastrophic backtracking); Go actions never nest braces.
|
||||
export const VARIABLE_RE = /\{\{[^{}]*\}\}/g;
|
||||
|
||||
const escapeRegExp = (value: string): string => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
|
||||
// Tests whether a single `{{ … }}` block references `variable` (`.Name` on a word boundary). Always used
|
||||
// block-first — extract `{{ … }}` blocks with the linear VARIABLE_RE, THEN probe each — never a lazy
|
||||
// `[^{}]*?` around the name, which backtracks O(n²) on an unclosed `{{`. Shared with settings-prompt.tsx
|
||||
// (panel cycle + count) so the "used" badge and the editor cycle agree on what counts as a use.
|
||||
export const variableProbe = (variable: string): RegExp => new RegExp(`\\.${escapeRegExp(variable)}\\b`);
|
||||
|
||||
const buildDecorations = (doc: PMNode): DecorationSet =>
|
||||
DecorationSet.create(
|
||||
doc,
|
||||
@@ -39,19 +31,6 @@ export const findVariableOccurrences = (doc: PMNode, variable: string): { from:
|
||||
.map(({ from, to }) => ({ from, to }));
|
||||
};
|
||||
|
||||
export const findVariableUseRanges = (value: string, variable: string): { index: number; length: number }[] => {
|
||||
const probe = variableProbe(variable);
|
||||
const ranges: { index: number; length: number }[] = [];
|
||||
|
||||
for (const match of value.matchAll(VARIABLE_RE)) {
|
||||
if (match.index !== undefined && probe.test(match[0])) {
|
||||
ranges.push({ index: match.index, length: match[0].length });
|
||||
}
|
||||
}
|
||||
|
||||
return ranges;
|
||||
};
|
||||
|
||||
export const VariableHighlight = Extension.create({
|
||||
addProseMirrorPlugins() {
|
||||
return [
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// Pure Go-template `{{ … }}` matching — no ProseMirror/tiptap imports, so consumers that only need the
|
||||
// syntax helpers (settings-prompt's variable panel: cycle + "used" count) can pull them without dragging the
|
||||
// editor (and its tiptap chunk) into their eager bundle. The DOM-facing decoration side lives in
|
||||
// markdown-editor-variable-highlight.ts, which reuses VARIABLE_RE / variableProbe from here.
|
||||
|
||||
// `[^{}]` keeps the scan linear (no catastrophic backtracking); Go actions never nest braces.
|
||||
export const VARIABLE_RE = /\{\{[^{}]*\}\}/g;
|
||||
|
||||
const escapeRegExp = (value: string): string => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
|
||||
// Tests whether a single `{{ … }}` block references `variable` (`.Name` on a word boundary). Always used
|
||||
// block-first — extract `{{ … }}` blocks with the linear VARIABLE_RE, THEN probe each — never a lazy
|
||||
// `[^{}]*?` around the name, which backtracks O(n²) on an unclosed `{{`. Shared with settings-prompt.tsx
|
||||
// (panel cycle + count) so the "used" badge and the editor cycle agree on what counts as a use.
|
||||
export const variableProbe = (variable: string): RegExp => new RegExp(`\\.${escapeRegExp(variable)}\\b`);
|
||||
|
||||
export const findVariableUseRanges = (value: string, variable: string): { index: number; length: number }[] => {
|
||||
const probe = variableProbe(variable);
|
||||
const ranges: { index: number; length: number }[] = [];
|
||||
|
||||
for (const match of value.matchAll(VARIABLE_RE)) {
|
||||
if (match.index !== undefined && probe.test(match[0])) {
|
||||
ranges.push({ index: match.index, length: match[0].length });
|
||||
}
|
||||
}
|
||||
|
||||
return ranges;
|
||||
};
|
||||
@@ -5,7 +5,8 @@ import type {
|
||||
KnowledgeGuideType as KnowledgeGuideTypeT,
|
||||
} from '@/graphql/types';
|
||||
|
||||
import { type EditorViewMode, MarkdownEditor } from '@/components/shared/markdown-editor';
|
||||
import { type EditorViewMode } from '@/components/shared/markdown-editor';
|
||||
import { MarkdownEditor } from '@/components/shared/markdown-editor/markdown-editor';
|
||||
import {
|
||||
Autocomplete,
|
||||
AutocompleteContent,
|
||||
|
||||
@@ -98,7 +98,9 @@ import { cn } from '@/lib/utils';
|
||||
|
||||
// Dynamic-only import: a static import would merge the tiptap editor chunk into this route bundle.
|
||||
const MarkdownEditor = lazy(() =>
|
||||
import('@/components/shared/markdown-editor').then((module) => ({ default: module.MarkdownEditor })),
|
||||
import('@/components/shared/markdown-editor/markdown-editor').then((module) => ({
|
||||
default: module.MarkdownEditor,
|
||||
})),
|
||||
);
|
||||
|
||||
const systemFormSchema = z.object({
|
||||
|
||||
@@ -46,7 +46,9 @@ import { cn } from '@/lib/utils';
|
||||
import { type Template, useTemplates } from '@/providers/templates-provider';
|
||||
|
||||
const MarkdownEditor = lazy(() =>
|
||||
import('@/components/shared/markdown-editor').then((module) => ({ default: module.MarkdownEditor })),
|
||||
import('@/components/shared/markdown-editor/markdown-editor').then((module) => ({
|
||||
default: module.MarkdownEditor,
|
||||
})),
|
||||
);
|
||||
|
||||
const formSchema = z.object({
|
||||
|
||||
Reference in New Issue
Block a user