A Progressive Web App (PWA) build of MarkText, the WYSIWYG markdown editor. The web build reuses the renderer (Vue 3 + Muya) from the upstream monorepo and replaces the Electron main process with a browser shim, so the same editor runs at a URL, installs to your device, and works offline.
Live site: https://sloth-os.github.io/marktext/ — published weekly
(every Monday 03:00 UTC) and on every relevant push by
.github/workflows/deploy.yml.
This repository does not fork MarkText's source. Instead, at build time it:
- Clones upstream
marktext/marktext(latestdevelop). - Applies small patches (
patches/):- fixes an upstream CSS
var()typo that trips strict minifiers, - makes muya share a single Prism instance (web bundlers can duplicate prismjs copies across chunks; Electron's single bundle never hits this).
- fixes an upstream CSS
- Overlays
web/overlay/onto the monorepo, adding apackages/webworkspace package that:- compiles the unmodified renderer sources through Vite with the same
aliases the Electron build uses (
@/,common/,@shared/), - provides browser equivalents for everything the renderer expects from
Electron's preload:
window.electron(IPC),window.path,window.fileUtils(Origin Private File System),window.ripgrep(in-browser search),window.i18nUtils, and more — seeweb/overlay/packages/web/src/web-shim/, - implements the
mt::state::*document/session protocol (the main process's state host) on top of OPFS + localStorage.
- compiles the unmodified renderer sources through Vite with the same
aliases the Electron build uses (
- Produces a static
dist/bundle with a service worker (vite-plugin-pwa). - Publishes
dist/to GitHub Pages every week (and on demand).
- Full MarkText editor — WYSIWYG markdown editing, themes, source-code mode, typewriter/focus modes, math (KaTeX), Mermaid/PlantUML diagrams, Prism syntax highlighting, export, preferences.
- PWA — installable app with icons and standalone window.
- Works offline — the service worker precaches the entire app shell (~700 assets); after the first visit no network access is required.
- PWA File Handling — the manifest registers
file_handlersfor.md/.markdown/… files withlaunch_handler: focus-existing: opening a markdown file from the OS launches (or focuses) the app and loads the file into a new tab. Files are imported into OPFS for editing; with the File System Access API the app also keeps live handles soSave/Save Aswrite back to the real file on disk. - Persistent sessions — untitled tabs and opened files live in the browser's OPFS and are restored on the next launch.
- Keyboard shortcuts & menus — the desktop keybinding set runs through a
global handler; the ☰ application menu and right-click context menus are
rendered as HTML menus speaking the same
mt::menu::*protocol. - In-browser search — Quick Open and sidebar search use an OPFS walker speaking the ripgrep event protocol.
# 1. Fetch upstream MarkText into ./marktext
./scripts/fetch-upstream.sh
# 2. Install + patch + build (single command does everything)
./scripts/build-web.sh
# 3. Serve the result
cd marktext/packages/web && pnpm exec vite preview
# or: npx serve marktext/dist
# 4. Run the headless smoke test (app boot, editor, menus, SW, offline)
cd marktext/packages/web && node test/smoke.mjs ../../dist
# Focused regression tests (tab switching / persisted-layout migration)
node test/repro-tab-switch.mjs local ../../dist
node test/migration-check.mjs ../../dist
# Keyboard accelerators (Ctrl+A/C/V, Ctrl+1, Ctrl+K, Ctrl+Shift+P, …)
node test/repro-accelerators.mjs ../../dist
# Long-menu scrolling (overflowed submenus stay open and scrollable)
node test/repro-menu-scroll.mjs ../../distThe tests locate a usable Chromium on their own: the CHROMIUM_EXECUTABLE
env var if set, then Playwright's expected revision if present on disk, then
any chromium-*/chrome-linux*/chrome binary in the Playwright cache.
Requirements: Node.js ≥ 22.12, pnpm ≥ 10 (corepack enable pnpm).
scripts/fetch-upstream.sh clone/update upstream marktext (develop)
scripts/apply-patches.sh idempotent patch + overlay application
scripts/build-web.sh full build pipeline
patches/ upstream patches (unified diffs)
web/overlay/packages/web/ the web package (shim sources, PWA assets, Vite)
src/bootstrap.ts web entry point (installs bridge, boots renderer)
src/web-shim/ browser implementation of the Electron bridge
src/sw.ts custom service worker (offline precache)
test/smoke.mjs headless browser smoke test (boot, editor, menus,
tabs, SW, offline)
test/repro-tab-switch.mjs tab-switch regression test (new tab via menu,
switch back to the old tab, reload restore)
test/migration-check.mjs persisted-layout migration test (pre-fix session
recovers a visible tab bar; deliberate toggles
survive)
test/repro-accelerators.mjs keyboard-accelerator test (Ctrl+A/C/V round-trip,
Ctrl+1 tab switch, Ctrl+K outline, Ctrl+Shift+P
palette, menu Edit actions)
test/repro-menu-scroll.mjs long-menu test (overflowed submenus scroll
without closing; viewport flipping)
.github/workflows/deploy.yml weekly Pages deployment
The workflow runs every Monday 03:00 UTC (and on manual dispatch — optionally
pinning an upstream ref — plus on pushes to main that touch the build):
- Check out upstream MarkText at the requested ref.
- Apply this repo's patches and overlay.
- Install the pnpm workspace and build the web bundle.
- Verify the PWA artifacts (manifest
file_handlers, maskable icons, SW precache) and run the headless smoke test. - Upload
dist/and deploy to GitHub Pages.
The repository needs Pages enabled with the GitHub Actions source (the
first deploy configures this via actions/configure-pages).
MIT — same as upstream MarkText. The deployed bundle includes MarkText's code and its third-party dependencies.