lots of improvements

This commit is contained in:
Fred K. Schott 2021-03-21 00:44:42 -07:00
parent 2082001ff8
commit 417657f138
31 changed files with 514 additions and 476 deletions

View file

@ -1,5 +1,4 @@
<Component> <section class="grid-banner">
<section class="grid-banner">
<div class="notification"> <div class="notification">
<div class="container"> <div class="container">
Snowpack 3.0 is out now! Snowpack 3.0 is out now!
@ -8,5 +7,4 @@
</a> </a>
</div> </div>
</div> </div>
</section> </section>
</Component>

View file

@ -1,5 +1,4 @@
<Component> <div class="hero">
<div class="hero">
<div class="section"> <div class="section">
<h1 class="header-snowpack">Snowpack</h1> <h1 class="header-snowpack">Snowpack</h1>
<p class="header-snowpack-subtitle">The faster frontend build tool.</p> <p class="header-snowpack-subtitle">The faster frontend build tool.</p>
@ -10,8 +9,12 @@
<button id="copy-button" class="copy-button hidden-mobile" data-clipboard-text="npm install snowpack"> <button id="copy-button" class="copy-button hidden-mobile" data-clipboard-text="npm install snowpack">
<span class="faded" style="margin-right: 0.75rem;">$</span> <span class="faded" style="margin-right: 0.75rem;">$</span>
<span id="copy-button-text">npm install snowpack</span> <span id="copy-button-text">npm install snowpack</span>
<svg style="height: 22px;width: 22px;margin: -0.1rem -0.1rem 0 0.75rem;" aria-hidden="true" focusable="false" data-prefix="far" data-icon="clone" class="svg-inline--fa fa-clone fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 512 512"> <svg style="height: 22px;width: 22px;margin: -0.1rem -0.1rem 0 0.75rem;" aria-hidden="true" focusable="false"
<path fill="currentColor" d="M464 0H144c-26.51 0-48 21.49-48 48v48H48c-26.51 0-48 21.49-48 48v320c0 26.51 21.49 48 48 48h320c26.51 0 48-21.49 48-48v-48h48c26.51 0 48-21.49 48-48V48c0-26.51-21.49-48-48-48zM362 464H54a6 6 0 0 1-6-6V150a6 6 0 0 1 6-6h42v224c0 26.51 21.49 48 48 48h224v42a6 6 0 0 1-6 6zm96-96H150a6 6 0 0 1-6-6V54a6 6 0 0 1 6-6h308a6 6 0 0 1 6 6v308a6 6 0 0 1-6 6z"></path> data-prefix="far" data-icon="clone" class="svg-inline--fa fa-clone fa-w-16" role="img"
xmlns="http://www.w3.org/2000/svg" viewbox="0 0 512 512">
<path fill="currentColor"
d="M464 0H144c-26.51 0-48 21.49-48 48v48H48c-26.51 0-48 21.49-48 48v320c0 26.51 21.49 48 48 48h320c26.51 0 48-21.49 48-48v-48h48c26.51 0 48-21.49 48-48V48c0-26.51-21.49-48-48-48zM362 464H54a6 6 0 0 1-6-6V150a6 6 0 0 1 6-6h42v224c0 26.51 21.49 48 48 48h224v42a6 6 0 0 1-6 6zm96-96H150a6 6 0 0 1-6-6V54a6 6 0 0 1 6-6h308a6 6 0 0 1 6 6v308a6 6 0 0 1-6 6z">
</path>
</svg> </svg>
</button> </button>
<script type="module"> <script type="module">
@ -22,7 +25,7 @@
document.getElementById('copy-button').style.minWidth = document.getElementById('copy-button').offsetWidth; document.getElementById('copy-button').style.minWidth = document.getElementById('copy-button').offsetWidth;
console.info('Trigger:', e); console.info('Trigger:', e);
document.getElementById('copy-button').innerHTML = '<span>copied to clipboard!</span>'; document.getElementById('copy-button').innerHTML = '<span>copied to clipboard!</span>';
document.getElementById('copy-button').addEventListener("mouseleave", function( event ) { document.getElementById('copy-button').addEventListener("mouseleave", function (event) {
document.getElementById('copy-button').innerHTML = copyText; document.getElementById('copy-button').innerHTML = copyText;
}, false); }, false);
@ -39,9 +42,9 @@
<div class="hero-cta"> <div class="hero-cta">
<!-- Place this tag where you want the button to render. --> <!-- Place this tag where you want the button to render. -->
<div class="hidden-mobile" style="text-align: center; height: 36px;"> <div class="hidden-mobile" style="text-align: center; height: 36px;">
<a class="github-button" href="https://github.com/snowpackjs/snowpack" data-icon="octicon-star" data-size="large" data-show-count="true" aria-label="Star snowpackjs/snowpack on GitHub">Star</a > <a class="github-button" href="https://github.com/snowpackjs/snowpack" data-icon="octicon-star"
data-size="large" data-show-count="true" aria-label="Star snowpackjs/snowpack on GitHub">Star</a>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</Component>

View file

@ -1,4 +1,3 @@
<Component>
<nav class="snow-toc"> <nav class="snow-toc">
<ol class="snow-toc-contents"> <ol class="snow-toc-contents">
<li class="snow-toc-section"> <li class="snow-toc-section">
@ -83,4 +82,3 @@
</li> </li>
</ol> </ol>
</nav> </nav>
</Component>

View file

