Switch to deno
This commit is contained in:
parent
4b4aa3ff79
commit
40723b32cf
|
@ -2,4 +2,3 @@ root = true
|
||||||
|
|
||||||
[*]
|
[*]
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
max_line_length = 100
|
|
||||||
|
|
19
bin/build.ts
19
bin/build.ts
|
@ -1,8 +1,8 @@
|
||||||
import { articles } from "../lib/tasks/articles.js";
|
import { articles } from "../lib/tasks/articles.ts";
|
||||||
import { css } from "../lib/tasks/css.js";
|
import { css } from "../lib/tasks/css.ts";
|
||||||
import { fonts } from "../lib/tasks/fonts.js";
|
import { fonts } from "../lib/tasks/fonts.ts";
|
||||||
import { images } from "../lib/tasks/images.js";
|
import { images } from "../lib/tasks/images.ts";
|
||||||
import { svg } from "../lib/tasks/svg.js";
|
import { svg } from "../lib/tasks/svg.ts";
|
||||||
|
|
||||||
import { argv, exit } from "node:process";
|
import { argv, exit } from "node:process";
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ const wrapTask = (name: string, task: () => Promise<void>) => async () => {
|
||||||
console.log("[end]", name);
|
console.log("[end]", name);
|
||||||
};
|
};
|
||||||
|
|
||||||
const TASKS = {
|
const TASKS: { [task: string]: () => Promise<void> } = {
|
||||||
articles: wrapTask("articles", articles),
|
articles: wrapTask("articles", articles),
|
||||||
css: wrapTask("css", css),
|
css: wrapTask("css", css),
|
||||||
fonts: wrapTask("fonts", fonts),
|
fonts: wrapTask("fonts", fonts),
|
||||||
|
@ -23,8 +23,9 @@ const TASKS = {
|
||||||
const ALL_TASKS = ["fonts", "images", "svg", "css", "articles"];
|
const ALL_TASKS = ["fonts", "images", "svg", "css", "articles"];
|
||||||
|
|
||||||
const args = argv.slice(2);
|
const args = argv.slice(2);
|
||||||
await (args.length ? args : ALL_TASKS)
|
console.log("args", args);
|
||||||
.map((task) => {
|
(args.length ? args : ALL_TASKS)
|
||||||
|
.map((task: string) => {
|
||||||
if (!TASKS.hasOwnProperty(task)) {
|
if (!TASKS.hasOwnProperty(task)) {
|
||||||
console.error("Unknown task", task);
|
console.error("Unknown task", task);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -32,4 +33,4 @@ await (args.length ? args : ALL_TASKS)
|
||||||
|
|
||||||
return TASKS[task];
|
return TASKS[task];
|
||||||
})
|
})
|
||||||
.reduce((prev, cur) => prev.then(cur), Promise.resolve());
|
.reduce((prev: Promise<void>, cur: () => Promise<void>) => prev.then(cur), Promise.resolve());
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
import { Worker } from "node:worker_threads";
|
|
||||||
import chokidar from "chokidar";
|
import chokidar from "chokidar";
|
||||||
|
|
||||||
const watch = (glob: string | string[], task: string) =>
|
const watch = (glob: string | string[], task: string) =>
|
||||||
chokidar.watch(glob).on("change", (path: string) => {
|
chokidar.watch(glob).on("change", (path: string) => {
|
||||||
console.log("[change]", path, "->", task);
|
console.log("[change]", path, "->", task);
|
||||||
return new Promise<void>((resolve) => {
|
return new Promise<void>((resolve) => {
|
||||||
const worker = new Worker(new URL(import.meta.resolve("./build.ts")), { argv: [task] });
|
const worker = new Worker(import.meta.resolve("../lib/watch-worker.ts"), { type: "module" });
|
||||||
worker.on("exit", () => resolve());
|
worker.addEventListener("message", () => {
|
||||||
|
worker.terminate();
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
worker.postMessage({ task });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
37
deno.jsonc
Normal file
37
deno.jsonc
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"@std/io": "jsr:@std/io@^0.224.2",
|
||||||
|
"asciidoctor": "https://esm.sh/asciidoctor@^3.0.4",
|
||||||
|
"chokidar": "npm:chokidar@^3.6.0",
|
||||||
|
"cssnano": "npm:cssnano@^7.0.2",
|
||||||
|
"glob": "npm:glob@^10.4.2",
|
||||||
|
"luxon": "npm:luxon@^3.4.4",
|
||||||
|
"postcss": "npm:postcss@^8.4.38",
|
||||||
|
"postcss-import": "npm:postcss-import@^16.1.0",
|
||||||
|
"postcss-nesting": "npm:postcss-nesting@^12.1.5",
|
||||||
|
"preact": "npm:preact@^10.22.0",
|
||||||
|
"preact-render-to-string": "npm:preact-render-to-string@^6.5.5",
|
||||||
|
"rehype": "npm:rehype@^13.0.1",
|
||||||
|
"rehype-external-links": "npm:rehype-external-links@^3.0.0",
|
||||||
|
"rehype-parse": "npm:rehype-parse@^9.0.0",
|
||||||
|
"rehype-preset-minify": "npm:rehype-preset-minify@^7.0.0",
|
||||||
|
"rehype-prism": "npm:@mapbox/rehype-prism@^0.9.0",
|
||||||
|
"rehype-stringify": "npm:rehype-stringify@^10.0.0",
|
||||||
|
"rxjs": "npm:rxjs@^7.8.1",
|
||||||
|
"tmp": "npm:tmp@^0.2.3",
|
||||||
|
"unified": "npm:unified@^11.0.4",
|
||||||
|
"unist-util-visit": "npm:unist-util-visit@^5.0.0",
|
||||||
|
"vinyl": "npm:vinyl@^3.0.0"
|
||||||
|
},
|
||||||
|
"compilerOptions": {
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"jsxImportSource": "preact"
|
||||||
|
},
|
||||||
|
"fmt": {
|
||||||
|
"lineWidth": 120
|
||||||
|
},
|
||||||
|
"tasks": {
|
||||||
|
"build": "deno run -A bin/build.ts",
|
||||||
|
"watch": "deno run -A bin/watch.ts"
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,11 +20,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1717646450,
|
"lastModified": 1719379843,
|
||||||
"narHash": "sha256-KE+UmfSVk5PG8jdKdclPVcMrUB8yVZHbsjo7ZT1Bm3c=",
|
"narHash": "sha256-u+D+IOAMMl70+CJ9NKB+RMrASjInuIWMHzjLWQjPZ6c=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "818dbe2f96df233d2041739d6079bb616d3e5597",
|
"rev": "b3f3c1b13fb08f3828442ee86630362e81136bbc",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
pkgs = import nixpkgs { inherit system; };
|
pkgs = import nixpkgs { inherit system; };
|
||||||
in {
|
in {
|
||||||
devShells.default = pkgs.mkShell {
|
devShells.default = pkgs.mkShell {
|
||||||
buildInputs = with pkgs; [ nodejs_20 python312Packages.fonttools python312Packages.brotli libavif pandoc imagemagick ];
|
buildInputs = with pkgs; [ deno python312Packages.fonttools python312Packages.brotli libavif pandoc imagemagick ];
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,18 +10,13 @@ export function reloadAssets() {
|
||||||
|
|
||||||
globSync("dist/_assets/*.manifest")
|
globSync("dist/_assets/*.manifest")
|
||||||
.map(
|
.map(
|
||||||
(manifest) =>
|
(manifest) => JSON.parse(readFileSync(manifest).toString()) as { [orig: string]: string },
|
||||||
JSON.parse(readFileSync(manifest).toString()) as { [orig: string]: string },
|
|
||||||
)
|
)
|
||||||
.forEach((mapping) =>
|
.forEach((mapping) => Object.entries(mapping).forEach(([orig, hashed]) => assetMap.set(orig, hashed)));
|
||||||
Object.entries(mapping).forEach(([orig, hashed]) => assetMap.set(orig, hashed)),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function asset(path: string): string {
|
export function asset(path: string): string {
|
||||||
const realPath = assetMap.has(path) ? assetMap.get(path) : path;
|
const realPath = assetMap.has(path) ? assetMap.get(path)! : path;
|
||||||
|
|
||||||
return env.ASSETS_HOSTS
|
return env.ASSETS_HOSTS ? new URL(realPath, env.ASSETS_HOSTS).toString() : join("/_assets/", realPath);
|
||||||
? new URL(realPath, env.ASSETS_HOSTS).toString()
|
|
||||||
: join("/_assets/", realPath);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { createHash } from "node:crypto";
|
import { createHash } from "node:crypto";
|
||||||
import File from "vinyl";
|
import File from "vinyl";
|
||||||
import { PRODUCTION } from "./environment.js";
|
import { PRODUCTION } from "./environment.ts";
|
||||||
import { Observable } from "rxjs";
|
import { Observable } from "rxjs";
|
||||||
|
import { Buffer } from "node:buffer";
|
||||||
|
|
||||||
function fileHash(buffer: Buffer) {
|
function fileHash(buffer: Buffer) {
|
||||||
const hash = createHash("sha256");
|
const hash = createHash("sha256");
|
||||||
|
@ -9,9 +10,7 @@ function fileHash(buffer: Buffer) {
|
||||||
return hash.digest("hex");
|
return hash.digest("hex");
|
||||||
}
|
}
|
||||||
|
|
||||||
const hashPath =
|
const hashPath = (mappings: Map<string, string>) => (file: File): File => {
|
||||||
(mappings: Map<string, string>) =>
|
|
||||||
(file: File): File => {
|
|
||||||
const hash = PRODUCTION ? fileHash(file.contents as Buffer) : "00000000";
|
const hash = PRODUCTION ? fileHash(file.contents as Buffer) : "00000000";
|
||||||
const newName = [
|
const newName = [
|
||||||
file.basename.substring(0, file.basename.length - file.extname.length),
|
file.basename.substring(0, file.basename.length - file.extname.length),
|
||||||
|
@ -23,7 +22,7 @@ const hashPath =
|
||||||
file.basename = newName;
|
file.basename = newName;
|
||||||
|
|
||||||
return file;
|
return file;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function (manifestName: string) {
|
export default function (manifestName: string) {
|
||||||
return (observable: Observable<File>): Observable<File> =>
|
return (observable: Observable<File>): Observable<File> =>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import Postcss from "postcss";
|
import Postcss from "postcss";
|
||||||
import { reloadAssets, assetMap } from "../assets.js";
|
import { assetMap, reloadAssets } from "../assets.ts";
|
||||||
|
|
||||||
export default (): Postcss.Plugin => {
|
export default (): Postcss.Plugin => {
|
||||||
return {
|
return {
|
||||||
|
@ -8,9 +8,9 @@ export default (): Postcss.Plugin => {
|
||||||
reloadAssets();
|
reloadAssets();
|
||||||
},
|
},
|
||||||
Declaration(decl: Postcss.Declaration) {
|
Declaration(decl: Postcss.Declaration) {
|
||||||
decl.value = decl.value.replace(/url\("([^"]+)"\)/, (v, url) => {
|
decl.value = decl.value.replace(/url\("([^"]+)"\)/, (v: string, url: string) => {
|
||||||
if (assetMap.has(url)) {
|
if (assetMap.has(url)) {
|
||||||
return v.replace(url, assetMap.get(url));
|
return v.replace(url, assetMap.get(url)!);
|
||||||
}
|
}
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { Observable, Subscriber, from, mergeMap } from "rxjs";
|
import { from, mergeMap, Observable, Subscriber } from "rxjs";
|
||||||
import File from "vinyl";
|
import File from "vinyl";
|
||||||
import { readFile } from "node:fs/promises";
|
import { readFile } from "node:fs/promises";
|
||||||
import { join, dirname } from "node:path";
|
import { dirname, join } from "node:path";
|
||||||
import { existsSync } from "node:fs";
|
import { existsSync } from "node:fs";
|
||||||
import { writeFile, mkdir } from "node:fs/promises";
|
import { mkdir, writeFile } from "node:fs/promises";
|
||||||
import { Glob } from "glob";
|
import { Glob } from "glob";
|
||||||
|
|
||||||
export function dest(prefix: string) {
|
export function dest(prefix: string) {
|
||||||
|
@ -33,12 +33,11 @@ export function onComplete<T>(f: (sink: Subscriber<T>) => Promise<void>) {
|
||||||
f(subscriber);
|
f(subscriber);
|
||||||
subscriber.complete();
|
subscriber.complete();
|
||||||
},
|
},
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadFile = async (path: string): Promise<File> =>
|
const loadFile = async (path: string): Promise<File> => new File({ path, contents: await readFile(path) });
|
||||||
new File({ path, contents: await readFile(path) });
|
|
||||||
|
|
||||||
export const fromGlob = (paths: string | string[]): Observable<File> =>
|
export const fromGlob = (paths: string | string[]): Observable<File> =>
|
||||||
from(new Glob(paths, {})).pipe(mergeMap(loadFile));
|
from(new Glob(paths, {})).pipe(mergeMap(loadFile));
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { readFileSync } from "node:fs";
|
import { readFileSync } from "node:fs";
|
||||||
import { join, basename, dirname } from "node:path";
|
import { basename, dirname, join } from "node:path";
|
||||||
import asciidoctor from "asciidoctor";
|
import asciidoctor from "asciidoctor";
|
||||||
import File from "vinyl";
|
import File from "vinyl";
|
||||||
import { DateTime } from "luxon";
|
import { DateTime } from "luxon";
|
||||||
|
@ -7,21 +7,22 @@ import { unified } from "unified";
|
||||||
import rehypeParse from "rehype-parse";
|
import rehypeParse from "rehype-parse";
|
||||||
import rehypeStringify from "rehype-stringify";
|
import rehypeStringify from "rehype-stringify";
|
||||||
import rehypePresetMinify from "rehype-preset-minify";
|
import rehypePresetMinify from "rehype-preset-minify";
|
||||||
import rehypePrism from "@mapbox/rehype-prism";
|
import rehypePrism from "rehype-prism";
|
||||||
import { PRODUCTION, DEFAULT_DATE } from "../environment.js";
|
import { DEFAULT_DATE, PRODUCTION } from "../environment.ts";
|
||||||
import rehypeExternalLinks from "rehype-external-links";
|
import rehypeExternalLinks from "rehype-external-links";
|
||||||
import visit from "unist-util-visit";
|
import { visit } from "unist-util-visit";
|
||||||
import renderLayout from "../views/layout.js";
|
import renderLayout from "../views/layout.tsx";
|
||||||
import renderArticleLayout, { Article } from "../views/article.js";
|
import renderArticleLayout, { Article } from "../views/article.tsx";
|
||||||
import renderIndex from "../views/index.js";
|
import renderIndex from "../views/index.tsx";
|
||||||
import { renderToStaticMarkup } from "preact-render-to-string";
|
import { renderToStaticMarkup } from "preact-render-to-string";
|
||||||
import { SITE_TITLE, SITE_DESCRIPTION } from "../constants.js";
|
import { SITE_DESCRIPTION, SITE_TITLE } from "../constants.ts";
|
||||||
import { JSX } from "preact/jsx-runtime";
|
import { JSX } from "preact/jsx-runtime";
|
||||||
import { reloadAssets } from "../assets.js";
|
import { reloadAssets } from "../assets.ts";
|
||||||
import { lastValueFrom, mergeMap, Observable, Subscriber } from "rxjs";
|
import { lastValueFrom, mergeMap, Observable, Subscriber } from "rxjs";
|
||||||
import { dest, fromGlob, onComplete } from "../rx-utils.js";
|
import { dest, fromGlob, onComplete } from "../rx-utils.ts";
|
||||||
|
import { Buffer } from "node:buffer";
|
||||||
|
|
||||||
const Asciidoctor = (asciidoctor as unknown as () => asciidoctor.Asciidoctor)();
|
const Asciidoctor = asciidoctor();
|
||||||
const EXTENSION_REGISTRY = Asciidoctor.Extensions.create();
|
const EXTENSION_REGISTRY = Asciidoctor.Extensions.create();
|
||||||
EXTENSION_REGISTRY.inlineMacro("abbr", function () {
|
EXTENSION_REGISTRY.inlineMacro("abbr", function () {
|
||||||
this.process(function (parent, target, attributes) {
|
this.process(function (parent, target, attributes) {
|
||||||
|
@ -35,7 +36,7 @@ EXTENSION_REGISTRY.inlineMacro("abbr", function () {
|
||||||
|
|
||||||
function extractImages(sink: (image: File) => void, articlePath: string) {
|
function extractImages(sink: (image: File) => void, articlePath: string) {
|
||||||
return function () {
|
return function () {
|
||||||
return function (tree) {
|
return function (tree: any) {
|
||||||
visit(tree, "element", function (node: any) {
|
visit(tree, "element", function (node: any) {
|
||||||
if (node.tagName !== "img") {
|
if (node.tagName !== "img") {
|
||||||
return;
|
return;
|
||||||
|
@ -57,10 +58,9 @@ function renderDocument(root: JSX.Element): Buffer {
|
||||||
return Buffer.concat([Buffer.from("<!doctype html>"), Buffer.from(renderToStaticMarkup(root))]);
|
return Buffer.concat([Buffer.from("<!doctype html>"), Buffer.from(renderToStaticMarkup(root))]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const transformArticle =
|
const transformArticle = (sink: (file: File) => void, articles: Article[]) => async (file: File) => {
|
||||||
(sink: (file: File) => void, articles: Article[]) => async (file: File) => {
|
|
||||||
const slug = basename(file.path, ".asciidoc");
|
const slug = basename(file.path, ".asciidoc");
|
||||||
const document = Asciidoctor.load(file.contents.toString(), {
|
const document = Asciidoctor.load(file.contents!.toString(), {
|
||||||
extension_registry: EXTENSION_REGISTRY,
|
extension_registry: EXTENSION_REGISTRY,
|
||||||
});
|
});
|
||||||
const date = DateTime.fromISO(document.getAttribute("docdate", { zone: "UTC" }));
|
const date = DateTime.fromISO(document.getAttribute("docdate", { zone: "UTC" }));
|
||||||
|
@ -71,12 +71,12 @@ const transformArticle =
|
||||||
}
|
}
|
||||||
|
|
||||||
const vfile = await unified()
|
const vfile = await unified()
|
||||||
.use(rehypeParse)
|
.use(rehypeParse as any)
|
||||||
.use(rehypeExternalLinks, { rel: "noopener", target: "_blank" })
|
.use(rehypeExternalLinks, { rel: "noopener", target: "_blank" })
|
||||||
.use(extractImages(sink, file.path))
|
.use(extractImages(sink, file.path))
|
||||||
.use(rehypePrism)
|
.use(rehypePrism)
|
||||||
.use(rehypePresetMinify)
|
.use(rehypePresetMinify as any)
|
||||||
.use(rehypeStringify)
|
.use(rehypeStringify as any)
|
||||||
.process(document.convert());
|
.process(document.convert());
|
||||||
const content = renderLayout({
|
const content = renderLayout({
|
||||||
title: document.getDoctitle({}) as string,
|
title: document.getDoctitle({}) as string,
|
||||||
|
@ -98,7 +98,7 @@ const transformArticle =
|
||||||
|
|
||||||
articles.push(article);
|
articles.push(article);
|
||||||
sink(file);
|
sink(file);
|
||||||
};
|
};
|
||||||
|
|
||||||
const finalizeArticles = (articles: Article[]) => async (sink: Subscriber<File>) => {
|
const finalizeArticles = (articles: Article[]) => async (sink: Subscriber<File>) => {
|
||||||
articles.sort(({ date: a }, { date: b }) => b.diff(a).toMillis());
|
articles.sort(({ date: a }, { date: b }) => b.diff(a).toMillis());
|
||||||
|
@ -117,7 +117,7 @@ const finalizeArticles = (articles: Article[]) => async (sink: Subscriber<File>)
|
||||||
|
|
||||||
export const articles = () => {
|
export const articles = () => {
|
||||||
reloadAssets();
|
reloadAssets();
|
||||||
const articles = [];
|
const articles: Article[] = [];
|
||||||
|
|
||||||
return lastValueFrom(
|
return lastValueFrom(
|
||||||
fromGlob("articles/**/*.asciidoc").pipe(
|
fromGlob("articles/**/*.asciidoc").pipe(
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
import postcss, { Result } from "postcss";
|
import postcss, { Result } from "postcss";
|
||||||
import config from "../../postcss.config.js";
|
import config from "../../postcss.config.ts";
|
||||||
import { dest, fromGlob } from "../rx-utils.js";
|
import { dest, fromGlob } from "../rx-utils.ts";
|
||||||
import { lastValueFrom, mergeMap } from "rxjs";
|
import { lastValueFrom, mergeMap } from "rxjs";
|
||||||
import hashPaths from "../hash.js";
|
import hashPaths from "../hash.ts";
|
||||||
|
import File from "vinyl";
|
||||||
|
import { Buffer } from "node:buffer";
|
||||||
|
|
||||||
export const css = () =>
|
export const css = () =>
|
||||||
lastValueFrom(
|
lastValueFrom(
|
||||||
fromGlob("src/index.css").pipe(
|
fromGlob("src/index.css").pipe(
|
||||||
mergeMap(
|
mergeMap(
|
||||||
(file) =>
|
(file) =>
|
||||||
new Promise((resolve) =>
|
new Promise<File>((resolve) =>
|
||||||
postcss(config.plugins)
|
postcss(config.plugins)
|
||||||
.process(file.contents, { from: file.path })
|
.process(file.contents, { from: file.path })
|
||||||
.then((result: Result) => {
|
.then((result: Result) => {
|
||||||
|
@ -17,7 +19,7 @@ export const css = () =>
|
||||||
file.path = "index.css";
|
file.path = "index.css";
|
||||||
|
|
||||||
resolve(file);
|
resolve(file);
|
||||||
}),
|
})
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
hashPaths("css.manifest"),
|
hashPaths("css.manifest"),
|
||||||
|
|
|
@ -2,17 +2,17 @@ import File from "vinyl";
|
||||||
import tmp from "tmp";
|
import tmp from "tmp";
|
||||||
import { execFile } from "node:child_process";
|
import { execFile } from "node:child_process";
|
||||||
import { readFileSync, unlinkSync } from "node:fs";
|
import { readFileSync, unlinkSync } from "node:fs";
|
||||||
import hashPaths from "../hash.js";
|
import hashPaths from "../hash.ts";
|
||||||
import { dest, fromGlob } from "../rx-utils.js";
|
import { dest, fromGlob } from "../rx-utils.ts";
|
||||||
import { mergeMap } from "rxjs";
|
import { mergeMap } from "rxjs";
|
||||||
|
|
||||||
const FONT_PRESETS = {
|
const FONT_PRESETS: { [variant: string]: { ranges: string[] } } = {
|
||||||
mono: { ranges: ["20-7F", "2205", "2E22-2E25", "2713", "2717"] },
|
mono: { ranges: ["20-7F", "2205", "2E22-2E25", "2713", "2717"] },
|
||||||
text: { ranges: ["20-7F", "A0-FF", "2000-206F", "20AC"] },
|
text: { ranges: ["20-7F", "A0-FF", "2000-206F", "20AC"] },
|
||||||
};
|
};
|
||||||
|
|
||||||
function compileFont(font: File): Promise<File> {
|
function compileFont(font: File): Promise<File> {
|
||||||
const [, variant, weight] = /([A-Z][a-z]+)-(\w+)\.ttf$/.exec(font.basename);
|
const [, variant, weight] = /([A-Z][a-z]+)-(\w+)\.ttf$/.exec(font.basename) as string[];
|
||||||
const tmpOutput = tmp.fileSync({ discardDescriptor: true });
|
const tmpOutput = tmp.fileSync({ discardDescriptor: true });
|
||||||
const unicodes = FONT_PRESETS[variant.toLowerCase()].ranges;
|
const unicodes = FONT_PRESETS[variant.toLowerCase()].ranges;
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ function compileFont(font: File): Promise<File> {
|
||||||
]).once("exit", () => {
|
]).once("exit", () => {
|
||||||
font.path = `iosevka-adaedra-${variant.toLowerCase()}-${weight.toLowerCase()}.woff2`;
|
font.path = `iosevka-adaedra-${variant.toLowerCase()}-${weight.toLowerCase()}.woff2`;
|
||||||
font.contents = readFileSync(tmpOutput.name);
|
font.contents = readFileSync(tmpOutput.name);
|
||||||
font.base = null;
|
(font as any).base = null;
|
||||||
|
|
||||||
unlinkSync(tmpOutput.name);
|
unlinkSync(tmpOutput.name);
|
||||||
resolve(font);
|
resolve(font);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import hashPaths from "../hash.js";
|
import hashPaths from "../hash.ts";
|
||||||
import { dest, fromGlob } from "../rx-utils.js";
|
import { dest, fromGlob } from "../rx-utils.ts";
|
||||||
import { mergeMap, tap } from "rxjs";
|
import { tap } from "rxjs";
|
||||||
|
|
||||||
export const images = () =>
|
export const images = () =>
|
||||||
fromGlob("src/*.avif")
|
fromGlob("src/*.avif")
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { tap } from "rxjs";
|
import { tap } from "rxjs";
|
||||||
import { dest, fromGlob } from "../rx-utils.js";
|
import { dest, fromGlob } from "../rx-utils.ts";
|
||||||
|
|
||||||
// SVG `use` has no way of allowing cross-origin, so we need to keep them with the HTML files.
|
// SVG `use` has no way of allowing cross-origin, so we need to keep them with the HTML files.
|
||||||
export const svg = () =>
|
export const svg = () =>
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
import { register } from "node:module";
|
|
||||||
|
|
||||||
register("ts-node/esm", import.meta.url);
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Document } from "asciidoctor";
|
import { Document } from "asciidoctor";
|
||||||
import { DateTime } from "luxon";
|
import { DateTime } from "luxon";
|
||||||
import { asset } from "../assets.js";
|
import { asset } from "../assets.ts";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
article: Article;
|
article: Article;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { asset } from "../assets.js";
|
import { asset } from "../assets.ts";
|
||||||
import { Article } from "./article.js";
|
import { Article } from "./article.tsx";
|
||||||
|
|
||||||
const Header = () => (
|
const Header = () => (
|
||||||
<header class="index-header">
|
<header class="index-header">
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { SITE_DEFAULT_META, SITE_TITLE } from "../constants.js";
|
import { SITE_DEFAULT_META, SITE_TITLE } from "../constants.ts";
|
||||||
import { JSX } from "preact/jsx-runtime";
|
import { JSX } from "preact/jsx-runtime";
|
||||||
import { asset } from "../assets.js";
|
import { asset } from "../assets.ts";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
title?: string;
|
title?: string;
|
||||||
|
|
17
lib/watch-worker.ts
Normal file
17
lib/watch-worker.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import { articles } from "./tasks/articles.ts";
|
||||||
|
import { css } from "./tasks/css.ts";
|
||||||
|
import { fonts } from "./tasks/fonts.ts";
|
||||||
|
import { images } from "./tasks/images.ts";
|
||||||
|
import { svg } from "./tasks/svg.ts";
|
||||||
|
|
||||||
|
const TASKS: { [task: string]: () => Promise<void> } = { articles, css, fonts, images, svg };
|
||||||
|
|
||||||
|
self.addEventListener("message", async (message) => {
|
||||||
|
const { task } = message.data;
|
||||||
|
|
||||||
|
console.log("[start]", task);
|
||||||
|
await TASKS[task]();
|
||||||
|
console.log("[done]", task);
|
||||||
|
|
||||||
|
self.postMessage({ done: true });
|
||||||
|
});
|
5797
package-lock.json
generated
5797
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
39
package.json
39
package.json
|
@ -1,39 +0,0 @@
|
||||||
{
|
|
||||||
"name": "@adaedra/blog",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"private": true,
|
|
||||||
"type": "module",
|
|
||||||
"dependencies": {
|
|
||||||
"@mapbox/rehype-prism": "^0.9.0",
|
|
||||||
"asciidoctor": "^3.0.4",
|
|
||||||
"chokidar": "^3.6.0",
|
|
||||||
"cssnano": "^7.0.2",
|
|
||||||
"glob": "^10.4.2",
|
|
||||||
"luxon": "^3.4.4",
|
|
||||||
"postcss": "^8.4.38",
|
|
||||||
"postcss-import": "^16.1.0",
|
|
||||||
"postcss-nesting": "^12.1.5",
|
|
||||||
"preact": "^10.22.0",
|
|
||||||
"preact-render-to-string": "^6.5.5",
|
|
||||||
"rehype": "^13.0.1",
|
|
||||||
"rehype-external-links": "^3.0.0",
|
|
||||||
"rehype-preset-minify": "^7.0.0",
|
|
||||||
"rxjs": "^7.8.1",
|
|
||||||
"tmp": "^0.2.3",
|
|
||||||
"ts-node": "^10.9.2",
|
|
||||||
"unified": "^11.0.4",
|
|
||||||
"vinyl": "^3.0.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/glob": "^8.1.0",
|
|
||||||
"@types/luxon": "^3.4.2",
|
|
||||||
"@types/tmp": "^0.2.6",
|
|
||||||
"@types/vinyl": "^2.0.12",
|
|
||||||
"prettier": "^3.3.1"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"build": "node --import ./lib/ts-loader.js ./bin/build.ts",
|
|
||||||
"watch": "node --import ./lib/ts-loader.js ./bin/watch.ts",
|
|
||||||
"dev": "python -m http.server -d dist"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +1,8 @@
|
||||||
import importPlugin from "postcss-import";
|
import importPlugin from "postcss-import";
|
||||||
import nestingPlugin from "postcss-nesting";
|
import nestingPlugin from "postcss-nesting";
|
||||||
import cssnanoPlugin from "cssnano";
|
import cssnanoPlugin from "cssnano";
|
||||||
import hashesPlugin from "./lib/postcss/hashes.js";
|
import hashesPlugin from "./lib/postcss/hashes.ts";
|
||||||
|
|
||||||
/** @type {import('postcss-load-config').Config} */
|
|
||||||
export default {
|
export default {
|
||||||
plugins: [
|
plugins: [
|
||||||
importPlugin(),
|
importPlugin(),
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"jsx": "react-jsx",
|
|
||||||
"jsxImportSource": "preact",
|
|
||||||
"module": "NodeNext",
|
|
||||||
"moduleResolution": "NodeNext",
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user