Skip to content

Commit

Permalink
feat: serve versioned matcha (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
lowlighter authored Jun 10, 2024
1 parent d7b6ff6 commit 92de343
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 4 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ To utilize **matcha.css**, just include the following line in the `<head>` secti
```

Assets are hosted on [Vercel](https://vercel.com) but _matcha.css_ is also available on
[![npm](https://img.shields.io/npm/v/@lowlighter%2Fmatcha?logo=npm&labelColor=cb0000&color=black)](https://www.npmjs.com/package/@lowlighter/matcha) and CDN services that distributes npm packages.
[![npm](https://img.shields.io/npm/v/@lowlighter%2Fmatcha?logo=npm&labelColor=cb0000&color=black)](https://www.npmjs.com/package/@lowlighter/matcha) and CDN services that distributes npm packages such
as [JSdelivr](https://www.jsdelivr.com/package/npm/@lowlighter/matcha).

All published versions are available in the [`/v/`](https://matcha.mizu.sh/v/) directory. By default, the `main` branch is served.

### 🍴 À la carte

Expand Down
71 changes: 70 additions & 1 deletion app/build/ssg.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// Imports
import { copy, emptyDir, ensureDir, expandGlob } from "jsr:@std/fs@0.229.1"
import { dirname, fromFileUrl } from "jsr:@std/path@0.225.1"
import { basename, dirname, fromFileUrl } from "jsr:@std/path@0.225.1"
import { root } from "./root.ts"
import { html, html_builder, html_builder_demo } from "./html.ts"
import { compatibility } from "jsr:@libs/bundle@5/css"
import { DOMParser } from " https://deno.land/x/deno_dom@v0.1.45/deno-dom-wasm.ts"

/** Highlight.js CDN */
export const highlight = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"
Expand All @@ -24,9 +25,13 @@ export async function ssg() {
console.log("Created .pages/mod.css")
// Generate CSS
const dist = fromFileUrl(new URL("dist", root)).replaceAll("\\", "/")
await ensureDir(new URL(".pages/v/main", root))
console.log("Created .pages/v/main")
for await (const { path, name } of expandGlob("**/*.css", { root: dist })) {
await copy(path, new URL(`.pages/${name}`, root))
console.log(`Created .pages/${name}`)
await copy(path, new URL(`.pages/v/main/${name}`, root))
console.log(`Created .pages/v/main/${name}`)
}
// Generate compatibility table
const table = await compatibility(new URL(".pages/matcha.css", root), { output: "html", style: false, verbose: true })
Expand All @@ -53,10 +58,74 @@ export async function ssg() {
const alias = `${dirname(subpath)}.css`
await copy(path, new URL(`.pages/${alias}`, root))
console.log(`Created .pages/${alias}`)
await copy(path, new URL(`.pages/v/main/${alias}`, root))
console.log(`Created .pages/v/main/${alias}`)
}
}
await copy(new URL(".pages/styles", root), new URL(".pages/v/main/styles", root))
console.log("Created .pages/v/main/styles")
// Download highlight.js
await Deno.writeTextFile(new URL(".pages/highlight.js", root), await fetch(highlight).then((response) => response.text()))
console.log("Created .pages/highlight.js")
// Download previous versions
const { tags: { latest }, versions } = await fetch("https://data.jsdelivr.com/v1/package/npm/@lowlighter/matcha").then((response) => response.json())
for (const version of versions.reverse()) {
await ensureDir(new URL(`.pages/v/${version}`, root))
console.log(`Created .pages/v/${version}`)
const url = `https://cdn.jsdelivr.net/npm/@lowlighter/matcha@${version}`
const dist = Array.from(
new DOMParser().parseFromString(await fetch(`${url}/dist/`).then((response) => response.text()), "text/html")!.querySelectorAll(`.listing a[href^="/npm/@lowlighter/matcha@${version}"]`),
)
await Promise.all(dist.map(async (_file) => {
const file = _file as unknown as HTMLAnchorElement
const href = file.getAttribute("href")!
await Deno.writeTextFile(new URL(`.pages/v/${version}/${basename(href)}`, root), await fetch(new URL(href, url)).then((response) => response.text()))
console.log(`Created .pages/v/${version}/${basename(href)}`)
}))
const styles = Array.from(
new DOMParser().parseFromString(await fetch(`${url}/styles/`).then((response) => response.text()), "text/html")!.querySelectorAll(`.listing a[href^="/npm/@lowlighter/matcha@${version}"]`),
)
await Promise.all(styles.map(async (_directory) => {
const directory = _directory as unknown as HTMLAnchorElement
const href = directory.getAttribute("href")!
const files = Array.from(
new DOMParser().parseFromString(await fetch(new URL(href, url)).then((response) => response.text()), "text/html")!.querySelectorAll(`.listing a[href^="/npm/@lowlighter/matcha@${version}"]`),
)
await Promise.all(Array.from(files.map(async (_file) => {
const file = _file as unknown as HTMLAnchorElement
const href = file.getAttribute("href")!
if (!href.endsWith(".css")) {
return
}
const subpath = `styles/${basename(directory.getAttribute("href")!)}/${basename(href)}`
const content = await fetch(new URL(href, url)).then((response) => response.text())
await ensureDir(new URL(`.pages/v/${version}/${dirname(subpath)}`, root))
await Deno.writeTextFile(new URL(`.pages/v/${version}/${subpath}`, root), content)
console.log(`Created .pages/v/${version}/${subpath}`)
if (basename(href) === "mod.css") {
await Deno.writeTextFile(new URL(`.pages/v/${version}/${basename(dirname(subpath))}.css`, root), content)
console.log(`Created .pages/v/${version}/${basename(dirname(subpath))}.css`)
}
})))
}))
}
await copy(new URL(`.pages/v/${latest}`, root), new URL(".pages/v/latest", root))
console.log(`Created .pages/v/latest from version ${latest}`)
for (const major of new Set<string>(versions.map((version: string) => version.split(".")[0]))) {
if (major === "0") {
continue
}
const version = versions.reverse().filter((version: string) => version.startsWith(`${major}.`))[0]
await copy(new URL(`.pages/v/${version}`, root), new URL(`.pages/v/${major}`, root))
console.log(`Created .pages/v/${major} from version ${version}`)
}
for (const minor of new Set<string>(versions.map((version: string) => `${version.split(".")[0]}.${version.split(".")[1]}`))) {
if (minor.startsWith("0.")) {
continue
}
const version = versions.reverse().filter((version: string) => version.startsWith(`${minor}.`))[0]
await copy(new URL(`.pages/v/${version}`, root), new URL(`.pages/v/${minor}`, root))
console.log(`Created .pages/v/${minor} from version ${version}`)
}
console.log("Done!")
}
6 changes: 5 additions & 1 deletion app/mod.html
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,11 @@ <h2 id="usage"><a href="#usage">Usage</a></h2>
<pre class="usage-snippet"><code data-hl="html">&lt;link rel="stylesheet" href="https://matcha.mizu.sh/matcha.css"&gt;</code></pre>
<p>
Assets are hosted on <a href="https://vercel.com">Vercel</a> but <em>matcha.css</em> is also available on <a href="https://www.npmjs.com/package/@lowlighter/matcha"><img alt="npm" src="https://img.shields.io/npm/v/@lowlighter%2Fmatcha?logo=npm&labelColor=cb0000&color=black"></a>
and <abbr data-title="Content Delivery Network">CDN</abbr> services that distributes npm packages.
and <abbr data-title="Content Delivery Network">CDN</abbr> services that distributes npm packages such as <a href="https://www.jsdelivr.com/package/npm/@lowlighter/matcha">JSdelivr</a>.
</p>
<p>
All published versions are available in the <a href="/v/" target="_blank"><code>/v/</code></a> directory.
By default, the <code>main</code> branch is served.
</p>
<section>
<h3 id="a-la-carte"><a href="#a-la-carte">À la carte</a></h3>
Expand Down
5 changes: 4 additions & 1 deletion app/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { css } from "./build/css.ts"
import { html, html_builder, html_builder_demo } from "./build/html.ts"
import { highlight, ssg } from "./build/ssg.ts"
import { dist } from "./build/dist.ts"
import { STATUS_CODE, STATUS_TEXT } from "jsr:@std/http@0.224.1"
import { serveDir, STATUS_CODE, STATUS_TEXT } from "jsr:@std/http@0.224.1"
import { root } from "./build/root.ts"
import api_minify from "../api/brew.ts"
import api_preview from "../api/preview.ts"
import { fromFileUrl } from "jsr:@std/path"

// Serve files
switch (Deno.args[0]) {
Expand Down Expand Up @@ -40,6 +41,8 @@ switch (Deno.args[0]) {
return api_preview(request)
case new URLPattern("/highlight.js", url.origin).test(url.href):
return fetch(highlight)
case new URLPattern("/v/*", url.origin).test(url.href):
return serveDir(request, { fsRoot: fromFileUrl(new URL(".pages/v", root)), urlRoot: "v", showDirListing: true, quiet: true })
default:
return new Response(STATUS_TEXT[STATUS_CODE.NotFound], { status: STATUS_CODE.NotFound })
}
Expand Down

0 comments on commit 92de343

Please sign in to comment.