@ -1,21 +1,27 @@
<Component>
<nav class="snow-nav"> <nav class="snow-nav">
<button id="toc-drawer-button" class="snow-nav-mobile-open" type="button" aria-expanded="false" aria-controls="nav-primary"> <button id="toc-drawer-button" class="snow-nav-mobile-open" type="button" aria-expanded="false"
aria-controls="nav-primary">
<svg focusable="false" class="snow-icon" role="img" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 448 512"> <svg focusable="false" class="snow-icon" role="img" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 448 512">
<title>Toggle mobile menu</title> <title>Toggle mobile menu</title>
<path d="M16 132h416c8.837 0 16-7.163 16-16V76c0-8.837-7.163-16-16-16H16C7.163 60 0 67.163 0 76v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16z"></path> <path
d="M16 132h416c8.837 0 16-7.163 16-16V76c0-8.837-7.163-16-16-16H16C7.163 60 0 67.163 0 76v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16z">
</path>
</svg> </svg>
</button> </button>
<a class="snow-nav-logo snow-logo" href="/"> <a class="snow-nav-logo snow-logo" href="/">
<svg class="snow-logo-icon" viewbox="0 0 640 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <svg class="snow-logo-icon" viewbox="0 0 640 512" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<g transform="translate(-1.000000, 0.000000)" fill-rule="nonzero"> <g transform="translate(-1.000000, 0.000000)" fill-rule="nonzero">
<path d="M635.92,462.7 L347.92,14.7 C342.03,5.54 331.89,0 321,0 C310.11,0 299.97,5.54 294.08,14.7 L6.08,462.7 C-0.250773249,472.547007 -0.699487627,485.064987 4.91,495.34 C10.522069,505.612419 21.2945349,512 33,512 L609,512 C620.71,512 631.48,505.61 637.09,495.33 C642.699457,485.058495 642.250708,472.543372 635.92,462.7 Z M321,91.18 L406.39,224 L321,224 L257,288 L218.94,249.94 L321,91.18 Z" id="Shape"></path> <path
d="M635.92,462.7 L347.92,14.7 C342.03,5.54 331.89,0 321,0 C310.11,0 299.97,5.54 294.08,14.7 L6.08,462.7 C-0.250773249,472.547007 -0.699487627,485.064987 4.91,495.34 C10.522069,505.612419 21.2945349,512 33,512 L609,512 C620.71,512 631.48,505.61 637.09,495.33 C642.699457,485.058495 642.250708,472.543372 635.92,462.7 Z M321,91.18 L406.39,224 L321,224 L257,288 L218.94,249.94 L321,91.18 Z"
id="Shape"></path>
</g> </g>
</svg> </svg>
<span class="snow-logo-type">Snowpack</span> <span class="snow-logo-type">Snowpack</span>
</a> </a>
<div class="search-form"> <div class="search-form">
<input type="text" name="search" placeholder="Search documentation..." class="search-form-input" id="search-form-input"> <input type="text" name="search" placeholder="Search documentation..." class="search-form-input"
id="search-form-input">
<span class="search-form-hint"> <span class="search-form-hint">
<span class="sr-only">Press </span> <span class="sr-only">Press </span>
<kbd class="font-sans"><abbr title="Command" style="text-decoration: none;">⌘</abbr></kbd> <kbd class="font-sans"><abbr title="Command" style="text-decoration: none;">⌘</abbr></kbd>
@ -29,20 +35,32 @@
{`v${props.version}`} {`v${props.version}`}
</a> </a>
<a href="https://github.com/snowpackjs/snowpack" target="_blank" class="snow-nav-link snow-nav-link__desktop"> <a href="https://github.com/snowpackjs/snowpack" target="_blank" class="snow-nav-link snow-nav-link__desktop">
<svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="github" class="snow-icon" role="img" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 496 512"> <svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="github" class="snow-icon" role="img"
<path fill="currentColor" d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"></path> xmlns="http://www.w3.org/2000/svg" viewbox="0 0 496 512">
<path fill="currentColor"
d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z">
</path>
</svg> </svg>
</a> </a>
<a href="https://twitter.com/snowpackjs" target="_blank" class="snow-nav-link snow-nav-link__desktop"> <a href="https://twitter.com/snowpackjs" target="_blank" class="snow-nav-link snow-nav-link__desktop">
<svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="twitter" class="snow-icon" role="img" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 512 512"> <svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="twitter" class="snow-icon" role="img"
<path fill="currentColor" d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"></path> xmlns="http://www.w3.org/2000/svg" viewbox="0 0 512 512">
<path fill="currentColor"
d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z">
</path>
</svg> </svg>
</a> </a>
<a href="https://discord.gg/snowpack" target="_blank" class="snow-nav-link snow-nav-link__desktop"> <a href="https://discord.gg/snowpack" target="_blank" class="snow-nav-link snow-nav-link__desktop">
<svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="discord" class="snow-icon" role="img" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 210 240"><path d="M84.79 90.45c-6.45 0-11.55 5.66-11.55 12.57s5.21 12.57 11.55 12.57c6.45 0 11.55-5.66 11.55-12.57.11-6.91-5.09-12.57-11.55-12.57zm41.32 0c-6.45 0-11.55 5.66-11.55 12.57s5.21 12.57 11.55 12.57c6.45 0 11.55-5.66 11.55-12.57s-5.09-12.57-11.55-12.57z"/><path fill="currentColor" d="M185.4 0H24.6C11.04 0 0 11.04 0 24.72v162.24c0 13.68 11.04 24.72 24.6 24.72h136.08l-6.36-22.2 15.36 14.28 14.52 13.44L210 240V24.72C210 11.04 198.96 0 185.4 0zm-46.32 156.72s-4.32-5.16-7.92-9.72c15.72-4.44 21.72-14.28 21.72-14.28-4.92 3.24-9.6 5.52-13.8 7.08-6 2.52-11.76 4.2-17.4 5.16-11.52 2.16-22.08 1.56-31.08-.12-6.84-1.32-12.72-3.24-17.64-5.16-2.76-1.08-5.76-2.4-8.76-4.08-.36-.24-.72-.36-1.08-.6-.24-.12-.36-.24-.48-.36-2.16-1.2-3.36-2.04-3.36-2.04s5.76 9.6 21 14.16c-3.6 4.56-8.04 9.96-8.04 9.96-26.52-.84-36.6-18.24-36.6-18.24 0-38.64 17.28-69.96 17.28-69.96 17.28-12.96 33.72-12.6 33.72-12.6l1.2 1.44c-21.6 6.24-31.56 15.72-31.56 15.72s2.64-1.44 7.08-3.48c12.84-5.64 23.04-7.2 27.24-7.56.72-.12 1.32-.24 2.04-.24 7.32-.96 15.6-1.2 24.24-.24 11.4 1.32 23.64 4.68 36.12 11.52 0 0-9.48-9-29.88-15.24l1.68-1.92s16.44-.36 33.72 12.6c0 0 17.28 31.32 17.28 69.96 0 0-10.2 17.4-36.72 18.24z"/></svg> <svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="discord" class="snow-icon" role="img"
xmlns="http://www.w3.org/2000/svg" viewbox="0 0 210 240">
<path
d="M84.79 90.45c-6.45 0-11.55 5.66-11.55 12.57s5.21 12.57 11.55 12.57c6.45 0 11.55-5.66 11.55-12.57.11-6.91-5.09-12.57-11.55-12.57zm41.32 0c-6.45 0-11.55 5.66-11.55 12.57s5.21 12.57 11.55 12.57c6.45 0 11.55-5.66 11.55-12.57s-5.09-12.57-11.55-12.57z" />
<path fill="currentColor"
d="M185.4 0H24.6C11.04 0 0 11.04 0 24.72v162.24c0 13.68 11.04 24.72 24.6 24.72h136.08l-6.36-22.2 15.36 14.28 14.52 13.44L210 240V24.72C210 11.04 198.96 0 185.4 0zm-46.32 156.72s-4.32-5.16-7.92-9.72c15.72-4.44 21.72-14.28 21.72-14.28-4.92 3.24-9.6 5.52-13.8 7.08-6 2.52-11.76 4.2-17.4 5.16-11.52 2.16-22.08 1.56-31.08-.12-6.84-1.32-12.72-3.24-17.64-5.16-2.76-1.08-5.76-2.4-8.76-4.08-.36-.24-.72-.36-1.08-.6-.24-.12-.36-.24-.48-.36-2.16-1.2-3.36-2.04-3.36-2.04s5.76 9.6 21 14.16c-3.6 4.56-8.04 9.96-8.04 9.96-26.52-.84-36.6-18.24-36.6-18.24 0-38.64 17.28-69.96 17.28-69.96 17.28-12.96 33.72-12.6 33.72-12.6l1.2 1.44c-21.6 6.24-31.56 15.72-31.56 15.72s2.64-1.44 7.08-3.48c12.84-5.64 23.04-7.2 27.24-7.56.72-.12 1.32-.24 2.04-.24 7.32-.96 15.6-1.2 24.24-.24 11.4 1.32 23.64 4.68 36.12 11.52 0 0-9.48-9-29.88-15.24l1.68-1.92s16.44-.36 33.72 12.6c0 0 17.28 31.32 17.28 69.96 0 0-10.2 17.4-36.72 18.24z" />
</svg>
</a> </a>
</nav> </nav>
<script> <script>
function handleMobileNav(evt) { function handleMobileNav(evt) {
evt.preventDefault(); evt.preventDefault();
/*If hidden-mobile class is enabled that means we are on desktop do overflow normal but we /*If hidden-mobile class is enabled that means we are on desktop do overflow normal but we
@ -89,4 +107,3 @@
apiKey: '562139304880b94536fc53f5d65c5c19', indexName: 'snowpack', inputSelector: '.search-form-input', debug: true // Set debug to true if you want to inspect the dropdown apiKey: '562139304880b94536fc53f5d65c5c19', indexName: 'snowpack', inputSelector: '.search-form-input', debug: true // Set debug to true if you want to inspect the dropdown
}); });
</script> </script>
</Component>

View file

@ -1,19 +1,21 @@
<Component> <script type="module" defer src="/js/index.js"></script>
<script type="module" defer src="/js/index.js"></script> <aside class="snow-toc snow-toc__subnav snow-view-subnav">
<aside class="snow-toc snow-toc__subnav snow-view-subnav">
<h2 class="content-title"> <h2 class="content-title">
{props.title} {props.title}
</h2> </h2>
{props.headers.length > 0 && <div>
<h4 class="snow-toc-section-header">On this page</h4> <h4 class="snow-toc-section-header">On this page</h4>
<nav class="toc"> <nav class="toc">
<ol> <ol>
{props.headings.map((heading) => { {props.headers.map((heading) => {
return <li><a href={heading.url}>{heading.text}</a></li> return <li><a href={"#" + heading.slug}>{heading.text}</a></li>
})} })}
</ol> </ol>
</nav> </nav>
<hr /> <hr />
</div>}
<h4 class="snow-toc-section-header">Suggest a change</h4> <h4 class="snow-toc-section-header">Suggest a change</h4>
<a href="https://github.com/snowpackjs/snowpack/blob/main/www/{props.inputPath}">Edit this page on GitHub</a> <a href="https://github.com/snowpackjs/snowpack/blob/main/www/{props.inputPath}">Edit this page on GitHub</a>
</aside> </aside>
</Component>

View file

@ -1,56 +1,56 @@
<script hmx="setup"> <script astro>
import Banner from '../components/Banner.hmx'; import Banner from '../components/Banner.hmx';
import Nav from '../components/Nav.hmx'; import Nav from '../components/Nav.hmx';
export function setup() { export function setup({ context }) {
return { return {
context: {
title: 'Snowpack', title: 'Snowpack',
description: 'Snowpack is a lightning-fast frontend build tool, designed for the modern web.', description: 'Snowpack is a lightning-fast frontend build tool, designed for the modern web.',
props: { currentSnowpackVersion: '3.0.13',
version: '3.0.13',
} }
}; };
} }
</script> </script>
<head> <slot:head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" /> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png" /> <link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png" /> <link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png"/> <link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png" />
<link rel="manifest" href="/favicon/site.webmanifest" /> <link rel="manifest" href="/favicon/site.webmanifest" />
<!-- Primary Meta Tags --> <!-- Primary Meta Tags -->
<title>{title}</title> <title>{context.title}</title>
<meta name="title" content={title} /> <meta name="title" content={context.title} />
<meta name="description" content="{description}" /> <meta name="description" content="{context.description}" />
<!-- Open Graph / Facebook --> <!-- Open Graph / Facebook -->
<meta property="og:type" content="website"/> <meta property="og:type" content="website" />
<meta property="og:url" content="https://www.snowpack.dev{props.permalink}"/> <meta property="og:url" content={context.permalink}/>
<meta property="og:title" content={title}/> <meta property="og:title" content={context.title} />
<meta property="og:description" content={description}/> <meta property="og:description" content={context.description} />
<meta property="og:image" content="https://www.snowpack.dev/img/social-2.jpg"/> <meta property="og:image" content="https://www.snowpack.dev/img/social-2.jpg" />
<!-- Twitter --> <!-- Twitter -->
<meta property="twitter:card" content="summary_large_image"/> <meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:url" content="https://www.snowpack.dev{props.permalink}"/> <meta property="twitter:url" content={context.permalink}/>
<meta property="twitter:title" content={title}/> <meta property="twitter:title" content={context.title} />
<meta property="twitter:description" content={description}/> <meta property="twitter:description" content={context.description} />
<meta property="twitter:image" content="https://www.snowpack.dev/img/social-2.jpg"/> <meta property="twitter:image" content="https://www.snowpack.dev/img/social-2.jpg" />
<!-- Global Stylesheets --> <!-- Global Stylesheets -->
<link rel="stylesheet" href="/css/app.css" /> <link rel="stylesheet" href="/css/app.css" />
<link href="https://fonts.googleapis.com/css2?family=Overpass:wght@400;700;900&display=swap" rel="stylesheet"/> <link href="https://fonts.googleapis.com/css2?family=Overpass:wght@400;700;900&display=swap" rel="stylesheet" />
<!-- Note: You can then add additional, custom things here as well. --> <!-- Note: You can then add additional, custom things here as well. -->
<!-- if no slot given, assume add to bottom --> <!-- if no slot given, assume add to bottom -->
<slot></slot> <slot></slot>
</head> </slot:head>
<body class="base 2"> <slot:body>
<Banner></Banner> <Banner></Banner>
<Nav version={props.version} /> <Nav version={context.currentSnowpackVersion} />
<!-- if no slot given, assume add to bottom --> <!-- if no slot given, assume add to bottom -->
<slot></slot> <slot></slot>
@ -65,4 +65,4 @@
gtag('js', new Date()); gtag('js', new Date());
gtag('config', 'UA-130280175-9', { page_path: location.pathname === '/' ? (location.pathname + location.hash) : (location.pathname) }); gtag('config', 'UA-130280175-9', { page_path: location.pathname === '/' ? (location.pathname + location.hash) : (location.pathname) });
</script> </script>
</body> </slot:body>

View file

@ -1,12 +1,14 @@
<script hmx="setup"> <script astro>
import Menu from '../components/Menu.hmx'; import Menu from '../components/Menu.hmx';
import Subnav from '../components/Subnav.hmx'; import Subnav from '../components/Subnav.hmx';
export function setup() {
return {layout: 'layouts/base.hmx', props: {}}; export const layout = 'layouts/base.hmx';
export function setup({ context }) {
return {};
} }
</script> </script>
<head> <slot:head>
<style> <style>
.cover-wrapper { .cover-wrapper {
width: 100%; width: 100%;
@ -47,13 +49,13 @@
</style> </style>
<slot></slot> <slot></slot>
</head> </slot:head>
<body> <slot:body>
<div class="cover-wrapper"> <div class="cover-wrapper">
<img class="cover-blur" src={props.cover} alt=""/> <img class="cover-blur" src={context.cover} alt=""/>
<img class="cover" src={props.cover} alt=""/> <img class="cover" src={context.cover} alt=""/>
</div> </div>
<div class="container"> <div class="container">
@ -66,7 +68,7 @@
<article class="snow-view-main"> <article class="snow-view-main">
<div class="content"> <div class="content">
<h2 class="content-title"> <h2 class="content-title">
{title} {context.title}
</h2> </h2>
<div class="content-layout"> <div class="content-layout">
<div class="content-body"> <div class="content-body">
@ -76,7 +78,7 @@
</div> </div>
</article> </article>
<Subnav title={title} /> <Subnav title={context.title} headers={context.content.headers} />
</section> </section>
</div> </div>
</body> </slot:body>

View file

@ -1,33 +1,22 @@
<script hmx="setup"> <script astro>
import Subnav from '../components/Subnav.hmx'; import Subnav from '../components/Subnav.hmx';
import Menu from '../components/Menu.hmx'; import Menu from '../components/Menu.hmx';
import markdownToAst from "mdast-util-from-markdown";
import markdownTableOfContents from "mdast-util-toc";
export function setup({content}) {
const mdAst = markdownToAst(content.source);
// This is super gross, and just me trying to get an existing table of contents generator to work
// we can either do this internally as helpful sugar, or build a simpler one as a plugin
const headingsAst = markdownTableOfContents(mdAst);
const headings = headingsAst.map ? headingsAst.map.children.map(ch => {
return {depth: 1, url: ch.children[0].children[0].url, text: ch.children[0].children[0].children[0].value};
}) : [];
export const layout = 'layouts/base.hmx';
export function setup({ context }) {
return { return {
layout: 'layouts/base.hmx', context: {
props: {
headings,
} }
}; };
} }
</script> </script>
<head> <slot:head>
<slot></slot> <slot></slot>
</head> </slot:head>
<body> <slot:body>
<div class="container"> <div class="container">
<section class="snow-view__docs has-subnav"> <section class="snow-view__docs has-subnav">
@ -35,12 +24,12 @@
<Menu /> <Menu />
</aside> </aside>
<Subnav title={title} headings={props.headings} /> <Subnav title={context.title} headers={context.content.headers} />
<article class="snow-view-main"> <article class="snow-view-main">
<div class="content"> <div class="content">
<h2 class="content-title"> <h2 class="content-title">
{title} {context.title}
</h2> </h2>
<div class="content-layout"> <div class="content-layout">
<div class="content-body"> <div class="content-body">
@ -52,4 +41,4 @@
</section> </section>
</div> </div>
</body> </slot:body>

View file

@ -1,20 +1,18 @@
<script hmx="setup"> <script astro>
import Menu from '../components/Menu.hmx'; import Menu from '../components/Menu.hmx';
export function setup() { export const layout = 'layouts/base.hmx';
return { export function setup({ context }) {
layout: 'layouts/base.hmx', return {};
props: {}
};
} }
</script> </script>
<head> <slot:head>
<!-- hi --> <!-- hi -->
<slot></slot> <slot></slot>
</head> </slot:head>
<body class="base 2"> <slot:body>
<div class="container"> <div class="container">
<section class="snow-view__docs is-full"> <section class="snow-view__docs is-full">
@ -28,4 +26,4 @@
</section> </section>
</div> </div>
</body> </slot:body>

View file

@ -1,11 +1,12 @@
<script hmx="setup"> <script astro>
import {format as formatDate, parseISO} from 'date-fns'; import {format as formatDate, parseISO} from 'date-fns';
export function setup() { export const layout = 'layouts/base.hmx';
return { layout: 'layouts/base.hmx', props: {} }; export function setup({ context }) {
return {};
} }
</script> </script>
<head> <slot:head>
<link rel="stylesheet" href="/css/legacy-post.css" /> <link rel="stylesheet" href="/css/legacy-post.css" />
<style> <style>
.markdown-body img, .markdown-body img,
@ -99,10 +100,9 @@
} }
</style> </style>
<slot></slot> <slot></slot>
</head> </slot:head>
<body>
<slot:body>
<div class="grid-extra-space"> <div class="grid-extra-space">
<div class="grid-body-header"> <div class="grid-body-header">
<svg height="80px" style="padding-left: 8px;" viewBox="0 0 640 512" version="1.1" <svg height="80px" style="padding-left: 8px;" viewBox="0 0 640 512" version="1.1"
@ -115,7 +115,7 @@
</g> </g>
</g> </g>
</svg> </svg>
<h1 class="header-snowpack">{title}</h1> <h1 class="header-snowpack">{context.title}</h1>
<p> <p>
@ -140,4 +140,4 @@
<slot></slot> <slot></slot>
</article> </article>
</div> </div>
</body> </slot:body>

View file

@ -1,16 +1,17 @@
<script hmx="setup"> <script astro>
export function setup() { export const layout = 'layouts/main.hmx';
export function setup({ context }) {
return { return {
context: {
title: '404 - Not Found', title: '404 - Not Found',
layout: 'layouts/main.hmx',
props: {
} }
}; };
} }
</script> </script>
<h2 class="content-title"> <h2 class="content-title">
{title} {context.title}
</h2> </h2>
<div class="content"> <div class="content">

View file

@ -1,26 +1,29 @@
<script hmx="setup"> <script astro>
import Card from '../components/Card.jsx'; import Card from '../components/Card.jsx';
export const layout = 'layouts/main.hmx';
// mocked for now, to be added later // mocked for now, to be added later
// 1. import {paginate} from 'magicthing'; // 1. import {paginate} from 'magicthing';
// 2. export default function ({paginate}) { // 2. export default function ({paginate}) {
function paginate(options) { function paginate(options) {
if (options.tag === 'guide') { if (options.tag === 'guide') {
return [ return [
{title: 'Test guide 1', href:"#"}, { title: 'Test guide 1', href: "#" },
{title: 'Test guide 2', href:"#"}, { title: 'Test guide 2', href: "#" },
]; ];
} }
if (options.tag === 'communityGuides') { if (options.tag === 'communityGuides') {
return [{title: 'Test communityGuides', href:"#"}]; return [{ title: 'Test communityGuides', href: "#" }];
} }
return []; return [];
} }
export function setup({/* paginate */}) {
export function setup({ context, /* paginate */ }) {
return { return {
context: {
title: 'Guides', title: 'Guides',
description: "Snowpack's usage and integration guides.", description: "Snowpack's usage and integration guides.",
layout: 'layouts/main.hmx',
props: { props: {
guides: paginate({ guides: paginate({
files: '/posts/guides/*.md', files: '/posts/guides/*.md',
@ -36,17 +39,18 @@
limit: 10, limit: 10,
}), }),
} }
}
}; };
} }
</script> </script>
<head> <slot:head>
</head> </slot:head>
<body> <slot:body>
<h2 class="content-title"> <h2 class="content-title">
{title} {context.title}
</h2> </h2>
<h3 class="content-title"> <h3 class="content-title">
@ -61,8 +65,8 @@
</ul> </ul>
</div> </div>
<br/> <br />
<br/> <br />
<h3 class="content-title"> <h3 class="content-title">
Popular Integration Guides Popular Integration Guides
@ -70,7 +74,8 @@
<div class="card-grid card-grid-4"> <div class="card-grid card-grid-4">
{props.communityGuides.map((post) => { {props.communityGuides.map((post) => {
return <Card item={post} />; return
<Card item={post} />;
})} })}
</div> </div>
</body> </slot:body>

