layout: html

本文をそのまま単体の HTML 文書として出力するレイアウト。ヘッダーもフッターも
AppDock もなく、サイトの CSS もフォントも Nuxt のランタイムも一切載らない。
書いた HTML がそのままブラウザに届く。

---
content_id: 01K...
layout: html
visibility: public
---

<style>
  body { margin: 0; background: #000 }
</style>

<canvas id="c" width="800" height="800"></canvas>

<script>
  const c = document.querySelector('#c')
  // …
</script>

何をしているか

server/middleware/html-layout.ts が Nuxt のレンダラより手前で応答する。
page.body(=ブラウザが描画するのと同じ AST)を utils/markdown/renderPageHtml.ts
が HTML 文字列に直列化し、最小限の骨格を被せて返す。アプリのバンドルも
hydration も発生しない。

GET /sketch  →  <!doctype html>
                <html lang="ja">
                <head>
                <meta charset="utf-8">
                <meta name="viewport" content="…">
                <title>Sketch</title>
                <style>…</style>          ← 本文の <style> がここへ上がる
                </head>
                <body>
                <canvas id="c"></canvas>
                <script>…</script>        ← <script> は本文中の位置のまま
                </body>
                </html>

<!doctype html><html><head>… まで含めたフル HTML を書いてもよい。Markdown
パーサは生 HTML をフラグメントとして読むので <html> / <head> / <body>
ラッパは落ち、中身だけがトップレベルに並ぶ。renderPageHtml はそのうち
<title> <meta> <link> <base> <style><head> に引き上げ直す。
<script> だけは引き上げない — 参照する要素より先に走ってしまうため、本文中の
位置を保つ。

charset / viewport / <title> は既定で補われるが、本文が自分で書いていれば
そちらが優先される。draft: false かつ visibility: public でないページには
noindex, nofollow の robots meta が付く(通常ページの pages/singular.vue
同じ規則)。

Markdown もそのまま使える

パイプラインは通常ページとまったく同じなので、# 見出し**強調**
Wikilink も効く。「HTML しか書けない」のではなく「HTML が素通しで通る」レイアウト。

制約

  • インラインイベントハンドラは消える。 onclick= などの on* 属性は MDC の
    パーサ(validateProps)が安全のために剥がす。<script> の中で
    addEventListener を使う。
  • ブロック要素でないタグは <p> に包まれる。 Markdown の HTML ブロック判定は
    CommonMark のタグ一覧に従うので、<canvas><custom-element> を単独行に
    書くと <p><canvas …></canvas></p> になる。リセット CSS が無い分、<p>
    デフォルトマージンがそのまま効く。<div> で包むか、CSS 側で p { margin: 0 }
    を書く。
  • MDC コンポーネントは描画されない。 ::hero:date[…] は Vue
    コンポーネントであり、ここには Vue がいない。<hero> のような不活性なカスタム
    要素として出力される。
  • 公開ページ専用の経路。 バイパスが効くのは visibilitypublic /
    unlisted のページだけ。private / protected はアクセス判定が
    アプリ側にあるので通常の SSR に落ち、記事として表示される。

編集する

素の HTML 文書には AppDock もコマンドパレットもないので、?edit を付けると
同じ URL で通常のアプリに戻れる。

/sketch        → 素の HTML
/sketch?edit   → いつもの Nuxt アプリ(エディタが開ける)

サイト内リンクから layout: html のページへ SPA 遷移した場合は、
pages/singular.vue がブラウザに URL を投げ直して本物のドキュメントリクエストに
切り替える。この再読み込みは「1 タブ・1 パスにつき 1 回」に制限してある
utils/pages/bareHtmlLayout.ts のコメント参照)— まだレプリケーションされて
いないページなど、サーバが応答できないケースでループしないため。