From c12dee20372c6557d6bc7e7d3bc35cf3822c7df5 Mon Sep 17 00:00:00 2001 From: Graham Barber Date: Thu, 7 Aug 2025 23:35:23 +0000 Subject: [PATCH] build(core): introduce script `dev` command --- deno.json | 21 +++- deno.lock | 276 ++++++++++++++++++++++++++++++++++++++++++++++++- scripts/dev.ts | 100 ++++++++++++++++++ 3 files changed, 392 insertions(+), 5 deletions(-) create mode 100644 scripts/dev.ts diff --git a/deno.json b/deno.json index d78feb8..283f026 100644 --- a/deno.json +++ b/deno.json @@ -1,15 +1,32 @@ { "tasks": { - "dev": "deno run --unstable-broadcast-channel --allow-env --allow-net --allow-read --allow-write --watch main.ts dev", - "build": "deno run --allow-env --allow-read --allow-write main.ts build" + "build": "deno run --allow-env --allow-read --allow-write main.ts build", + "dev": "deno run --allow-env --allow-run --allow-read --allow-write scripts/dev.ts", + "dev:core": "deno run --unstable-broadcast-channel --allow-env --allow-net --allow-read --allow-write --watch main.ts dev ./slides.mdoc", + "dev:runtime": "deno bundle --outdir dist --platform browser runtime/morkdeck.ts" + }, + "compilerOptions": { + "lib": [ + "dom", + "dom.iterable", + "dom.asynciterable", + "deno.ns", + "deno.unstable" + ] }, "imports": { "@cliffy/command": "jsr:@cliffy/command@1.0.0-rc.8", + "@deno/esbuild-plugin": "jsr:@deno/esbuild-plugin@^1.1.5", "@eta-dev/eta": "jsr:@eta-dev/eta@^3.5.0", "@markdoc/markdoc": "https://esm.sh/@markdoc/markdoc@0.5.2", "@std/assert": "jsr:@std/assert@1", + "@std/async": "jsr:@std/async@^1.0.14", + "@std/http": "jsr:@std/http@^1.0.20", + "@std/path": "jsr:@std/path@^1.1.1", + "esbuild": "npm:esbuild@^0.25.8", "hast": "npm:@types/hast@^3.0.4", "hast-util-is-element": "npm:hast-util-is-element@^3.0.0", + "lit": "npm:lit@^3.3.1", "shiki": "npm:shiki@^3.8.1" } } diff --git a/deno.lock b/deno.lock index b52d035..04c773b 100644 --- a/deno.lock +++ b/deno.lock @@ -5,15 +5,31 @@ "jsr:@cliffy/flags@1.0.0-rc.8": "1.0.0-rc.8", "jsr:@cliffy/internal@1.0.0-rc.8": "1.0.0-rc.8", "jsr:@cliffy/table@1.0.0-rc.8": "1.0.0-rc.8", + "jsr:@deno/esbuild-plugin@^1.1.5": "1.1.5", + "jsr:@deno/loader@~0.3.3": "0.3.4", "jsr:@eta-dev/eta@^3.5.0": "3.5.0", "jsr:@std/assert@1": "1.0.13", + "jsr:@std/async@^1.0.14": "1.0.14", + "jsr:@std/cli@^1.0.21": "1.0.21", + "jsr:@std/encoding@^1.0.10": "1.0.10", + "jsr:@std/fmt@^1.0.8": "1.0.8", "jsr:@std/fmt@~1.0.2": "1.0.8", + "jsr:@std/fs@^1.0.19": "1.0.19", + "jsr:@std/html@^1.0.4": "1.0.4", + "jsr:@std/http@^1.0.20": "1.0.20", "jsr:@std/internal@^1.0.6": "1.0.9", + "jsr:@std/internal@^1.0.9": "1.0.9", + "jsr:@std/media-types@^1.1.0": "1.1.0", + "jsr:@std/net@^1.0.4": "1.0.4", + "jsr:@std/path@^1.1.1": "1.1.1", + "jsr:@std/streams@^1.0.10": "1.0.10", "jsr:@std/text@~1.0.7": "1.0.15", "npm:@markdoc/markdoc@*": "0.5.2", "npm:@types/hast@^3.0.4": "3.0.4", "npm:@types/node@*": "22.15.15", + "npm:esbuild@~0.25.8": "0.25.8", "npm:hast-util-is-element@3": "3.0.0", + "npm:lit@^3.3.1": "3.3.1", "npm:shiki@^3.8.1": "3.8.1" }, "jsr": { @@ -23,7 +39,7 @@ "jsr:@cliffy/flags", "jsr:@cliffy/internal", "jsr:@cliffy/table", - "jsr:@std/fmt", + "jsr:@std/fmt@~1.0.2", "jsr:@std/text" ] }, @@ -39,29 +55,222 @@ "@cliffy/table@1.0.0-rc.8": { "integrity": "8bbcdc2ba5e0061b4b13810a24e6f5c6ab19c09f0cce9eb691ccd76c7c6c9db5", "dependencies": [ - "jsr:@std/fmt" + "jsr:@std/fmt@~1.0.2" ] }, + "@deno/esbuild-plugin@1.1.5": { + "integrity": "c9cde95990b97802a0da6c73c26ab4a48f30d286818845e365dddcd8297abd7d", + "dependencies": [ + "jsr:@deno/loader", + "jsr:@std/path" + ] + }, + "@deno/loader@0.3.4": { + "integrity": "c56003bc7027606301c3fe62704723b207a9e508c9fb154cf5131abb9d4d2673" + }, "@eta-dev/eta@3.5.0": { "integrity": "6b70827efc14c7cbf08498ac7a922ecab003641caf3852a6cb5b1b12ee58fb37" }, "@std/assert@1.0.13": { "integrity": "ae0d31e41919b12c656c742b22522c32fb26ed0cba32975cb0de2a273cb68b29", "dependencies": [ - "jsr:@std/internal" + "jsr:@std/internal@^1.0.6" ] }, + "@std/async@1.0.14": { + "integrity": "62e954a418652c704d37563a3e54a37d4cf0268a9dcaeac1660cc652880b5326" + }, + "@std/cli@1.0.21": { + "integrity": "cd25b050bdf6282e321854e3822bee624f07aca7636a3a76d95f77a3a919ca2a" + }, + "@std/encoding@1.0.10": { + "integrity": "8783c6384a2d13abd5e9e87a7ae0520a30e9f56aeeaa3bdf910a3eaaf5c811a1" + }, "@std/fmt@1.0.8": { "integrity": "71e1fc498787e4434d213647a6e43e794af4fd393ef8f52062246e06f7e372b7" }, + "@std/fs@1.0.19": { + "integrity": "051968c2b1eae4d2ea9f79a08a3845740ef6af10356aff43d3e2ef11ed09fb06" + }, + "@std/html@1.0.4": { + "integrity": "eff3497c08164e6ada49b7f81a28b5108087033823153d065e3f89467dd3d50e" + }, + "@std/http@1.0.20": { + "integrity": "b5cc33fc001bccce65ed4c51815668c9891c69ccd908295997e983d8f56070a1", + "dependencies": [ + "jsr:@std/cli", + "jsr:@std/encoding", + "jsr:@std/fmt@^1.0.8", + "jsr:@std/fs", + "jsr:@std/html", + "jsr:@std/media-types", + "jsr:@std/net", + "jsr:@std/path", + "jsr:@std/streams" + ] + }, "@std/internal@1.0.9": { "integrity": "bdfb97f83e4db7a13e8faab26fb1958d1b80cc64366501af78a0aee151696eb8" }, + "@std/media-types@1.1.0": { + "integrity": "c9d093f0c05c3512932b330e3cc1fe1d627b301db33a4c2c2185c02471d6eaa4" + }, + "@std/net@1.0.4": { + "integrity": "2f403b455ebbccf83d8a027d29c5a9e3a2452fea39bb2da7f2c04af09c8bc852" + }, + "@std/path@1.1.1": { + "integrity": "fe00026bd3a7e6a27f73709b83c607798be40e20c81dde655ce34052fd82ec76", + "dependencies": [ + "jsr:@std/internal@^1.0.9" + ] + }, + "@std/streams@1.0.10": { + "integrity": "75c0b1431873cd0d8b3d679015220204d36d3c7420d93b60acfc379eb0dc30af" + }, "@std/text@1.0.15": { "integrity": "91f5cc1e12779a3d95f1be34e763f9c28a75a078b7360e6fcaef0d8d9b1e3e7f" } }, "npm": { + "@esbuild/aix-ppc64@0.25.8": { + "integrity": "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==", + "os": ["aix"], + "cpu": ["ppc64"] + }, + "@esbuild/android-arm64@0.25.8": { + "integrity": "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==", + "os": ["android"], + "cpu": ["arm64"] + }, + "@esbuild/android-arm@0.25.8": { + "integrity": "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==", + "os": ["android"], + "cpu": ["arm"] + }, + "@esbuild/android-x64@0.25.8": { + "integrity": "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==", + "os": ["android"], + "cpu": ["x64"] + }, + "@esbuild/darwin-arm64@0.25.8": { + "integrity": "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==", + "os": ["darwin"], + "cpu": ["arm64"] + }, + "@esbuild/darwin-x64@0.25.8": { + "integrity": "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==", + "os": ["darwin"], + "cpu": ["x64"] + }, + "@esbuild/freebsd-arm64@0.25.8": { + "integrity": "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==", + "os": ["freebsd"], + "cpu": ["arm64"] + }, + "@esbuild/freebsd-x64@0.25.8": { + "integrity": "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==", + "os": ["freebsd"], + "cpu": ["x64"] + }, + "@esbuild/linux-arm64@0.25.8": { + "integrity": "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==", + "os": ["linux"], + "cpu": ["arm64"] + }, + "@esbuild/linux-arm@0.25.8": { + "integrity": "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==", + "os": ["linux"], + "cpu": ["arm"] + }, + "@esbuild/linux-ia32@0.25.8": { + "integrity": "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==", + "os": ["linux"], + "cpu": ["ia32"] + }, + "@esbuild/linux-loong64@0.25.8": { + "integrity": "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==", + "os": ["linux"], + "cpu": ["loong64"] + }, + "@esbuild/linux-mips64el@0.25.8": { + "integrity": "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==", + "os": ["linux"], + "cpu": ["mips64el"] + }, + "@esbuild/linux-ppc64@0.25.8": { + "integrity": "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==", + "os": ["linux"], + "cpu": ["ppc64"] + }, + "@esbuild/linux-riscv64@0.25.8": { + "integrity": "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==", + "os": ["linux"], + "cpu": ["riscv64"] + }, + "@esbuild/linux-s390x@0.25.8": { + "integrity": "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==", + "os": ["linux"], + "cpu": ["s390x"] + }, + "@esbuild/linux-x64@0.25.8": { + "integrity": "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==", + "os": ["linux"], + "cpu": ["x64"] + }, + "@esbuild/netbsd-arm64@0.25.8": { + "integrity": "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==", + "os": ["netbsd"], + "cpu": ["arm64"] + }, + "@esbuild/netbsd-x64@0.25.8": { + "integrity": "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==", + "os": ["netbsd"], + "cpu": ["x64"] + }, + "@esbuild/openbsd-arm64@0.25.8": { + "integrity": "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==", + "os": ["openbsd"], + "cpu": ["arm64"] + }, + "@esbuild/openbsd-x64@0.25.8": { + "integrity": "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==", + "os": ["openbsd"], + "cpu": ["x64"] + }, + "@esbuild/openharmony-arm64@0.25.8": { + "integrity": "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==", + "os": ["openharmony"], + "cpu": ["arm64"] + }, + "@esbuild/sunos-x64@0.25.8": { + "integrity": "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==", + "os": ["sunos"], + "cpu": ["x64"] + }, + "@esbuild/win32-arm64@0.25.8": { + "integrity": "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==", + "os": ["win32"], + "cpu": ["arm64"] + }, + "@esbuild/win32-ia32@0.25.8": { + "integrity": "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==", + "os": ["win32"], + "cpu": ["ia32"] + }, + "@esbuild/win32-x64@0.25.8": { + "integrity": "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==", + "os": ["win32"], + "cpu": ["x64"] + }, + "@lit-labs/ssr-dom-shim@1.4.0": { + "integrity": "sha512-ficsEARKnmmW5njugNYKipTm4SFnbik7CXtoencDZzmzo/dQ+2Q0bgkzJuoJP20Aj0F+izzJjOqsnkd6F/o1bw==" + }, + "@lit/reactive-element@2.1.1": { + "integrity": "sha512-N+dm5PAYdQ8e6UlywyyrgI2t++wFGXfHx+dSJ1oBrg6FAxUj40jId++EaRm80MKX5JnlH1sBsyZ5h0bcZKemCg==", + "dependencies": [ + "@lit-labs/ssr-dom-shim" + ] + }, "@markdoc/markdoc@0.5.2": { "integrity": "sha512-clrqWpJ3+S8PXigRE+zBIs6LVZYXaJ7JTDFq1CcCWc4xpoB2kz+9qRUQQ4vXtLUjQ8ige1BGdMruV6gM/2gloA==", "optionalDependencies": [ @@ -176,6 +385,39 @@ "dequal" ] }, + "esbuild@0.25.8": { + "integrity": "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==", + "optionalDependencies": [ + "@esbuild/aix-ppc64", + "@esbuild/android-arm", + "@esbuild/android-arm64", + "@esbuild/android-x64", + "@esbuild/darwin-arm64", + "@esbuild/darwin-x64", + "@esbuild/freebsd-arm64", + "@esbuild/freebsd-x64", + "@esbuild/linux-arm", + "@esbuild/linux-arm64", + "@esbuild/linux-ia32", + "@esbuild/linux-loong64", + "@esbuild/linux-mips64el", + "@esbuild/linux-ppc64", + "@esbuild/linux-riscv64", + "@esbuild/linux-s390x", + "@esbuild/linux-x64", + "@esbuild/netbsd-arm64", + "@esbuild/netbsd-x64", + "@esbuild/openbsd-arm64", + "@esbuild/openbsd-x64", + "@esbuild/openharmony-arm64", + "@esbuild/sunos-x64", + "@esbuild/win32-arm64", + "@esbuild/win32-ia32", + "@esbuild/win32-x64" + ], + "scripts": true, + "bin": true + }, "hast-util-is-element@3.0.0": { "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", "dependencies": [ @@ -207,6 +449,28 @@ "html-void-elements@3.0.0": { "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==" }, + "lit-element@4.2.1": { + "integrity": "sha512-WGAWRGzirAgyphK2urmYOV72tlvnxw7YfyLDgQ+OZnM9vQQBQnumQ7jUJe6unEzwGU3ahFOjuz1iz1jjrpCPuw==", + "dependencies": [ + "@lit-labs/ssr-dom-shim", + "@lit/reactive-element", + "lit-html" + ] + }, + "lit-html@3.3.1": { + "integrity": "sha512-S9hbyDu/vs1qNrithiNyeyv64c9yqiW9l+DBgI18fL+MTvOtWoFR0FWiyq1TxaYef5wNlpEmzlXoBlZEO+WjoA==", + "dependencies": [ + "@types/trusted-types" + ] + }, + "lit@3.3.1": { + "integrity": "sha512-Ksr/8L3PTapbdXJCk+EJVB78jDodUMaP54gD24W186zGRARvwrsPfS60wae/SSCTCNZVPd1chXqio1qHQmu4NA==", + "dependencies": [ + "@lit/reactive-element", + "lit-element", + "lit-html" + ] + }, "mdast-util-to-hast@13.2.0": { "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", "dependencies": [ @@ -365,10 +629,16 @@ "workspace": { "dependencies": [ "jsr:@cliffy/command@1.0.0-rc.8", + "jsr:@deno/esbuild-plugin@^1.1.5", "jsr:@eta-dev/eta@^3.5.0", "jsr:@std/assert@1", + "jsr:@std/async@^1.0.14", + "jsr:@std/http@^1.0.20", + "jsr:@std/path@^1.1.1", "npm:@types/hast@^3.0.4", + "npm:esbuild@~0.25.8", "npm:hast-util-is-element@3", + "npm:lit@^3.3.1", "npm:shiki@^3.8.1" ] } diff --git a/scripts/dev.ts b/scripts/dev.ts new file mode 100644 index 0000000..2accb2b --- /dev/null +++ b/scripts/dev.ts @@ -0,0 +1,100 @@ +import * as esbuild from "esbuild"; +import { globToRegExp } from "@std/path"; +import { denoPlugin } from "@deno/esbuild-plugin"; +import { debounce } from "@std/async/debounce"; + +const devCommand = new Deno.Command(Deno.execPath(), { + args: [ + "run", + "--unstable-broadcast-channel", + "--allow-env", + "--allow-read", + "--allow-net", + "main.ts", + "dev", + "./slides.mdoc", + ], +}); + +// Watch esbuild watching `runtime/` +async function rebuildRuntime() { + const context = await esbuild.context({ + entryPoints: ["runtime/morkdeck.ts"], + outfile: "dist/morkdeck.js", + bundle: true, + plugins: [denoPlugin()], + }); + + await context.rebuild(); + + return context; +} + +async function dev() { + const watcher = Deno.watchFs("."); + + // Runtime goes first to Morkdeck can serve the output + const ctx = await rebuildRuntime(); + let child = devCommand.spawn(); + + const runtimeGlob = globToRegExp("**/runtime/**/*.ts"); + const rebuild = debounce(async () => { + performance.mark("rebuild-start"); + await ctx.rebuild(); + performance.mark("rebuild-finish"); + const { duration } = performance.measure( + "rebuild-duration", + "rebuild-start", + "rebuild-finish", + ); + + console.log( + `runtime: change detected. rebuilt in ${duration.toFixed(0)}ms`, + ); + }, 150); + + const coreGlob = globToRegExp("**/{core,server,cli}/**/*.ts"); + const restart = debounce(() => { + performance.mark("restart-start"); + child.kill(); + child = devCommand.spawn(); + performance.mark("restart-finish"); + const { duration } = performance.measure( + "restart-duration", + "restart-start", + "restart-finish", + ); + + console.log( + ` core: change detected. restarted in ${duration.toFixed(0)}ms`, + ); + }, 150); + + async function handleEvents() { + for await (const e of watcher) { + if (e.kind === "any" || e.kind === "access" || e.kind === "other") { + continue; + } + + if (e.paths.some((s) => runtimeGlob.test(s))) { + rebuild(); + } + + if (e.paths.some((s) => coreGlob.test(s))) { + restart(); + } + } + } + + handleEvents(); + + Deno.addSignalListener("SIGINT", async () => { + await Promise.all([ + watcher.close(), + child.kill(), + ctx.dispose(), + ]); + }); +} + +if (import.meta.main) await dev(); -- 2.51.2