View file

@ -1,22 +1,21 @@
<script hmx="setup"> <script astro>
import Menu from '../components/Menu.hmx'; import Menu from '../components/Menu.hmx';
import Hero from '../components/Hero.hmx'; import Hero from '../components/Hero.hmx';
export function setup() {
return { export const layout = 'layouts/base.hmx';
layout: 'layouts/base.hmx', export function setup({context}) {
props: {} return {}
}
} }
</script> </script>
<head> <slot:head>
<!-- Head Stuff --> <meta charset="AAA" />
</head> </slot:head>
<body> <slot:body>
<Hero bar={title}></Hero> <Hero bar={context.title}></Hero>
<div foo={title} class="container" style="margin: 0 auto"> <div foo={context.title} class="container" style="margin: 0 auto">
<section class="snow-view__docs is-full is-home"> <section class="snow-view__docs is-full is-home">
<aside id="nav-primary" class="snow-view-nav"> <aside id="nav-primary" class="snow-view-nav">
@ -95,4 +94,4 @@
<!-- Place this tag in your head or just before your close body tag. --> <!-- Place this tag in your head or just before your close body tag. -->
<script async="async" defer="defer" src="https://buttons.github.io/buttons.js"></script> <script async="async" defer="defer" src="https://buttons.github.io/buttons.js"></script>
</body> </slot:body>

