Frontage for VS Code
What an editor knows about html(t"…").
Inside a template string every other tool is blind — to a type checker it is one opaque
str — so this is where the markup gets completed, documented and checked.
What it does
- Diagnostics. The four things a template enforces and a type checker cannot see, because
to it the whole template is one opaque
str: a lambda in a template string's braces (name
the function — it reads better in a hole), html(f"…") where a t-string was meant, HTML the
browser's parser rewrites — a block element inside <p>, a <tr> straight under <table>,
an <a> inside an <a> — and an <img> with no alt. The rewriting one is why a
prerendered page fails to hydrate, and until now it was only ever discovered as a blank
screen.
- Completion. Elements, attributes per element, and frontage's own prefixes first:
on:, oncapture:, prop:, class:, style:, bind:, attr: and ref. Inside on:
it lists events, inside bind: the three targets, inside style: CSS properties. </
closes the innermost open element.
- Hover on an element, an attribute, a prefix, and on frontage's own names in the Python
around the template.
- Go to definition on a component named inside
{…} — the one position a Python
language server cannot reach, because as far as it is concerned that name is a character
in a string.
- Highlighting, twice over: a TextMate injection grammar so markup is coloured before the
server starts, and semantic tokens from the server, which knows exactly where a hole ends.
- Commands for
check, serve, build, prerender, site and tailwind.
It stays out of Python's territory: no syntax errors, no completions for your own variables,
nothing a type checker already says. Run it alongside Pylance or Pyright, not instead.
Settings
|
|
frontage.enable |
Run the server at all. |
frontage.server.command |
How to start it. Empty means the workspace's .venv if it has frontage, else uvx --python 3.14 frontage lsp. |
frontage.python |
A Python 3.14 interpreter to run it with. |
frontage.trace.server |
Log the traffic, for when something is wrong. |
Nothing to install
With no setting and no workspace .venv, the server runs through uvx, which fetches the
published frontage without installing anything — so uv is the one thing that has to be
there, and if it is not, the extension installs it, with uv's own installer and without
asking. It is a prerequisite, not a choice: someone opening their first app.py cannot tell
a missing dependency from a broken extension, and a dialog about a package manager is not
what they came here to learn. uv installs into your own home (~/.local/bin), touches
nothing system-wide and needs no privileges. Only if that fails — offline, or a machine that
does not allow it — do you get a message, with the command to run by hand.
uv is also looked for where the installer puts it — ~/.local/bin, ~/.cargo/bin,
$UV_INSTALL_DIR, $XDG_BIN_HOME — and not only on PATH, then spawned by absolute path. A
VS Code started from the dock inherits a PATH that usually has none of those in it, so a
machine with uv on it otherwise presents as a machine without, and would be sent through an
install it does not need.
Python 3.14 matters: template strings do not parse below it, so two of the four checks
cannot fire. The server says so on connect rather than going quiet.
Building it
npm install
npm run package # frontage-<version>.vsix
The extension lives in the framework's own repository, at editors/vscode/, so the commit
that changes a template rule changes the editor's understanding of it in the same diff.