1. Tổng quan hệ thống (System Overview)
Dự án Leandix Editor là một VS Code Custom Editor Extension. Hệ thống cho phép mở, xem và soạn thảo trực quan tệp Microsoft Word (.docx) và tệp PDF (.pdf) ngay trong cửa sổ làm việc của VS Code.
Do giới hạn bảo mật và kiến trúc của VS Code, hệ thống được phân tách thành hai tiến trình độc lập:
- Extension Host (Node.js Context): Chạy ở backend của VS Code, có quyền đọc/ghi tệp từ hệ thống đĩa, giao tiếp trực tiếp với VS Code APIs.
- Webview (Chromium Browser Context): Chạy trong môi trường sandbox an toàn để hiển thị giao diện soạn thảo Tiptap/React hoặc xem PDF mà không ảnh hưởng tới tiến trình chính của VS Code.
2. Mô hình phân lớp kiến trúc (Architectural Layers)
Dưới đây là sơ đồ phân khối kiến trúc của toàn bộ dự án. Sơ đồ này được vẽ ở cấu hình trang ngang (Left-to-Right) để tận dụng tối đa chiều rộng màn hình:
graph LR
%% Môi trường Node.js (Extension Host)
subgraph ExtensionHost["Extension Host (Node.js Context)"]
ext_entry["extension.ts (Activation)"]
ed_provider["LeandixEditorProvider.ts
(Custom Editor Lifecycle)"]
pdf_provider["PdfViewerProvider.ts
(PDF Viewer Provider)"]
doc_mgr["DocumentManager.ts
(File Watcher & Cache)"]
docx_parser["DocxParser.ts
(DOCX XML → HTML Converter)"]
docx_ser["DocxSerializer.ts
(HTML → DOCX Converter)"]
pdf_print["Headless Chrome / Edge
(PDF Exporter)"]
end
%% Môi trường Webview (Frontend)
subgraph WebviewContext["Webview Sandbox (Chromium Context)"]
subgraph EditorWebview["DOCX Editor Webview (React 19)"]
app_editor["App.tsx (State & Panel Coordinator)"]
tiptap["TiptapEditor.tsx (ProseMirror Core)"]
ruler["Ruler.tsx (Indent & Margin Guides)"]
comments["CommentsPanel.tsx (Threaded Comments)"]
exts["Tiptap Extensions (Image, Table, Fonts)"]
end
subgraph PdfWebview["PDF Viewer Webview (React 19)"]
app_pdf["PdfViewerApp.tsx"]
pdf_viewport["PdfViewport.tsx (PDF.js Render)"]
end
end
%% Khối dùng chung
subgraph SharedLib["src/shared/"]
types["types.ts"]
constants["constants.ts"]
page_utils["pageUtils.ts"]
end
%% Luồng giao tiếp và phụ thuộc
ext_entry --> ed_provider
ext_entry --> pdf_provider
ed_provider --> doc_mgr
ed_provider --> docx_parser
ed_provider --> docx_ser
ed_provider --> pdf_print
%% Phụ thuộc thư viện
docx_ser --> docx_lib["docx (npm package)"]
docx_parser --> mammoth_lib["mammoth.js (npm package)"]
pdf_viewport --> pdfjs_lib["pdfjs-dist (PDF.js)"]
%% IPC Bridge
ed_provider <-->|VS Code Webview Message API| app_editor
pdf_provider <-->|VS Code Webview Message API| app_pdf
%% Phụ thuộc Shared
ExtensionHost -.-> SharedLib
WebviewContext -.-> SharedLib
🔑 Chú thích Ký hiệu Sơ đồ Kiến trúc:
➡️ Mũi tên đơn liền (Solid Arrow): Mối quan hệ gọi hàm trực tiếp (Method Call) hoặc phụ thuộc bắt buộc (Code Dependency).
↔️ Mũi tên hai chiều (Double Arrow): Cầu nối giao tiếp hai chiều không đồng bộ (Asynchronous IPC Bridge) thông qua postMessage API của VS Code.
⤏ Mũi tên đứt nét (Dotted Arrow): Quan hệ tham chiếu/dùng chung kiểu dữ liệu tĩnh (Type Imports) từ thư viện
src/shared/.
3. Chi tiết vai trò các cấu phần chính
3.1. Phân khu Extension Host (src/extension/)
- extension.ts: Khởi tạo mở rộng, đăng ký cấu hình kích hoạt.
- LeandixEditorProvider.ts: Quản lý trạng thái Custom Document, phối hợp lưu/phục hồi file, xử lý sao lưu tự động khi crash (backup).
- DocxParser.ts: Đọc ZIP/XML nhị phân của tệp
.docx, chuyển ngữ định dạng sang HTML để truyền sang cho Webview. - DocxSerializer.ts: Dựng ngược cây HTML DOM nhận từ Webview sang XML tương thích định dạng Microsoft Word.
- PdfViewerProvider.ts: Cấp phát mảng byte nhị phân của tệp PDF sang cho ứng dụng Viewer và xử lý hiển thị hộp thoại hỏi mật khẩu tệp.
3.2. Phân khu Editor Webview (src/webview/)
- App.tsx: Trọng tâm thu thập trạng thái giao diện, bắt các sự kiện chỉnh sửa thước kẻ, thay đổi khổ giấy, thêm bình luận.
- TiptapEditor.tsx: Khởi tạo ProseMirror Engine, tích hợp các bộ phím tắt và chức năng chỉnh sửa.
- extensions/: Thư mục chứa các plugin mở rộng tùy chỉnh (Custom Image với
data-wrap-mode, căn lề thước kẻ, co dãn kích thước bảng).
3.3. Phân khu PDF Viewer Webview (src/pdf-webview/)
- Sử dụng thư viện PDF.js (pdfjs-dist) để vẽ trực tiếp dữ liệu nhị phân PDF lên các thẻ Canvas trình duyệt.
- Hỗ trợ bôi đen, copy và tìm kiếm chữ nhờ việc phủ một lớp
TextLayertrong suốt nằm đè lên các trang Canvas vẽ đồ họa.
4. Các giao thức dữ liệu (Data Contracts)
Hai tiến trình trao đổi thông tin chặt chẽ qua các định nghĩa kiểu dữ liệu thống nhất tại src/shared/types.ts:
- Trạng thái ảnh và wrapMode: Sử dụng thuộc tính chuẩn hóa
data-wrap-modetrên ảnh để chuyển đổi qua lại giữa thẻ<img>nổi trong HTML và cấu trúc neo văn bản Word XML (wp:anchor). - Kích thước trang và lề trang (PageSettings): Backend tính toán bằng đơn vị Twips để ghi file Word chuẩn xác, trong khi Frontend tính bằng Pixels (qua tỷ lệ quy đổi 96 DPI) để đảm bảo thước kẻ vẽ khớp với lề trang hiển thị thực tế trên màn hình.