View file

@ -1,31 +1,33 @@
<script hmx="setup"> <script astro>
import Card from '../components/Card.jsx'; import Card from '../components/Card.jsx';
import CompanyLogo from '../components/CompanyLogo.jsx'; import CompanyLogo from '../components/CompanyLogo.jsx';
import NewsAssets from '../components/NewsAssets.svelte'; import NewsAssets from '../components/NewsAssets.svelte';
import NewsTitle from '../components/NewsTitle.vue'; import NewsTitle from '../components/NewsTitle.vue';
export const layout = 'layouts/main.hmx';
import news from '../data/news.json'; import news from '../data/news.json';
import users from '../data/users.json'; import users from '../data/users.json';
export function setup({ findContent }) { export function setup({ context, request }) {
console.log(request);
return { return {
context: {
title: 'Community & News', title: 'Community & News',
description: "Snowpack community news and companies that use Snowpack.", description: "Snowpack community news and companies that use Snowpack.",
layout: 'layouts/main.hmx',
// Using Snowpack? Want to be featured on snowpack.dev? // Using Snowpack? Want to be featured on snowpack.dev?
// Add your project, organization, or company to the end of this list! // Add your project, organization, or company to the end of this list!
props: {
news, news,
users, users,
} }
}; }
} }
</script> </script>
<head> </head> <slot:head> </slot:head>
<body> <slot:body>
<NewsTitle title={title} /> <NewsTitle title={context.title} />
<p> <p>
Get the latest news, blog posts, and tutorials on Snowpack. <a href="/feed.xml">Also available via RSS.</a> Get the latest news, blog posts, and tutorials on Snowpack. <a href="/feed.xml">Also available via RSS.</a>
@ -45,7 +47,8 @@
working on!</div> working on!</div>
</article> </article>
{props.news.reverse().map((item) => <Card:dynamic item={item} />)} {context.news.reverse().map((item) =>
<Card:dynamic item={item} />)}
</div> </div>
<div class="content"> <div class="content">
@ -54,7 +57,8 @@
<div class="company-logos"> <div class="company-logos">
{props.users.map((user) => <CompanyLogo user={user} />)} {context.users.map((user) =>
<CompanyLogo user={user} />)}
<a href="https://github.com/snowpackjs/snowpack/edit/main/www/_template/news.md" target="_blank" <a href="https://github.com/snowpackjs/snowpack/edit/main/www/_template/news.md" target="_blank"
title="Add Your Project/Company!" class="add-company-button"> title="Add Your Project/Company!" class="add-company-button">
@ -70,4 +74,4 @@
<NewsAssets /> <NewsAssets />
</div> </div>
</body> </slot:body>

View file

@ -1,29 +1,24 @@
<script hmx="setup"> <script astro>
import news from '../data/news.json';
import users from '../data/users.json';
import PluginSearchPage from '../components/PluginSearchPage.jsx'; import PluginSearchPage from '../components/PluginSearchPage.jsx';
export function setup({ findContent }) { export const layout = 'layouts/main.hmx';
export function setup({ context }) {
return { return {
context: {
title: 'The Snowpack Plugin Catalog', title: 'The Snowpack Plugin Catalog',
description: 'Snowpack plugins allow for configuration-minimal tooling integration.', description: 'Snowpack plugins allow for configuration-minimal tooling integration.',
layout: 'layouts/main.hmx',
// Using Snowpack? Want to be featured on snowpack.dev?
// Add your project, organization, or company to the end of this list!
props: {
news,
users,
} }
}; };
} }
</script> </script>
<head> <slot:head>
</head> </slot:head>
<body> <slot:body>
<h2 class="content-title"> <h2 class="content-title">
{ title } { context.title }
</h2> </h2>
<h3 class="pluginPage-subheading">Customize Snowpack with optimized build plugins.</h3> <h3 class="pluginPage-subheading">Customize Snowpack with optimized build plugins.</h3>
@ -33,4 +28,4 @@
</p> </p>
<PluginSearchPage:dynamic /> <PluginSearchPage:dynamic />
</body> </slot:body>

View file

@ -1,4 +1,4 @@
<script hmx="setup"> <script astro>
import Subnav from '../components/Subnav.hmx'; import Subnav from '../components/Subnav.hmx';
import { content as Menu } from '../components/Menu.hmx'; import { content as Menu } from '../components/Menu.hmx';
// import contentful from 'skypack:contentful'; // import contentful from 'skypack:contentful';
@ -16,12 +16,12 @@
<Menu /> <Menu />
</aside> </aside>
<Subnav title={title} /> <Subnav title={context.title} headers={context.content.headers} />
<article class="snow-view-main"> <article class="snow-view-main">
<div class="content"> <div class="content">
<h2 class="content-title"> <h2 class="content-title">
{title} {context.title}
</h2> </h2>
<div class="content-layout"> <div class="content-layout">
<div class="content-body"> <div class="content-body">

21
package-lock.json generated
View file

@ -167,6 +167,12 @@
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.46.tgz", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.46.tgz",
"integrity": "sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==" "integrity": "sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg=="
}, },
"@types/github-slugger": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@types/github-slugger/-/github-slugger-1.3.0.tgz",
"integrity": "sha512-J/rMZa7RqiH/rT29TEVZO4nBoDP9XJOjnbbIofg7GQKs4JIduEO3WLpte+6WeUz/TcrXKlY+bM7FYrp8yFB+3g==",
"dev": true
},
"@types/json-schema": { "@types/json-schema": {
"version": "7.0.7", "version": "7.0.7",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz",
@ -1562,6 +1568,21 @@
"pump": "^3.0.0" "pump": "^3.0.0"
} }
}, },
"github-slugger": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.3.0.tgz",
"integrity": "sha512-gwJScWVNhFYSRDvURk/8yhcFBee6aFjye2a7Lhb2bUyRulpIoek9p0I9Kt7PT67d/nUlZbFu8L9RLiA0woQN8Q==",
"requires": {
"emoji-regex": ">=6.0.0 <=6.1.1"
},
"dependencies": {
"emoji-regex": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.1.1.tgz",
"integrity": "sha1-xs0OwbBkLio8Z6ETfvxeeW2k+I4="
}
}
},
"glob": { "glob": {
"version": "7.1.6", "version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",

View file

@ -36,6 +36,7 @@
"deepmerge": "^4.2.2", "deepmerge": "^4.2.2",
"domhandler": "^4.0.0", "domhandler": "^4.0.0",
"es-module-lexer": "^0.4.1", "es-module-lexer": "^0.4.1",
"github-slugger": "^1.3.0",
"gray-matter": "^4.0.2", "gray-matter": "^4.0.2",
"htmlparser2": "^6.0.0", "htmlparser2": "^6.0.0",
"kleur": "^4.1.4", "kleur": "^4.1.4",
@ -54,6 +55,7 @@
"yargs-parser": "^20.2.7" "yargs-parser": "^20.2.7"
}, },
"devDependencies": { "devDependencies": {
"@types/github-slugger": "^1.3.0",
"@types/sass": "^1.16.0", "@types/sass": "^1.16.0",
"@types/yargs-parser": "^20.2.0", "@types/yargs-parser": "^20.2.0",
"@typescript-eslint/eslint-plugin": "^4.18.0", "@typescript-eslint/eslint-plugin": "^4.18.0",

View file

@ -12,58 +12,10 @@ module.exports = function (snowpackConfig, { resolve } = {}) {
output: ['.js'], output: ['.js'],
}, },
async load({ filePath }) { async load({ filePath }) {
const { compilePage, compileComponent } = await transformPromise; const { compileComponent } = await transformPromise;
const projectRoot = snowpackConfig.root; const projectRoot = snowpackConfig.root;
const contents = await readFile(filePath, 'utf-8'); const contents = await readFile(filePath, 'utf-8');
if (!filePath.includes('/pages/') && !filePath.includes('/layouts/')) {
const result = await compileComponent(contents, { compileOptions: { resolve }, filename: filePath, projectRoot }); const result = await compileComponent(contents, { compileOptions: { resolve }, filename: filePath, projectRoot });
return result.contents;
}
const result = await compilePage(contents, {
compileOptions: { resolve },
filename: filePath,
projectRoot,
});
try {
return /* js */ `
${result.contents}
export default async (childDatas, childRenderFns) => {
// Kind of hacky, can clean up if this works
const renderHmx = {setup, head, body};
const merge = (await import('deepmerge')).default;
const content = childDatas && childDatas[0].content;
const _data = await renderHmx.setup({content});
if (_data.layout) {
const renderLayout = (await import('/_hmx/layouts/' + _data.layout.replace(/.*layouts\\//, "").replace(/\.hmx$/, '.js'))).default;
return renderLayout(
[...(childDatas || []), _data],
[...(childRenderFns || []), renderHmx]
);
}
const data = merge.all([_data, ...(childDatas || [])]);
let headResult;
let bodyResult;
for (const renderFn of (childRenderFns || [])) {
let headAndBody = await Promise.all([
renderFn.head(data, headResult),
renderFn.body(data, bodyResult)
]);
headResult = headAndBody[0];
bodyResult = headAndBody[1];
}
return h(Fragment, null, [
renderHmx.head(data, headResult, true),
renderHmx.body(data, bodyResult, true),
]);
};
`;
} catch (err) {
console.error(err);
}
return result.contents; return result.contents;
}, },
}; };

View file

@ -17,9 +17,12 @@ export interface JsxItem {
export interface TransformResult { export interface TransformResult {
script: string; script: string;
head: JsxItem | undefined;
body: JsxItem | undefined;
items: JsxItem[]; items: JsxItem[];
} }
export interface CompileResult { export interface CompileResult {
result: TransformResult;
contents: string; contents: string;
} }

View file

@ -53,6 +53,10 @@ function getAttributes(attrs: Attribute[]): Record<string, string> {
continue; continue;
} }
const val: TemplateNode = attr.value[0]; const val: TemplateNode = attr.value[0];
if (!val) {
result[attr.name] = '(' + val + ')';
continue;
}
switch (val.type) { switch (val.type) {
case 'MustacheTag': case 'MustacheTag':
result[attr.name] = '(' + val.expression + ')'; result[attr.name] = '(' + val.expression + ')';
@ -143,33 +147,37 @@ function getComponentWrapper(_name: string, { type, url }: { type: string; url:
} }
function compileScriptSafe(raw: string, loader: 'jsx' | 'tsx'): string { function compileScriptSafe(raw: string, loader: 'jsx' | 'tsx'): string {
let compiledCode = compileExpressionSafe(raw, loader);
// esbuild treeshakes unused imports. In our case these are components, so let's keep them. // esbuild treeshakes unused imports. In our case these are components, so let's keep them.
const imports = eslexer const imports = eslexer
.parse(raw)[0] .parse(raw)[0]
.filter(({ d }) => d === -1) .filter(({ d }) => d === -1)
.map((i: any) => raw.substring(i.ss, i.se)); .map((i) => raw.substring(i.ss, i.se));
for (let importStatement of imports) {
if (!compiledCode.includes(importStatement)) {
compiledCode = importStatement + '\n' + compiledCode;
}
}
return compiledCode;
}
function compileExpressionSafe(raw: string, loader: 'jsx' | 'tsx'): string {
let { code } = transformSync(raw, { let { code } = transformSync(raw, {
loader, loader,
jsxFactory: 'h', jsxFactory: 'h',
jsxFragment: 'Fragment', jsxFragment: 'Fragment',
charset: 'utf8', charset: 'utf8',
}); });
for (let importStatement of imports) {
if (!code.includes(importStatement)) {
code = importStatement + '\n' + code;
}
}
return code; return code;
} }
export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Promise<TransformResult> { export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Promise<TransformResult> {
await eslexer.init; await eslexer.init;
// Compile scripts as TypeScript, always // Compile scripts as TypeScript, always
const script = compileScriptSafe(ast.instance ? ast.instance.content : '', 'tsx'); const script = compileScriptSafe(ast.module ? ast.module.content : '', 'tsx');
// Todo: Validate that `h` and `Fragment` aren't defined in the script // Todo: Validate that `h` and `Fragment` aren't defined in the script
const [scriptImports] = eslexer.parse(script, 'optional-sourcename'); const [scriptImports] = eslexer.parse(script, 'optional-sourcename');
@ -182,6 +190,8 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
); );
const additionalImports = new Set<string>(); const additionalImports = new Set<string>();
let headItem: JsxItem | undefined;
let bodyItem: JsxItem | undefined;
let items: JsxItem[] = []; let items: JsxItem[] = [];
let mode: 'JSX' | 'SCRIPT' | 'SLOT' = 'JSX'; let mode: 'JSX' | 'SCRIPT' | 'SLOT' = 'JSX';
let collectionItem: JsxItem | undefined; let collectionItem: JsxItem | undefined;
@ -192,7 +202,7 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
enter(node: TemplateNode) { enter(node: TemplateNode) {
switch (node.type) { switch (node.type) {
case 'MustacheTag': case 'MustacheTag':
let code = compileScriptSafe(node.expression, 'jsx'); let code = compileExpressionSafe(node.expression, 'jsx');
let matches: RegExpExecArray[] = []; let matches: RegExpExecArray[] = [];
let match: RegExpExecArray | null | undefined; let match: RegExpExecArray | null | undefined;
@ -230,8 +240,12 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
return; return;
} }
break; break;
case 'Head':
case 'Body':
case 'InlineComponent': case 'InlineComponent':
case 'Element': case 'Title':
case 'Element': {
const name: string = node.name; const name: string = node.name;
if (!name) { if (!name) {
throw new Error('AHHHH'); throw new Error('AHHHH');
@ -241,6 +255,16 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
currentItemName = name; currentItemName = name;
if (!collectionItem) { if (!collectionItem) {
collectionItem = { name, jsx: '' }; collectionItem = { name, jsx: '' };
if (node.type === 'Head') {
collectionItem.jsx += `h(Fragment, null`;
headItem = collectionItem;
return;
}
if (node.type === 'Body') {
collectionItem.jsx += `h(Fragment, null`;
bodyItem = collectionItem;
return;
}
items.push(collectionItem); items.push(collectionItem);
} }
collectionItem.jsx += collectionItem.jsx === '' ? '' : ','; collectionItem.jsx += collectionItem.jsx === '' ? '' : ',';
@ -249,10 +273,6 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
collectionItem.jsx += `h("${name}", ${attributes ? generateAttributes(attributes) : 'null'}`; collectionItem.jsx += `h("${name}", ${attributes ? generateAttributes(attributes) : 'null'}`;
return; return;
} }
if (name === 'Component') {
collectionItem.jsx += `h(Fragment, null`;
return;
}
const [componentName, componentKind] = name.split(':'); const [componentName, componentKind] = name.split(':');
const componentImportData = components[componentName]; const componentImportData = components[componentName];
if (!componentImportData) { if (!componentImportData) {
@ -265,6 +285,7 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
collectionItem.jsx += `h(${wrapper}, ${attributes ? generateAttributes(attributes) : 'null'}`; collectionItem.jsx += `h(${wrapper}, ${attributes ? generateAttributes(attributes) : 'null'}`;
return; return;
}
case 'Attribute': { case 'Attribute': {
this.skip(); this.skip();
return; return;
@ -293,7 +314,7 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
return; return;
} }
default: default:
throw new Error('Unexpected node type: ' + node.type); throw new Error('Unexpected (enter) node type: ' + node.type);
} }
}, },
leave(node, parent, prop, index) { leave(node, parent, prop, index) {
@ -314,6 +335,9 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
if (!collectionItem) { if (!collectionItem) {
return; return;
} }
case 'Head':
case 'Body':
case 'Title':
case 'Element': case 'Element':
case 'InlineComponent': case 'InlineComponent':
if (!collectionItem) { if (!collectionItem) {
@ -329,13 +353,15 @@ export async function codegen(ast: Ast, { compileOptions }: CodeGenOptions): Pro
return; return;
} }
default: default:
throw new Error('Unexpected node type: ' + node.type); throw new Error('Unexpected (leave) node type: ' + node.type);
} }
}, },
}); });
return { return {
script: script + '\n' + Array.from(additionalImports).join('\n'), script: script + '\n' + Array.from(additionalImports).join('\n'),
head: headItem,
body: bodyItem,
items, items,
}; };
} }

View file

@ -58,7 +58,7 @@ export interface Parser {
export interface Script extends BaseNode { export interface Script extends BaseNode {
type: 'Script'; type: 'Script';
context: string; context: 'runtime' | 'setup';
content: string; content: string;
} }
@ -75,8 +75,8 @@ export interface Style extends BaseNode {
export interface Ast { export interface Ast {
html: TemplateNode; html: TemplateNode;
css: Style; css: Style;
instance: Script;
module: Script; module: Script;
// instance: Script;
} }
export interface Warning { export interface Warning {
@ -94,38 +94,6 @@ export type ModuleFormat = 'esm' | 'cjs';
export type CssHashGetter = (args: { name: string; filename: string | undefined; css: string; hash: (input: string) => string }) => string; export type CssHashGetter = (args: { name: string; filename: string | undefined; css: string; hash: (input: string) => string }) => string;
export interface CompileOptions {
format?: ModuleFormat;
name?: string;
filename?: string;
generate?: 'dom' | 'ssr' | false;
sourcemap?: object | string;
outputFilename?: string;
cssOutputFilename?: string;
sveltePath?: string;
dev?: boolean;
accessors?: boolean;
immutable?: boolean;
hydratable?: boolean;
legacy?: boolean;
customElement?: boolean;
tag?: string;
css?: boolean;
loopGuardTimeout?: number;
namespace?: string;
cssHash?: CssHashGetter;
preserveComments?: boolean;
preserveWhitespace?: boolean;
}
export interface ParserOptions {
filename?: string;
customElement?: boolean;
}
export interface Visitor { export interface Visitor {
enter: (node: Node) => void; enter: (node: Node) => void;
leave?: (node: Node) => void; leave?: (node: Node) => void;

View file

@ -232,33 +232,34 @@ export default function parse(template: string, options: ParserOptions = {}): As
); );
} }
const instance_scripts = parser.js.filter((script) => script.context === 'default'); // const instance_scripts = parser.js.filter((script) => script.context === 'default');
const module_scripts = parser.js.filter((script) => script.context === 'module'); // const module_scripts = parser.js.filter((script) => script.context === 'module');
const hmx_scripts = parser.js.filter((script) => script.context === 'setup');
if (instance_scripts.length > 1) { if (hmx_scripts.length > 1) {
parser.error( parser.error(
{ {
code: 'invalid-script', code: 'invalid-script',
message: 'A component can only have one instance-level <script> element', message: 'A component can only have one <script astro> element',
}, },
instance_scripts[1].start hmx_scripts[1].start
); );
} }
if (module_scripts.length > 1) { // if (module_scripts.length > 1) {
parser.error( // parser.error(
{ // {
code: 'invalid-script', // code: 'invalid-script',
message: 'A component can only have one <script context="module"> element', // message: 'A component can only have one <script context="module"> element',
}, // },
module_scripts[1].start // module_scripts[1].start
); // );
} // }
return { return {
html: parser.html, html: parser.html,
css: parser.css[0], css: parser.css[0],
instance: instance_scripts[0], // instance: instance_scripts[0],
module: module_scripts[0], module: hmx_scripts[0],
}; };
} }

View file

