Skip to content

Copy and rebase user-declared stylesheets (format.html.css) — bd-format-css-not-copied-crn3bjdz - #538

Open
cscheid wants to merge 6 commits into
mainfrom
bugfix/bd-format-css-not-copied-crn3bjdz
Open

Copy and rebase user-declared stylesheets (format.html.css) — bd-format-css-not-copied-crn3bjdz#538
cscheid wants to merge 6 commits into
mainfrom
bugfix/bd-format-css-not-copied-crn3bjdz

Conversation

@cscheid

@cscheid cscheid commented Aug 14, 2026

Copy link
Copy Markdown
Member

Summary

A website project declaring stylesheets the ordinary way

format:
  html:
    css:
      - styles.css
      - _extensions/acme/widget/widget.css

previously got a <link> to each file on every page while neither file was written into the output tree and the href was emitted verbatim at every page depth — every link 404'd, silently (exit 0, no diagnostic). Real-world impact: all 352 pages of the Posit Connect docs port linked two nonexistent stylesheets.

This PR makes user-declared css a first-class project asset, Q1-parity:

  • Copy: project-relative paths mirror into the output (_site/styles.css); entries under _extensions/ relocate to <lib_dir>/quarto-contrib/quarto-project/** so the _extensions/ tree (manifests, Lua sources, READMEs) never ships. Copies ride the per-page ResourceCopyIntent channel, so websites, default projects/books, and single-doc renders are all covered.
  • Rebase: hrefs are depth-correct per page (styles.css at the root, ../../styles.css two levels down), computed by the per-page ResourceResolverContext.
  • Layer-aware resolution: _quarto.yml entries anchor at the project root, _metadata.yml at its directory, document front matter at the document's own directory; a leading / anchors at the site root. Provenance is captured by existence-driven Path-kind marking inside the metadata merge (the same seam Q1's toInputRelativePaths uses), while emission stays resolver-driven.
  • Revealjs: user css: was previously dropped entirely on reveal decks (not even a broken link); the resolved list is now appended after the vendored deck assets.
  • Diagnostic: a missing declared stylesheet warns with new code Q-5-29 (catalog entry + docs page included) — once per render for project-config entries, per document for front-matter entries. The broken link is still emitted (favicon posture), and external URLs pass through untouched.
  • Q-5-29 emission is native-only: the WASM preview leg probes the VFS, which is not authoritative for non-qmd files, and produced false warnings in the preview overlay before the gate.

Design + evidence trail: claude-notes/plans/2026-08-14-format-css-not-copied.md (includes the quarto-cli study of the quarto-contrib/quarto-project layout rationale and the q2 asset-boundary audit).

One deliberate Q1 divergence: Q1 relocates _extensions/ css only for website/book projects and mirrors it verbatim for default-type projects; q2 relocates uniformly, so bundled extension css also survives a separate output-dir in default projects.

Follow-ups filed (discovered-from): bd-b3oq2fsy (preview does not apply user css — VFS-mode no-op), bd-dxp854dw (css url()/@import chasing), bd-ptb0v2lk (format-resources accepted but never consumed).

Test plan

  • 9 new end-to-end integration tests (crates/quarto-core/tests/integration/format_css.rs) driving ProjectPipeline / render_to_file, written first and verified failing at HEAD: copy, per-depth hrefs, quarto-contrib relocation, doc-relative front-matter css, Q-5-29 + render-continues, external-URL passthrough, default-project coverage, revealjs linking, theme-before-user-css ordering.
  • 6 unit tests for the marking helper (scalar/array/URL/rooted/!path cases).
  • Full cargo xtask verify green (all legs, incl. WASM); workspace suite 12182 passed.
  • End-to-end through the real binary on two fixtures (in-repo + the Connect docs repro): output matches Q1's expected table exactly; q2 preview exercised in a real browser session (no warning overlay; page renders).
  • No snapshot (.snap) changes. One smoke-all fixture expectation updated (extensions/format-with-theme): bundled extension css now links at its relocated quarto-contrib path and is actually copied.

🤖 Generated with Claude Code

cscheid and others added 6 commits August 14, 2026 16:01
…r copied nor rebased

Plan skeleton + minimal repro fixture. Both defects confirmed at HEAD
(10d8682): declared css files never written to _site, hrefs emitted
verbatim at every page depth beside correctly-rebased site_libs links,
no diagnostic. Verdict: ready to design; open questions on output
layout (Q1 site_libs/quarto-contrib parity vs project-relative copy),
rebase mechanism (Path-kind metadata marking vs resource resolver),
and scope (books, js/format-resources, doc-level css).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Record user design decisions; add Q1 (quarto-cli) evidence for the
site_libs/quarto-contrib/quarto-project relocation rationale and the
metadata-time rebase mechanism (toInputRelativePaths); add q2 boundary
audit (revealjs drops user css entirely; format-resources accepted but
never consumed; books use DefaultProjectType with no post-render).
Propose hybrid mechanism (merge-time Path marking + render-time
resolver transform); four follow-up questions (F1-F4) pending.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… filed

F1 hybrid mechanism approved (merge-time Path marking + render-time
resolver transform); F2 revealjs user-css drop fixed in-strand; F3
css url() chasing filed as bd-dxp854dw (p2); F4 format-resources
no-op filed as bd-ptb0v2lk (p2). Ready to implement on go-ahead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…opied-crn3bjdz)

User-declared stylesheets (format.html.css / document css:) are now
copied into the output tree and linked with depth-correct per-page
hrefs, Q1-parity:

- project-relative paths mirror into the output (_site/styles.css);
- _extensions/** entries relocate to
  <lib_dir>/quarto-contrib/quarto-project/** so the _extensions tree
  never ships (manifests, Lua sources, READMEs stay out);
- document front-matter css: resolves against the document's own
  directory; a leading / anchors at the project root;
- external URLs pass through verbatim;
- revealjs decks now link user css (previously dropped entirely);
- missing files warn with new code Q-5-29 (catalog + docs page):
  once per project render for _quarto.yml entries, per document for
  front-matter entries; the broken link is still emitted.

Mechanism (per the plan's settled design): existence-driven per-layer
Path-kind marking in MetadataMergeStage (project/format_css.rs)
+ a Normalization-phase FormatCssTransform that pushes
ResourceCopyIntents and rewrites entries to resolver-computed hrefs.
Works for websites, default projects/books, and single-doc renders;
VFS/preview mode deliberately untouched (Phase 4 follow-up).

Snapshot note: no .snap files changed. One smoke-all fixture
expectation updated (extensions/format-with-theme): bundled extension
css now links at its relocated quarto-contrib path instead of the
in-source _extensions path — and is actually copied, so it survives
a separate output-dir.

Tests: 9 new end-to-end integration tests (format_css.rs, written
first and verified failing at HEAD), 6 unit tests; full workspace
suite green (12182 passed).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…bjdz)

The WASM preview/hub leg runs the same orchestrator and metadata
merge, but its runtime probes the VFS — which is not authoritative
for non-qmd project files. A stylesheet that exists on disk but is
not synced produced a false 'Q-5-29 css refers to missing file'
warning in the preview overlay (observed in a real browser session
against q2 preview). Emit the missing-css diagnostics only in native
renders, where the output tree is real.

Verified in the browser after rebuilding the WASM -> SPA -> q2
chain: the preview renders the fixture with no warning overlay.
Preview still does not APPLY user css (VFS-mode transform no-op,
per the settled design) — filed as bd-b3oq2fsy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@posit-snyk-bot

posit-snyk-bot commented Aug 14, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants