Architecture
This page uses one overview diagram to show NanoMD's three components, the conversion pipeline they share, and how the source is layered.
System Overview
graph LR
User[User input] --> Editor[MDEditor]
Editor -->|"init() triggers re-render"| Viewer[MDViewer]
Viewer -->|"reads each editor row"| Editor
Viewer -->|Markdown| Trans["transToHTML()"]
Parser[MDParser] -->|Markdown| Trans
Editor -->|"download('html')"| Trans
Trans -->|HTML string| Viewer
Trans -->|HTML string| Parser
Trans --> Funcs["set* transform functions<br/>src/function/"]
None of the three components parses Markdown itself; all of them call the same transToHTML(). Only the arguments differ: MDViewer passes the hashtag path and target and always uses the extended syntax; MDParser passes its standard flag; MDEditor calls it only when exporting HTML.
Layers
| Layer | Location | Responsibility |
|---|---|---|
| Public classes | src/model/editor.js, viewer.js, parser.js |
Public API; attached to window.MDEditor / MDViewer / MDParser |
| Editor sub-modules | src/model/editorCaret.js, editorSelection.js, editorHistory.js, editorKeydown.js, editorTab.js |
Caret, selection range, undo stack, shortcut mapping, toolbar |
| Virtual DOM | src/model/vDOM.js |
Old/new node tree comparison; the viewer currently replaces content with replaceChildren(), so the diff is not active |
| Transform functions | src/function/set*.js, transToHTML.js |
One function per syntax, run in a fixed order |
| Shared constants | src/data.js |
Regexes, string constants, CDN resource injection, isDarkMode |
| Styles | src/sass/ → dist/NanoMD.css, dist/NanoMD-output.css |
Editor/viewer styles and the stylesheet for exported HTML |
Cross-cutting Principles
| Principle | How it shows |
|---|---|
| No framework | Native DOM APIs only; createElement() is an in-house lightweight builder |
| Single conversion entry | All HTML comes from transToHTML(), so syntax behaves the same in all three components (except for the standard flag) |
| Placeholder isolation | Converted fragments become {{tag-uuid}} so later steps do not re-parse them; they are restored once at the end |
| Global build | terser concatenates src/**/*.js into one script, so functions and constants share a single script scope |
Further Reading
- Parsing Pipeline: the step order inside
transToHTML() - Rendering and Sync: when and how the viewer re-renders
- Full architecture document: per-module diagrams, event sequence, vDOM state machine