@ -7,15 +7,16 @@ import { Node, Program } from 'estree';
const script_closing_tag = '</script>'; const script_closing_tag = '</script>';
function get_context(parser: Parser, attributes: any[], start: number): string { function get_context(parser: Parser, attributes: any[], start: number): 'runtime' | 'setup' {
const context = attributes.find((attribute) => attribute.name === 'context'); const context = attributes.find((attribute) => attribute.name === 'astro');
if (!context) return 'default'; if (!context) return 'runtime';
if (context.value === true) return 'setup';
if (context.value.length !== 1 || context.value[0].type !== 'Text') { if (context.value.length !== 1 || context.value[0].type !== 'Text') {
parser.error( parser.error(
{ {
code: 'invalid-script', code: 'invalid-script',
message: 'context attribute must be static', message: 'astro attribute must be static',
}, },
start start
); );
@ -23,11 +24,11 @@ function get_context(parser: Parser, attributes: any[], start: number): string {
const value = context.value[0].data; const value = context.value[0].data;
if (value !== 'module') { if (value !== 'setup') {
parser.error( parser.error(
{ {
code: 'invalid-script', code: 'invalid-script',
message: 'If the context attribute is supplied, its value must be "module"', message: 'If the "astro" attribute has a value, its value must be "setup"',
}, },
context.start context.start
); );

View file

@ -14,13 +14,14 @@ import list from '../../utils/list.js';
const valid_tag_name = /^\!?[a-zA-Z]{1,}:?[a-zA-Z0-9\-]*/; const valid_tag_name = /^\!?[a-zA-Z]{1,}:?[a-zA-Z0-9\-]*/;
const meta_tags = new Map([ const meta_tags = new Map([
['svelte:head', 'Head'], ['slot:head', 'Head'],
['svelte:options', 'Options'], ['slot:body', 'Body'],
['svelte:window', 'Window'], // ['astro:options', 'Options'],
['svelte:body', 'Body'], // ['astro:window', 'Window'],
// ['astro:body', 'Body'],
]); ]);
const valid_meta_tags = Array.from(meta_tags.keys()).concat('svelte:self', 'svelte:component', 'svelte:fragment'); const valid_meta_tags = Array.from(meta_tags.keys()); //.concat('astro:self', 'astro:component', 'astro:fragment');
const specials = new Map([ const specials = new Map([
[ [
@ -39,9 +40,10 @@ const specials = new Map([
], ],
]); ]);
const SELF = /^svelte:self(?=[\s/>])/; const SELF = /^astro:self(?=[\s/>])/;
const COMPONENT = /^svelte:component(?=[\s/>])/; const COMPONENT = /^astro:component(?=[\s/>])/;
const SLOT = /^svelte:fragment(?=[\s/>])/; const SLOT = /^astro:fragment(?=[\s/>])/;
const HEAD = /^head(?=[\s/>])/;
function parent_is_head(stack) { function parent_is_head(stack) {
let i = stack.length; let i = stack.length;
@ -79,7 +81,7 @@ export default function tag(parser: Parser) {
if (meta_tags.has(name)) { if (meta_tags.has(name)) {
const slug = meta_tags.get(name).toLowerCase(); const slug = meta_tags.get(name).toLowerCase();
if (is_closing_tag) { if (is_closing_tag) {
if ((name === 'svelte:window' || name === 'svelte:body') && parser.current().children.length) { if ((name === 'astro:window' || name === 'astro:body') && parser.current().children.length) {
parser.error( parser.error(
{ {
code: `invalid-${slug}-content`, code: `invalid-${slug}-content`,
@ -115,9 +117,9 @@ export default function tag(parser: Parser) {
const type = meta_tags.has(name) const type = meta_tags.has(name)
? meta_tags.get(name) ? meta_tags.get(name)
: /[A-Z]/.test(name[0]) || name === 'svelte:self' || name === 'svelte:component' : /[A-Z]/.test(name[0]) || name === 'astro:self' || name === 'astro:component'
? 'InlineComponent' ? 'InlineComponent'
: name === 'svelte:fragment' : name === 'astro:fragment'
? 'SlotTemplate' ? 'SlotTemplate'
: name === 'title' && parent_is_head(parser.stack) : name === 'title' && parent_is_head(parser.stack)
? 'Title' ? 'Title'
@ -197,13 +199,13 @@ export default function tag(parser: Parser) {
parser.allow_whitespace(); parser.allow_whitespace();
} }
if (name === 'svelte:component') { if (name === 'astro:component') {
const index = element.attributes.findIndex((attr) => attr.type === 'Attribute' && attr.name === 'this'); const index = element.attributes.findIndex((attr) => attr.type === 'Attribute' && attr.name === 'this');
if (!~index) { if (!~index) {
parser.error( parser.error(
{ {
code: 'missing-component-definition', code: 'missing-component-definition',
message: "<svelte:component> must have a 'this' attribute", message: "<astro:component> must have a 'this' attribute",
}, },
start start
); );
@ -281,27 +283,29 @@ function read_tag_name(parser: Parser) {
parser.error( parser.error(
{ {
code: 'invalid-self-placement', code: 'invalid-self-placement',
message: '<svelte:self> components can only exist inside {#if} blocks, {#each} blocks, or slots passed to components', message: '<astro:self> components can only exist inside {#if} blocks, {#each} blocks, or slots passed to components',
}, },
start start
); );
} }
return 'svelte:self'; return 'astro:self';
} }
if (parser.read(COMPONENT)) return 'svelte:component'; if (parser.read(COMPONENT)) return 'astro:component';
if (parser.read(SLOT)) return 'svelte:fragment'; if (parser.read(SLOT)) return 'astro:fragment';
if (parser.read(HEAD)) return 'head';
const name = parser.read_until(/(\s|\/|>)/); const name = parser.read_until(/(\s|\/|>)/);
if (meta_tags.has(name)) return name; if (meta_tags.has(name)) return name;
if (name.startsWith('svelte:')) { if (name.startsWith('astro:')) {
const match = fuzzymatch(name.slice(7), valid_meta_tags); const match = fuzzymatch(name.slice(7), valid_meta_tags);
let message = `Valid <svelte:...> tag names are ${list(valid_meta_tags)}`; let message = `Valid <astro:...> tag names are ${list(valid_meta_tags)}`;
if (match) message += ` (did you mean '${match}'?)`; if (match) message += ` (did you mean '${match}'?)`;
parser.error( parser.error(

View file

@ -52,6 +52,7 @@ export default async function (astroConfig: AstroConfig) {
await writeFile(outPath, html, 'utf-8'); await writeFile(outPath, html, 'utf-8');
} catch (err) { } catch (err) {
console.error('Unable to generate page', rel); console.error('Unable to generate page', rel);
console.error(err);
} }
} }

View file

@ -1,32 +0,0 @@
import type { HtmlExtension, Token } from 'micromark/dist/shared-types';
const characterReferences = {
'"': 'quot',
'&': 'amp',
'<': 'lt',
'>': 'gt',
'{': 'lbrace',
'}': 'rbrace',
};
type EncodedChars = '"' | '&' | '<' | '>' | '{' | '}';
function encode(value: string): string {
return value.replace(/["&<>{}]/g, (raw: string) => {
return '&' + characterReferences[raw as EncodedChars] + ';';
});
}
const plugin: HtmlExtension = {
exit: {
codeFlowValue() {
const token: Token = arguments[0];
const serialize = (this.sliceSerialize as unknown) as (t: Token) => string;
const raw = (this.raw as unknown) as (s: string) => void;
const value = serialize(token);
raw(encode(value));
},
},
};
export { plugin as default };

View file

@ -0,0 +1,35 @@
import slugger from 'github-slugger';
// NOTE: micromark has terrible TS types. Instead of fighting with the
// limited/broken TS types that they ship, we just reach for our good friend, "any".
export function createMarkdownHeadersCollector() {
const headers: any[] = [];
let currentHeader: any;
return {
headers,
headersExtension: {
enter: {
atxHeading(node: any) {
currentHeader = {};
headers.push(currentHeader);
},
atxHeadingSequence(node: any) {
currentHeader.depth = this.sliceSerialize(node).length;
},
atxHeadingText(node: any) {
currentHeader.text = this.sliceSerialize(node);
},
} as any,
exit: {
atxHeading(node: any) {
currentHeader.slug = slugger.slug(currentHeader.text);
this.tag(`<h${currentHeader.depth} id="${currentHeader.slug}">`);
this.raw(currentHeader.text);
this.tag(`</h${currentHeader.depth}>`);
// console.log(this.sliceSerialize(node));
},
} as any,
} as any,
};
}

View file

@ -58,7 +58,14 @@ async function load(config: RuntimeConfig, rawPathname: string | undefined): Pro
try { try {
const mod = await snowpackRuntime.importModule(selectedPageUrl); const mod = await snowpackRuntime.importModule(selectedPageUrl);
const html = (await mod.exports.default()) as string; const html = (await mod.exports.__renderPage({
request: {
host: fullurl.hostname,
path: fullurl.pathname,
href: fullurl.toString(),
},
children: [],
})) as string;
return { return {
statusCode: 200, statusCode: 200,

View file

@ -7,7 +7,7 @@ import matter from 'gray-matter';
import gfmHtml from 'micromark-extension-gfm/html.js'; import gfmHtml from 'micromark-extension-gfm/html.js';
import { CompileResult, TransformResult } from './@types/astro'; import { CompileResult, TransformResult } from './@types/astro';
import { parse } from './compiler/index.js'; import { parse } from './compiler/index.js';
import markdownEncode from './markdown-encode.js'; import { createMarkdownHeadersCollector } from './micromark-collect-headers.js';
import { defaultLogOptions } from './logger.js'; import { defaultLogOptions } from './logger.js';
import { optimize } from './optimize/index.js'; import { optimize } from './optimize/index.js';
import { codegen } from './codegen/index.js'; import { codegen } from './codegen/index.js';
@ -51,33 +51,35 @@ async function convertMdToJsx(
contents: string, contents: string,
{ compileOptions, filename, fileID }: { compileOptions: CompileOptions; filename: string; fileID: string } { compileOptions, filename, fileID }: { compileOptions: CompileOptions; filename: string; fileID: string }
): Promise<TransformResult> { ): Promise<TransformResult> {
// This doesn't work.
const { data: _frontmatterData, content } = matter(contents); const { data: _frontmatterData, content } = matter(contents);
const {headers, headersExtension} = createMarkdownHeadersCollector();
const mdHtml = micromark(content, { const mdHtml = micromark(content, {
extensions: [gfmSyntax()], extensions: [gfmSyntax()],
htmlExtensions: [gfmHtml, markdownEncode], htmlExtensions: [gfmHtml, headersExtension],
}); });
const setupData = { console.log("headers", headers);
title: _frontmatterData.title, const setupContext = {
description: _frontmatterData.description, ..._frontmatterData,
layout: _frontmatterData.layout,
content: { content: {
frontmatter: _frontmatterData, frontmatter: _frontmatterData,
headers,
// This is an awful hack due to Svelte parser disliking script tags badly. source: content,
source: content.replace(/<\/?script/g, '<SCRIPT'),
html: mdHtml, html: mdHtml,
}, },
props: {
..._frontmatterData,
},
}; };
// </script> can't be anywhere inside of a JS string, otherwise the HTML parser fails.
// Break it up here so that the HTML parser won't detect it.
const stringifiedSetupContext = JSON.stringify(setupContext).replace(/\<\/script\>/g, `</scrip" + "t>`);
return convertHmxToJsx( return convertHmxToJsx(
`<script hmx="setup">export function setup() { `<script astro>
return ${JSON.stringify(setupData)}; ${_frontmatterData.layout ? `export const layout = ${JSON.stringify(_frontmatterData.layout)};` : ''}
}</script><head></head><body>${mdHtml}</body>`, export function setup({context}) {
return {context: ${stringifiedSetupContext} };
}
</script><slot:head></slot:head><slot:body><section>{${JSON.stringify(mdHtml)}}</section></slot:body>`,
{ compileOptions, filename, fileID } { compileOptions, filename, fileID }
); );
} }
@ -97,49 +99,85 @@ async function transformFromSource(
} }
} }
export async function compilePage(
source: string,
{ compileOptions = defaultCompileOptions, filename, projectRoot }: { compileOptions: CompileOptions; filename: string; projectRoot: string }
): Promise<CompileResult> {
const sourceJsx = await transformFromSource(source, { compileOptions, filename, projectRoot });
const headItem = sourceJsx.items.find((item) => item.name === 'head');
const bodyItem = sourceJsx.items.find((item) => item.name === 'body');
const headItemJsx = !headItem ? 'null' : headItem.jsx.replace('"head"', 'isRoot ? "head" : Fragment');
const bodyItemJsx = !bodyItem ? 'null' : bodyItem.jsx.replace('"head"', 'isRoot ? "body" : Fragment');
const modJsx = `
${sourceJsx.script}
import { h, Fragment } from '${internalImport('h.js')}';
export function head({title, description, props}, child, isRoot) { return (${headItemJsx}); }
export function body({title, description, props}, child, isRoot) { return (${bodyItemJsx}); }
`.trim();
return {
contents: modJsx,
};
}
export async function compileComponent( export async function compileComponent(
source: string, source: string,
{ compileOptions = defaultCompileOptions, filename, projectRoot }: { compileOptions: CompileOptions; filename: string; projectRoot: string } { compileOptions = defaultCompileOptions, filename, projectRoot }: { compileOptions: CompileOptions; filename: string; projectRoot: string }
): Promise<CompileResult> { ): Promise<CompileResult> {
const sourceJsx = await transformFromSource(source, { compileOptions, filename, projectRoot }); const sourceJsx = await transformFromSource(source, { compileOptions, filename, projectRoot });
const headItem = sourceJsx.head;
// throw error if <Component /> missing const bodyItem = sourceJsx.body;
if (!sourceJsx.items.find(({ name }) => name === 'Component')) throw new Error(`${filename} <Component> expected!`); const headItemJsx = !headItem ? 'null' : headItem.jsx;
const bodyItemJsx = !bodyItem ? 'null' : bodyItem.jsx;
// sort <style> tags first // sort <style> tags first
// TODO: remove these and inject in <head> // TODO: remove these and inject in <head>
sourceJsx.items.sort((a, b) => (a.name === 'style' && b.name !== 'style' ? -1 : 0)); sourceJsx.items.sort((a, b) => (a.name === 'style' && b.name !== 'style' ? -1 : 0));
// return template // return template
const modJsx = ` let modJsx = `
import { h, Fragment } from '${internalImport('h.js')}'; // <script astro></script>
export default function(props) { return h(Fragment, null, ${sourceJsx.items.map(({ jsx }) => jsx).join(',')}); } ${sourceJsx.script}
`.trim();
// \`__render()\`: Render the contents of the HMX module. "<slot:*>" elements are not
// included (see below).
import { h, Fragment } from '${internalImport('h.js')}';
export default function __render(props) { return h(Fragment, null, ${sourceJsx.items.map(({ jsx }) => jsx).join(',')}); }
// <slot:*> render functions
export function __slothead(context, child) { return h(Fragment, null, ${headItemJsx}); }
export function __slotbody(context, child) { return h(Fragment, null, ${bodyItemJsx}); }
`;
if (headItemJsx || bodyItemJsx) {
modJsx += `
// \`__renderPage()\`: Render the contents of the HMX module as a page. This is a special flow,
// triggered by loading a component directly by URL.
// If the page exports a defined "layout", then load + render those first. "context", "slot:head",
// and "slot:body" should all inherit from parent layouts, merging together in the correct order.
export async function __renderPage({request, children}) {
const currentChild = {
__slothead,
__slotbody,
setup: typeof setup === 'undefined' ? (passthrough) => passthrough : setup,
layout: typeof layout === 'undefined' ? undefined : layout,
};
// find all layouts, going up the layout chain.
if (currentChild.layout) {
const layoutComponent = (await import('/_hmx/layouts/' + layout.replace(/.*layouts\\//, "").replace(/\.hmx$/, '.js')));
return layoutComponent.__renderPage({
request,
children: [currentChild, ...children],
});
}
const isRoot = true;
const merge = (await import('deepmerge')).default;
// call all children setup scripts, in order, and return.
let mergedContext = {};
for (const child of [currentChild, ...children]) {
const childSetupResult = await child.setup({request, context: mergedContext});
mergedContext = childSetupResult.context ? merge(mergedContext, childSetupResult.context) : mergedContext;
}
Object.freeze(mergedContext);
let headResult;
let bodyResult;
for (const child of children.reverse()) {
headResult = await child.__slothead(mergedContext, headResult);
bodyResult = await child.__slotbody(mergedContext, bodyResult);
}
return h(Fragment, null, [
h("head", null, currentChild.__slothead(mergedContext, headResult)),
h("body", null, currentChild.__slotbody(mergedContext, bodyResult)),
]);
};\n`;
}
return { return {
result: sourceJsx,
contents: modJsx, contents: modJsx,
}; };
} }

View file

@ -1,4 +1,4 @@
<script hmx="setup"> <script astro>
export function setup() { export function setup() {
return { return {
props: {} props: {}
@ -6,10 +6,10 @@
} }
</script> </script>
<head> <slot:head>
<!-- Head Stuff --> <!-- Head Stuff -->
</head> </slot:head>
<body> <slot:body>
<h1>Hello world!</h1> <h1>Hello world!</h1>
</body> </slot:body>